Kaigi on Railsでリモートワークについて発表しました

Kaigi on Railsにて「快適なリモートワークを実現するために〜RailsでSSOを実現する3パターン」というタイトルで発表しましたshimojuです。無事燃え尽きていましたが、遅ればせながら感想ブログを書きました。

資料はこちらです。動画については順次公開中なのでそのうちアップされるはずです。

初めてのオンライン登壇ですが、特にトラブルなく終えられて一安心でした。当日の配信環境については上に書いてありますが、事前に練習会があり、Zoomの画面共有やYouTube配信側でどう見えるかのテストができたのがよかったです。これがなかったら当日かなり焦っていました。

発表では会社特有の事情などもあるためどう説明すればいいか悩む箇所もありましたが、単にSAMLでSSOしました、というだけでなく、内部統制上の要件を検討してSSOを選択したこと、その実装のパターン、それを支える運用としてPull Requestを通した承認管理など、どのような考えのもとにやっていったかを説明するようにしました。
10分枠のため思い切って具体的なコードは省略しましたが、予想より好意的な反応があってありがたかったです。セキュリティや統制に関しては実装だけではすまないことが多いため参考になれば幸いです。

実はプロポーザルは2通応募していて、もうひとつを気合入れて書いて20分枠にしていたためこっちは10分枠にしようかな〜と気軽に選んだらこちらが採択となった…という経緯があります。
発表練習をしたところ10分を余裕でオーバーしたのである程度台本を作り、本番では9分でまとめのスライドまで来れたので余裕をもって締めることができました。20分枠にしておけばよかったと後悔していますが、言いたいことを凝縮して話せたかなとは思います。

発表スライドにScrapboxを使う

今回は発表スライドにScrapboxのプレゼンテーションモードを利用しました。最近の社内勉強会などではスライド作成に時間をかけずにScrapboxでさっと発表することが多く、大きなイベントですが挑戦的にこれでやってみることにしました。

オンライン登壇においては個々人それぞれのディスプレイで見るので視認性にそこまで気を使う必要がなく、かわりに資料としての参照性や再利用性を高めたほうがよいのではという考えもありました。スライドアップロードサイトではテキストのコピーやリンクが不便なため、テキストとして読める資料がそのままスライド形式にできるScrapboxは便利です。
直前にTwitterで資料を流したり、発表冒頭で資料URLを案内したりなどの工夫もしてみました。

実際に使ってみて、問題なく発表はできるもののやはりちょっと不格好な印象は拭えないですね。しかし画像を多数使ったりレイアウトにこだわるものでなければ有力なオンライン発表方法にできそうな手応えはありました。

感謝

直前まで準備をしててあまり聞けなかった発表もありましたが、バリエーション豊かな発表で楽しかったです。

OBS Studioで画面を作ってYouTube Liveで配信する本格的な配信環境や、幕間の廊下でやる雑談の雰囲気を再現するべく懇親会以外もSpatialChatが開放されていたりなど、初開催とは思えない工夫が凝らされていて感心しました。スタッフ、登壇者、そして参加者の皆様ありがとうございました!

最後に、Kaigi on RailsのグッズはSUZURIにてまだ販売しているのでぜひよろしくお願いします!!
https://suzuri.jp/kaigionrails


2019年にやったゲーム:ポケモン、モンハン、そしてスマブラ

GMOペパボ Advent Calendar 2019の7日目の記事です。

今回はまったく技術と関係なく、今年やったゲームについて書きます。

ポケットモンスター ソード・シールド

部署のみんながポケモン大好きなので買っちゃいました。SUZURI Advent Calendarでもポケモンの話が出るんじゃないかと思います。

ポケモンは第三世代(ルビー・サファイア)までしかやってないので久しぶりのポケモンです。一応ピカブイも買ってましたがあれは初代のリメイクだしシステムだいぶ違うし…。
とはいえ技が4つなのは変わりないし、「もちもの」はもう第二世代にあったし、「とくせい」「せいかく」も第三世代からだし、システムとしてはあまり変わってないですね。その組み合わせがとてつもなく増えたって感じ。

