BLOGTIMES
2013/05/03

EXIF からレンズ名を取得する(Nikon編)

  nikon  php  exif 
このエントリーをはてなブックマークに追加

以前、Panasonic 機の EXIF からレンズデータを抽出するというのをやりましたが、最近メインのカメラが D600 になったので、今回は Nikon 機の EXIF からのレンズデータの抽出にチャレンジすることにします。

プログラミングの大きな問題点は2つ。Pana機の場合はレンズ名が直接 EXIF に埋まっていましたが、Nikon 機はレンズの ID 情報だけが埋め込まれているだけのようなので、 ID とレンズ名の関連づけは自分でやらなくてはなりません。また、Nikon 機の EXIF は項目によっては暗号化がされていて、そのままではデータが読めないようになっているので、これを復元してやる必要があります。

レンズの ID については下記のサイトに纏められていたので、これを利用させてもらいました。

もう一つの暗号化されたデータの復元については FITS*1 というプロジェクトに Perl で書かれた Decypt()*2 という復号化ルーチンがあったので、これを丸々 PHP にポーティングしました。
EXIF のパースは前回と同様に、The PHP Metadata Toolkitを用います。

作成したサンプルプログラム

基本的には Nikon.pm の Perl のルーチンをそのまま使っています。
復号時にシャッターカウント(Makernote #167)とカメラのシリアルナンバー(Makernote #29)が必要になるので、EXIF内から取得取得しています。
また、レンズの ID は 8 バイトなのですが、何故か復号すると最後の1バイトが一致しなかったので、最初の7バイトでレンズ名を照合するようにしています。
# これはもしかしたら僕の作り込んだバグかもしれません。

exiftest_nikon.php

<?php $Toolkit_Dir = "./"; include $Toolkit_Dir . 'EXIF.php'; // Lens List $NikonLensDB = array ( 'AE 54 62 62 0C 0C B0' => array('Nikon','AF-S Nikkor 85mm f/1.4G'), 'AF 54 44 44 0C 0C B1' => array('Nikon','AF-S Nikkor 35mm f/1.4G'), 'B0 4C 50 50 14 14 B2' => array('Nikon','AF-S Nikkor 50mm f/1.8G'), 'B1 48 48 48 24 24 B3' => array('Nikon','AF-S DX Micro Nikkor 40mm f/2.8G'), 'B2 48 5C 80 30 30 B4' => array('Nikon','AF-S Nikkor 70-200mm f/4G ED VR'), 'B3 4C 62 62 14 14 B5' => array('Nikon','AF-S Nikkor 85mm f/1.8G'), 'B4 40 37 62 2C 34 B6' => array('Nikon','AF-S Nikkor 24-85 mm f/3.5-4.5G ED VR'), 'B5 4C 3C 3C 14 14 B7' => array('Nikon','AF-S Nikkor 28mm f/1.8G'), 'B7 44 60 98 34 3C B9' => array('Nikon','AF-S Nikkor 80-400mm f/4.5-5.6G ED VR'), 'dummy' => array()); // Decrypt Routine function _decryptNikonDataBlock($dataPt, $serial, $count){ $xlat0 = array( 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d, 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d, 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f, 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f, 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1, 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17, 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89, 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f, 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b, 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb, 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3, 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f, 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35, 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43, 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5, 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7); $xlat1 = array( 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c, 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34, 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad, 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05, 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee, 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d, 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b, 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b, 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc, 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33, 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8, 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6, 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c, 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49, 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb, 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f); $serial = (int) $serial; $count = (int) $count; $len = strlen($dataPt); if($len <= 0) return ''; $key = 0; for ($i=0; $i<4; ++$i) { $key ^= ($count >> ($i*8)) & 0xff; } $ci = $xlat0[$serial & 0xff]; $cj = $xlat1[$key]; $ck = 0x60; $data = unpack("C*", $dataPt); foreach ($data as $i => $dat) { $cj = ($cj + $ci * $ck) & 0xff; $ck = ($ck + 1) & 0xff; $data[$i] ^= $cj; } return $data; } $filename = "hoge.jpg"; $exif = get_EXIF_JPEG( $filename ); $makerNote = $exif[0][34665]['Data'][0][37500]["Decoded Data"][0]; $shutterCount = $makerNote[167]["Data"][0]; $serialNo = $makerNote[29]["Data"][0]; $lensDataVer = substr($makerNote[152]['Data'],0,4); $offset = -0x04; $nikonLensDataRaw = substr($makerNote[152]['Data'],4); $nikonLensDataDecrypted = _decryptNikonDataBlock($nikonLensDataRaw,$serialNo,$shutterCount); $nikonLensIDRaw = array_slice($nikonLensDataDecrypted, 0x0c+$offset, 7); $nikonLensID = vsprintf('%02X %02X %02X %02X %02X %02X %02X', $nikonLensIDRaw); $nikonLens = $NikonLensDB[$nikonLensID]; //var_dump($exif); var_dump($nikonLens);

実行結果の例

こんな感じでメーカー名とレンズ名が取れるようになりました。
まだレンズ1本しか持ってないので、プログラム的には宝の持ち腐れですけど。

$ php exiftest_nikon.php array(2) { [0]=> string(5) "Nikon" [1]=> string(23) "AF-S Nikkor 50mm f/1.8G" }

2013/05/09 追記

レンズ ID の8バイト目の謎が解けて、完全版のプログラムを書くことができました


トラックバックについて
Trackback URL:
お気軽にどうぞ。トラックバック前にポリシーをお読みください。[policy]
このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/5777
Trackbacks
このエントリにトラックバックはありません
Comments
愛のあるツッコミをお気軽にどうぞ。[policy]
古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
コメントはありません
Comments Form

コメントは承認後の表示となります。
OpenIDでログインすると、即時に公開されます。

OpenID を使ってログインすることができます。

Identity URL: Yahoo! JAPAN IDでログイン