例によって blog からの転載です。
写真などの Exif 情報から GPS の緯度/経度情報を削除するための Shll Script です。
Shell Script だって 無理すれば バイナリデータを編集できるという事を示したモノで、殆どネタとしか思えない様なスクリプトになっていますが、シェルスクリプトでバイナリデータを扱うさらにもう一つの方法なので参考になればと思い投稿してみます。
処理内容は、画像ファイルに格納されている Exif 情報を簡単に解析して GPS 情報を格納している領域 (GPSInfoIFD) から緯度/経度情報だけをゼロに置換する処理となっています。
#!/bin/sh
#
# Endian を考慮して 4 バイト数字を取得する
# 一度 od(1) で 16 進数に変換しバイト並びを修正した後に 10 進数に変換する
#
# $1: ファイル
# $2: オフセット
#
get4Byte()
{
if [ ${endian} = "MM" ]
then
printf "%d" `dd if="${1}" bs=1 skip=${2} count=4 2> /dev/null | od -x |
sed -n "s/^0000000 *\(..\)\(..\)[ ]*\(..\)\(..\)/0x\2\1\4\3/p"`
else
printf "%d" `dd if="${1}" bs=1 skip=${2} count=4 2> /dev/null | od -x |
sed -n "s/^0000000 *\(..\)\(..\)[ ]*\(..\)\(..\)/0x\1\2\3\4/p"`
fi
}
#
# Endian を考慮して 2 バイト数字を取得する
# 一度 od(1) で 16 進数に変換しバイト並びを修正した後に 10 進数に変換する
#
# $1: ファイル
# $2: オフセット
#
get2Byte()
{
if [ ${endian} = "MM" ]
then
printf "%d" `dd if="${1}" bs=1 skip=${2} count=2 2> /dev/null | od -x |
sed -n "s/^0000000 *\(..\)\(..\)/0x\2\1/p"`
else
printf "%d" `dd if="${1}" bs=1 skip=${2} count=2 2> /dev/null | od -x |
sed -n "s/^0000000 *\(..\)\(..\)/0x\1\2/p"`
fi
}
#
# 任意の長さの文字列を取得する
#
# $1: ファイル
# $2: オフセット
# $3: 文字列長
#
getString()
{
dd if="${1}" bs=1 skip=${2} count=${3} 2> /dev/null
}
#
# GPSInfoIFD の解析を行い緯度/経度情報をクリアする
#
# $1: ファイル
# $2: GPSInfoIFD のタグ数
# $3: GPSInfoIFD のオフセット位置
#
gps()
{
local i j offset tag val
i=0
while [ ${i} -lt ${2} ]
do
# GPSInfoIFD のタグ情報
offset=`expr ${3} + 14 + \( ${i} \* 12 \)`
tag=`get2Byte "${1}" ${offset}`
# タグ種類
# 2: 緯度
# 4: 経度
if [ ${tag} -eq 2 -o ${tag} -eq 4 ]
then
# データの数とデータのオフセットを取得
# 緯度/経度情報は値のタイプに RATIONAL(8バイト長) が指定されている
num=`get4Byte "${1}" \`expr ${offset} + 4\``
val=`get4Byte "${1}" \`expr ${offset} + 8\``
# 情報を削除するためにオフセットから 8 * データの数をゼロクリア
dd if=/dev/zero of="${1}" bs=1 conv=notrunc \
seek=`expr ${val} + 12` count=`expr ${num} \* 8` 2> /dev/null
fi
i=`expr $i + 1`
done
}
#
# 0th IFD データの解析処理
#
# $1: ファイル
# $2: 0th IFD のタグ数
#
ifd()
{
local i offset count position
i=0
while [ ${i} -lt ${2} ]
do
# 0th IFD のタグ情報
offset=`expr 22 + \( ${i} \* 12 \)`
# GPSInfoIFDPointer の場合はオフセットとタグ数を取得
if [ `get2Byte "${1}" ${offset}` -eq 34853 ]
then
position=`get4Byte "${1}" \`expr ${offset} + 8\``
count=`get2Byte "${1}" \`expr ${position} + 12\``
gps "${1}" ${count} ${position}
fi
i=`expr $i + 1`
done
}
# 処理開始
if [ "`getString "${1}" 6 4`" = "Exif" ]
then
endian=`getString "${1}" 12 2`
ifd "${1}" `get2Byte "${1}" 20`
fi
実行結果
処理前 | 処理後 |
---|---|