ふぁメモ

主に技術系のメモをしたいけどやっぱり適当日記。たまにPHPコード載ってるけどメモ書き程度のスクリプトなのでそのまま使っちゃダメ。

iPhoneで撮影したHEIC型式の画像ファイルのExif情報をExifToolで取得する

最近のiPhoneで撮影した写真

HEICで撮影すると容量が抑えられるのは良いのだけどほぼ独自形式と同じなので利用しづらい。

  • 編集情報が別ファイル(AAE)になったりする。利用方法なし。
  • Windows10(とMac?)以外では閲覧もままならない。(最近Windows10でならIrfanViewでも閲覧・変換できることを知って楽になった。)
  • そこらへんのビューアでExif情報が見られない。iPhoneでは見られるので記録されていることは間違いないのだが…。

条件によってはiPhone側でJPEG変換して渡してくれるのだけど、最初からJPEGでいいのでは…って気もしてきます。

ExifToolがHEIC対応していた

最近MediaInfoばかり注目していてPerlでお世話になったExifToolはすっかり失念していました。

MediaInfoではHEICファイルから意味のない情報の羅列しか取得できないので諦めていました。

ExifToolの知識は2016年で止まっていました(2017年に対応してた)。

PHPでの利用

私はPHPスマホで撮った写真のファイル名をリネームするスクリプトを自作して利用しています。

PHPは標準関数 exif_read_dataExifが読めますが、HEICは非対応とエラーが出て読めません。

ググるPHPでExifToolを扱うライブラリはいくつか見つかりますが、やっぱり2016年頃でメンテされなくなっている模様。

代わりにシェル実行関数でExifToolバイナリを開くことにします。

define('EXIFTOOL_PATH','/path/to/exiftool.exe');
function read_exif($file) {
    $shell = shell_exec(constant('EXIFTOOL_PATH').escapeshellcmd(' -j "'.$file.'"'));
    $m = json_decode($shell,true);
    if (is_array($m)){
        return $m[0];
    }
    return array();
}

ExifToolでは-jオプションを使うとJSONで結果を得られます。 -phpオプションを使うとPHPの配列型式になりますが、逆にどうやって使うんだこれ…。

exif_read_data()で得られる配列との違い

だいたい項目名と値の関係は同じですが、GPS周りの型式が違うので注意しましょう。

exif_read_data()は経緯度が配列で返ってきますが、ExifToolでJSON出力したものは文字列です。

exif_read_data()の場合

[GPSLatitudeRef] => N
[GPSLatitude] => Array
    (
        [0] => 35/1
        [1] => 43/1
        [2] => 4991/100
    )

[GPSLongitudeRef] => E
[GPSLongitude] => Array
    (
        [0] => 139/1
        [1] => 42/1
        [2] => 4597/100
    )

ExifToolのJSONから変換した場合

[GPSLatitude] => 35 deg 43' 49.91" N
[GPSLongitude] => 139 deg 42' 45.97" E
[GPSPosition] => 35 deg 43' 49.91" N, 139 deg 42' 45.97" E

利用し辛っ。

どっちも再利用しづらい…。

ググるとわかりますが度分秒から度への変換は北半球南半球の処理分けもあるのでなかなか面倒です。

ExifTool側は-c "%+.6f"オプションを利用しましょう。

define('EXIFTOOL_PATH','/path/to/exiftool.exe');
function read_exif($file) {
    $shell = shell_exec(constant('EXIFTOOL_PATH').escapeshellcmd(' -j -c "%+.6f" "'.$file.'"'));
    $m = json_decode($shell,true);
    if (is_array($m)){
        return $m[0];
    }
    return array();
}
[GPSLatitude] => +35.730531
[GPSLongitude] => +139.712769
[GPSPosition] => +35.730531, +139.712769

そのままGoogle等に投げられる型式になりました。(位置情報は池袋西口公園です)

DeepFusion判定

iPhone11Proではいわゆる超解像写真が撮影できます。

ファイル名がIMG_????S.HEICとなっているのでファイル名でも判別できますが、

"Megapixels": 23.9,

標準は12.2Mピクセルなので、13以上などで判定できそうです。クロップされていなければ。

HEIC以外にも使える

上のGPSの書式変換もそうですが、ExifToolを使うと360度写真の判定なんかもできるようになります。

手持ちのInsta360 ONEで撮影した写真(iPhone用アプリで変換しアルバムに出力したもの)には下記のようなExifがくっついてました。

"ProjectionType": "equirectangular",
"UsePanoramaViewer": true,
"PoseHeadingDegrees": 0,
"PosePitchDegrees": 0,
"PoseRollDegrees": 0,

同じInsta360 ONEで撮影した写真でもスナップショットを切り出した写真には入ってこないのでこれで判定できます。

これは拡張子は普通のJPGですが、PHPexif_read_data()では取得できません。

とはいえ

シェル拡張で使うとセキュリティとかパフォーマンスとか気になるので、PHPの標準関数で扱えるようになってほしいですね。