道中のポケモンすべて捕まえてたら全然進まなくて、ワイルドエリアに吸い込まれながらようやくバッジ7個まで来ました。バトルより捕まえるほうが楽しいお年頃になってしまった。

モンスターハンターワールド:アイスボーン

前作のモンスターハンター:ワールドを買ったときはゲーム自体数年ぶりで、部署の人に誘われて買ったらすっかりハマってしまいました。そこからSwitchも買ったし、ゲーマー魂を思い出すきっかけになったやつですね。

当然拡張コンテンツのアイスボーンも買い、ようやくマスターランク100まで到達して一通りのモンスターを倒すところまでいけました。
武器は操虫棍、太刀、ランスと最近は狩猟笛にハマり始めています。味方サポートしてる感すごいし気絶取れるし演奏音も凝っててたのしい。旋律覚えるのちょっと大変だけど。

あとはちょこちょこやるだけかなあと思ってたら新モンスターのゼノ・ジーヴァ成体と覚醒武器も発表されて!?って感じ。年末年始は忙しくなりそうです。
お金は子供のときより増えたけど、ひとつのゲームをやりこみがちなのは変わっていない…。

大乱闘スマッシュブラザーズ SPECIAL

昨年発売ですが、今年一番やった、というか真面目にやったやつ。

スマブラはパーティーゲームとしてやったことはありますが自分で買ったことはなくて、最弱の人生を歩んできたのでちょっとは強くなろうと思って買いました。
キャラ出しに大苦戦していたくらいの初心者でしたが、グループ会社内での大会が行われてそれに出たのをきっかけに、週1回は社のスマブラ勢でトレーニングをしたりしてます。

大会の雰囲気はこんな感じでした。「リュカのミラーマッチで場が湧き」がわたしです。

スマツク!という企業対抗戦にも出場しました。こっちは予選敗退で実力不足を痛感。


ゲームのおかげで部署外や社外の人とも交流できて面白いです。やっぱり仲間がいるって楽しいですね。
来年は何やろうかなー


2019年、SUZURIの怪事件

SUZURI Advent Calendar 2019の5日目の記事です。ちょっと遅れました。

SUZURIでエンジニアをしているしもじゅーです。最近はSUZURIのAndroidアプリを開発するために目下勉強中で、Android何もわからない…となっています。

今年自分が担当したのは目に見えない裏側部分や長い調査を必要としたものが多かったです。謎の不具合にも悩まされたのでそこからいくつか紹介します。
ご迷惑をおかけしたものもありますが、裏側ではこんなことやっているんだ、と感じていただければ幸いです。

祝日消滅事件

SUZURIの商品の納期は「○営業日」となっているため、発送予定日を算出するときは土日祝日を考慮する必要があります。
日本の祝日をリスト化しているholiday_jpという便利なライブラリがあるのですが、あるときから動作がおかしくなり、祝日のはずなのに祝日ではないという判定になってしまいました。
このままでは祝日が存在しないブラックな世界が訪れてしまうので調査して原因を特定し、無事祝日を取り戻すことができました。

原因はObject#to_msgpackを独自に定義していたせいで、bootsnapのYAMLキャッシュが意図通り動作しなくなり、デコードしたときに元のDateオブジェクトに復元できなくなっていた…ということなのですが、詳しいことは別記事で書ければと思います。

画像合成サーバを過保護にしていた

SUZURIではアップロードされた画像をアイテムに合成して、実物さながらのサムネイル画像を作っています。
キャンペーンなどでアクセス数が増えた際に、サーバの負荷自体はそれほどでもないのにエラーが多発する、という問題がありました。

これは突発的なアクセス急増から保護するために数年前に設定された制限(Nginxのlimit_conn)が残っており、サーバ台数が増えて実際には余裕がある今もエラーを返していた、という過保護なものでした。こういう設定は定期的に見直さないといけないですね。

ステッカーでだけ追加サムネイル画像が出ない

アイテムによっては正面以外にもいくつかのアングルからの画像を用意していますが、iOSアプリでステッカーだけ追加画像が出ない不具合がありました。

