LoginSignup
5

More than 5 years have passed since last update.

Shell Script で exif 情報から GPS の緯度/経度情報を削除する

Posted at

例によって 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

実行結果

処理前 処理後
処理前 処理後

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5