店舗の写真を処理する

DockerBeginner
オンラインで実践に進む

はじめに

Form & Field は次の店舗コレクションを準備しています。陶器のカップの写真と、透明なブランド画像が用意されています。原本と透明な背景を保ちながら、小さい Web 用画像を作りましょう。処理用コンテナが消えた後も、通常のユーザーが完成ファイルを編集できる必要があります。

Docker と準備済みの ImageMagick ツールイメージを利用できます。基本的な端末操作とパスの知識が前提です。Docker、バインドマウント、画像オプション、シェル構文は使用前に説明します。ワークステーションへのソフトウェアのインストールや画像処理コードの作成は不要です。店舗は架空で、写真は CC0、ブランド画像はオリジナルの教材です。

コマンドは Workstation、実際の画像の確認とダウンロードは Photo Desk を使います。このラボはコースのチャレンジと独立しています。読解と通常の間違いへの対応を含め、約 55 分を見込んでください。これは著者の見積もりです。

小さなサンプルを処理する

短時間だけ動くコンテナで、実際に縮小した写真を作ります。Photo Desk の Source collection から始めてください。写真を開き、Back to collection で戻ってからブランド画像を開きます。画像の背後の市松模様は透明なピクセルを示し、画像自体の一部ではありません。コレクションに戻ってください。

用意された写真と透明な画像

Workstation に切り替えます。開始位置は /home/labex/project/photo-studio です。pwd は現在のディレクトリを表示し、ls はその内容を一覧にします。ここから移動した場合は次の cd コマンドで戻れます。cd はシェルの現在のディレクトリを変更します。

cd /home/labex/project/photo-studio
ls

準備済みの source、samples、web は、それぞれ原本、練習結果、最終成果物用です。reference.jpg は変更しないでください。これは別の見本であり、あなたの出力ではありません。

イメージはプログラムと依存関係をまとめたものです。コンテナはそのイメージをプロセスとして実行します。ここでは dk01-photo-tools:1 に ImageMagick の convert が入っています。:1 は準備済みイメージのバージョンで、コンテナ名ではありません。docker run はコンテナを作成して開始し、--rm はプロセス終了後にそのコンテナを削除します。イメージ名の後の引数は convert に渡されます。

まずバージョンを確認します。-version は Docker ではなく ImageMagick のオプションです。

docker run --rm dk01-photo-tools:1 -version

出力に ImageMagick 6.9.11-60 が含まれるはずです。プログラムはコンテナ内で動くため、Workstation に convert がインストールされるわけではありません。

入力と出力を接続する

コンテナには独自のファイルシステムのパスがあります。バインドマウントはワークステーションのディレクトリをコンテナ内のパスで利用できるようにします。サンプルでは次のように接続します。

ワークステーションのディレクトリ コンテナのパス アクセス
現在のディレクトリ内の source /input 読み取り専用
現在のディレクトリ内の samples /output 読み書き

ワークステーション側がマウントの src、コンテナ側が dst です。type=bind はこの種類を指定します。readonly はそのマウント経由で入力に書き込むことを防ぎます。各 --mount は 1 つの接続を表します。/output に書いた結果は samples に届き、コンテナを削除しても残ります。

ファイルの所有者にも数値 ID があります。id -u はユーザー ID、id -g はグループ ID を表示します。

id -u
id -g

1000 と決めつけず、実際の値を使います。次のコマンドの $(...) は括弧内のコマンドを実行し、その出力を挿入します。そのため --user "$(id -u):$(id -g)" は実際の数値ユーザーとグループでツールを実行します。$PWD は現在のディレクトリの完全なパスに展開されます。二重引用符は、パスに空白があってもマウントの指定を 1 つにまとめます。

ImageMagick の -resize '320x320>' は、縦横比を保って写真を 320 × 320 ピクセル以内に収めます。> は縮小のみを意味します。単一引用符によってシェルの出力リダイレクトとして解釈させず、ImageMagick に渡します。行末のバックスラッシュは同じコマンドを次行へ続ける記号です。ブロック全体をコピーしてください。

docker run --rm --user "$(id -u):$(id -g)" \
  --mount "type=bind,src=$PWD/source,dst=/input,readonly" \
  --mount "type=bind,src=$PWD/samples,dst=/output" \
  dk01-photo-tools:1 /input/cups.jpg -resize '320x320>' /output/sample.jpg

成功時には通常何も表示されません。ls -l で結果と所有者を確認します。

ls -l samples/sample.jpg

labex 所有の通常ファイルが実用的な結果です。--rm でコンテナはすでに削除されていますが、マウント先の出力は残ります。入力ディレクトリ名を間違えると、Docker は有効な写真を作らず、無効なマウントを報告します。pwd と ls source を確認し、パスを直して同じブロックを再実行します。パスの誤りを隠すために sudo やディレクトリ権限の変更を使わないでください。

写真と透明画像を納品する

最終的な Web 用画像を 2 枚作ります。Photo Desk で Your delivery を選んでください。必要な形式と上限が示されていますが、最初は画像がありません。不足した成果物は不足したままです。このページが原本で穴埋めすることはありません。

カップ写真は縦横比を保った 640 × 640 ピクセル以内の JPEG、ブランド画像は透明度を保った 256 × 256 以内の PNG にします。各枠内で最大の等比サイズを使い、すでに小さい入力は拡大しません。枠は上限であり、正方形への切り抜きではありません。縦写真は 480 × 640、横長の画像は 256 × 128 になります。

