2016/11/21

画像の回転スクリプト

blog などに添付する画像を回転するためのスクリプト。
回転処理は ImageMagickrotate (1) コマンドで行うのだが、 一部のブラウザでは exif 情報に含まれる Orientation の値で画像を回転して表示するので、 回転した後で exif の Orientation の情報を修正している。
exif 情報の取得と設定は Perl モジュール Image-ExifTool を利用している。

getor: exif 情報から Orientation を取得する。

  1#!/usr/bin/perl -w
  2use Image::ExifTool ':Public';
  3my $file = shift or die "Please specify filename";
  4
  5$exifTool = new Image::ExifTool;
  6$exifTool->ExtractInfo($file);
  7
  8print $exifTool->GetValue('Orientation') . "\n";
    

setor: Orientation に水平 Horizontal (normal) を設定する。

  1#!/usr/bin/perl -w
  2use Image::ExifTool ':Public';
  3my $file = shift or die "Please specify filename";
  4
  5$exifTool = new Image::ExifTool;
  6$exifTool->SetNewValue('Orientation', 'Horizontal (normal)');
  7$exifTool->WriteInfo($file);
    

引数で指定されたファイルを回転して Orientation を設定する。

  1#!/bin/sh
  2for i in $*
  3do
  4    n=$(getor $i | awk '/^Rotate/{ print $2 }')
  5    if [ ${n:-0} -gt 0 ]
  6    then
  7        convert -rotate $n $i /tmp/_$$.jpg &&
  8        mv /tmp/_$$.jpg $i
  9        setor $i
 10    fi
 11done
    

2016/11/22 追記

以前作成した Exif 情報から GPS の緯度/経度情報を削除する を元に 全てシェルスクリプトで画像を回転するスクリプトを作ってみた。
dd (1) を利用してバイナリファイルの入出力を行い、 Exif 情報の取得と更新を実施している。
  1#!/bin/sh
  2# 画像を回転し Exif 情報の 'Orientation' を設定する
  3#
  4
  5#
  6# Endian を考慮して 2 バイト数字を取得する
  7#
  8#   $1: ファイル
  9#   $2: オフセット
 10#
 11get2Byte()
 12{
 13
 14    dd ${conv} if="${1}" bs=1 skip=$((${skip} + ${2})) count=2 2> /dev/null | od -d | awk '/^0000000/{ print $2 }'
 15
 16}
 17
 18#
 19# 任意の長さの文字列を取得する
 20#
 21#   $1: ファイル
 22#   $2: オフセット
 23#   $3: 文字列長
 24#
 25getString()
 26{
 27
 28    dd if="${1}" bs=1 skip=$((${skip} + ${2})) count=${3} 2> /dev/null
 29
 30}
 31
 32#
 33# 0th IFD データの解析処理
 34#
 35#   $1: ファイル
 36#   $2: 0th IFD のタグ数
 37#
 38ifd()
 39{
 40
 41    local   i offset
 42
 43    i=0
 44
 45    while [ ${i} -lt ${2} ]
 46    do
 47        # 0th IFD のタグ情報
 48        offset=$((${3} + 22 + (${i} * 12)))
 49        # Orientation の場合はオフセットを表示して終了
 50        if [ $(get2Byte "${1}" ${offset}) -eq 274 ]
 51        then
 52            echo ${offset}
 53            break
 54        fi
 55        i=$((i + 1))
 56    done
 57
 58}
 59
 60#
 61# Orientation 情報の取得
 62#
 63#   $1: ファイル
 64#   $2: Orientation IFD のオフセット
 65#
 66getOrient()
 67{
 68
 69    echo $(get2Byte "${1}" $((${2} + 8)))
 70
 71}
 72
 73#
 74# Orientation 情報のセット
 75#
 76#   $1: ファイル
 77#   $2: Orientation IFD のオフセット
 78#
 79setOrient()
 80{
 81
 82    echo -ne "\00\01" | dd conv=notrunc of="${1}" bs=1 seek=$((${2} + 8 + ${skip})) 2> /dev/null
 83
 84}
 85
 86#
 87# ファイルフォーマットから skip するバイト数を取得
 88#
 89#   $1: ファイル
 90#
 91getSkip()
 92{
 93
 94    if [ "$(getString "${1}" 6 4)" = "Exif" ]
 95    then
 96        # Exif 情報格納
 97        echo 0
 98    elif [ "$(getString "${1}" 24 4)" = "Exif" ]
 99    then
100        # JFIF 情報格納
101        echo 18
102    else
103        # Exif 情報なし
104        echo -1
105    fi
106
107}
108
109#
110# convert(1) のオプション取得
111#
112#   $1: ファイル
113#
114get_conv()
115{
116
117    offset=$(ifd "${1}" $(get2Byte "${1}" 20))
118    if [ ${offset:-0} -gt 0 ]
119    then
120        case $(getOrient "${1}" ${offset}) in
121            2 ) opt="-flip";;                       # 上下反転
122            3 ) opt="-rotate 180";;                 # 180度回転
123            4 ) opt="-flop";;                       # 左右反転
124            5 ) opt="-flop -rotate 90";;            # 上下反転+270度回転
125            6 ) opt="-rotate 270";;                 # 90度回転
126            7 ) opt="-flip rotate 270";;            # 上下反転+90度回転
127            8 ) opt="-rotate 90";;                  # 270度回転
128        esac
129        echo ${opt}
130    fi
131
132}
133
134# メイン処理
135for i in $*
136do
137    skip=$(getSkip "${1}")
138    if [ ${skip} -ge 0 ]
139    then
140        # Endian
141        test $(getString "${1}" 12 2) = "MM" && conv="conv=swab"
142        opt=$(get_conv $i)
143        if [ -n "${opt}" ]
144        then
145            # 画像を回転
146            convert ${opt} "${i}" /tmp/_$$.jpg && mv /tmp/_$$.jpg "${i}"
147            # conviert(1) により TFIF 情報が付加される
148            skip=$(getSkip "${i}")
149            setOrient "${i}" $(ifd "${i}" $(get2Byte "${i}" 20))
150        fi
151    fi
152done
    

2016/11/23 追記

convert (1) だけで出来る事が判明
$ convert -auto-orient 入力ファイル.jpg 出力ファイル.jpg 
    
更に identify (1) を利用すると Exif 情報も取得できるので ImageMagic が導入されている場合は以下のスクリプトで完結する。
  1#!/bin/sh
  2for i in $*
  3do
  4    test "`identify -verbose $i | awk '/exif:Orientation/{ print $2 }'`" != 1 &&
  5        convert -auto-orient $i /tmp/_$$.jpg &&
  6        mv /tmp/_$$.jpg $i
  7done
    


Copyright © 2008-2020 Mitzyuki IMAIZUMI. All rights reserved.