これはアプリの問題ではなくAPI側の問題で、設定値をArray#delete_ifで破壊的に操作している箇所があり、そのせいでステッカーの追加画像の設定が抜け落ちてしまうというバグでした。破壊的操作よくない。

HTMLメール空っぽ問題

これまでSUZURIから送られるメールはテキスト形式のみでしたが、5月頃からHTMLメールの対応を進め、7月頃にほぼすべてのメールをHTMLメール化しました。
作業自体はデザイナーが爆速で進めてくれたのですが、時間がかかったのはたまに本文が空のメールが送られてしまう問題があり一旦差し止めていたためです。ご迷惑をおかけいたしました。

これはHTMLメール作成に使っていたmjmlがメモリを消費しすぎてkillされていたが、mjml-railsでのハンドリングが甘く例外を返さずに正常終了していたためで、サーバの増強とメール送信前に本文が空でないかチェックしてリトライさせるようにして解決しました。こちらも詳しい記事をどこかで書ければと思います。

これによってメール内に画像を差し込むなど、よりわかりやすく情報を見渡しやすいメールを作れるようになりました。
例えばズッキュンお祝いメールにはかわいいGIF画像のついたHTMLメールが送られるようになっています。どう動くかは5回ズッキュンされてからのお楽しみ。


2020年はついにAndroidアプリのリリースを予定しています。ご期待ください。


Herokuでzip_code_jp gemの郵便番号データを定期更新したい

日本の郵便番号データを扱うRuby gemとしてはzip_code_jpが有名です。ECサイトなどでは郵便番号から住所を補完する機能はもはや当たり前になっていますが、そのような機能を作りたいときに便利なライブラリです。

この郵便番号データはZipCodeJp.export_jsonで更新できますが、このときgemのdata/zip_codeディレクトリ内にあるJSONファイルを直接更新します。
一般的なサーバ環境であればcronで回すなどすれば普通に更新できますが、Herokuの場合はローカルにファイルを書き込んでも再起動のタイミングで自動で消滅します。Heroku Schedulerなどで定期実行しても、既にパッケージされたslug内のデータは変更できないので意味がありません。
Release Phaseでいけないかな?とも思いましたが、Release Phaseはslugのビルド後に実行されるのでこれも使えません。

どうしようかなと考えた結果、デプロイ時に更新処理を実行するようにして、slugに最新の郵便番号データを入れてあげることにしました。

lib/tasks以下に適当な名前でRakeタスクを作り、以下のように書きます。

1
2
3
4
5
6
# lib/tasks/heroku_deploy.rake
Rake::Task['assets:precompile'].enhance do
Rails.logger.info 'Update zip code data'
ZipCodeJp.export_json
Rails.logger.info 'Done!'
end

任意のタスクのあとに別のタスクを実行するため、Rake::Task#enhanceを使っています。ドキュメントには「自身に事前タスクとアクションを追加します。」としか書かれておらず使い方がわかりにくいですが、enhanceの引数に指定したタスクは事前に実行され、ブロック内に記述したタスクは事後に実行されます

Herokuへのデプロイ時にはassets:precompileが毎回実行されるので、Rake::Task['assets:precompile'].enhanceとすることで、デプロイ時に任意のタスクを実行できるようになります。ここで郵便番号データを更新するようにしました。
郵便番号データ更新に限らず、デプロイ時に実行したい処理があれば同じように書けます。

更新にかかる時間は約20秒でした。少し時間はかかりますが、デプロイのたびに最新の郵便番号データを含めることができるので安心ですね。

