2024/03/18(月)写真画像ファイルにフィルム写真風の日付を挿入するシェルスクリプト

写真の画像ファイルに,フィルム写真風の日付を追加できると良いと思い立ち,シェルスクリプトを作成しました.
これは,仕事の写真の説明や保存管理にも使えるでしょうし,
手抜きのフォトアルバムを作るのにも使えそうです.

処理結果は次のような感じになります*1
_IMP0222.JPG.jpg
[2018:08:13 14:34:22, PENTAX Q7 , / 3.8mm F5.0 0.001秒 ISO100]


日付情報は,通常写真ファイルに埋め込んであるので,それを読み出して写真画面上に描き込みます.
7セグ・14セグフォント 「DSEG」から,14セグメントなフォントをいただいて*2,それっぽく見せます.

以下のスクリプトはWSL上のDebian 12で動作確認しました.
Debian 12のImageMagickは6.9系なのでmagickコマンドではなく,昔ながらのidentifyやconvertコマンドです.
ImageMagick7系の場合は書き換える必要があります.
引数の処理対象のリストファイルはUNIX系のパス記述方法で記載します.lsの出力結果を整形するのが良さそうです.
#!/bin/bash
# 引数の説明
# $1: 操作対象パス(ファイル)リストが記載されたファイル.
# SEIREKI_BACKQUOTE="\`" # "`"はグレイヴアクセント.西暦の略記はアポストロフィ“'”.
SEIREKI_BACKQUOTE=`echo -e "\U0027"` # グレイヴアクセントや文字コード指定がsed中で上手くエスケープできないので変数に分けた.
while read IMAGENAME # $1の各行に記載された画像ファイルのパス.
 do
                 echo "\"${IMAGENAME}\"の撮影日時の取得……"
                 DateTimeOriginal=`identify -verbose ${IMAGENAME} |
                         grep "DateTimeOriginal" |
                         sed -e "s/^.*exif:DateTimeOriginal: //g" |
                         sed -e "s/ .*$//g" |
                         sed -e "s/:/     /g" |
                         sed -e "s/20/${SEIREKI_BACKQUOTE}/g" `
                 echo "${DateTimeOriginal}"
                 OUTPUT_IMAGENAME=`echo "${IMAGENAME}.jpg"`
                 echo "出力ファイル名: ${OUTPUT_IMAGENAME}"
                 convert -resize 3096x2064 -font DSEG14-Classic-Bold -fill orange -pointsize 100 -gravity southeast -annotate 0x0+300+150 "${DateTimeOriginal}" ${IMAGENAME} ${OUTPUT_IMAGENAME}
done < $1

*1 : ただしこの例はconvertコマンドを直接実行しただけです.イメージはつかめるでしょう.

*2 : 素敵なフォントをありがとうございます.

改良版

