ImageMagick/GraphicsMagick: 一時ファイルなしで 1 つのステップで複数の (3+) イメージをマージ/合成するには?

ImageMagick/GraphicsMagick: 一時ファイルなしで 1 つのステップで複数の (3+) イメージをマージ/合成するには?

テキスト/フォント/サイズが異なる複数(2つ以上)の小さな画像を作成し、それを一時的な名前のファイルを直接作成するのではなく、1つの手順で別の場所の単一ソース画像にオーバーレイしようとしています。

これまでに試したことは次のとおりです。

  • 単一のテキストを生成し、パイプとMIFFストリームを使用してどこかにマージします。(動作しますが、複数の画像が必要です):

    gm convert \
      -background transparent \
      -fill black \
      -font Calibri \
      -size 300x100 \
      -pointsize 36 \
      -gravity SouthEast \
      label:'large text' \
      miff:- \
    | gm composite -geometry +10+10 miff:- source.tif out.tif
    
  • 最初のイメージの作成とマージ、出力一時ファイルの保存、一時ファイルのロード、ソースへのマージ(動作するが必要gmな一時ファイルへの2回の呼び出しを作成し、手動で削除する必要があります):

    gm convert \
      -background transparent \
      -fill black \
      -font Calibri \
      -size 300x100 \
      -pointsize 36 \
      -gravity SouthEast \
      label:'large text' \
      miff:- \
    | gm composite -geometry +10+10 miff:- source.tif tmp.tif ; \
    gm convert \
      -background transparent \
      -fill grey \
      -font Calibri \
      -size 200x50 \
      -pointsize 12 \
      -gravity SouthEast \
      label:'small text' \
      miff:- \
    | gm composite -geometry +300+100 miff:- tmp.tif out.tif
    
  • 複数のテキストを生成し、最後の場所のみを計算し、すべてのファイルに適用される1つの場所にマージします。(動作しません。最初のテキストのみが上書きされます。):

    { gm convert \
      -background transparent \
      -fill black \
      -font Calibri \
      -size 300x100 \
      -pointsize 36 \
      -gravity SouthEast \
      label:'large text' \
      miff:- ; \
      gm convert \
      -background transparent \
      -fill grey \
      -font Calibri \
      -size 200x50 \
      -pointsize 12 \
      -gravity SouthEast \
      label:'small text' \
      miff:- ; } \
    | gm composite miff:- -geometry +10+10 miff:- -geometry +300+100 source.tif -geometry +0+0 out.tif
    
  • 構文を使用して、( ... )「text1.tif」と「text2.tif」を中gm convert括弧内のコマンドに置き換えます。(とにかく動作しません。たぶん間違って使っているのでしょうか?)

  • flatten代わりに使用composite (動作しますが、すべてのファイルが異なる場所ではなく同じ場所にある場合は、複数ページの画像が壊れます。)
  • append単一パイプで複数のファイルを使用する(並んで重ならずに重ねなければならない)

一時ファイルを保存して読み込むことなく、3つ以上の画像を結合して、各画像が出力画像内で異なる場所になるようにすることはできますか?あるいは、画像を書き込む前に重なる画像のz順序をどのように設定できますか?可能であればgm 1.3.25bash 4.3実行可能な選択肢に開いています。

ベストアンサー1

もともとの要求によれば、一度に2つの画像でしか作業できないので、3つの画像(ファイルから1つ、生成された2つ)を一度に組み合わせる必要があることがわかります。

また、一時データをディスクに保存したくないことも理解しています。最も速い解決策は、@nominal-animalの以前の答えで提案されているように「tmpfs」を使用することです。

ただし、さらに一歩進むと、一時ファイルの生成を防ぎ、基本的にすべての処理を一度に実行できます。私が見つけた解決策は、データをディスクに保存せずに受信部分も準備されるまで、パイプのすべての転送を一時停止する特別なファイルである「名前付きパイプ」を使用することでした。指定したコマンド全体(コマンド、入力、出力のみ)を使用せずに、必要なパラメータを自由に入力してください。

# First it's necessary to have the pipes created, one time operation and they can be reused over and over.
mknod /tmp/pipe1 p
mknod /tmp/pipe2 p
mknod /tmp/pipe3 p

# generate the 2 images and send each to a pipe 
gm convert ... miff:- > pipe1 &
gm convert ... miff:- > pipe2 &
# merge the source image to the 1st generated image
gm composite ... source.tif pipe1 miff:- > pipe3 &
# finally merge the result to the 2nd generated image
gm composite ... pipe3 pipe2 out.tif

タスクは4つのステップしか必要と思われないかもしれませんが、実際には何もディスクに書き込むのではなく、すべてのタスクが一度に実行されます。

動作方法とコマンドがこのように書かれた理由は次のとおりです。

  • 最初のイメージを生成するコマンドは要求処理を開始しますが、出力は名前付きパイプに移動する必要があります。今はパイプから何も読み取らないので、出力はリスニングを停止します。プロセスが終了したりエラーが表示されないため、続行するためにバックグラウンドに切り替えられます。
  • 2番目の図はパイプだけが異なるだけで同じです。
  • ソースイメージと最初のパイプのデータをマージすると、パイプ1から読み取られ、最初のビルドコマンドは解放されますが、出力は別のパイプに移動するため、最後のステップを待つ必要があります。
  • Pipe3とPipe2のデータをマージすると、操作が完了し、必要な出力ファイルが生成され、最初の2つのコマンドがリリースされます。

パイプをファイルではなく一時ファイルとして考えることができます。バックグラウンドに何かを置くことを忘れないでください。それ以外の場合、スクリプトはCtrl + Cを待ちます。各コマンドはバックグラウンドで別々に配置する必要があります!前のコマンドが完了した後に出力を生成すると、このようなスクリプトに出力を入れるのに問題はありません。

良い機能は、4つのコマンドすべてがパイプからの着信データに依存するため、バックグラウンドで最初に3つのコマンドを開始してから、通常は最後のコマンドを開始できることです。また、パイプを追加するだけで複数のコマンドに簡単に拡張できます。

制限があります。同じパイプラインを並列に使用することはできません。必要に応じて、並列に実行される各インスタンスに対して異なるパイプライングループを使用する必要があります。そうでなければ驚きます。 :) そのような問題はありません。順次処理として。

パフォーマンスの観点からは、これが「tmpfs」に一時ファイルを作成するよりも速いかどうかはわかりません。実際のシナリオでテストして調べる必要があります。これを行うには、4つのプロセスとそのデータをすべてメモリに収容するのに十分なメモリが必要です。 (これは処理/作成する画像のサイズによって大きく異なります。)

おすすめ記事