ObjecTips

基本Objective-Cで iOS とか OS X とか

画像のExifデータの取得方法と取得データの比較 iOS

検証環境
  • Xcode 9.2, iOS 11.2 Simulator
  • iOS 11.1 iPhone X の背面カメラで撮影したものを AirDrop で Mac に送ってシミュレータ経由で iCloud Photo Library に取り込んだ写真を用いてデータを確認

Exifの取得

まず取得方法をざっくり
Exif等のデータをプロパティとして Core ImageImage I/O で取得可能

CoreImage
    CIImage *image = [CIImage imageWithContentsOfURL:URL];
    NSDictionary<NSString *,id> *properties = image.properties;
    NSLog(@"%@", properties);
Image I/O + CGImageSourceCopyPropertiesAtIndex
    CGImageSourceRef src = CGImageSourceCreateWithURL((__bridge CFURLRef)URL, nil);
    NSDictionary *properties = CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(src, 0, nil));
    NSLog(@"%@", properties);
    CFRelease(src);


Image I/O でメタデータとしても取得可能

Image I/O + CGImageSourceCopyMetadataAtIndex
    CGImageSourceRef src = CGImageSourceCreateWithURL((__bridge CFURLRef)URL, nil);
    CGImageMetadataRef metadataRef = CGImageSourceCopyMetadataAtIndex(src, 0, nil);
    NSArray *tags = CFBridgingRelease(CGImageMetadataCopyTags(metadataRef));
    for (id tag in tags) {
        CGImageMetadataTagRef tagRef = (__bridge CGImageMetadataTagRef)tag;
        CFShow(tagRef);
    }
    CFRelease(src);
    CFRelease(metadataRef);
結果1

CoreImageImage I/O + CGImageSourceCopyPropertiesAtIndex で取得出来る内容は同じ。
ただし後者の CGImageSourceCopyPropertiesAtIndex の場合は1つのファイルに複数の画像が含まれる画像形式に対応しているので、仮に複数画像が存在して且つ画像毎に取得出来るプロパティが異なっている場合 CIImage から取得出来るプロパティとどう違いがあるかは検証が必要。(おそらくindex 0の1枚目の画像のプロパティを返すんじゃないかと予想)

以下が取得出来るプロパティのサンプル

Exif data with iOS 11 iPhone X back camera

結果2

Image I/O + CGImageSourceCopyMetadataAtIndex で取得出来るものは他のものと内容や形式が異なっている。
ちなみに NSArray のままログ出力すると CFBasicHash あたりの表示が見辛くなってしまうのでサンプルではfor文で回して CFShow でタグを1つずつログ出力した。

以下が取得出来るメタデータのサンプル

Metadata with iOS 11 iPhone X back camera

取得データの比較

結果1と結果2を見比べると、ざっと見て結果2の方が数が少なそうに見える。比較して確認してみる。
メタデータのタグに対応するプロパティのキーやデータを探して、対応するものをCSVの別カラムに記載した。(MakerApple のキー2は512バイトのデータなので記載を省略)

Compare Exif and metadata tag.

補足

  • exifEX:PhotographicSensitivity

exifEX:PhotographicSensitivity はプロパティを見ると対応するものが無いように見える。
ググって見つけたCIPA(一般社団法人カメラ映像機器工業会)に掲載のPDFによると

http://www.cipa.jp/std/documents/e/DC-010-2012_E.pdf

PhotographicSensitivity は Exif 2.3以降の規格で、Exif 2.21 まで使用されていた ISOSpeedRatings を代替するものらしい。ISOSpeedRatings は deprecated との事。
テストに利用した写真の ExifVersion を見てみると 0221 とあるので、この写真では PhotographicSensitivity は使用されておらず ISOSpeedRatings に値が入っていて、タグ取得のAPIではマッピングによりこれを参照しているという事らしい。


  • iio:hasXMP

iio:hasXMP は正確な仕様は不明。
iio は ImageIO の prefix でApple独自のメタデータタグだと思われる。(ImageIOBase.h を見ると IIO_HAS_IOSURFACEIIO_BRIDGED_TYPE といった定義が見られる。)
名前の通りxmp のタグが存在しているかどうかを示すものだと推測。


  • xmp:CreateDate
  • xmp:ModifyDate
  • photoshop:DateCreated

先のCIPAのPDFには以下のように掲載されていたので、xmp:CreateDatexmp:ModifyDate はそれをそのまま適用。

DateTimeDigitized = xmp:CreateDate
DateTimeOriginal = exif:DateTimeOriginal
DateTime = xmp:ModifyDate

またメタデータタグには exif:DateTimeOriginal が存在しておらず、またプロパティには photoshop:DateCreated のタグに当てはまるものは無かった。
このタグの扱いをどうしたものかと思っていると CGImageMetadata.h のコメントに以下の記載を発見

  • Metadata Working Group guidance is factored into the mapping of CGImageProperties to
  • XMP compatible CGImageMetadataTags.
  • For example, kCGImagePropertyExifDateTimeOriginal will get the value of the
  • corresponding XMP tag, which is photoshop:DateCreated.

という事で、マッピングされているらしい。
よって DateTimeOriginal = photoshop:DateCreated として適用。

結果より

メタデータタグ CGImageMetadataRef を使うと exif:Flash のビットや exif:ExifVersion の配列を利用しやすい形式に変換してくれたり、マッピングにより Exif のバージョンの違いを吸収をしてくれるという利点がある。
また GPSLatitude を例にとるとメタデータタグに表記されている 34,59.1905 の度、分、秒が大元の記録データであり、プロパティの 34.98650833333333 はこれを計算した結果になる。
よって正確なrawデータを表示する場合にはメタデータタグを利用した方が良さそう。
ただし ColorModelProfileName だったりプライベート仕様の MakerApple の情報も余す事なく表示したい場合はプロパティを使用する必要がある。
用途に合わせてうまく併用するのが良いかも知れない。