フォントに陰をつけて可読性を高めました.手抜きのためjpgファイルの編集を2回繰り返しているので,画質劣化の傾向あるかもしれません.
フォント系で凝った処理を入れたい場合は文字列部分をpngで作成して,重ね処理をし,最後に写真画像と重ね合わせると良いと思います.
後,下の例はImageMagick7系のコマンドになっているのでご注意ください.
#!/bin/bash
# 引数の説明
# $1: 操作対象パス(ファイル)リストが記載されたファイル.
# SEIREKI_BACKQUOTE="\`" # "`"はグレイヴアクセント.西暦の略記はアポストロフィ“'”.
SEIREKI_BACKQUOTE=`echo -e "\U0027"` # グレイヴアクセントや文字コード指定がsed中で上手くエスケープできないので変数に分けた.
while read IMAGENAME # $1の各行に記載された画像ファイルのパス.
 do
                 echo "\"${IMAGENAME}\"の撮影日時の取得……"
                 DateTimeOriginal=`magick identify -verbose ${IMAGENAME} |
                         grep "DateTimeOriginal" |
                         sed -e "s/^.*exif:DateTimeOriginal: //g" |
                         sed -e "s/ .*$//g" |
                         sed -e "s/:/     /g" |
                         sed -e "s/20/${SEIREKI_BACKQUOTE}/g" `
                 echo "OK! ${DateTimeOriginal}"
                 OUTPUT_IMAGENAME=`echo "${IMAGENAME}-tmp.jpg"`
                 OUTPUT_IMAGENAME2=`echo "${IMAGENAME}.jpg"`
                 magick convert -resize 3096x2064 -font DSEG14-Classic-Bold -fill black -pointsize 100 -gravity southeast -annotate 0x0+300+150 "${DateTimeOriginal}" ${IMAGENAME} ${OUTPUT_IMAGENAME}
                 magick convert -font DSEG14-Classic-Bold -fill orange -pointsize 100 -gravity southeast -annotate 0x0+303+153 "${DateTimeOriginal}" ${OUTPUT_IMAGENAME} ${OUTPUT_IMAGENAME2}
                 rm ${OUTPUT_IMAGENAME}
                 OUTPUT_IMAGENAME3=`echo ${OUTPUT_IMAGENAME2} |
                         sed -e "s/\.JPG\.jpg/_TS.jpg/g"`
                 mv ${OUTPUT_IMAGENAME2} ${OUTPUT_IMAGENAME3}
                 echo "出力ファイル名: ${OUTPUT_IMAGENAME3}"
done < $1

改良版2

上の改良版だと,日付が20日のとき,日付もアポストロフィに置換されてしまうことに気がついたので修正します.
過去記事『ある文字列を囲んでいる記号を別の記号に置換する』に記載の方法で問題を回避しました.
  • strokeおよび-strokewidthオプションの存在を知ったので,陰を付けて縁取りもするようにしました.
#!/bin/bash
# 引数の説明
# $1: 操作対象パス(ファイル)リストが記載されたファイル.
# SEIREKI_BACKQUOTE="\`" # "`"はグレイヴアクセント.西暦の略記はアポストロフィ“'”.
SEIREKI_BACKQUOTE=`echo -e "\U0027"` # グレイヴアクセントや文字コード指定がsed中で上手くエスケープできないので変数に分けた.“\U0027”はアポストロフィの文字コード.
while read IMAGENAME # $1の各行に記載された画像ファイルのパス.
 do
                 echo "\"${IMAGENAME}\"の撮影日時の取得……"
                 DateTimeOriginal=`magick identify -verbose ${IMAGENAME} | 
                         grep "DateTimeOriginal" | #表示結果例:『    exif:DateTimeOriginal: 2024:03:20 08:00:23』
                         sed -e "s/^.*exif:DateTimeOriginal: //g" | #処理結果例:『2024:03:20 08:00:23』
                         sed -e "s/ .*$//g" | #処理結果例:『2024:03:20』
                         sed -e "s/20\(..\)/${SEIREKI_BACKQUOTE}\1/g" |  #処理結果例:『'24:03:20』
                         sed -e "s/:/     /g"`  #処理結果例:『'24     03     20』
                 echo "OK! ${DateTimeOriginal}"
                 OUTPUT_IMAGENAME=`echo "${IMAGENAME}-tmp.jpg"`
                 OUTPUT_IMAGENAME2=`echo "${IMAGENAME}.jpg"`
                 magick convert -resize 3096x2064 -font DSEG14-Classic-Bold -fill black -pointsize 100 -gravity southeast -annotate 0x0+300+150 "${DateTimeOriginal}" ${IMAGENAME} ${OUTPUT_IMAGENAME}
                 magick convert -font DSEG14-Classic-Bold -fill orange -stroke black -strokewidth 2 -pointsize 100 -gravity southeast -annotate 0x0+303+153 "${DateTimeOriginal}" ${OUTPUT_IMAGENAME} ${OUTPUT_IMAGENAME2}
                 rm ${OUTPUT_IMAGENAME}
                 OUTPUT_IMAGENAME3=`echo ${OUTPUT_IMAGENAME2} |
                         sed -e "s/\.JPG\.jpg/_TS.jpg/g"`
                 mv ${OUTPUT_IMAGENAME2} ${OUTPUT_IMAGENAME3}
                 echo "出力ファイル名: ${OUTPUT_IMAGENAME3}"
