はじめに
PNG や GIF 画像で identify を実行すると、よく分からない座標が表示される件です。JPEG では問題になりません。
なお、このエントリは実質 +repage の紹介記事となります。
% identify crop.png
crop.png PNG 200x200 640x480+100+100 8-bit sRGB 183c 4344B 0.000u 0:00.000
ImageMagick はこの 640x480 を (Layer) Canvas サイズ、200x200 は (Image) Page サイズと呼びます。
(canvas は書き込み作業途中の image データを表す事もあって多義的なので注意)
Canvas / Page のイメージ図 |
---|
ImageMagick で crop を繰り返すと意図しない動きをしたり、GIF アニメーションの resize でたまに画像が乱れたりといった罠があります。一応、不具合ではありません。ちょっと直感的な動きじゃないだけで整合性は取れた挙動です。
サンプル画像
ImageMagick 埋め込み画像の logo: をサンプルにします。
% magick convert logo: logo.png
% magick identify logo.png
logo.png PNG 640x480 640x480+0+0 8-bit sRGB 256c 27434B 0.000u 0:00.000
logo.png |
---|
ImageMagick 7 系の magick コマンドでサンプル画像を処理していきますが、magick コマンドを省略してそれに続く identify や convert を使えば ImageMagick 6 系でも動作します。
crop
例として、logo 画像をオフセット付きで crop してみます。
% magick convert logo.png -crop 200x200+100+100 crop.png
logo.png | crop.png |
---|---|
上記のような crop 操作で、PNG や GIF 画像に出力すると、元の画像の大きさと、そのどの部分を Crop したかの情報が残ります。
% magick identify crop.png
crop.png PNG 200x200 640x480+100+100 8-bit sRGB 183c 4344B 0.000u 0:00.000
ImageMagick 的に、元の画像の大きさは Canvas、 crop 済みの実画像は Page と呼びます。
GIF だと Screen と Image、 に対応します。
-flatten と +rapage
-flatten を使うと、元の画像配置を復元できます。
% magick convert crop.png -flatten crop-flatten.png
% magick identify crop-flatten.png
crop-flatten.png PNG 640x480 640x480+0+0 8-bit sRGB 183c 5717B 0.000u 0:00.000
crop-flatten.png |
---|
なお、実画像 (real image) は crop 済みなので、消えた部分は戻せません。
実用上、この余計な情報を無くしたい事が多いので、その為に +repage がお勧めです。
% magick convert crop.png +repage crop+repage.png
% magick identify crop+repage.png
crop+repage.png PNG 200x200 200x200+0+0 8-bit sRGB 183c 4316B 0.000u 0:00.000
crop+repage.png |
---|
crop と page の罠
crop.png | crop+repage.png |
---|---|
単に -crop した画像と +repage 済みの画像とは、画像ビューア上で区別できない事が多いです。
% magick identify crop.png crop+repage.png
crop.png PNG 200x200 640x480+100+100 8-bit sRGB 183c 4344B 0.000u 0:00.000
crop+repage.png PNG 200x200 200x200+0+0 8-bit sRGB 183c 4316B 0.000u 0:00.000
この (+repage 無しの) -crop しただけの crop.png 画像を更に -crop すると、以下のような罠にハマります。
% magick convert crop.png -crop 50x50+0+0 crop-crop.png
convert: geometry does not contain image ("50x50+0+0") `crop.png' @ warning/transform.c/CropImage/596.
これは画像が存在しない場所を選択したからです。
Canvas 内の 100x100 から右下に画像が展開されているので、50x50 だとそこまで届かない為です。
厄介な事に画像は生成されます。非表示枠の 1x1 最小サイズの画像です。
crop-crop.png |
---|
% magick identify crop-crop.png
crop-crop.png PNG 1x1 640x480-1-1 8-bit sRGB 352B 0.000u 0:00.000
+repage を使うか、+repage 済みの画像であれば大丈夫です。
% magick convert crop+repage.png -crop 50x50+0+0 crop-+repage-crop.png
crop-+repage-crop.png |
---|
% magick identify crop-+repage-crop.png
% crop-+repage-crop.png PNG 50x50 200x200+0+0 8-bit sRGB 55c 919B 0.000u 0:00.000
更なる crop 処理で混乱しないように、こちらも +repage する事をお勧めします。
% magick convert crop-+repage-crop.png +repage crop-+repage-crop+repage.png
% crop-+repage-crop+repage.png PNG 50x50 50x50+0+0 8-bit sRGB 55c 919B 0.000u 0:00.000
取り込んだ PNG が Screen と Page が異なるか画像ビューアの見た目で判断出来ないので、以下のように +repage を実行すると安全です。
- -crop を実行したらその後に +repage を実行する。(クロップした場所をあえて保存したいケースは別)
- ImageMagick で crop されてないと確信出来ない PNG 読み込み時に +repage を実行する
公式にもこう書かれています。
Always use "+repage" after any 'crop' like operation.Unless you actually need to preserve that info.
(訳) "crop" などの操作の後には、常に "+repage" を使用してください。実際にその情報を保存する必要がある場合を除きます。
oFFs, vpAg, caNv チャンク
本来は、JPEG と同じく PNG もこの罠と無縁のはずですが、MNG (APNG以前のPNGアニメーション仕様) で oFFs が必要になり、 2005年に ImageMagick は PNG 公式仕様の oFFs, vpAg チャンクに対応して Canvas 座標の保存を行うようになりました。その後、oFFs を使う他のアプリケーション(GIMP)と折り合いがつかなかった為、2017年に oFFs, vpAg に保存するのは辞めて、独自チャンク caNv の利用に踏み切ったようです。
- PHP の ImageMagick で作成した PNG 画像にオフセットが設定されてしまった場合の対応方法
対応の具体的な時期は以下のような流れです。
-
ImageMagick-6.2.4-7 〜 6.2.5-5 (2005年9月〜11月頃) のどこかで oFFs, vpAg 対応。
-
ImageMagick-6.9.7-6 (2017年1月28日) で caNv 対応。
-
ImageMagick-6.9.9-4 (2017年7月29日) で oFFs, vpAg 書き込みを廃止
-
ImageMagick-6.9.7-6差分
-
ImageMagick-6.9.9-4差分
GIF アニメーションの罠
GIF にも Canvas / Page の概念があり、同様の罠があります。特に GIF アニメーションの変換で躓きがちです。
GIF アニメーションは最適化の一環として2コマ目以降を差分フレームとして持つ事があるので、その場合、内部的に Canvas より小さな Page として差分画像を持つ為、そのまま -resize 等の処理を行うと画像が崩れます。
以下のように -coalesce で GIF アニメーションの最適化を解き、処理を行い、その後 -layers optimize で最適化し直す事で対処可能です。
% magick convert anim.gif -coalesce -resize 50% -layers optimize output.gif