Workstation に切り替えます。入力マウント、ユーザー、ツールは同じです。出力マウントを web にし、サイズ上限と出力名だけを変更します。

docker run --rm --user "$(id -u):$(id -g)" \
  --mount "type=bind,src=$PWD/source,dst=/input,readonly" \
  --mount "type=bind,src=$PWD/web,dst=/output" \
  dk01-photo-tools:1 /input/cups.jpg -resize '640x640>' /output/cups.jpg

透明な画像も処理します。PNG は透明度をサポートしますが JPEG はしません。すでに背景と合成されている場合、PNG 拡張子だけを残しても不十分です。このコマンドは元の透明なピクセルを保ちます。

docker run --rm --user "$(id -u):$(id -g)" \
  --mount "type=bind,src=$PWD/source,dst=/input,readonly" \
  --mount "type=bind,src=$PWD/web,dst=/output" \
  dk01-photo-tools:1 /input/brand.png -resize '256x256>' /output/brand.png

Photo Desk に切り替え、Your delivery を再読み込みし、各結果を開きます。表示寸法と写真の比率を確認してください。ブランド画像の背後の市松模様は引き続き透けて見えるはずです。各結果で Download file を使い、Back to collection で戻ります。ダウンロードされるのは web 内の実際のファイルです。

完成した Web 用画像の組

この画面は読み取り用で、処理や採点はしません。画像が見えるだけでは原本が無変更か、別フォルダーでスクリプトが動くかは分かりません。画像がない場合は Workstation に戻って入出力パスを確認し、該当コマンドを再実行します。ファイル不足のページと、画面全体への接続失敗は別の状態です。

移動できる処理手順を保存する

成功した 2 つの Docker コマンドを保存し、別のスタジオフォルダーでも自分の原本を処理できるようにします。Workstation の /home/labex/project/photo-studio から始めます。

シェルスクリプトはコマンドを含むテキストファイルです。bash run-photos.sh は Bash に順番に実行させます。次の here-document は RECIPE の印の間の行をファイルに書きます。cat がテキストを供給し、> が保存し、<<'RECIPE' が文字どおりのテキストブロックを示します。最初の印を引用すると、保存時に $PWD と $(id ...) が展開されません。これらは後で、利用者が自分のフォルダーで実行するときに展開する必要があります。終了の印は単独の行に置きます。

set -e はツールのコマンドが失敗したら停止し、後続コマンドが前の失敗を隠さないようにします。完全な手順を保存してください。

cat > run-photos.sh <<'RECIPE'
#!/bin/bash
set -e
docker run --rm --user "$(id -u):$(id -g)" \
  --mount "type=bind,src=$PWD/source,dst=/input,readonly" \
  --mount "type=bind,src=$PWD/web,dst=/output" \
  dk01-photo-tools:1 /input/cups.jpg -resize '640x640>' /output/cups.jpg
docker run --rm --user "$(id -u):$(id -g)" \
  --mount "type=bind,src=$PWD/source,dst=/input,readonly" \
  --mount "type=bind,src=$PWD/web,dst=/output" \
  dk01-photo-tools:1 /input/brand.png -resize '256x256>' /output/brand.png
RECIPE

リダイレクトなしの cat はファイルを表示します。保存内容に $PWD と id の置換が文字どおり残っていることを確認します。

cat run-photos.sh

このスタジオディレクトリから実行します。同じ 2 つの派生ファイルを意図的に更新しますが、原本は決して書き換えません。

bash run-photos.sh

再利用の契約は、source、web、このスクリプトを含むフォルダーです。別の場所にコピーした場合、空白を含むフォルダー名でも、同じファイル名の別の互換画像を処理できる必要があります。小さい原本は拡大せず、元の寸法を保ちます。PATH 上の通常の docker run を使い、sudo、固定の数値 UID、ワークステーションの絶対パス、入力編集、追加のホストマウントは使いません。同じ安全な入出力関係ならコンテナ側のパスは異なっても構いません。Bash 経由で呼ぶため、実行権限は不要です。

最後に通常のファイル操作を試します。cp はコピー、mv は名前変更または移動を行います。次の 2 つは派生サンプルのコピーだけを操作します。

cp web/cups.jpg samples/shop-preview.jpg
mv samples/shop-preview.jpg samples/ready.jpg
ls -l samples/ready.jpg

管理者権限は不要です。web には指定された 2 ファイルだけを残し、練習物は samples に置きます。もっともらしい名前だけでは不十分です。チェックは実画像をデコードし、独立した互換入力で変更のないスクリプトを実行します。納品物を生成し直すことはありません。

Photo Desk に切り替え、Your delivery を再読み込みし、両出力をもう一度開いてコレクションに戻ります。すべての処理コンテナが消えてもファイルは存在します。提供された source ファイルと reference.jpg を保ってください。

まとめ

Docker イメージを使い捨ての写真ツールとして使い、入力と出力を別々にマウントし、読み取り専用入力で原本を保護しました。実際の UID/GID でツールを実行したため、本物の JPEG と透明 PNG はコンテナ削除後も編集できます。保存した処理スクリプトは、ツールをワークステーションにインストールせず、移動したフォルダーで互換入力を処理できます。