ImageMagick 使用例 -- API とスクリプティング
- Windows と DOS
- PHP
- シェルコマンドを使う PHP
- PHP Imagick(PHP の ImageMagick API)
-
PerlMagick(Perl Magick スクリプト)
-
より良い ImageMagick シェル/PHP スクリプトのためのヒント なぜ複数の "magick" コマンドを使うのか IM を速くする(一般論) ソースから ImageMagick をコンパイルする
- Ubuntu でソースから ImageMagick を
- MacOSX 上の ImageMagick
- HDRI 版 IM のコンパイル
- 個人用 ImageMagick インストールを作る
この使用例で扱う ImageMagick のコマンドラインインターフェース(CLI)は、ImageMagick のコア関数ライブラリ(MagickCore)を使い、画像の変更や制御を行うための一つの方法に過ぎません。これは基本的に 'シェル' API インターフェースです。多くのプログラミング言語からより直接的に使える、他にもたくさんのアプリケーションプログラミングインターフェース(API)があります。ImageMagick API を参照してください。ここでは、IM のスクリプティングやプログラミングを改善する方法、Windows と Unix のスクリプティングの違い、そして他の API やプログラミング言語から IM を使う基本を見ていきます。
API とその他の IM 利用方法
実際の画像処理のための API(Application Programming Interface)は、実は CLI コマンド("magick" のような。これ自体が一種のシェル API を表しています)を使うより速いわけではありません。IM のすべての画像処理には同じ 'コア' ライブラリが使われます。ですから、画像の歪み処理のような複雑なタスクを行う場合、シェルの "magick" よりも API を使うことは、全体の処理 '速度' という点ではほとんど違いを生みません。では、なぜコマンドラインより API を使うのでしょうか? シェルは多くの異なるコマンド(IM の "magick" コマンドだけでなく、シェルにはいくつかの 'ビルトイン' もありますが)を絶えず 'フォーク' して起動し、それぞれが実行されるたびに読み込まれ、初期化されなければなりません。すべての IM コマンドもまた、設定ファイルを再初期化し、コマンドライン引数を解析し、作業対象の画像を再読み込みし、しばしば結果をディスクに保存し直す必要があります。これらすべてに時間がかかり、遅くなる原因となります。つまり、これらすべての余分なステップは時間と処理能力を消費するので、それを頻繁に行うなら、API が意味を持ち始めます。API はまた、コマンドラインではできない他のことを可能にもしてくれます。
- API がすでに実行中なら、セットアップ時間はほとんど、あるいは全く不要です。
- 任意の順序で処理できる、多数の画像リストの配列をメモリに保持できます。例えば私は、数百枚の画像を読み込みながら 32x32 ピクセルの画像としてサムネイル化し、それらすべてを一組ずつペアにして magick で比較するプログラムを持っています(100 枚の画像なら 9,900 回の比較)。別の例としては、画像をメモリ内で全体的な色によってソートする、といったこともできます!
- 多くの異なる画像処理のスレッドを、任意の順序で行えます。次の画像やステップに取りかかる前に、一連の処理を '終わらせる' 必要はありません。例えば、ジグソーパズルを解くプログラムを想像してみてください!
- 画像から情報を取得し、その情報を複雑な方法で使って、画像処理の再初期化(設定や画像の再読み込み)を何度も繰り返すことなく、画像処理を変更できます。例えば、画像の枠組みの要件を割り出す前に画像サイズを取得する、といったことです。
- 画像をループ処理しながら、一つ一つの画像に対して全く異なることを行えます! 例えば、各フレームをわずかに異なる方法で歪ませたアニメーションシーケンスを生成する、といったことです。
- 画像データへの直接かつ完全にランダムなアクセス。例えば、画像の中から '顔' を探す、といったことです。
しかし、大量の画像を扱わない、あるいは明確に定義された方法での一般的な画像処理であるほとんどの場合、コマンドラインはまずまず同じくらい速いです。とはいえ、次のようにすることで多くの時間と再処理を節約できます... * 中間画像の MPC 画像保存(より速い再読み込みのため)を活用しましょう。私のスクリプト divide_vert を参照してください。 * パイプライン化を使った並列処理(異なるステップに異なるマシンを使うことさえ!)で、プロセッサをより有効に活用し、中間画像のディスクへの保存を避けましょう。1 つのステップが画像をシーケンスの次の(時には任意の)ステップへパイプで送り込む、パイプライン化されたスクリプトの例として enlarge_image を参照してください。 * ループを使って各画像を個別に処理し、その後、画像結果のストリームを最終的な 'すべてをマージする' ステップへパイプで送り込みましょう。私はこのようなスクリプトをたくさん持っています... そのようなスクリプトの一つとして レイヤー画像のプログラム配置 を参照してください。
もちろん API では、画像へのアクセスを伴う特別な処理タスクのために、異なるより速い技法を使うこともできたでしょう。そして、見つけて時間が取れたときに、私たちはしばしばそうした技法をコアライブラリにプログラムします。画像の歪みやさまざまな FX 式がその一例です。
Windows と DOS
CLI API を使った Windows と DOS のスクリプティングに関する使用例は、Windows での使い方 に移動しました。
PHP("system()" 関数からの IM コマンド)
PHP ユーザーには ImageMagick を使う 3 つの方法があります。
- "
imagick" PECL インターフェース - "
MagicWand" インターフェース - "system()" と "exec()" 関数を使って CLI の "
magick" コマンドを実行する
IM 使用例 が存在するため、この後者の方法(と、次に見る最初の方法)は近年、PHP から IM を使う最も一般的な方法になりました。もちろん、ものによってはこれが最良の方法ではないかもしれません(上記参照)。その場合は API インターフェースが利用可能ですが、システム管理者にあなたの PHP 環境で使えるようにしてもらう必要があるかもしれません。
シェルコマンドを使う PHP
この技法を使うことに関する具体的な情報の最良の情報源は、IM フォーラムユーザーの Bonzo と彼のウェブサイト RubbleWebs です。なお、PHP はコマンドラインから得られるものとは異なる環境で、おそらく異なるユーザーとしてさえ "magick" を実行します。そのため、コマンドラインで動作するものが、PHP のウェブ駆動スクリプトから動作させるには少し調整が必要かもしれません。以下は、リモートシステムに直接コマンドライン 'シェル' アクセスがないと仮定した場合の、ISP のコマンドライン IM インターフェースの初期テストのための推奨手順です。つまり、実行のためにウェブファイルをアップロードすることしかできない場合です。そこでまず最初に必要なのは、システム上の "magick" コマンドを探し出し、どのバージョンがインストールされているか、そして PHP が実行されている環境を調べることです。Linux ウェブサービスでは、この PHP スクリプトを ISP のウェブサーバーにアップロードしてアクセスしてください...
<?php
header('Content-Type: text/plain');
system("exec 2>&1; pwd");
system("exec 2>&1; type magick");
system("exec 2>&1; locate */magick");
system("exec 2>&1; magick -version");
system("exec 2>&1; magick -list type"); <!-- before IM v6.3.5-7 -->
system("exec 2>&1; magick -list font");
print("------ENVIRONMENT VARIABLES-------\n");
system("exec 2>&1; env");
?>
これは、あなたの環境がどのようなものかを調べるために、かなりの数のコマンドを実行します。最初の "pwd" は、PHP スクリプトが実行されたカレントディレクトリを教えてくれます。これは PHP スクリプトが置かれているディレクトリと同じかもしれませんし、違うかもしれません。また、PHP スクリプトからそのディレクトリに書き込めないかもしれません。次の 2 つのコマンドは、デフォルトで提供されるコマンド PATH 上で "magick" が利用可能かどうかを "type" を使って教えてくれ、もしそうならどこにあるかを教えてくれます。"locate" コマンドは、サーバー上に存在するすべての "magick" コマンドを見つけるはずですが(linux サーバーであると仮定して)、ImageMagick 以外の "magick" コマンド、ファイル、ディレクトリも見つけるかもしれません。結果を解釈する必要があります。次の 3 つのコマンドは、"magick" がコマンド PATH 上にあると仮定して、バージョン番号と、IM がアクセスできると考えているフォントを報告するよう求めます。どのコマンドがどのフォントを報告するかは、インストールされている IM のバージョンの古さに依存します。エラーしか表示されない場合、"magick" はコマンドラインパス上になく、ISP プロバイダがウェブサーバーの "PATH" と "LD_LIBRARY_PATH" を正しく初期化してそれを含めなかったということです。彼らが何を定義したかは "env" コマンドの出力を参照してください。もしそうなら、それが正確にどこにあるかを調べ、以下のような PHP スクリプトを使う必要があります。これは、その特定の ISP 向けにハードコードされるため、スクリプトの可搬性を低下させます。例えば、"magick" コマンドが "/opt/php5extras/ImageMagick/bin" にあるとすると、その場所を指定する変数を設定できます。これは、異なる ISP ホストで使われる PHP スクリプトのために、アプリケーションの設定とインストールプロセスの一部としてしばしば行われます。
<?php
$im_path="/opt/php5extras/ImageMagick/bin"
header('Content-Type: text/plain');
system("exec 2>&1; $im_path/magick -version");
system("exec 2>&1; $im_path/magick -list type");
system("exec 2>&1; $im_path/magick -list font");
?>
"ldd" ライブラリエラーが出る場合、"LD_LIBRARY_PATH" が間違っており、ISP はインストール時に確実に仕事を怠っています。エラーを報告し、ウェブサーバーの "LD_LIBRARY_PATH" 環境変数の設定を修正してもらうか、ImageMagick を再インストールしてもらう必要があります。magick コマンドの場所を設定する代わりに、先頭に次のような行を使って PATH 環境変数を調整することもできます。ただし、この方法は典型的な PHP のシステム設定によってデフォルトでしばしば '拒否' されます...
putenv("PATH=" . $_ENV["PATH"] . ":/opt/php5extras/ImageMagick/bin");
putenv("LD_LIBRARY_PATH=" . $_ENV["LD_LIBRARY_PATH"] .
":/opt/php5extras/ImageMagick/lib");
その後、IM 使用例から、より単純な例のいくつかを試して動作させてみてください。例えば、IM の 'rose' 画像を JPEG 画像ファイルとしてウェブユーザーに出力するには...
<?php
header( 'Content-Type: image/jpeg' );
passthru("magick rose: jpg:-");
?>
magick コマンドの場所を設定する必要がある場合は、次のように使えます...
<?php
header( 'Content-Type: image/jpeg' );
$magick="/opt/php5extras/ImageMagick/bin/magick"
passthru("$magick rose: jpg:-");
?>
あるいはライブラリの問題がある場合は、次のようなことを試せます...
<?php
header( 'Content-Type: image/jpeg' );
$magick="/opt/php5extras/ImageMagick/bin/magick";
$libs="LD_LIBRARY_PATH=\'" . $_ENV["LD_LIBRARY_PATH"] .
":/opt/php5extras/ImageMagick/bin/magick\'";
system("$libs $magick rose: jpg:-");
?>
それでも何も表示されない場合は、エラーメッセージのリダイレクト技法に関する情報を、私の生の PHP ヒントとコツ ファイルで参照してください。
その基本的なスクリプトが動作するようになったら、PHP テストスクリプトでリストされたフォントの一つを試せます(以下をあなたの PHP サーバーに合わせて変更してください)。例えば、当時利用できた Solaris サーバーで、'Utopia' フォントセットが利用可能であることに気づいたので、そのフォントでラベルを作成してみることができました...
<?php
header('Content-Type: image/gif');
passthru("magick -pointsize 72 -font Utopia-Italic label:'Font Test' gif:-");
?>
シェルから PHP への変換例
ここに、かなり典型的な ImageMagick コマンドがあります...
magick -background none -fill red -gravity center \
-font Candice -size 140x92 caption:"A Rose by any Name" \
\( rose: -negate -resize 200% \) +swap -composite output.gif
PHP に変換すると、次のようなものになります...
<?php
header('Content-Type: image/gif');
$color="red";
$image="rose:";
$scale="200%";
$size="140x96";
$string="A Rose by any Name";
passthru( "magick -background none -fill '$color' -gravity center" .
" -font Candice -size '$size' caption:'$string'" .
" \\( '$image' -negate -resize '$scale' \\) +swap -composite" .
" gif:-" );
?>
"magick" コマンドの長いコマンドラインを、画像処理シーケンスを追いやすく、後で編集しやすくするために、どのように分割しているかに注目してください。これは、シェルスクリプトで使われるシェルの行継続ではなく、PHP の連結文字列を使って行いました。また、後続行の先頭の余分なスペースにも注目してください。そして、元のコマンドにあった他のバックスラッシュを二重にしている点にも。あるいは、バックスラッシュの代わりに単一引用符を使ってそれらのオプションを保護することもできます。また、生成される PHP スクリプト画像を調整しやすくし、結果をよりよく制御できるように、いくつかの PHP 変数も使いました。ただし、それらのオプションを "magick" に挿入する際には、シェルによるさらなる変更から保護するために単一引用符を使いました。ただし、挿入される文字列内の単一引用符には注意してください! それらのオプションを PHP の入力引数にすれば、ウェブリクエストから渡された任意の入力テキストに対して画像を生成できます。同じ system 呼び出し文字列内から複数のシェルコマンドを実行することもできます。実際、単一の system 呼び出しに、望むなら完全なシェルスクリプトを含めることができます! ですから、シェルループや複数のコマンド(クリーンアップ付き)を、すべて一つの system 呼び出しの中で行えます。これが可能だと気づいていない人が多いことです。基本的に、注意すれば、PHP が提供する数学と、シェルのスクリプティング能力をうまく活用できます。すべてを同時に。ただクォートに注意してください。PHP から ImageMagick コマンドを呼び出すさまざまな例については、約 4 つの異なる技法を説明している Rubble Web, PHP で IM コードを書く を参照してください。
余分なクォートに注意
典型的には、PHP 内の IM コマンドは追加のクォートのセット(通常は二重引用符)で囲まれることに注意してください。そのため、この追加のクォートレベルの使用を考慮するよう注意が必要です。PHP が文字列を実行するとき... を覚えておいてください。PHP がクォート、バックスラッシュ、変数の置換を行う。シェル が次に引数を分割し、それ自身の変数とクォートの置換を行う。また、もし存在すれば "2>&1" 型のファイル記述子リダイレクトも行う。ImageMagick は引数の配列を受け取りますが、DOS のためのファイル名メタ文字の処理(dos 環境はメタ文字を扱えません)や、シェルが coder: プレフィックスや [...] の読み込み修飾子のために展開に失敗する coder:*.gif[50x50] のような引数のための処理も独自に行います。つまり、大量の引数解析です! これは大量のクォートとバックスラッシュの処理を意味し得ます。注意と先見の明が必要です。少なくとも、プログラム実行関数 に関する PHP マニュアルを読むことをお勧めします。これには次のものが含まれます。PHP exec()、system()、passthru()。また バッククォート演算子 も見てください。特に重要なのは、何が正確に返され(一般的に最後の行のみ)、何が呼び出し元のクライアントに渡される(それ以外すべて)のかを理解することです。
PHP のセキュリティ
覚えておいてください...
_ネット上で、潜在的に敵対的でないと信頼できる唯一のユーザーは、
*積極的に* 敵対的なユーザーである。
-- Programming Perl - Camel Book, r3_
ユーザーから IM コマンドに渡されるすべての入力引数を徹底的にチェックしなければなりません。引数がまさに期待通りのものであることを確認してください。World Wide Web を扱うときは、制限が緩すぎるよりも厳しすぎる方がはるかに良いです。注意すべき一般的なことには次のものが含まれます。
- 引数内のバイナリ文字 - よくあるクラッカーの手口
- 引数内の予期しないスペース、タブ、改行、復帰
- バックスラッシュ(ディレクトリ区切り文字)と '
..' パス。さらに windows では、ファイル名内の '\' と ';' - "
~*?[]{}<>" を含むファイル展開メタ文字に加えて、ImageMagick 特有の特別な "@" メタ文字 - "
$#;" を含む他のシェルメタ文字と、3 つのクォート文字 '''、'"'、'```' - 引数が ImageMagick の期待するものと一致しない。特定のオプションに対して IM がどんな種類の引数を理解するかを読むには "
[-list](https://imagemagick.org/command-line-options/#list)" を使ってください。例えば、ユーザー入力の "[-gravity](https://imagemagick.org/command-line-options/#gravity)" オプションには、10 種類の設定しかありません。 - その他...
あらゆる種類のウェブプログラミング作業には、セキュリティと、ハッカーが特別に細工された引数を使って呼び出されたコマンドをどのように転覆させ得るかの理解が不可欠です。PHP だけでなく、シェルや ImageMagick についてもです。IM は特別な注意が必要で、例えばパスワードファイルを読み込んで画像化し、返すことができるからです。繰り返しますが... ウェブが関わるときは、予期しないセキュリティホールを開けるよりも、過度に制限する方がはるかに良いのです。
ファイルシステムへの書き込み
上で述べたように、そして上記の初期手順に従ったなら、確実にわかるでしょうが、PHP は一般にサーバー上で異なる、より制限されたユーザーとして実行されます。このため、スクリプトを含むディレクトリ(あるいは実際に実行されている場所)には通常書き込めません。セキュリティ上の理由から、一般にそのディレクトリには 書き込みたくありません! 本当に PHP にファイルを書き込ませたいなら、画像(やデータ)を "/tmp" 内のユニークなファイル名に保存させ、そして何より、通常の終了時でも、いかなるエラー時でも、後始末をしてください。きちんと後始末をしないアプリケーションの残りの一時ファイルで、どれほど早くディスクを埋め尽くせるか、驚くほどです。保存されたファイル(画像)がウェブサーバーから見える必要があるなら、それらのファイルのために特別な 'プログラムによる書き込み' サブディレクトリを作りましょう。どうあるべきか。 ほとんどの PHP アプリケーションは、実際にはデータベースバックエンドを使うことで、ファイルシステムへの書き込みを一切避けています。つまり、クッキー、トークン、ユーザーデータ、画像などはすべて、(複雑さと規模の順に)SQLite、PostgresSQL、MySQL、Oracle のようなデータベースに書き込まれます。ファイルシステムには何も保存しません。システムプログラマは典型的に、アプリケーションのインストール時にその情報を PHP アプリケーションに設定します。画像は典型的に、同じ、あるいは別の PHP スクリプトが画像の 'blob' を検索してクライアントに出力することで再現されます。画像は HTML 自体と共に 'インライン' 画像として送られる(HTML インライン画像のデモがある "[inline:](files.html#inline)" フォーマットを参照)か、あるいは単一の '全部入り' の複数画像として送られ、クライアントの HTML/JAVA が 20 個の別々のリクエストではなく 1 つの画像リクエストだけで済むようにします。最後に一点。古いデータを片付ける何らかの方法は常に備えておくべきです。2 年間ログインしていないユーザーは、おそらくデータを削除すべきでしょう。
エラー出力を得る
次の方法のいずれかを試してください...
<?php
exec("/usr/local/bin/magick -version",$out,$returnval);
print_r($out[0]);
?>
あるいは
<?php
exec("/usr/local/bin/magick -list",$out,$returnval);
print_r($out);
?>
あるいは次のように shell_exec を使う
<?php
$IM_version=shell_exec("/usr/local/bin/magick -version");
echo $IM_version
?>
STDERR 出力を含めるには...
<?php
$array=array();
echo "<pre>";
exec("magick read_test.png write_test.png 2>&1", $array);
echo "<br>".print_r($array)."<br>";
echo "</pre>";
?>
上記は IM ユーザーフォーラムの議論 php で IM のエラー情報を表示するには? から来ています。私自身の PHP デバッグエラーログ のメモも参照してください。そこは PHP マニュアルのエラーロギング PHP のエラー処理とロギング を指しています。特に例のセクションを見てください。
より安全な ImageMagick コマンド...
セキュリティ上の理由から、理想的には、単一の長い文字列を別々のコマンドと引数に解析するためにシェルを使うことは避けたいものです。自分でやる方が良いのです! これは、引数をコマンドに、単一のシェル解析される文字列としてではなく、別々の文字列の配列として提供することを意味します。これにより、シェル構文エラーの可能性、シェルが必要とする余分なクォートの負担を防ぎ、ハッカーがシェルコマンドを破って自分自身のコマンドを実行する可能性(非常に悪い)を防ぎます。一方で、シェルのスクリプティング、パイプ、ファイルリダイレクトは失われますが、すでに PHP や他のラッピング言語を使っているなら、それは典型的に大きな損失ではありません。PHP では、シェルなしでコマンドを直接呼び出せる唯一の関数として私が見つけられたのは pcntl_exec() 関数です。これは基本的にシェルを避け、コマンドを直接呼び出します。ただし、これは真の 'execl()' システムコールで、現在のプロセスを与えられたコマンドで置き換えます。つまり、サブプロセスとして実行するために必要な 'fork()' とファイル記述子のリンクを行いません。そのため pcntl_exec() は、一般的な使用には実に低レベルすぎ、'シェルなし' のコマンドを実装するのはかなり複雑になり得ます。より単純で安全な 'シェルを避ける' コマンド呼び出しが PHP インターフェースによってまだ提供されていないことに、私は非常に驚いています。とはいえ、私は PHP プログラマではありません。一方 Perl は、サブコマンドやプロセスを安全に呼び出すいくつかの方法を提供しており、それがしばしば PHP よりもウェブインターフェースとして好ましいものにしています。PHP セキュリティの知識のある方、より詳しい情報を教えてくれたり、ポインタを示してくれたりしませんか?
PHP 'IMagick' API
PHP PECL Imagick モジュールが実際に動作しているかをテストするには、単純なテスト用 "image.jpg" 画像と、この PHP スクリプトを同じウェブからアクセス可能なディレクトリにアップロードしてください。
<?php
$handle = imagick_readimage( getcwd() . "image.jpg" );
if ( imagick_iserror( $handle ) ) {
$reason = imagick_failedreason( $handle ) ;
$description = imagick_faileddescription( $handle ) ;
print "Handle Read failed!<BR>\n";
print "Reason: $reason<BR>\n";
print "Description: $description<BR>\n";
exit ;
}
header( "Content-type: " . imagick_getmimetype( $handle ) );
print imagick_image2blob( $handle );
?>
PHP IMagick ブック がオンラインで利用可能で、IMagick を使うより多くの例は Mikko のブログ で見つけられます。IMagick の唯一の問題は、保守と更新がされてこなかったため、動作しなかったり欠けていたりする関数が多数あるかもしれないことです。IMagick の v3.x と現行バージョンの IM を使っていることを確認してください。それは動作し、ほとんどのことでうまく機能しますが、他のことをする必要があるなら、他の PHP の方法がより良い選択肢かもしれません。
PHP 'MagickWand'
PHP MagickWand モジュールが PHP インストールの一部かどうかは、次のように確認できます...
<?php
if (extension_loaded('magickwand')) {
echo "PHP MagickWand is available!\n";
} else {
echo "PHP MagickWand is NOT available!\n";
}
?>
ただし、それが実際に正しく動作しているかを確認するには、何らかのテスト用 "image.png" とこのスクリプトをアップロードしてください...
<?php
$image = NewMagickWand();
if( MagickReadImage( $image, 'image.png' ) ) {
header( 'Content-Type: image/jpeg' );
MagickSetImageFormat( $image, 'JPEG' );
MagickEchoImageBlob( $image );
} else {
echo "Error in MagickReadImage()";
echo MagickGetExceptionString($image);
}
?>
上記について保証はありませんが、より多くのフィードバックを歓迎します。私は一般に PHP でプログラムしませんが、SunONE-PHP5 のテストインストール(3 つの方法すべて: コマンドライン、magick、MagickWand)をテストするために上記を使いました。
複雑な PHP スクリプト...
HTML と画像の両方を生成して出力する必要があるなら、別々の HTML リクエストや入力オプションが、ウェブドキュメント上で必要なさまざまな部分を、同じ、あるいは異なる PHP スクリプトから生成するように、PHP スクリプトを設計することを検討してください。つまり、トップレベルの PHP スクリプトは適切な タグを含む HTML を出力し、それが適切なオプションを付けて自分自身(または別の PHP スクリプト)を呼び出して、最初のトップレベル PHP スクリプトに表示される画像を作成または変更するのです。これは多くのフォトアルバムやグラフ作成 PHP スクリプトがしていることです。すべては URL 呼び出しへの GET と PATH_INFO の拡張によって制御されます。なお、IMG タグ内で POST は使えません。このようにすることで、PHP が生成するウェブページのための一時画像を生成、保存、後始末する必要を完全に避けられるはずです。それは、リソース制限やガベージコレクションのような問題に満ちた解決策で、非常に悪いプログラミング技法です。この技法は ImageMagick ブック の両方で扱われていますが、実際に使われている ImageMagick は少し古くなってきています。
Perl Magick スクリプト
PerlMagick API は、"magick" コマンドを、データベース、大量の画像、あるいはそれ以外では可能なより複雑な画像処理も扱えるスクリプトに変換する良い方法です。最良の助けは、PerlMagick の 'demo' スクリプトを見ることです。これはソースの中にあり、通常 PerlMagick のドキュメント領域にもインストールされています。私のシステムでは "/usr/share/doc/ImageMagick-perl-*/demo/" にありました。このディレクトリには、さまざまな画像を読み込み、書き込み、処理する単純な例が増え続けています。また、ほとんどすべての一般的な画像処理オプションと、それらをどう使えるかをリストした "demo.pl" スクリプトもあります。コマンドラインの "magick" コマンドを perl に変換するとき、覚えておくべきことがいくつかあります。
- 最初に覚えておくべきことは、PerlMagick は処理された新しい画像を自動的に削除しないということです。多くの演算子は古い画像から新しい変更された画像を作りますが、他のものは既存の画像を直接変更します。
- また、多くの演算子は特定の操作を画像のリスト全体には適用せず、与えたリストの最初の画像にだけ適用します。これは、画像シーケンス(perl 配列)自体をループ処理する必要があることを意味します。
- 多くの画像シーケンスを持てます。実際、コマンドライン上のように単一の画像シーケンスで間に合わせるのではなく、典型的にはすべての画像をそれぞれ独自の別々の画像シーケンスに読み込みます。
- また、画像をメモリに入れたら、既存の画像のサイズを簡単に取得できます。これは、コマンドライン上でするように既存の画像をクローンしてクリアする必要なく、新しいキャンバスを作成できることを意味します。ただし、画像のクローンは画像のメタデータもコピーするので、デジタル写真のような画像については、そのメタデータを把握しておきたいかもしれません。
- すべての主要な処理の後、特に画像を読み込むときは、(PerlMagick ページに示されているように)画像エラーをチェックしてください。
コマンドラインを perl に変換するには、基本的にまったく同じ操作を、まったく同じ順序で行います。ただし、画像は一般に削除されず、複数の画像シーケンスが一般的なので、"magick" コマンドにおける括弧や余分なクローン操作の使用は通常問題になりません。スクリプト変換で最も難しい部分は、通常、コマンドラインオプションを PerlMagick の関数呼び出しにマッピングすることです。私が見つけた最速の方法は、IM のソースコードを取得し、ファイル "MagickWand/mogrify.c" を見て、問題を抱えている特定のコマンドラインオプションを検索することです。例えば -threshold オプションなら、クォートを含めて "threshold" を検索します。2 つの一致があり、1 つはすべてのオプションが見つかることを確認する素早い構文解析用で、もう 1 つはそのオプションの実際の内部呼び出し用です。ここで、使われているライブラリ関数の名前が見つかり、それが通常 Perl の関数に直接マッピングされます。この場合は... BilevelImageChannel()
セキュリティ警告
公開用のスクリプト、特に世界中の誰もが実行する可能性のあるウェブベースの PHP スクリプトを書くときは、未知の(あるいは既知ですら)ユーザーから来た可能性のあるすべてをチェックすることが極めて重要です。引数、ファイル名、URL、そして画像も含めて、です。ある入力引数を検証するまで、その引数は文字、数字、スペース、句読点、あるいは 'null' や制御文字さえ含み得ます。徹底的にチェックするまでは、それは疑わしいものとして扱われるべきで、使われるべきではありません。何らかのウェブ制御された入力フォームを使っているかどうかは問題ではありません。少し知識のある人なら、その入力フォームを一切使わずに、あなたの PHP を自分自身の引数で簡単に呼び出せます。そして、彼らがそれをしないと信じてはいけません。ロボットがそこにいて、入力フォームを読み、ランダムなスクリプトに侵入しようと自分自身の 'ハッキングされた' 引数を作っているのです。
ファイル名内のメタ文字
セキュリティ問題として、特に注意すべきは、スペース、クォート、句読点、制御文字、その他のメタ文字を含むファイル名です。IM もシェルもそれらを展開しようとするかもしれないからです。問題は、'*?@${&) .jpg' というファイルが実は UNIX では完全に正当なファイル名なのに、(シェルや IM のように)ファイル名展開も行うプログラム(のような)であれば、多くのプログラムがそれを扱うのに苦労する、ということです。シェルが 'glob' メタ文字展開を行うのを防いだとしても、IM 自体もこの展開を行う(DOS の使用のため)ことを覚えておいてください。そのため、そのようなすべての文字を(エラーを出して)防ぐことが、おそらく賢明でしょう。セキュリティ対策として、ファイル名に未知の、あるいは普通でない文字、つまり文字、数字、期待される接尾辞以外の何かが含まれていたら、エラーを出して中止するのが、しばしば良い考えです。そのようなファイル名をシェルコマンドや IM に渡す前に、です。何か悪いものを通してしまうほど寛容であるよりも、ずっと厳しく物事を防ぐ方が良いのです。
より良い ImageMagick シェル/PHP スクリプトのためのヒント
これらは、他の人が使うために IM メーリングリストに送られた、寄稿されたシェルスクリプトについて私が指摘した、いくつかの基本的なスクリプトプログラミングの要点です。私は元々これらを著者に個人的に(その人は匿名のままにします)送り、彼は感謝してくれました。これらはすべてが IM 特有のものではありませんが、標準的なプログラミングの慣行として、ともかく適用すべきです。特に、他の誰かにあなたのプログラムやスクリプトを使ってもらったり、見てもらったり、バグ修正してもらったりするつもりなら。それは結果としてあなたのスクリプトをより役立つものにします。
- 'ヘルプ' や 'ドキュメント' をスクリプトやプログラムの先頭に置きましょう。これにより、スクリプトをインストールしたり実行したりする必要なく、特定のプログラムが何をするのかを他の人が理解するのがずっと簡単になります。私自身、何のためのものかが明確なコメントのないプログラムは、その未知のスクリプトをコンパイルしたり実行したりしようとするよりも、しばしば捨ててしまいます。実際、最初の README ファイルが、その巨大で複雑なプロジェクトが何をするのかさえ言っていない巨大なプロジェクトを見たことがあります! プログラマは、ダウンロードしたのだから何をするか知っているに違いないと、ただ思い込んでいるのです! また、'-?' のような '不正なオプション' が、オプションだけでなく、プログラムが何のためのものか、あるいはそのヘルプをどこで見つけられるかの簡単な要約も表示するようにしてください。10 年後に消えるかもしれないリモートのウェブサイトを指すだけにしないでください! 自身の '冒頭のコメント' を表示するスクリプトの例として、IM の scripts 領域にある "jigsaw" スクリプトを参照してください。Perl は自己ドキュメント化に POD を使えます(perl の "
Pod::Usage" モジュールを参照)。例えば、寄稿された dpx_timecode.pl スクリプトを参照してください。ヘルプを最初のサブルーチン内の 'ヒアドキュメント' として持つことも許容でき、ほとんどの言語で機能します。ただし、そのサブルーチンはスクリプトやプログラムの末尾や中ほどではなく、先頭に置いてください。 - コードをきれいにし、古くなって不要になったコードやコメントを削除し、できる限り整然と整理してください。簡潔に、(可能なら)簡単にコメントされた段階で。再び "jigsaw" スクリプトを参照してください。
- 一時ファイルが最後に片付けられることを確認してください。ファイルの終了時や割り込み時にそれらを削除するために "trap" シェルコマンドを使いましょう。もちろん、単一の一時ファイルを複数回再利用できるので、特に IM v6 の magick コマンドでは、それほど多くは必要ありません。再び "jigsaw" スクリプトを参照し、"trap" を検索してください。
- また、誰もがあなたのように システム X を使うわけではありません。あなたにはそう見えるかもしれませんが。特定のシステム要件や、問題を是正する方法に言及しないでください。あなたにとって機能するものが、彼らのシステムや設定には完全に不適切かもしれません。彼らはインターネットアクセスさえないかもしれません! ただ、ImageMagick の "
magick" コマンドが見つからなかった、とだけ言いましょう。インストール要件や提案を加えたいなら、別のより詳しいドキュメントの一部として加えてください。 - 使われている IM が十分に高いバージョンであることを確認するか、後方互換の変更を加えてください。私は、まさにこの目的のために、さまざまな特別な機能がいつ追加されたかについて、IM 使用例の全体にわたって意図的に 'バージョン警告' のメモを記しています。これにより、単一の最小限のバージョンチェックでスクリプトを作成するのが容易になります。これは、シェルスクリプトでテスト目的の単一のバージョン番号を取得する一つの簡単な方法です。4 つのバージョン番号を抽出し、各数を 2 桁にするために適切な数のゼロを挿入し、単純な 8 桁の数を生成します。
IM_VERSION=`magick -list configure | \ sed '/^LIB_VERSION_NUMBER /!d; s//,/; s/,/,0/g; s/,0*\([0-9][0-9]\)/\1/g'`
例えば IM v6.3.5-10 は "06030510" を生成し、すぐ次のリリースの IM v6.3.6.0 は "06030600" を生成します。上記の PHP 版は RubbleWeb, フォントリスト の例ページから利用できます。結果の文字列は、単純な数値テストまたは文字列テストのいずれかを使ってテストでき、利用可能な ImageMagick のバージョンが、スクリプトがしようとしていることに対して十分に新しいかを調べられます。例えば...
if [ "$IM_VERSION" -lt '06030600' ]; then
echo >&2 "The perspective distortion operator is not available."
echo >&2 "Sorry your installed ImageMagick is too old -- ABORTING"
exit 10
fi
また、中止の正確な理由と、特にそのバージョンチェックが何のためのものだった特別な機能を、どのようにユーザーに出力しているかに注目してください。さもないと、後でなぜその特定のバージョン(以上)が必要だったのかを忘れてしまうかもしれません。特定のバージョンに対して IM の動作を変更することもできます。例えば、利用可能なフォントのリストを取得したいとします。IM のバージョン v6.3.5-7 より前は、"[-list](https://imagemagick.org/command-line-options/#list)" の設定 "type" が '既知のフォント' リストを返していました。それ以降のバージョンでは、代わりに "font" 設定を使う必要があります。そこでここでは、必要な情報を取得するために正しい設定を使うようバージョンチェックを行えます。
if [ "$IM_VERSION" -lt '06030507' ];
then font_list="type";
else font_list="font";
fi
avail_fonts=`magick -list $font_list | cut -d\ -f1 |\
egrep -v '^($|----|Path:|Name$)'`
警告: PERL では '0' で始まる文字列は 8 進数として解釈されるかもしれません!!! ただし、2 つの 8 進数を比較しても、最初の桁が '0' のままである限り、依然として正しく出ます。注意と、バージョンテストのチェックが推奨されます。バージョンをテストする別の代替手段は、"[" テストの代わりに "expr" を使うことです...
if expr + "$im_version" \>= "06030507" >/dev/null; then
...
警告: 上記の余分な '+' は、少なくともこのテストでは通常必要ありませんが、変数が特別なキーワード 'match" を含み得る場合には必要です。それは "expr" に問題を引き起こすからで、特に文字列や部分文字列の処理に使われている場合です。
* "[-list](https://imagemagick.org/command-line-options/#list)" の情報出力を活用して、何らかの特別な機能が現在インストールされている ImageMagick に追加されているかをチェックすることもできます。
magick -list distort | grep 'Arc' >/dev/null 2>&1
if [ "$?" -ne 0 ]; then
echo >&2 "Arc distortion method not available."
echo >&2 "Sorry your installed ImageMagick is too old -- ABORTING"
exit 10
fi
ただし、しばしば "[-distort](https://imagemagick.org/command-line-options/#distort) Arc" のような新しいメソッドは、一般的な使用に正しく対応できる前に IM の開発中に現れ得ることに注意してください。そのため、バージョンチェックの方が依然として良い考えかもしれません。これが、IM 使用例で、新しい機能が一般的な使用に十分安定したときの IM のバージョンを(記号を探してください)私が記そうとしている理由です。
* 非常に非常に長い単一行を使わないでください。特に複雑な 'convert' コマンドでは。UNIX の '\'、DOS の '^'、PHP の '.' 文字列連結のような行継続の方法(上記参照)を使って分割してください。ただし、すべての設定と操作を別々の行に置けという意味ではありません。1 行につき 1 つの主要な操作や段階を行ってください。新しい画像を作る、画像を変更する、他の画像とマージする、など。特定の演算子に必要なすべての操作設定を、その演算子の直前に置いてください。各行を単一の処理ステップと考えてください。これにより、行を分離して、個々の処理ステップをより読みやすく、理解しやすくできます。演算子の分離が明確であるほど、複雑な画像処理を追いやすくなります。余分な 括弧 を使ったり、さまざまな段階にわたって行をインデントしたり、あるいは大きな処理ブロックの間に空行を加えたりすることで、大きく長い操作の主要な段階を見るのをさらに容易にできます。私はこれらの技法を IM 使用例の至る所で使い、例を追いやすく理解しやすくしているので、ぜひ見回してみてください! 最後に、特定のコマンドが何をしているかについての余分なコメントは、他の誰か(あるいは 2 か月後のあなた自身)があなたのスクリプトを読んで理解するのに大きな違いを生み得ます。残念ながら、現在は長いコマンドラインにコメントを挿入できません!
* あまり多くの外部プログラムに依存しないようにするか、利用可能な場合にのみそれらを使ってください(可能な代替手段とともに)。他の人はおそらくそのプログラムを持っていなかったり、別のものを使うのを好んだりするでしょう。プログラムの使用をオプションにできるなら、オプションにしてください。ユーザーの制御下に置くか、見つかったら自動的に使うか、です。可能な限り、それを必須要件にしないようにしてください。例えば、IM が通常提供するよりも PNG をうまく圧縮するために、"pngcrush"、"optipng"、"pngnq" を活用できます(IM は具体的ではなく一般的であるように設計されています)。また、GIF アニメーションの LZW 圧縮最適化のための "gifsicle"、"intergif"、その他にも、良い点と悪い点があります。ただ、それをスクリプトが動作するための明確な要件にしないでください。実践的な例として、古いバージョンの "gif2anim" は、GIF 特有のメタデータを調べるために ImageMagick の "magick identify" を使わず、パッチ適用版の "[giftrans](http://www.ict.griffith.edu.au/anthony/software/#giftrans)" に依存していました。この要件は、ImageMagick の "magick identify" の改善により後に不要になったので、スクリプトをより広く使えるようにするためにその要件を削除しました。ImageMagick 自体にも、postscript と PDF ドキュメントの読み込みのための "ghostscript" や、SVG ベクター画像の正しい処理のための "librsvg" のような、多くのオプション要件があります。IM は利用可能なときには問題なく動作します。IM はこれらのライブラリをオプションとして扱い、それらのフォーマットの画像を処理したい場合にのみ必要とします。スクリプトの依存関係をチェックするために使えるコードスニペットがここにあります(特に非常に最小限の cygwin 環境で有用です)...
# Check Dependencies to scripts correct working
DEPENDENCIES="sed awk grep tr bc magick identify" # adjust to suit
for i in $DEPENDENCIES; do
type $i >/dev/null 2>&1 ||
Usage "Required program dependency \"$i\" missing"
done
- 前述の点をさらに進めます。IM を使うシェルスクリプトで浮動小数点演算が必要なら、'
awk' や 'bc' のような(特に windows 上の cygwin では利用できないかもしれない)他のプログラムに依存する代わりに、IM 自体を使ってその演算を行えます。例えば、ここでは 'magick' に処理させて、度数で与えられた特定の角度の sin() を計算します...angle=-20 sine=`magick xc: -format "%[fx:sin( $angle *pi/180)]" info:` echo $sine
上記は値 '-0.34202' を出力します。小数点以下の桁数は 精度の操作制御 を使って調整できます。デフォルトでは 6 桁に設定されています。
* 使う入出力画像フォーマットはユーザーに決めさせてください。ImageMagick は主に画像コンバータであり、たくさんの異なるフォーマットを使えます。画面、postscript、プリンタに出力したり、さらなる処理のために画像を別のコマンドにパイプで送ったりできます。ユーザーを特定のフォーマットに限定しないでください。例えば "jigsaw" や "gif_anim_montage" のスクリプトは、ユーザーが任意の入力または出力画像を指定できるようにしています。そうすれば、ユーザーはそのスクリプトに画像をパイプで出し入れでき、他のプログラムやスクリプトを使ったさらなる処理を可能にします。例えば、私はしばしば次のようなコマンドを使います...
gif_anim_montage animation.miff show:
スクリプトの結果をファイルに保存するのではなく、ディスプレイ画面に表示するために、です。実際、私の多くのスクリプトでは、出力が欠けている場合はデフォルトで "show:" を使います。入力を GIF アニメーションファイルからのみに限定したり、出力を GIF、PNG、JPEG の画像フォーマットだけに限定したりせず、スクリプトが ImageMagick の扱えるあらゆるフォーマットを読み込んで処理できるようにしました。実際、IM はファイル、パイプライン、現在のディスプレイ、あるいは "URL:" や "HTTP:" の入力フォーマットを使って World Wide Web からさえ読み込めます。(ウェブ利用のような)セキュリティ上の懸念にならない限り、これらの可能性を制限しないでください。
* 入力画像を読み込み、複数画像を出力するのは、一度だけにしてください! ユーザーがパイプラインのファイル名や URL を提供する場合、それらの画像を一度より多く読み込もうとすべきではありません。さもないと事態が悪化し得ます。その画像を複数回参照する必要があるときは、一時ファイル、クローンされた画像、あるいは "[MPC:](files.html#mpc)" で入力画像のコピーを保存してください。パイプラインからの複数画像を扱えるなら、なお良いです。再び "jigsaw" スクリプトを参照してください。入力画像を複数回、あるいはプログラムの引数が示すのとは異なる順序で処理せざるを得ないときに、入力画像を一時ファイルに保存する例です。
これらは基本的に、あなたのプログラムを使うユーザーに、あなたが彼らの望みだと思うことよりも、彼ら自身が望むことをするより多くの自由を与えます。スクリプトが何に使われるかについて思い込みをして、彼らやあなた自身を制限しないでください。追記: 私の主な専門は UNIX のスクリプト書きで、UNIX、LINUX、その他の UNIX ライクなシステムの多くの異なるアーキテクチャや '系統' にわたり、25 年以上の経験があります。上記について何を言っているか、私はわかっているはずです。
なぜ複数の "magick" コマンドを使うのか
- Willem が 2006 年 10 月 25 日(水)に書きました...
- 不思議に思っていたのですが、あなたの例では、望む結果を得るために Convert を 1 回以上呼び出しているのを時々見かけます。一般に、magick を 1 回以上呼び出すのは必要ないと思うのですが。すべて 1 回の呼び出しで可能なはずです(ただしコマンドはもっと複雑になるでしょうが)。この主張に同意しますか?
私は完全に同意します。ただし IM のバージョン 6 より前は、それは実際には不可能でした。当時の IM は 1 つのコマンドで 1 つ、せいぜい 2 つの操作以上を行うようには設計されていなかったからです。しかし IMv7 では、すべての処理を 1 つのコマンドで行えるはずです。ただ、残念ながらそれさえも常に可能なわけではありません。私はいくつかの考え得る理由で複数のコマンドを使います。典型的には、例のページでは、中間画像の結果を表示できるようにするためにそうしています。そうして、関わっている中間処理の段階をよりよく示すのです。同じ例の領域で後ほど、おそらくもう少し複雑にして、単一のコマンドを使ってそのプロセスを繰り返すかもしれません。そのため、原則として、はい、単一のコマンドですべての画像処理を行えます。画像処理技法をすべて単一のコマンドに組み合わせて構いません。私自身いつもこれをしています。これの例外は、情報を抽出して後でその情報を次のコマンドに挿入する必要がある場合です。この例は ファジー トリム の技法で、これは画像のぼかしたコピーに対するトリムの結果を抽出する必要があります。この結果が次に元の画像をクロップするために使われます。私は サムネイルの角丸 の例の更新でもこれをしました。そこでは、次のコマンドのために画像のサイズを使って draw コマンドを生成するのに IM 自体を使いました。ただし、以前にメモリに読み込まれた画像から直接オプションを生成できるようにする 提案 があります。'jigsaw' スクリプト(高度な技法、ジグソーピース を参照)のようなスクリプトでは、私は別の理由 -- オプションの処理 -- で複数のコマンドを使うことになります。これにより、ユーザーが提供するさまざまな入力オプションが、画像処理シーケンスに追加のステップを選択できるようになります。そこでオプションの処理のために、私は典型的に各処理段階に別々のコマンドを使います。そのような場合、一時ファイルは基本的に避けられません。ただし、私は典型的に多くても 1 つか 2 つの一時画像しか必要とせず、各ステップは次のオプション処理ステップが続けられるよう、画像を同じか前の一時ファイル名に処理し戻します。例えば、ソース画像を置き換えながら画像を処理します。
magick /tmp/image1.png ..operations.. /tmp/image1.png
この場合、MPC ファイルは、次の処理ステップでの中間ファイルの読み込みをほぼ瞬時にできます。画像は単純にメモリからディスクにダンプされ、次のコマンドによって 'ページイン' し戻されるからです。これにより、IM が画像ファイルフォーマットを整形して解析する必要がなくなりますが、単純に非圧縮のメモリなので一時ファイルは大きくなります。一時ファイルを避けるために私が使うもう一つの代替手段は、作業中の画像を 1 つのシェルコマンド(if-then-else-fi や while ループ)から別のものへパイプライン化することです。これは画像パイプラインとして知られ、いくつかの例で示されています。この例は MIFF 画像ストリーミング に示されており、そこでは複数の画像が次々に同じ出力パイプラインに生成され、次のコマンドがそれらをすべて拾い上げて最終的な画像にマージします。そして最後に、以前の処理ステップの結果に基づいて処理スタイルを変える必要があるかもしれません。例えば画像比較では、後の処理ステップで使うために何らかの情報を見つけ出したり、後の段階で画像がどう処理されるべきかを変えたりする必要がしばしばあります。図やマンガを比較するには、実写の写真画像とはかなり異なる比較技法が必要になり得ます。複数のコマンドの使用が問題になりつつあるなら、おそらく PerlMagick のような API インターフェースに移る頃合いです。そこでは、不必要なディスク IO を避けるために複数の画像シーケンスをすべてメモリに保持できます。
IM を速くする(一般論)
IM をより速く動作させる方法はたくさんあります。ここに、心に留めておくべき最も重要な側面があります。リストを下るにつれて、速度向上は小さくなるか、IM のインストールへのより複雑な変更を必要とします。
- IM Q8(色値あたり 8 ビット、ピクセルあたり 3 から 4 バイト)は、より高い色解像度を持つ IM Q16 のデフォルトよりもずっと速い(3 から 4 倍速い)です。画像に Q16 が必要ないなら、IM を Q8 版に置き換えるべきかもしれません。ただし、8 ビットの内部品質しか使わないと、中間画像が情報を失うため、全体の画像処理に影響し得ることに注意してください。これの反対については HDRI を参照してください。
- 可能なら単一の "
magick" コマンドを使い、単一の画像に必要なすべての処理を行ってください。これにより、初期化、一時ファイルやコマンド間のパイプラインの作成、さらにはそれらのパイプラインのための画像ファイルフォーマットへのエンコード/デコードやディスク I/O が節約されます。もちろん、画像サイズ、色を伴う計算や、オプションの処理ステップのような、オプションの画像処理ステップを可能にするために、依然として複数のコマンドを使う必要がある場合もあります。IMv7 のスクリプティングはこの点で助けになるでしょう。 - シェルスクリプトは本質的に遅いです。インタプリタ式で、複数のステップと、ディスクへの余分なファイル処理を必要とします。これはもちろん、新しい IM v6 のオプション処理のおかげでより良くなっており、多数の画像処理操作を単一のコマンドで行えます。それでも、すべてを単一の "
magick" コマンドで行えることはめったになく、望むことを達成するためにしばしば複数のコマンドを使わなければなりません。そのため、perl、ruby、あるいは PHP の magick モジュールのような API は、シェルと IM コマンドライン API の両方の解釈の側面を取り除くので、より速いです。また、IM がフォントと色の定義を読み込む際に経る初期化ステップも減らします。 - API はまた、(十分なメモリがある限り)プログラムの存続期間中、すべての画像、あるいは複数の画像リストさえも保持できます。これは、コマンドライン上でするように画像をシャッフルしてやりくりする必要なく、どの画像が処理されているかを自由に変えられることを意味します。これは、以前の画像処理ステップに基づく余分な計算も行う必要があるときに特に有用です。
- GIF 画像ファイルフォーマットの書き込みは遅いです。IM は、画像の色をファイルフォーマットの限られた色に収めるために、色を削減(量子化)しようと懸命に働かなければなりません。それでも、特に GIF アニメーションでは、正しくするためにしばしば余分な作業が必要です。PNG と JPEG はより速いですが、PNG はサイズの、JPEG は品質低下の代償を伴います。とはいえ、品質という点では実際 GIF 画像の方が悪いのですが!
- 背景、オーバーレイ、フレーム、マスクのような画像の事前準備とキャッシュ、あるいは色のルックアップテーブル、歪みマップ、テンプレート、マスクなどの事前生成。これらすべては、処理時間に大きな違いを生み得ます。事前にできることを考えてください。事前生成された画像の大きなライブラリは、必要に応じて画像を作成しようとするよりずっと速くなり得ます。中間画像とキャッシュ画像のための "MPC:" の使用も参照してください。これらはディスク上のメモリマップされた画像で、本質的に読み込み時間がゼロですが、他のことや他のマシン上では役に立ちません。それらは主要な画像処理プロセスの開始時にのみ作成されるべきで、長期間保存すべきではありません。ソフトウェアやシステムのほんの少しのアップグレードでもそれらを無効にし、おそらくセグメンテーションフォルトを引き起こすからです。
- FX, 特殊効果画像演算子 を使うのは、代わりに アルファ合成、あるいはより単純な Evaluate, 単純な数学操作、その他の技法を使えるなら避けてください。それらを使う必要がある場合は、その使用を可能な限り小さな画像に、あるいは画像の単一チャンネルに(グレースケールを扱うとき)制限してみてください。
- いくつかの小さなものの方が速いかもしれないときに、大きなサイズの 画像ぼかし を使うのは避けてください。どちらが速いか確認するためにいくつかのタイミングテストをしてください。同じことが、ガウシアンやシャドウの演算子のような他の モルフォロジー や 畳み込み演算子 にも当てはまります。
- 小さな領域の複雑な処理には、より小さなサブ画像、すなわち領域を使ってください。例えば、(領域を使って)人物の目を見つけて抽出してから、マスクして再着色する方が、画像の大きなフルバージョンを処理するよりも大きな速度向上をもたらし得ます。差が大きいほど、節約も大きくなります。
- 大きな、あるいは多数の画像を読み込むときは、各画像を読み込んだ直後にリサイズまたはクロップする 読み込み修飾子 を使い、全体のメモリ要件を減らす方が良いです。JPEG では、特別な '
[jpeg:size](formats.html#jpg_read)' ライブラリ修飾子を使って、メモリの割り当てさえ避けられます。これは次に 'ディスク スラッシング'(コンピュータを非常に遅くする)を防ぎます。特に、モンタージュされたディレクトリ索引 や他の複数画像コラージュを生成するときのように、多くの大きな画像が関わるときに。 - ディスクから処理しなければならない 本当に途方もなく大きな画像 については、それらをより小さなチャンクで処理する方が良いかもしれません。
- また大きな画像については... Windows 64 ビット OS をお持ちなら、64 ビット版の ImageMagick ディストリビューションを使ってください。より大きなアドレス空間を使い、32 ビット Windows よりも大きな画像をメモリに収められます。
- IM はデフォルトで、個々の画像処理操作に複数のスレッドを使います。これは、2 つ以上の 'コア' を持つコンピュータが、一般に単一 CPU のマシンよりも速く画像を処理することを意味します。大きな画像では、OpenMP のマルチスレッド機能は、個々の画像処理操作を完了するためにより多くの CPU を使うので、明確な速度上の利点を生み得ます。IM 内では、並列化されるのは個々の画像処理操作のみであることに注意してください。ですから、節約は大きな画像処理での方が大きく、多数の画像を処理するときではありません(次を参照)。
- 小さな画像では、IM のマルチスレッド機能はそれほどの利点を与えません。この場合、異なる画像に対して複数の convert を同時に実行する方が、より多くのスループットを生み得ます。これは、複数の PHP ウェブリクエストが複数の画像 "magick" コマンドを起動するような状況でも起こり得ます。これらのいずれの状況でも、マルチスレッドが有効になっていると CPU の競合のため非常に有害になり得るので、'
MAGICK_THREAD_LIMIT' 環境変数を '1' に設定して OpenMP を無効にする方が良いです。IM フォーラムの議論 'convert' を遅くするスレッディング を参照してください。また、より適切な箇所で ImageMagick により頻繁に CPU の制御を手放させるために、MAGICK_THROTTLEを見てみるのもよいでしょう。 - 画像に対して多くの小さな操作(描画など)を行っているなら、色名をいっさい使わないようにしてください。"
#00AA99" のようなハッシュ色や、"rgb(0,160,100)" のような rgb 数を使って色を指定し、IM が色名テーブル(これはかなり大きい!)を読み込まなければならないのを止めましょう。また、("type.xml" から)システムの 'フォント' リスト定義ファイルを削除したり削ったりしてみることもできます。あるいはそれらのファイルを完全に削除し、代わりにファイル名で直接フォントを指定してください。基本的に、特定の画像処理に必要なときに IM が読み込んで初期化する余分な設定情報の読み込みを減らしてください。ですから、それらを使わないか、設定ファイルのサイズと影響を減らしてください。 - ImageMagick を共有ライブラリ(デフォルト)としてビルドすると、読み込み時間を大きく減らせます。ライブラリとコーダモジュールは必要に応じてのみ読み込まれるので、動的版の IM は画像処理中に使う必要のないものは何も読み込みません。また、共有ライブラリは利用可能なまま残る傾向があるので、2 回目の実行のために再読み込みする必要がないかもしれません。
- ImageMagick を Apache モジュールの一部として呼び出すと、これも起動時間を減らします。一部が一度読み込まれて複数回の使用のために利用可能なまま保たれ、何度も再読み込みする必要がなくなるからです。これは将来、常時実行される 'デーモン' IM プロセスで、より実用的になるかもしれません。
ソースから ImageMagick をコンパイルする
SRPM から linux 用 ImageMagick RPM をビルドする
RPM を実際にビルドするのに root は必要 ありません が、RPM をインストールするには root が必要です。私はこれを Fedora Linux システム 下で IM を生成してインストールするために使っていますが、CentOS 5.4(Enterprise Redhat)Linux システム でも機能すると 報告 されています(CentOS 上の IM のより具体的なメモ を参照)。まず Linux ソース RPM から最新のソース RPM リリースを取得してください。まず、マシンに必要なすべてのコンパイラとツールがあることを確認してください。
sudo yum groupinstall "Development Tools"
sudo yum install rpmdevtool libtool-ltdl-devel
| "sudo" は、許可されていれば root としてコマンドを実行するプログラムです。そうでなければ root シェルを使い、上記から "sudo" の部分を削除してください。
---|---
CentOS 5.5 のような古いシステムでは、これらのパッケージも必要なようです。
sudo yum compat-libstdc++ gcc-c++ gcc-objc++ libstdc++ libstdc++-devel
次に、IM がビルドのために必要とするライブラリの開発パッケージもインストールすべきです。最も一般的なものを得る簡単な方法は、まず開発版の IM をインストールすることです。後でそれを置き換える新しいものをビルドするのですが。
sudo yum install ImageMagick-devel
これらのパッケージとその依存関係(jpeg や png の開発ライブラリなど)もインストールされていることを確認すべきです。
freetype-devel ghostscript-devel libwmf-devel jasper-devel lcms-devel bzip2-devel librsvg2 librsvg2-devel liblpr-1 liblqr-1-devel libtool-ltdl-devel autotrace-devel
"ImageMagick examples" の一部の例は、これらのオプションのパッケージやライブラリが提供するプログラムも使うかもしれませんが、これらはビルドプロセスには必要ありません。
gnuplot autotrace
一般に、これらのパッケージはすべてオプションですが、インストールされていないと、それらのライブラリを使う 'コーダ' や演算子が自動的にビルドされないかもしれません。例えば "liblqr" モジュールは リキッドリスケール演算子 を有効にするために必要です。さて、バイナリ RPM をビルドするための SRPM(ソース RPM)パッケージをダウンロードしてください。あるいは、既存の TAR や SVN のダウンロードから、次のようにして SRPM をビルドしてください...
rm config.status config.log
nice ./configure
rm *.src.rpm
make srpm
SRPM を取得したら、インストールするための実際の RPM をビルドできることに注意してください。
nice rpmbuild --nodeps --rebuild ImageMagick*.src.rpm
これはあなたのホームに "rpmbuild" サブディレクトリを作成し、その中で SRPM のソースを展開し、IM のコンパイル済みパッケージ RPM 版をビルドします。 |
古いバージョンの Fedora と Redhat では、これは一般に root のみに制限されている "/usr/src" で行われていました。ただし、このディレクトリをあなたの所有または書き込み可能にすれば、ビルドのために完全な root アクセスを必要とせずに依然として行えます。 |
|---|---|
| さて、ビルドしたばかりの RPM をビルドディレクトリから取得してください。これは ImageMagick コアと PerlMagick のパッケージだけを取得します。これら 2 つ以上を取得したいかもしれませんが、それはあなた次第です... |
cp -p ~/rpmbuild/RPMS/*/ImageMagick-[6p]*.i[36]86.rpm .
ビルド領域(あなたのために作成されたかもしれないものも含む)を片付けて削除してください...
rm -rf /var/tmp/rpm-tmp.* ~/rpmbuild
さて、ビルドした RPM パッケージをインストールできます。これには root である必要があります(上記の "sudo" コマンドに関するメモを参照)...
sudo rpm -ihv --force --nodeps ImageMagick-*.i[36]86.rpm
"--nodeps" は、Linux システムに時々存在する、いくつかの普通でない依存関係のため、典型的に必要です。既存のインストールをアップグレードするには、私は一般にこうします(root として)。
sudo rpm -Uhv --force --nodeps ImageMagick-*.i[36]86.rpm
さらに進めたいなら、IM のウェブサイトから 高度な Unix ソースインストールガイド を見ることをお勧めします。
後で IM を削除するには、こうしてパッケージを削除するだけです(再び root として)...
sudo rpm -e --nodeps ImageMagick\*
時々、システムから IM のすべての痕跡を完全にクリーンにして消し去りたいことがあります。これを行うには、まず前のコマンドを使ってシステムから実際のパッケージを削除します(下にバリエーションを示します)。それから次の削除コマンドを実行します。注意: これについては保証しませんし、削除すべきでないものを削除しないことを確認するために、事前にコマンドを徹底的にチェックします。何か見落としていたり、削除すべきでないものを削除したりしたら、更新できるよう教えてください。
rpm -e --nodeps `rpm -q ImageMagick ImageMagick-perl`
rpm -e --nodeps `rpm -q ImageMagick-devel`
rm -rf /usr/lib/ImageMagick-*
rm -rf /usr/lib/lib{Magick,Wand}*
rm -rf /usr/share/ImageMagick-*
rm -rf /usr/share/doc/ImageMagick-*
rm -rf /usr/include/{ImageMagick,Magick++,magick,wand}
rm -rf /usr/lib/perl5/site_perl/*/i386-linux-thread-multi/Image/Magick*
rm -rf /usr/lib/perl5/site_perl/*/i386-linux-thread-multi/auto/Image/Magick*
rm -rf /usr/share/man/man?/*Magick*
rm -f /usr/lib/pkgconfig/ImageMagick.pc
警告: 他のパッケージが IM のインストールを必要とするかもしれないので、それを削除する場合は、すぐにコンピュータシステムをパッケージ更新することをお勧めします。そうすれば、あなたの Linux システムに供給された元のデフォルト(通常はかなり古い)版の ImageMagick が再びインストールされます。これは一般に、'GUI ソフトウェア更新' パッケージや "yum upgrade" コマンドを使うことを伴います。お楽しみください。
Ubuntu でソースから ImageMagick を
ImageMagick をビルドするためのすべての開発ライブラリを得るには、次を使ってください。
sudo apt-get install imagemagick libmagick++-dev
"Shane" によるウェブページが、Ubuntu 8.04 でソースから ImageMagick をインストールする 方法を説明しています。私は試していませんが、これは "make" を使って IM を "/usr/local" に直接インストールしました。インストール用の 'DEB' パッケージを生成せず、それは理想的な解決策ではありません。誰か Ubuntu 用の 'DEB' パッケージの作り方を知っていたら、教えてください。おそらく Debian パッケージングの入門 を使って。
MacOSX 上でのコンパイル
MacOSX に ImageMagick をインストールする最も簡単な方法は MacPorts を使うことです。ただし、以下は MacOSX 向けにコンパイルする情報へのポインタです。私はそれを使ったことがないので、機能するか、役立つかはわかりません。ですが Fink や MacPorts なしで ImageMagick をインストールする と Snow Leopard に ImageMagick をインストールする を参照してください。上記は IM ユーザーフォーラムでの議論 を言い換えたものです。
HDRI 版 IM のコンパイル
HDRI 版の IM のコンパイルに関する情報は、IM のメインウェブサイトの ImageMagick で HDRI を有効にする を参照してください。また Windows と Ubuntu Linux 固有の情報については、ユーザーフォーラムの フーリエ変換のお知らせの議論 を参照してください。
個人用 ImageMagick を作る
画像作業をしているマシンへのスーパーユーザーアクセスが常に得られるとは限らず、そのアクセスを持つ人がしばしば自分の ImageMagick インストールを更新したがらないこともあります。おそらくパッケージ管理の問題や、互換性の問題のためです。コマンドラインアクセス(例えば SSH 経由)があれば、すべてが失われたわけではありません。個人用の ImageMagick 版をインストールして使えます。悪い知らせは、依然としてシステム管理者にコンパイラと開発パッケージをインストールしてもらう必要があること(上記参照)ですが、しばしばこれらはすでに存在しているので、常に問題になるわけではありません。まず、自分の IM 版をどのサブディレクトリにインストールしたいかを決めてください。専用ディレクトリが最良の選択です。インストールを削除するにはそのディレクトリ全体を削除するだけでよくなるからです。私の場合、ホームの "apps/im" サブディレクトリにインストールします。
export MAGICK_HOME=$HOME/apps/im
さて、個人用版をインストールするには、ImageMagick のソースをダウンロードし、展開し、その中にディレクトリを移動してください。それから 'uninstalled'(未インストール)版として設定してください。
rm config.status config.log
nice ./configure --prefix=$MAGICK_HOME --disable-installed \
--enable-shared --disable-static --without-modules --with-x \
--without-perl --without-magick-plus-plus --disable-openmp \
--with-wmf --with-gslib --with-rsvg --with-xml \
CFLAGS=-Wextra \
;
nice make clean
nice make
nice make install
上記の定義で重要なのは、"--prefix" を伴う "--disable-installed" です。他の部分は、個人用版 ImageMagick のよりオプション的な側面のコンパイルを無効にします。お好みに合わせて変更してください。さて、通常のシステム版ではなく自分自身でインストールした版を使うには、次の環境変数を設定するだけでよいです。
export MAGICK_HOME=$HOME/apps/im
export PATH="$MAGICK_HOME/bin:$PATH"
export LD_LIBRARY_PATH="$MAGICK_HOME/lib:$LD_LIBRARY_PATH"
さて、こうタイプすると
magick -version
インストールしたばかりの、より最新の IM 版がデフォルトで表示されます。変数 "$MAGICK_HOME" は、"--disable-installed" オプションで作成された Imagemagick には設定が必要であることに注意してください。他の 2 つの環境変数は、同時にインストールされているかもしれないシステム版ではなく、個人用版を確実に使うようにします。
警告: 上記の変数を混在させないでください。それらすべてを定義するか、このように定義しないでください。使う IM 実行ファイルは、その実行ファイルがビルドされたときと同じライブラリ、コーダ、設定ファイルも使わなければなりません。システム版と個人用版を混在させると、おそらくセグメンテーションフォルトとメモリフォルトを引き起こします。
再コンパイルせずに個人用 IM の場所を移動できますが、上記の環境変数を変更するだけでなく、個人用にインストールした "delegate.xml" ファイル内の "[show:](files.html#show)" デリゲートで使われる "magick display" プログラムへのハードコードされたパスも変更(または削除)する必要があります。IM のこの側面に関するより多くの情報は デリゲート を参照してください。
システムにインストールされた版と複数の個人用版の IM を簡単に切り替えられるよう、私は典型的に上記の変数をまったく設定しません。代わりに、特定の版の IM を呼び出す前にそれらの変数を設定するスクリプトを呼び出します。例えば、私は HDRI でコンパイルした個人用版の IM を持っており、ImageMagick 使用例の特定の例にのみ使います。ほとんどの画像作業には非 HDRI のシステムインストール版を好み、この版を通常は使いたくありません。そこで私は個人用領域 "$HOME/apps/im_hdri" に 'HDRI' 版の IM をインストールし、"hdri" と呼ぶスクリプトを作成しました。中身は...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
さて、こうタイプすると...
hdri magick -version
必要なときにだけ、HDRI 品質版の ImageMagick を実行したことがわかります。上記の前に "hdri" を付けなければ、通常のシステム版の IM を実行することになります。警告: 個人用版の IM がスクリプトによって見つからない場合、サイレントにシステム版の使用に戻ります。上記の 'version' チェックは、私が実際に個人用版を使っており、システム版ではないことを確認する重要なテストです。スクリプトが実行しようとしている magick コマンドが正確にどれかを 'which' を使って確認することもできます。
hdri which convert
つまり、スクリプトは柔軟なので、実際には "magick" を実行する必要はなく、ImageMagick シェルスクリプトのような任意のコマンドを実行でき、そのスクリプトが通常のシステムの convert ではなく HDRI の magick を使うようにできます。
hdri some_im_script image.png image_result_hdri.png
![[IM Text]](../static/img/api/hdri_version.txt.gif)