2024/11/16(土)exiftool(CLI付Perlライブラリ)の存在とインストール,使い方(編集中)
そのインストール方法とコマンドとしての使い方,スクリプトの例を紹介しようと思います.
元の情報は『Ubuntu Weekly Recipe 第553回Ubuntuで写真のメタデータを扱う方法』というgihyo.jpの記事です.
これを参考にして,先日作った写真画像ファイルにフィルム写真風の日付を挿入するシェルスクリプト改3にさらに手を加え,
カメラ本体やレンズの情報を写真に挿入するスクリプトを作成します.
exiftoolのインストール
リンク先はUbuntu向けの記事ですが,Debian 12でも同じパッケージをインストールできるのでそうします*1.$ su - # apt install libimage-exiftool-perl
使い方(コマンド単発)
写真ファイル名が“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
2024/09/30(月)LaTeXで空白記号を出力する
半角スペースを明示する必要があったので空白記号を使おうとして,探したが見つからず…….
『LaTeX 空白記号』とかでGoogle先生に尋ねるとLaTeXにおける空白の調整を行う方法が列挙され,欲しい情報が出てきませんでした*1.
そして,また空白記号を使う必要があったので探し直していたのですが,漸く見つけました.
『LaTeX2e 美文書作成入門 改訂第8版』*2の付録E,385ページに記載.
次のコマンドが空白記号に対応します.そのまんまなコマンド名ですね.
\textvisiblespaceインターネット(検索エンジン)は万能ではないと改めて思った次第です.
2024/09/06(金)写真画像ファイルにフィルム写真風の日付を挿入するシェルスクリプト改3
前回の記事は,説明がわかりづらく,不十分だったため,もう少し解説を充実させました.
簡単な内容ですが,誰かのお役に立てれば嬉しいです.

1 できること
本バージョン“改3”では,次の機能が実装されています.- 一般的なデジタルカメラで撮影した写真ファイルに,後付けでフィルム写真風の日付を追加します.
- 実際のフィルムカメラのデート機能による日付よりも大きく,ハッキリと表示されるように設定してあります.
- これは,プロジェクター等で投影したときに判読しやすいことが必要と考えたからです*1.用途に応じて調整してください.
- 出力される文字は,オレンジ色に塗りつぶされ,指定幅でグレー(透過の薄い黒)にて縁取られた文字です.
- 写真ファイルのピクセル幅と高さを数えて,画面と日付の大きさの比率を維持して日付を挿入します.
- 機材によって写真のピクセルサイズが異なるのは当然なので,この調整機能は必須と考えました.
- 写真のピクセルサイズが小さすぎると破綻すると思います.撮って出しの大きなJPEGファイルを処理対象にするのが推奨です.
- 処理後の写真ファイルは先頭に年月日が追加されます.
- 元ファイルの名前が“_IMP0221.JPG”だった場合,“p20180813__IMP0221_TS.jpg”のようになります.
- 元ファイルの名前は恐らくどのような文字列・長さでも対応しています.ただし半角英数の短めのファイル名が推奨です.
- 万が一画像処理に失敗しても元のファイルが消失することは多分ありません.
- 処理後の写真ファイルのEXIF情報は維持されます.写真のピクセルサイズも変わりません.画質は少し劣化します(JPEGファイルをそのまま複数回処理しているため.).
- 無料(ただし無保証.(一応ですが)GPLライセンスとします)
- 好きなフォントに差し替え可能.
- 日付の位置や大きさ等を,コードを改変して自由に設定できる.
- コマンドライン(bashシェル)からお手軽に操作できる.
- 写真ファイルのピクセルサイズがバラバラでも,配置やサイズの比率を維持して大量に処理できる.
- 日付を挿入するだけなのに割と時間が掛かる(ImageMagickを何度も実行しているため).
- パイプ入力に対応していない.
- 1999年以前の日付に対応していない*4.
- 縦構図の写真を処理する際,処理前に画像を回転していると,日付の挿入位置が縦横反転してしまう*5.
挿入位置を揃えたい場合は,本シェルスクリプトの処理前に回転操作をしないようにするのが手っ取り早いですね.
2024/03/18(月)写真画像ファイルにフィルム写真風の日付を挿入するシェルスクリプト
これは,仕事の写真の説明や保存管理にも使えるでしょうし,
手抜きのフォトアルバムを作るのにも使えそうです.
※改良版の“改3”を作成し,内容を整理しました.以下よりはわかりやすいと思いますので,適宜参照してください.
処理結果は次のような感じになります*1.

日付情報は,通常写真ファイルに埋め込んであるので,それを読み出して写真画面上に描き込みます.
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
2024/03/04(月)Let's Encryptの証明書で古いドメインを削除する
このドメインは二度と使うことはないので,削除する.
Rocky Linux 8.9での作業である.
端折っているが,ウェブサーバ等の設定ファイルで“ac206223.ppp.asahi-net.or.jp”が記述されていないかをチェックした方がいいかもしれない.
少なくとも,下の案内文にはその旨書いてある.
[root@server ~]# certbot delete Saving debug log to /var/log/letsencrypt/letsencrypt.log Which certificate(s) would you like to delete? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1: ac206223.ppp.asahi-net.or.jp 2: cshs-small-worlds.aa0.netvolante.jp - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Select the appropriate numbers separated by commas and/or spaces, or leave input blank to select all options shown (Enter 'c' to cancel): 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The following certificate(s) are selected for deletion: * ac206223.ppp.asahi-net.or.jp WARNING: Before continuing, ensure that the listed certificates are not being used by any installed server software (e.g. Apache, nginx, mail servers). Deleting a certificate that is still being used will cause the server software to stop working. See https://certbot.org/deleting-certs for information on deleting certificates safely. Are you sure you want to delete the above certificate(s)? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: Y Deleted all files relating to certificate ac206223.ppp.asahi-net.or.jp. [root@server ~]# systemctl restart httpd [root@server ~]#