dondakeshimoの丸太

データサイエンス/Webアプリケーション/

node.jsのgmライブラリでCopyOpacityするのに1日ハマった話するわ

gmライブラリ

node.jsにおける画像編集の鉄板?ライブラリである。 バックでGraphicsMagick(ImageMagick)が動いており、 それらをnode.jsの機能のように使うことをapiなのだろうか。 今回はこのgmライブラリを使ってはまりまくったので、 後に筆者のような愚かな人間が生まれないように記事を書く。 多少心が荒んでいるので、丁寧語が抜けていることをお許し願いたい。

今回やりたかったこと

blog.yug1224.com

サムネイルを作る目的ではないが、 こちらの記事にあるようにmaskとなるpngファイルから 透過値をコピーして、丸く切り取るようなことがしたかった。 また、作業に際し速度が必要であったため、 ImageMagickではなくGraphicsMagickを使うことにした。

compositeとconvert

おそらく、ちゃんとした区分があるのだろうが、筆者のなんとなくの理解では

  • 画像の変換系はconvert
  • 画像の合成系はcomposite

である。 GraphicsMagickにある、コマンドはそんなに多くない。 というかむしろほとんどのことは convertですませるのだろう。 convertを使う場合、基本的に画像ファイルの引数は二つだ。 ここで、問題が生じる。 maskを用いた透過値のコピーには引数が3つ必要なのである。 上記ページからもわかる通り、このような場合はcompositeを用いる他ない。

gmライブラリの仕様上注意

今回のメインディッシュである。 gmライブラリは今のところ、convertコマンドしかサポートしていないのだ。 これが何を意味するかというと,

gmライブラリで今回の目的が達成できない

最終的な筆者のソリューションは、おそらくみなさんが行なっているであろう。 child_processを使って、シェルに直接実行してもらう方針である。

// gmモジュールがcompositeをサポートしていないため関数定義
internals.gmcomposite = function(maskImagePath, tempImagePath, newImagePath, callback) {
  var gmspawn = spawn('gm', ['composite', '-quality', 100, '-compose', 'CopyOpacity', maskImagePath, tempImagePath, newImagePath]);

  gmspawn.stdout.on('data', function(data) {
    console.log('stdout: ' + data);
  })

  gmspawn.stderr.on('data', function(data) {
    console.log('stderr: ' + data);
  })

  gmspawn.on('exit', function(code) {
    if (code !== 0) {
      callback(code, null)
    }else {
      callback(null, null)
    }
  })
};

これでひとまずは実行できた。 恥ずかしい話、ここにたどり着くまでに1日の時間を要した。

GraphicsMagickのややこしいオプション

今回、ここまで時間がかかったのにはgmがサポートしていなかったことと 合い重なってGraphicsMagickのオプションがわかりづらいと言うことがある なんと、

  • convertコマンドには-composite
  • compositeコマンドには-convert

オプションが存在するのだ。 筆者は永遠とgmライブラリの-compositeオプションを使い、 どのオペレータを用いればmaskを用いたCopyOpacityができるのか延々と悩んでいたわけである。

まとめ

え、今回の問題に直面した時の反省点ですか?…マジでわからん。。。 こう言う泥沼にハマった時の対処法誰か教えてください。。