2016/11/21
画像の回転スクリプト
blog などに添付する画像を回転するためのスクリプト。
回転処理は ImageMagick の rotate (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