2024/11/16(土)exiftool(CLI付Perlライブラリ)の存在とインストール,使い方(編集中)

ImageMagickよりも高速なEXIF情報読み書きツールの存在を知ったので,
そのインストール方法とコマンドとしての使い方,スクリプトの例を紹介しようと思います.
元の情報は『Ubuntu Weekly Recipe 第553回Ubuntuで写真のメタデータを扱う方法』というgihyo.jpの記事です.
これを参考にして,先日作った写真画像ファイルにフィルム写真風の日付を挿入するシェルスクリプト改3にさらに手を加え,
カメラ本体やレンズの情報を写真に挿入するスクリプトを作成します.

exiftoolのインストール

リンク先はUbuntu向けの記事ですが,Debian 12でも同じパッケージをインストールできるのでそうします*1
$ su -
# apt install libimage-exiftool-perl

*1 : ただし,流儀の違いでsudoは使わず,“su -”でrootにスイッチして作業しています.

使い方(コマンド単発)

写真ファイル名が“IMGP55○○.JPG”として,次のようにオプションなしで実行すると,読み出し可能なEXIF情報が整形されて表示されます.
カメラ本体やレンズのモデルまでしっかり表示されます.
ImageMagickの“ magick identify -verbose”コマンドはレンズのモデル名が表示されず,表示に時間も掛かるので,exiftoolコマンドは優秀です.
$ exiftool IMGP55○○.JPG
このオプションなしのコマンドは,シェルスクリプト等で利用する際に少し不便です.
対策として-sオプションを付けると,項目名が短縮されたものに変わるため,使いやすくなります.
$ exiftool -s IMGP55○○.JPG

スクリプトの例

