これまでは、画像中にRTCの日時を埋め込んでSDカードに保存していました。しかし、JPEGを生成することができるようになったので、次の段階としてExif情報として撮影日時を記録することにします。
IJGのlibjpegを普通に使って生成したJPEGファイルは、色空間としてYCbCrを使った場合には上図左側に示したようにSOIマーカーに続いてAPP0マーカのセグメントを持つJFIF形式となっています。一方、デジカメで生成されるExif情報を持つJPEGファイルではAPP0の代わりにAPP1マーカのセグメントを持ち、この中にExif情報が書かれています。つまり、Exifの規格にそったファイルを生成するためには、
まず、jpeg_compress_struct構造体の中のwrite_JFIF_headerをFALSEに設定します。これでJFIFを含むAPP0セグメントが出力されなくなります。入力/出力する色空間としてYCbCrを選択、ファイルサイズが16KBを超えるようにqualityとして90を指定しておいて、jpeg_start_compress()を呼びだします。そして、jpeg_write_marker()を使ってAPP1マーカーを持つセグメント情報(すなわちExif情報)を書き出します。この後で、jpeg_write_scanlines()を呼ぶ事でExif情報ならびに圧縮関連情報の後に圧縮画像データが続くことになります。
こうして作られたのが上の画像です。見かけ上はこれまでと変わりありませんが、Exif情報が追加されています。次のような情報を追加していますが、ほとんどのタグ情報は固定値であり動的に変化するのは撮影日時だけとなっています。
いやはや役に立たない値ばかりです。撮影データとしてはシャッタースピードとか絞りとかの値が欲しいところですが、どうやって求めればいいのかわかりません。Eye-FiでGoogle+に自動アップロードされたアルバム画像を見れば主要Exif情報を確認できますが、このように空欄が目立ちます。
IJGのlibjpegを普通に使って生成したJPEGファイルは、色空間としてYCbCrを使った場合には上図左側に示したようにSOIマーカーに続いてAPP0マーカのセグメントを持つJFIF形式となっています。一方、デジカメで生成されるExif情報を持つJPEGファイルではAPP0の代わりにAPP1マーカのセグメントを持ち、この中にExif情報が書かれています。つまり、Exifの規格にそったファイルを生成するためには、
- JFIFをもつAPP0セグメントを出力しないようにする。
- Exif情報を持つAPP1セグメントを代わりに出力する。
struct jpeg_compress_struct cinfo; uint8_t raster_buffer[QVGA_WIDTH*2]; JSAMPLE jwbuffer[QVGA_WIDTH*3]; JSAMPROW jrow; ..... jpeg_create_compress(&cinfo); ..... cinfo.input_components = 3; cinfo.in_color_space = JCS_YCbCr; /* 入力の色空間をYCbCrに設定 */ jpeg_set_defaults(&cinfo); jpeg_set_colorspace(&cinfo, JCS_YCbCr); /* 出力の色空間をYCbCrに設定 */ cinfo.write_JFIF_header = FALSE; /* JFIFヘッダ(APP0)を出力しない */ jpeg_set_quality(&cinfo, 90, TRUE); jpeg_start_compress(&cinfo, TRUE); /* Exif情報 (APP1)を出力 */ jpeg_write(marker(&cinfo, JPEG_APP0+1, &exif_info, sizeof(exif_info)); jrow = jwbuffer; for (i = 0; i < cinfo.image_height;i++) { /* 1ライン分データをFIFOから読み出し */ read_fifo(raster_buffer, cinfo.image_width); /* カメラからのYCbCr4:2:2データを YCbCr4:4:4に変換 */ ycbcr422_to_ycbcr444(raster_buffer, jw_buffer); /* Libjpegを使って1ライン分を圧縮 */ jpeg_write_scanlines(&cinfo, &jrow, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo);
まず、jpeg_compress_struct構造体の中のwrite_JFIF_headerをFALSEに設定します。これでJFIFを含むAPP0セグメントが出力されなくなります。入力/出力する色空間としてYCbCrを選択、ファイルサイズが16KBを超えるようにqualityとして90を指定しておいて、jpeg_start_compress()を呼びだします。そして、jpeg_write_marker()を使ってAPP1マーカーを持つセグメント情報(すなわちExif情報)を書き出します。この後で、jpeg_write_scanlines()を呼ぶ事でExif情報ならびに圧縮関連情報の後に圧縮画像データが続くことになります。
こうして作られたのが上の画像です。見かけ上はこれまでと変わりありませんが、Exif情報が追加されています。次のような情報を追加していますが、ほとんどのタグ情報は固定値であり動的に変化するのは撮影日時だけとなっています。
タグ名 | 意味 | 値 |
---|---|---|
Make | メーカ名 | sirius506 |
Model</rd> | モデル | sirius506 ov7670 |
DateTimeOriginal | 原画像データの生成日時 | YYYY:MM:DD HH:MM:SS |
ExifVersion | Exifバージョン | 0230 |
MeteringMode | 測光方式 | 不明 |
LightSource | 光源 | 不明 |
ExposureMode | 露出モード | 露出自動 |
WhiteBalance | ホワイトバランス | 自動 |
いやはや役に立たない値ばかりです。撮影データとしてはシャッタースピードとか絞りとかの値が欲しいところですが、どうやって求めればいいのかわかりません。Eye-FiでGoogle+に自動アップロードされたアルバム画像を見れば主要Exif情報を確認できますが、このように空欄が目立ちます。