写真ワークフロー自動化 - スクリプトで大量画像を効率処理する方法
なぜ写真ワークフローを自動化すべきか - 手動処理の限界
EC サイトの商品画像更新、メディアサイトの記事画像準備、写真家のポートフォリオ管理など、大量の画像を定期的に処理する場面は多くあります。手動で 1 枚ずつ処理する場合、リサイズ・フォーマット変換・メタデータ除去・ファイル名変更の一連の作業に 1 枚あたり 2-3 分かかります。100 枚なら 3-5 時間、1000 枚なら丸 3 日以上の作業です。
自動化スクリプトを使えば、同じ処理を 100 枚で 30 秒、1000 枚で 5 分程度に短縮できます。さらに重要なのは、手動処理で発生する「設定の揺れ」を排除できることです。品質パラメータの統一、出力サイズの正確性、メタデータ除去の漏れ防止など、品質の一貫性が自動化の最大のメリットです。
本記事では、コマンドラインツールと Node.js スクリプトを組み合わせた実践的なバッチ処理ワークフローを構築します。対象読者は、ターミナル操作の基本を理解しており、数百枚以上の画像を定期的に処理する必要がある方です。
使用するツールは以下の 3 つです。ImageMagick (汎用画像処理、豊富なフィルター)、sharp (Node.js、高速なリサイズとフォーマット変換)、ExifTool (メタデータの読み書き・除去)。これらを組み合わせることで、あらゆる画像処理要件に対応できます。
ImageMagick によるバッチ処理の基本
ImageMagick は 30 年以上の歴史を持つ画像処理ツールで、200 以上のフォーマットに対応し、コマンドラインから複雑な画像操作を実行できます。バッチ処理では mogrify コマンド (上書き変換) と convert コマンド (新規ファイル生成) を使い分けます。
一括リサイズ: mogrify -resize 1200x1200> -quality 82 *.jpg - 全 JPEG ファイルを最大 1,200 px (アスペクト比維持) にリサイズし、品質 82 で再圧縮します。> フラグにより、元画像が 1,200 px 以下の場合は拡大されません。
フォーマット変換: mogrify -format webp -quality 80 *.jpg - 全 JPEG を WebP に変換します。元ファイルは残り、同名の .webp ファイルが生成されます。
条件付き処理: find . -name "*.png" -size +500k -exec convert {} -quality 85 {}.webp \; - 500KB 以上の PNG のみを WebP に変換します。小さいファイルは変換のオーバーヘッドが効果を上回るため除外します。
複合操作: convert input.jpg -resize 800x600^ -gravity center -extent 800x600 -strip -quality 80 output.jpg - リサイズ → 中央クロップ → メタデータ除去 → 品質設定を 1 コマンドで実行します。-strip で EXIF/ICC プロファイルを除去し、^ フラグでアスペクト比を維持しつつ指定サイズ以上にリサイズした後、-extent でクロップします。
並列処理: find . -name "*.jpg" | parallel -j 8 convert {} -resize 1200x -quality 80 output/{/.}.webp - GNU Parallel を使って 8 並列で処理します。8 コア CPU で処理速度が 6-7 倍に向上します。
sharp (Node.js) による高速バッチ処理スクリプト
sharp は libvips をバインディングした Node.js の画像処理ライブラリで、ImageMagick より 4-5 倍高速に動作します。特にリサイズとフォーマット変換のパフォーマンスに優れ、大量画像の処理に最適です。
基本的なバッチ処理スクリプト:
const sharp = require('sharp');
const glob = require('glob');
const path = require('path');
const files = glob.sync('./input/**/*.{jpg,jpeg,png}');
const CONCURRENCY = 8;
async function processImage(file) {
const name = path.basename(file, path.extname(file));
await sharp(file)
.resize(1200, null, { withoutEnlargement: true })
.webp({ quality: 78 })
.toFile(`./output/${name}.webp`);
await sharp(file)
.resize(1200, null, { withoutEnlargement: true })
.avif({ quality: 62, speed: 6 })
.toFile(`./output/${name}.avif`);
}
このスクリプトは入力ディレクトリの全画像を WebP と AVIF の 2 フォーマットに変換します。withoutEnlargement: true で小さい画像の拡大を防止し、並列度 8 で処理します。
複数解像度の一括生成: レスポンシブ画像用に複数サイズを生成する場合、[400, 800, 1200, 1600] の配列をループし、各サイズ × 各フォーマットの組み合わせを生成します。1 枚の元画像から 8 バリアント (4 サイズ × 2 フォーマット) を生成する場合、1000 枚で 8000 ファイルが出力されます。sharp の処理速度なら、8 並列で約 3-5 分で完了します。
エラーハンドリング: バッチ処理では一部のファイルが破損している場合があります。try-catch で個別のエラーをキャッチし、失敗したファイルをログに記録して処理を継続する設計が重要です。全体を止めずに、最後にエラーレポートを出力します。
ExifTool によるメタデータ管理の自動化
ExifTool は画像のメタデータ (EXIF、IPTC、XMP) を読み書きする専門ツールです。プライバシー保護のための GPS 情報除去、著作権情報の一括付与、ファイル名の日時ベースリネームなど、メタデータに関するあらゆる操作を自動化できます。
プライバシー保護 - GPS 情報の除去: exiftool -gps:all= -xmp:geotag= *.jpg - GPS 関連のタグのみを除去し、他のメタデータ (カメラ設定、撮影日時) は保持します。Web 公開前の必須処理です。
全メタデータの除去: exiftool -all= -tagsfromfile @ -colorspace -icc_profile *.jpg - 全メタデータを除去しつつ、ICC プロファイル (色空間情報) のみ保持します。色空間情報を除去すると、広色域ディスプレイで色が正しく表示されなくなるため、この方法が推奨されます。
著作権情報の一括付与: exiftool -artist="Photographer Name" -copyright="2024 All Rights Reserved" -overwrite_original *.jpg - 全画像に著作権情報を埋め込みます。-overwrite_original でバックアップファイルの生成を抑制します。
撮影日時ベースのリネーム: exiftool '-filename<DateTimeOriginal' -d '%Y%m%d_%H%M%S%%-c.%%e' *.jpg - 撮影日時に基づいてファイル名を変更します (例: 20240315_143022.jpg)。%%-c で同一秒の重複を連番で回避します。
条件付きフィルタリング: exiftool -if '$ImageWidth > 3000' -print *.jpg - 幅 3,000 px 以上の画像のみをリストアップします。これを xargs と組み合わせて、条件に合致する画像のみを処理対象にできます。大量のファイルから特定条件の画像を抽出する際に非常に有用です。
JSON 出力: exiftool -json -ImageWidth -ImageHeight -FileSize *.jpg > metadata.json - メタデータを JSON 形式で出力し、後続のスクリプトで利用できます。画像カタログの作成や、処理対象の選別に活用します。
実践的なワークフロー構築 - EC サイト商品画像の例
EC サイトの商品画像処理を例に、複数ツールを組み合わせた実践的なワークフローを構築します。要件は以下の通りです: 撮影した RAW/JPEG 画像を、Web 配信用に最適化し、複数サイズ・フォーマットで出力する。
ワークフローの全体像:
- Step 1: 入力検証 - ファイル形式、最小解像度 (2,000 px 以上) の確認
- Step 2: メタデータ処理 - GPS 除去、著作権付与
- Step 3: 色補正 - sRGB への変換 (印刷用 Adobe RGB からの変換)
- Step 4: リサイズ・クロップ - 商品画像の正方形クロップ (1:1)
- Step 5: フォーマット変換 - AVIF + WebP + JPEG の 3 フォーマット × 3 サイズ
- Step 6: 出力検証 - ファイルサイズ、解像度、品質スコアの確認
Step 4 の詳細 (正方形クロップ): EC サイトでは商品画像を正方形で統一することが多いです。sharp の .resize(1200, 1200, { fit: 'cover', position: 'centre' }) で中央基準の正方形クロップを実行します。被写体が中央にない場合は、sharp の attention ストラテジー (position: sharp.strategy.attention) を使用すると、被写体を自動検出してクロップ位置を最適化します。
Step 5 の出力マトリクス: 1 枚の入力画像から以下の 9 ファイルを生成します。400px (サムネイル)、800px (一覧表示)、1,200 px (詳細表示) × AVIF/WebP/JPEG = 9 バリアント。1000 商品で 9000 ファイル、処理時間は 8 並列で約 8-12 分です。
CI/CD パイプラインへの統合と監視
ワークフローを CI/CD パイプラインに統合することで、画像のアップロードから最適化・デプロイまでを完全自動化します。
GitHub Actions での実装例: 画像ファイルが images/raw/ ディレクトリにプッシュされたことをトリガーに、最適化パイプラインを実行します。ワークフローの構成は: (1) 変更された画像ファイルの検出、(2) バッチ処理スクリプトの実行、(3) 出力画像の品質検証 (SSIM チェック)、(4) S3 へのアップロード、(5) CDN キャッシュのインバリデーション。
品質ゲートの設定: 自動処理の品質を担保するため、以下のチェックをパイプラインに組み込みます。ファイルサイズの上限チェック (1,200 px WebP で 200KB 以下)、最小解像度の確認 (出力が指定サイズを満たしているか)、SSIM スコアの下限チェック (元画像との類似度 0.93 以上)。いずれかの条件を満たさない画像がある場合、パイプラインを失敗させて手動確認を促します。
処理結果のレポート: バッチ処理の完了後、以下の情報をレポートとして出力します。処理枚数、成功/失敗数、合計入力サイズと出力サイズ (削減率)、処理時間、品質チェックの結果。Slack や Teams への通知を設定し、処理完了を即座に把握できるようにします。
増分処理の最適化: 全画像を毎回処理するのではなく、変更された画像のみを処理する増分処理を実装します。Git の差分検出 (git diff --name-only) で変更ファイルを特定し、該当ファイルのみをパイプラインに渡します。これにより、1 枚の画像追加で全画像を再処理する無駄を排除し、CI/CD の実行時間を数秒に短縮できます。
監視とアラート: 処理時間の異常増加 (通常の 3 倍以上)、エラー率の上昇 (5% 以上)、出力ファイルサイズの異常 (平均の 2 倍以上) を監視し、問題を早期に検出します。