ImageMagick6系用のシェルスクリプトです.
#!/bin/bash
# 写真ファイルを整理し,画像中に各種撮影情報を追記するシェルスクリプトです.
#
# 引数の説明
# $1: 操作対象パス(ファイル)リストが記載されたファイル.
#
# 使い方: 例えば,
# A. Linux端末上で処理したい場所に移動し,このスクリプトファイル(例では“magick-010.sh”です)を実行可能にして置いてください.
# B. “ls | grep JPG > list.txt”等で処理リストを作成します.
# C. “./magick-010.sh list.txt”のようにして実行してください.
#
# 実行に必要なソフト: ImageMagickとexiftoolコマンド,bcコマンド,および使用するフォント.
# 他は標準でインストールされていると思います.
#
# SEIREKI_BACKQUOTE="\`" # "`"はグレイヴアクセント.西暦の略記はアポストロフィ“'”.
SEIREKI_BACKQUOTE=`echo -e "\U0027"` # グレイヴアクセントや文字コード指定がsed中で上手くエスケープできないので変数に分けた.
while read IMAGENAME # $1の各行に記載された画像ファイルのパス.
 do
                echo "\"${IMAGENAME}\"の撮影情報の取得……"
                DateTimeOriginal=`exiftool -s -lang ja -DateTimeOriginal ${IMAGENAME} | #表示結果例: 『DateTimeOriginal                : 2024:08:17 09:50:58』
                       sed -e "s/^DateTimeOriginal.*: //g" ` #処理結果例: 『2024:08:17 09:50:58』
                FILENAME_DATETIME=`echo ${DateTimeOriginal} |
                        sed -e "s/ /-/g" | 	#処理結果例: 『2024:08:17-09:50:58』
                        sed -e "s/^/p/g" | 	#処理結果例: 『p2024:08:17-09:50:58』
                        sed -e "s/://g" ` 	#処理結果例: 『p20240817-095058』
                DateOriginal=`echo ${DateTimeOriginal} | 
                        sed -e "s/ .*$//g" |					#処理結果例: 『2024:08:17』
                        sed -e "s/20\(..\):/${SEIREKI_BACKQUOTE}\1:/g" |	#処理結果例: 『'24:08:17』
                        sed -e "s/:/     /g" `					#処理結果例: 『'24     08     17』(これくらいスペースを空けないと体裁整わない.)
                Model=`exiftool -s -lang ja -Model ${IMAGENAME} | #表示結果例: 『Model                           : PENTAX K-3 Mark III』
                       sed -e "s/^Model.*: //g" ` #処理結果例: 『PENTAX K-3 Mark III』
                LensType=`exiftool -s -lang ja -LensType ${IMAGENAME} | #表示結果例: 『LensID                          : HD PENTAX-DA 16-85mm F3.5-5.6 ED DC WR』
                       sed -e "s/^LensType.*: //g" ` #処理結果例: 『HD PENTAX-DA 16-85mm F3.5-5.6 ED DC WR』
                FocalLength=`exiftool -s -lang ja -FocalLength ${IMAGENAME} | #表示結果例: 『FocalLength                     : 16.0 mm』
                       sed -e "s/^FocalLength.*: //g" ` #処理結果例: 『16.0 mm』
                FNumber=`exiftool -s -lang ja -FNumber ${IMAGENAME} | #表示結果例: 『FNumber                         : 8.0』
                       sed -e "s/^FNumber.*: //g" ` #処理結果例: 『8.0』
                ExposureTime=`exiftool -s -lang ja -ExposureTime ${IMAGENAME} | #表示結果例: 『ExposureTime                    : 1/40』
                       sed -e "s/^ExposureTime.*: //g" ` #処理結果例: 『1/40』
                ISO=`exiftool -s -lang ja -ISO ${IMAGENAME} | #表示結果例: 『ISO                             : 6400』
                       sed -e "s/^ISO.*: //g" ` #処理結果例: 『6400』
                ExposureCompensation=`exiftool -s -lang ja -ExposureCompensation ${IMAGENAME} | #表示結果例: 『ExposureCompensation            : 0』
                       sed -e "s/^ExposureCompensation.*: //g" ` #処理結果例: 『0』
		FOV=`exiftool -s -lang ja -FOV ${IMAGENAME} | #表示結果例: 『FOV                             : 73.7 deg』
                       sed -e "s/^FOV.*: //g" ` #処理結果例: 『73.7 deg』
                FocalLength35efl=`exiftool -s -lang ja -FocalLength35efl ${IMAGENAME} | #表示結果例: 『FocalLength35efl                : 17.0 mm (35 mm equivalent: 17.0 mm)』
                       sed -e "s/^FocalLength35efl                : //g" ` #処理結果例: 『17.0 mm (35 mm equivalent: 17.0 mm)』この項目だけコロンが2つあるので,置換パターンを決め打ちで入力.
                Time=`exiftool -s -lang ja -Time ${IMAGENAME} | #表示結果例: 『Time                            : 09:50:58』
                       sed -e "s/^Time.*: //g" ` #処理結果例: 『09:50:58』
                echo "撮影情報読み込みOK! ${DateOriginal}, ${FILENAME_DATETIME}, ${Model}, ${LensType}, ${FocalLength35efl}, F${FNumber}, ${ExposureTime}, ISO${ISO}, EV ${ExposureCompensation}"

		IMAGE_WIDTH=`exiftool -s -b -ImageWidth ${IMAGENAME}`
		IMAGE_HEIGHT=`exiftool -s -b -ImageHeight ${IMAGENAME}`

		#日付情報のフォント・位置設定
		DATE_POINTSIZE=`echo "${IMAGE_WIDTH} * 0.03" | bc -l | xargs printf "%.0f"`
		DATE_STROKEWIDTH=`echo "${IMAGE_WIDTH} * 0.00065" | bc -l | xargs printf "%.0f"`
		DATE_POSITION_X=`echo "${IMAGE_WIDTH} * 0.1" | bc -l | xargs printf "%.0f"`
		DATE_SHADOW_POSITION_X=`echo "${DATE_POSITION_X} - ${DATE_STROKEWIDTH}" | bc -l | xargs printf "%.0f"`
		DATE_POSITION_Y=`echo "${IMAGE_HEIGHT} * 0.08" | bc -l | xargs printf "%.0f"`
		DATE_SHADOW_POSITION_Y=`echo "${DATE_POSITION_Y} - ${DATE_STROKEWIDTH}" | bc -l | xargs printf "%.0f"`
		#時刻のみタイムスタンプ
		TIME_POINTSIZE=`echo "${IMAGE_WIDTH} * 0.02" | bc -l | xargs printf "%.0f"`
		TIME_STROKEWIDTH=`echo "${IMAGE_WIDTH} * 0.00065" | bc -l | xargs printf "%.0f"`
		TIME_POSITION_X=`echo "${IMAGE_WIDTH} * 0.02" | bc -l | xargs printf "%.0f"`
		TIME_SHADOW_POSITION_X=`echo "${DATE_POSITION_X} - ${DATE_STROKEWIDTH}" | bc -l | xargs printf "%.0f"`
		TIME_POSITION_Y=`echo "${IMAGE_HEIGHT} * 0.07" | bc -l | xargs printf "%.0f"`
		TIME_SHADOW_POSITION_Y=`echo "${DATE_POSITION_Y} - ${DATE_STROKEWIDTH}" | bc -l | xargs printf "%.0f"`
		
		#撮影情報のフォント・位置設定
		#上段
		INFO_POINTSIZE=`echo "${IMAGE_WIDTH} * 0.02" | bc -l | xargs printf "%.0f"`
		INFO_STROKEWIDTH=`echo "${IMAGE_WIDTH} * 0.00065" | bc -l | xargs printf "%.0f"`
		INFO_POSITION_X=`echo "${IMAGE_WIDTH} * 0.04" | bc -l | xargs printf "%.0f"`
		INFO_SHADOW_POSITION_X=`echo "${INFO_POSITION_X} - ${INFO_STROKEWIDTH}" | bc -l | xargs printf "%.0f"`
		INFO_POSITION_Y=`echo "${IMAGE_HEIGHT} * 0.032" | bc -l | xargs printf "%.0f"`
		INFO_SHADOW_POSITION_Y=`echo "${INFO_POSITION_Y} - ${INFO_STROKEWIDTH}" | bc -l | xargs printf "%.0f"`
		#下段
		INFO2_POSITION_X=`echo "${IMAGE_WIDTH} * 0.04" | bc -l | xargs printf "%.0f"`
		INFO2_SHADOW_POSITION_X=`echo "${INFO_POSITION_X} - ${INFO_STROKEWIDTH}" | bc -l | xargs printf "%.0f"`
		INFO2_POSITION_Y=`echo "${IMAGE_HEIGHT} * 0.004" | bc -l | xargs printf "%.0f"`
		INFO2_SHADOW_POSITION_Y=`echo "${INFO_POSITION_Y} - ${INFO_STROKEWIDTH}" | bc -l | xargs printf "%.0f"`

		#一時ファイル
                OUTPUT_IMAGENAME=`echo "${IMAGENAME}-tmp.jpg"`		#一時ファイルの名前
                OUTPUT_IMAGENAME2=`echo "${IMAGENAME}.jpg"`		#一時ファイルの名前2

		#本処理.
		#↓黒文字で日付の陰を先に生成する.
                convert  -font DSEG14-Classic-Bold -fill "#00000010" -pointsize ${DATE_POINTSIZE} \
			-gravity southeast -annotate 0x0+${DATE_SHADOW_POSITION_X}+${DATE_SHADOW_POSITION_Y} "${DateOriginal}" ${IMAGENAME} ${OUTPUT_IMAGENAME}
                #↓日付を生成する.
		convert -font DSEG14-Classic-Bold -fill "#fd7e0070" -stroke "#00000070" -strokewidth ${DATE_STROKEWIDTH} -pointsize ${DATE_POINTSIZE} \
			-gravity southeast -annotate 0x0+${DATE_POSITION_X}+${DATE_POSITION_Y} "${DateOriginal}" ${OUTPUT_IMAGENAME} ${OUTPUT_IMAGENAME}
		#↓時刻を生成する.
	        convert -font Nimbus-Sans-Narrow-Bold -fill "#fd7e0070" -stroke "#00000070" -strokewidth ${TIME_STROKEWIDTH} -pointsize ${TIME_POINTSIZE} \
			-gravity southeast -annotate 0x0+${TIME_POSITION_X}+${TIME_POSITION_Y} \
			"${Time}" ${OUTPUT_IMAGENAME} ${OUTPUT_IMAGENAME}
		#↓撮影情報を追記する.
		#上段
	        convert -font Nimbus-Sans-Narrow-Bold -fill "#fd7e0070" -stroke "#00000070" -strokewidth ${INFO_STROKEWIDTH} -pointsize ${INFO_POINTSIZE} \
			-gravity southwest -annotate 0x0+${INFO_POSITION_X}+${INFO_POSITION_Y} \
			"${Model},    ${LensType}" ${OUTPUT_IMAGENAME} ${OUTPUT_IMAGENAME}
		#下段
	        convert -font Nimbus-Sans-Narrow-Bold -fill "#fd7e0070" -stroke "#00000070" -strokewidth ${INFO_STROKEWIDTH} -pointsize ${INFO_POINTSIZE} \
			-gravity southeast -annotate 0x0+${INFO2_POSITION_X}+${INFO2_POSITION_Y} \
			"${FocalLength35efl},  F${FNumber},  ${ExposureTime},  ISO${ISO},  EV ${ExposureCompensation}" ${OUTPUT_IMAGENAME} ${OUTPUT_IMAGENAME2}

                rm ${OUTPUT_IMAGENAME}						#一時ファイルを削除する.
                OUTPUT_IMAGENAME3=`echo ${OUTPUT_IMAGENAME2} |			#OUTPUT_IMAGENAME2を元に出力ファイル名を決定
                        sed -e "s/\.JPG\.jpg/_TS.jpg/g" |			#
                        sed -e "s/^.*_TS.jpg/${FILENAME_DATETIME}_&/g"`		#先頭に日付の文字列を追加.
		mv ${OUTPUT_IMAGENAME2} "${OUTPUT_IMAGENAME3}"
                echo "出力ファイル名: ${OUTPUT_IMAGENAME3}"
done < $1