done < $1

ファイル名に日付を追加する機能も付加

#!/bin/bash
# 引数の説明
# $1: 操作対象パス(ファイル)リストが記載されたファイル.
# SEIREKI_BACKQUOTE="\`" # "`"はグレイヴアクセント.西暦の略記はアポストロフィ“'”.
SEIREKI_BACKQUOTE=`echo -e "\U0027"` # グレイヴアクセントや文字コード指定がsed中で上手くエスケープできないので変数に分けた.
while read IMAGENAME # $1の各行に記載された画像ファイルのパス.
 do
                echo "\"${IMAGENAME}\"の撮影日時の取得……"
                DateTimeOriginal=`magick identify -verbose ${IMAGENAME} |
                        grep "DateTimeOriginal" | #表示結果例: 『    exif:DateTimeOriginal: 2024:03:20 08:00:23』
                        sed -e "s/^.*exif:DateTimeOriginal: //g" ` #処理結果例: 『2024:03:20 08:00:23』
                FILENAME_DATETIME=`echo ${DateTimeOriginal} |
                        sed -e "s/ /_/g" | 	#処理結果例: 『2024:03:20_08:00:23』
                        sed -e "s/^/p/g" | 	#処理結果例: 『p2024:03:20_08:00:23』
                         sed -e "s/_.*$//g" |  	#処理結果例: 『p2024:03:20』
                        sed -e "s/://g" ` 	#処理結果例: 『p20240320』
                DateTimeOriginal=`echo ${DateTimeOriginal} | 
                        sed -e "s/ .*$//g" |					#処理結果例: 『2024:03:20』
                        sed -e "s/20\(..\):/${SEIREKI_BACKQUOTE}\1:/g" |	#処理結果例: 『'24:03:20』
                        sed -e "s/:/     /g" `					#処理結果例: 『'24     03     20』(これくらいスペースを空けないと体裁整わない.)
                echo "OK! ${DateTimeOriginal}"
                OUTPUT_IMAGENAME=`echo "${IMAGENAME}-tmp.jpg"`		#一時ファイルの名前
                OUTPUT_IMAGENAME2=`echo "${IMAGENAME}.jpg"`		#一時ファイルの名前2
                magick convert -resize 3096x2064 -font DSEG14-Classic-Bold -fill black -pointsize 100 -gravity southeast -annotate 0x0+297+147 "${DateTimeOriginal}" ${IMAGENAME} ${OUTPUT_IMAGENAME}
		#↑黒文字で日付の陰を先に生成する.
                magick convert -font DSEG14-Classic-Bold -fill orange -stroke black -strokewidth 2 -pointsize 100 -gravity southeast -annotate 0x0+300+150 "${DateTimeOriginal}" ${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"`	#ピリオドで半角英数8文字の写真ファイル名をマッチさせ,先頭に文字列を追加.
		#デジカメのファイル名は『カメラ映像機器工業会規格 CIPA DC-009- 2010カメラファイルシステム規格』で長さが厳密に半角英数8文字と決められている.
		#これに従っているファイルならば,この正規表現で置換可能.同一書式のディレクトリがパス中に存在する場合はダメ.
		mv ${OUTPUT_IMAGENAME2} "${OUTPUT_IMAGENAME3}"
                echo "出力ファイル名: ${OUTPUT_IMAGENAME3}"
done < $1

参考: フォントのインストール

WSL上でのフォントインストールの例.Debian GNU/Linux 12.
Windows上でフォントのあるフォルダを確認し,フォントファイルを管理者権限で“/usr/local/share/fonts/”へコピーします.
これだけで使用可能になります.
sudo cp /mnt/c/Users/user/Downloads/fonts-DSEG_v046/DSEG14-Classic/*.ttf /usr/local/share/fonts/