1
2
remote:        I, [2018-08-28T17:24:33.195355 #823]  INFO -- : Update zip code data
remote: I, [2018-08-28T17:24:55.116512 #823] INFO -- : Done!

(もし毎回実行されるのが気に入らなければ、前回の実行日をどこかに覚えておくとか、日付を見て○日にのみ実行する…といった方法が考えられます)


Sidekiq + Heroku RedisでERROR: ERR max number of clients reachedと言われたら

Redisの同時接続数制限が原因です。

Sidekiqのconcurrencyのデフォルトは25となっており、Redisにもその数だけ接続するため、デフォルトのままだと一気に25接続を消費します。Heroku RedisのHobby Dev(接続数制限20)のような低価格なプランでは、concurrencyの設定をせずにデプロイすると一瞬でログがエラーまみれになってしまうので注意しましょう……。

上記Wikiにもあるように、変更するにはsidekiq.ymlに以下のように書きます。RAILS_ENVごとに切り替えることもできます。

1
2
3
4
5
:concurrency: 5
staging:
:concurrency: 10
production:
:concurrency: 20

HerokuのRelease PhaseでDBマイグレーション忘れを防ぐ

HerokuにはRelease Phaseという機能があります。
これはアプリケーションのビルドが終わってリリースする直前に任意のコマンドを実行するもので、DBのマイグレーションやキャッシュの削除といった用途に使えます。

設定方法はProcfilerelease: commandの形式で書くだけです。例えば、Railsでmigrateとseed-fuを実行するのであれば以下のようになります。

1
2
release: bin/rails db:migrate db:seed_fu
web: bundle exec puma -C config/puma.rb

DBマイグレーションを忘れて500エラーはあるあるな話ですが、これで防ぐことができます。
コマンドが失敗したとき(0以外のステータスで終了したとき)はもちろんデプロイは行われません。

Herokuはかゆいところに手が届いて便利ですね。


WerckerでRailsアプリをCIしてSlack通知する

オラクルに買収されてから存在感が薄くなった(?)ような気がするWerckerですが、使う機会があったのでRailsでの設定をメモしておきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# wercker.yml
box:
id: ruby:2.5.1

services:
- id: mysql:5.7
env:
# rails-database-yml stepはrootユーザーを使わないのでランダムパスワードにしておく
MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
# 以下の3つを設定する必要がある
MYSQL_DATABASE: rails_test
MYSQL_USER: rails
MYSQL_PASSWORD: password

- id: redis:4

build:
steps:
# Node.jsは入っていないのでインストールする
- script:
name: install node.js
code: curl -fsSL https://deb.nodesource.com/setup_8.x | bash - && apt-get install -qq nodejs
# bundleのキャッシュもしてくれる
# https://github.com/wercker/step-bundle-install
- bundle-install
# 自動的にdatabase.ymlの設定をしてくれる
# https://github.com/wercker/step-rails-database-yml
- rails-database-yml
- script:
name: copy .env
code: cp .env.sample .env
# Redisの接続先この方法でしか取れなかったけどもっといい方法ありそう
- script:
name: redis config
code: echo REDIS_URL=redis://$REDIS_PORT_6379_TCP_ADDR:$REDIS_PORT_6379_TCP_PORT >> .env
- script:
name: db setup
code: bundle exec rails db:schema:load db:seed_fu
- script:
name: rspec
code: bundle exec rspec

after-steps:
# Slack通知
# https://github.com/wercker/step-slack
- slack-notifier:
# 環境変数で設定
url: $SLACK_WEBHOOK_URL
channel: channel_name
username: wercker

環境変数はWeb画面上で設定し、wercker.yml内では$変数名で参照します。「Protected」にすると設定値が見えなくなるので、秘匿情報を設定するときに便利です。


better_errorsがやたら遅いときは最新版にアップデートするとよい

better_errorsが入ったRailsプロジェクトを最近触っているのですが、エラー画面の表示がやたら遅く、コンソールが使い物にならない状態になっていました。
Puma 3系で発生しており、リクエスト・レスポンス変数内のpuma.configのサイズが非常に大きく、通信に時間がかかってしまっているからのようです。

この対策として、最新バージョンの2.4.0(2017年10月リリース)でサイズの大きいインスタンス変数をフィルタする機能が追加されていました。フィルタ設定はデフォルトで有効なので、最新版にアップデートすればいい感じになります。

1
2
3
4
5
6
7
# e.g. in config/initializers/better_errors.rb
# This will stop BetterErrors from trying to render larger objects, which can cause
# slow loading times and browser performance problems. Stated size is in characters and refers
# to the length of #inspect's payload for the given object. Please be aware that HTML escaping
# modifies the size of this payload so setting this limit too precisely is not recommended.
# default value: 100_000
BetterErrors.maximum_variable_inspect_size = 100_000

最近ではweb-consoleがあるのでbetter_errorsをやめることも検討したのですが、これで快適に使えるようになりました。


Scrapboxでリアルタイム共同日報をやってみた

この記事はGMOペパボ Advent Calendar 2017の17日目……になる予定だった記事です。
担当日に風邪を引いてしまって穴を空けてしまいましたが、なんとか年内に投稿してギリギリセーフの雰囲気を出していこうと思います😇

朝会の機能不全

どのようなチームでも、人数が増えてくると「誰が何やってるのかわからない」という状況は起こるのではないかと思います。そのための情報共有の場として朝会はよく実施されていますが、自分のチームでは有効に機能していない状態でした。

  • 当初は朝会をやっていたが、チーム6人中フレックス勤務対象者が2人おり、その時間に出勤していないことが多々ある
  • 今度は夕会にしたが、会議がその時刻に入って欠席者が出たり、作業に集中していると夕会のことを忘れたりする
  • その日にやったことは翌日になると(夕方でも)割と忘れており、シュッと出てこない

また、現在弊社では自由度の高い働き方をしていくための各種施策が進められており、来年には全従業員にフレックス勤務が導入される予定です。在宅勤務の拡大も検討中であり、今後「チーム全員が確実にその場に集まれる状況」はますます減っていくことになります。そのような状況にも対応できるような形にした方がよいと感じていました。

共同で、リアルタイムに、無理なく日報を書く

このような課題を感じていたころ、先輩の@yuta25さんがScrapboxで共同日報を書くという記事を見つけ、よさそうだからやってみないかという話になりました。

Scrapboxはリアルタイムに共同編集ができるノートアプリで、一言でいえば動作が軽いGoogleドキュメントみたいな感じです。Markdownをより簡単にしたようなScrapbox記法があります。

共同日報の運用方法はほぼ上記参考記事と同様です。1日ごとにページをひとつ作り、各人が今日やるタスクや作業ログを随時箇条書きで書いていきます。自分のタスクはできるだけ一箇所にまとめるようにします。
アイコンショートカットを行末にいちいち入れるのが面倒なので、アイコンのみの行をひとつ作ってそれ以下はその人のエリア、みたいに示しています。これは明確にルールにしたわけではなく、自然とこうなりました。

面倒くさがりで飽きっぽいひとが(自分も含め)多いチームですが、12月8日から始めて今のところ毎日続いており、これは続きそう!という感触を得られています。

良かった点

情報共有の場としては、朝会や日報、分報などの取り組みがありますが、それらと比較しながら共同日報の良かった点を紹介します。

作業負荷が低い

日報ではそれを書くこと自体に結構な時間が費やされてしまいます。文章の形にまとめるのは負荷の高い作業なので、定時間際では疲れで億劫になりますし、「日報残業」になってしまうと本末転倒です。
共同日報では作業ログのような形で随時書いていって、そうしていたらいつの間にか日報ができている、という環境を作れます。箇条書きであれば文章が苦手な人でも書きやすく、続けやすいのではないかと思います。

「今日やること・やったこと」なので小さなことも書ける

タスク管理としてTrelloを使っていたこともありますが、粒度の設定がまちまちで、いつまでも動かないタスクが出たりしていました。また、「タスクにならないタスク」が出て、タスク管理してるはずなのにいま何をやってるの?という状態になりがちでした(Trelloが悪いのではなく運用が悪いので、もっとよくできたとは思います…)。
日報という形式のいいところは「今日やったこと」を書くので、チームの業務に関わらない事務作業とか、ランチの内容とか、仕事中の気持ちの面とかも書きやすい点があると思っています。実はそこにボトルネックや改善のヒントがあったりするものです。その利点を活かしつつ、随時書いていくことでToDoリスト的にも使っていくことができます。

全員が同じページに書いていくので気付きやすい

チャットを使った「分報チャンネル」では、全員が全員のチャンネルを見ていないと喫煙所で重要事項が決定されていた問題が生じることがあります。これを回避しながら分報をうまく機能させるのは難しいのではないかと思います。チーム全員でひとつの分報チャンネルを使う手もありますが、チャットでは時系列に制約されるため、話題が入り乱れたり、ちょっと前の話題には言及しにくかったりします。
共同日報ではひとりにつき1ページではなく全員が同じページに書いていくので、自分が書くときに自然と他人のコメントが目に入ります。時系列ではないので行を入れ替えたり、インデントや改行で適切に話題を整理することもできます。

悪かった点

Markdownじゃない

Markdownじゃないのは最初は面食らいます。アイコンの設定のためにページを作るなど独特の仕様もあるので、既にScrapboxのユーザーがいるほうがスムーズだと思います。
ただし綺麗に文章を整えるような使い方ではないのでそこまで困っていません。箇条書き(行頭でスペースorタブ)とアイコンショートカット(Ctrl+i)さえ覚えれば十分でした。

作業ログの粒度を調整するのが難しい

参考記事では「楽しくなって会話がはじまってしまう」「細かく実況しすぎてしまう」とありましたが、今のところそこまでの状況には至っていません。逆にもうちょっと細かくしてもいいかなと感じます。とはいえ細かくしようとして細かくすると途端に面倒になるので、うまい距離のとり方は考えどころです。メンバーの性格にもよるところがあると思います。

まとめ

  • 「チーム全員が確実にその場に集まれる状況」を前提としない、無理なく続けられるような情報共有の場が必要と感じていた
  • そのために、Scrapboxを使った共同日報を導入してみた
  • 共同でリアルタイムに書くことで、作業負荷が低くメンバーが気付きやすい日報になった

まだ導入して1ヶ月なので結論するには早いですが、今までの形よりも手応えがあり、自分のチームには合っているのではないかと感じています。

チームの状況や好みによって様々な手段がありますが、朝会や日報といった情報共有の取り組みの必要性はどのチームも感じていると思います。その手段のひとつとして共同日報をやってみても面白いかもしれません。


ImageMagickで画像処理に入門する

この記事は、ImageMagickと画像加工について発表したときの資料を文章に起こして加筆修正したものです。

ImageMagickとは

  • 画像加工といえばこれという有名ライブラリ
  • メジャーからマイナーまでさまざまな画像形式に対応
    • 機能が多すぎて脆弱性もたびたび発見されるくらい…
  • Cで実装され、多くの言語でバインディングがある

インストール

Mac Homebrew

1
$ brew install imagemagick

Debian / Ubuntu

1
$ sudo apt-get install -y imagemagick

CentOS

1
$ sudo yum -y install ImageMagick

コマンド

  • imagemagickというコマンドはない(!)
  • 機能ごとにconvertidentifyなどのコマンドにわかれている
    • ただし、ImageMagick 7からはすべてmagickコマンドへのシンボリックリンクになっている

ImageMagick 6 (Ubuntu 16.04)

1
2
3
4
5
6
7
8
9
10
11
12
13
$ ls -Alh /usr/lib/x86_64-linux-gnu/ImageMagick-6.8.9/bin-Q16
total 88K
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 animate
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 compare
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 composite
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 conjure
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 convert
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 display
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 identify
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 import
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 mogrify
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 montage
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 stream

ImageMagick 7 (Mac Homebrew)

magickコマンドへのシンボリックリンクになっていることがわかる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ ls -Alh /usr/local/Cellar/imagemagick/7.0.7-7/bin | grep -v config
total 64
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 animate -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 compare -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 composite -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 conjure -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 convert -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 display -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 identify -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 import -> magick
-r-xr-xr-x 1 shimoju admin 18K 10 9 18:25 magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 magick-script -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 mogrify -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 montage -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 stream -> magick

identify

  • 画像の情報を出力できる
  • サイズをさっと知りたいときとか、大量の画像の中からサイズが違うものを探したりとかに便利
  • フォーマット文字列はこちら参照:Format and Print Image Properties @ ImageMagick
1
2
3
$ identify *.jpg
original.jpg JPEG 800x533 800x533+0+0 8-bit sRGB 104823B 0.000u 0:00.000
resize.jpg JPEG 400x267 400x267+0+0 8-bit sRGB 37116B 0.000u 0:00.000

JSON形式で出力してjqに食わせる

1
2
3
4
5
$ identify -format '{"width": %w, "height": %h}' *.jpg | jq
{
"width": 800,
"height": 533
}

grep -vで指定のサイズではない画像を抽出

1
2
$ identify -format '%wx%h %f\n' *.jpg | grep -v 800x533
200x200 crop.jpg

convert

  • さまざまな画像加工を行える、ImageMagickのメインコマンド
  • 適当な画像をoriginal.jpgとして用意しておきます

回転 (rotate)

-rotateで指定した角度回転する

1
$ convert -rotate 90 original.jpg rotate.jpg

上下反転

1
$ convert -flip original.jpg flip.jpg

左右反転

1
$ convert -flop original.jpg flop.jpg

上下左右反転

1
$ convert -flip -flop original.jpg flipflop.jpg

サンプル (sample)

ピクセルを間引く

1
$ convert -sample 10% original.jpg sample.jpg

10%になるようにピクセルを間引いたあと、1000%になるように拡大
→元画像と同じサイズでモザイクがかかる

1
$ convert -sample 10% -sample 1000% original.jpg mosaic.jpg

リサイズ (resize)

デフォルトではアスペクト比を変えない:指定した幅・高さに収まるようにリサイズされる

1
2
3
$ convert -resize 400x400 original.jpg resize.jpg
$ identify resize.jpg
resize.jpg JPEG 400x267 400x267+0+0 8-bit sRGB 37116B 0.000u 0:00.000

!をつけるとアスペクト比を無視して指定した値にリサイズする

1
$ convert -resize 400x400! original.jpg resize2.jpg

幅または高さのみ指定できる

1
$ convert -resize 400x original.jpg resize3.jpg

エッジ検出 (edge)

不連続に変化している箇所を検出する

1
$ convert -edge 5 original.jpg edge.jpg

値を変化させてみよう

1
2
$ convert -edge 10 original.jpg edge2.jpg
$ convert -edge 1 original.jpg edge3.jpg

切り抜き (crop)

-gravityで基準点を指定し、-crop widthxheightで切り抜くサイズを指定

1
$ convert -gravity center -crop 200x200+0+0 original.jpg crop.jpg

+/-で基準点からのx,y座標を指定できる
画像右上を基準に、xに140px,yに50px移動し、その点から200x200px切り抜く

1
$ convert -gravity northeast -crop 200x200+140+50 original.jpg crop.jpg

塗り足し (extent)

指定したサイズになるように余白を追加する
正方形のサイズが必要なのに4:3の画像しかないときなどに便利

1
2
$ convert -background black -gravity center \
-extent 800x800 original.jpg extent.jpg

余白の色は-backgroundで指定する
PNG(透過が扱えるフォーマット)であれば、-background transparentで透過できる

1
2
$ convert -background transparent -gravity north \
-extent 1000x1000 original.jpg extent.png

文字の画像を作る

1
2
$ convert -background transparent \
-fill '#ff6060' -font Arial -pointsize 128 label:LGTM lgtm.png

指定サイズで作成

1
2
$ convert -size 400x200 -gravity center -background transparent \
-fill '#ff6060' -font Arial -pointsize 128 label:LGTM lgtm.png

合成 (composite)

original.jpgの上にlgtm.pngを合成して、compose-over.jpgとして出力

1
2
$ convert original.jpg lgtm.png -gravity center \
-compose over -composite compose-over.jpg

-geometryで基準点から移動

1
2
$ convert original.jpg lgtm.png -gravity center -geometry +150+50 \
-compose over -composite compose-over.jpg

描画モード (blend mode)

乗算 (multiply)

1
2
$ convert original.jpg lgtm.png -gravity center -geometry +150+50 \
-compose multiply -composite compose-multiply.jpg

オーバーレイ (overlay)

1
2
$ convert original.jpg lgtm.png -gravity center -geometry +150+50 \
-compose overlay -composite compose-overlay.jpg

減算 (subtract)

1
2
$ convert original.jpg lgtm.png -gravity center -geometry +150+50 \
-compose subtract -composite compose-subtract.jpg