libtiff: Exif、GPSタグの読み込み・書き込み

TIFFファイルにはJPEGファイルと同様にEXIF情報を含めることができます。同様にGPS情報も持つことができます。
これらのタグを説明する前に、まず筆者自身のおさらいとして、TIFFのタグ、ディレクトリ構造を説明します。

IFDとタグ

TIFFファイルは1つのファイル内に複数の画像を持つことができますが、
その各画像セットをIFD(Image File Directory)と呼びます。
IFDはタグと画像データからなっているので、同一ファイル内にフォーマット(色数やビット深度等)が異なる画像を複数持つことも可能です。

タグは12byte固定長で記録されています。
タグは、タグID、データ型、データ数、データまたはデータへのオフセットからなります。
データは4byte以下ならタグフィールド内に、それ以上であればファイルの何処かに記録され、タグにはそのデータまでのオフセットが記録されます。

格納されるデータはタグによって決まっており、例えばImageLengthタグでは4byte符号なし整数が格納されることとなっています。

libtiffにおけるIFD、タグの取り扱い

libtiffを使用する場合、タグのデータを取得する関数はTIFFGetField()です。
この関数は引数にタグIDとデータを格納する変数を指定します。場合によってはデータカウントも指定します。

つまり、プログラマ側はIFDを先頭からなぞっていく必要はなく、欲しいタグを直接指定してデータを取り出すことが出来るようになっています。
ただし、上記のとおりタグに格納されるデータはタグによって決まっているので、
プログラマ側はどのタグにどのような情報がいくつ入っているかを正しく知っておく必要があります。
間違って指定すると赤バツが出たりします。

タグにどのような情報が入っているかはtif_dirinfo.c内にTIFFField型の配列という形で定義されています。
TIFFField型の定義は以下のとおりです。

   1: 
   2: struct _TIFFField {
   3: 	uint32 field_tag;                       /* field's tag */
   4: 	short field_readcount;                  /* read count/TIFF_VARIABLE/TIFF_SPP */
   5: 	short field_writecount;                 /* write count/TIFF_VARIABLE */
   6: 	TIFFDataType field_type;                /* type of associated data */
   7: 	uint32 reserved;                        /* reserved for future extension */
   8: 	TIFFSetGetFieldType set_field_type;     /* type to be passed to TIFFSetField */
   9: 	TIFFSetGetFieldType get_field_type;     /* type to be passed to TIFFGetField */
  10: 	unsigned short field_bit;               /* bit in fieldsset bit vector */
  11: 	unsigned char field_oktochange;         /* if true, can change while writing */
  12: 	unsigned char field_passcount;          /* if true, pass dir count on set */
  13: 	char* field_name;                       /* ASCII name */
  14: 	TIFFFieldArray* field_subfields;        /* if field points to child ifds, child ifd field definition array */
  15: };

field_readcountfield_writecountは、カウント数が決まっている場合の読み込み、書き込みのカウント数です。
ここに-1(TIFF_VARIABLE)または-3(TIFF_VARIABLE2)の場合は可変長であることを示します。
読み込みと書き込みで値が違う場合があるようですが、これはよくわかりません。

field_typeはデータの型です。
この後のset_field_typeget_field_typeと関連してはいますが、同じとは限らないようです。
これもいまいちよくわかっていません。

field_passcountは、1ならばTIFFGetField()およびTIFFSetField()
関数で第3引数にカウント数を与える必要があります。

通常タグとEXIFタグではTIFFField型の配列がtif_dirinfo.cで定義されているのでプログラマ側はあまり意識する必要はありませんが、
GPSタグは定義されていないのでユーザ側がTIFFField型の配列を定義する必要があります。
また、EXIFタグの定義はv4.0以降からのようです。
それ以前のバージョンの場合はGPSタグと同様に自前でフィールド定義を作成する必要があります。

EXIF、GPSのIFD

EXIF、GPS情報は単一ではなく多数の情報からなっています。
したがって、それらを他のタグと同様にずらずらと並べると取り扱いが煩雑になってしまいそうです。

フォーマットの策定者がそのように考えたかどうかはわかりませんが、EXIF、GPSタグはそれぞれ別のIFDとして格納され、
先頭のIFDには、EXIFやGPSのIFDまでのオフセットがExifIfdGpsIfdタグにそれぞれ記録されます。

EXIF、GPSのタグを読み込むには、上記のoffsetを取得してEXIFやGPSのIFDを読み込んでからEXIF、GPSのタグを取得していきます。
タグの取得は通常のタグと同様にTIFFGetField()関数を使用します。
ただし、GPSタグはlibtiff内に定義されていないので、自分でTIFFField型の配列を定義する必要があります。

EXIFタグをすべて取得するには

ところで、TIFFGetField()はタグを指定して取得する形なので、
ファイル内にある全てのタグを取得したいといった場合には意外と不便だったりします。
以下の例はhttp://docs.thefoundry.co.uk/nuke/63/ndkdevguide/examples/tiffReader.cpp
の例をもとに少し修正したものです。
取得したデータを保持しておく箇所は省いているので注意してください。
タグによって取得される型が異なるので、なにかVariant型のようなものを用意できると便利でしょう。

   1: // 取得したデータは何かVariant型のようなものが用意出来ればそれに詰め込むと良いでしょう
   2: // 同時にカウント数も保持しておく必要がある
   3: 
   4: //
   5: // 文字列、Undefined以外のデータの場合
   6: //
   7: template<class T, class V>
   8: static bool getMetaData( TIFF* metatif, const TIFFField* fi )
   9: {
  10:   if (fi->field_readcount == TIFF_VARIABLE2 || fi->field_readcount == TIFF_VARIABLE ||
  11:       fi->field_readcount > 1)
  12:   {
  13:     size_t count = 0;
  14:     T* data;
  15: 
  16:     if (fi->field_readcount == TIFF_VARIABLE)
  17:     {
  18:       uint16 gotcount = 0;
  19:       TIFFGetField(metatif, fi->field_tag, &gotcount, &data);
  20:       count = gotcount;
  21:     }
  22:     else if (fi->field_readcount == TIFF_VARIABLE2)
  23:     {
  24:       uint32 gotcount = 0;
  25:       TIFFGetField(metatif, fi->field_tag, &gotcount, &data);
  26:       count = gotcount;
  27:     }
  28:     else 
  29:     {
  30:       TIFFGetField(metatif, fi->field_tag, &data);
  31:       count = fi->field_readcount;
  32:     }
  33: 
  34: 	info.nCount = count;
  35: 
  36:     for (unsigned i = 0; i < count; i++)
  37:     {
  38:       // データを何処かに記録
  39:       // カウントも記録しておく必要がある
  40:     }
  41: 
  42:     return true;
  43:   }
  44:   else if (fi->field_readcount == 1)
  45:   {
  46:     T data;
  47:     TIFFGetField(metatif, fi->field_tag, &data);
  48:    
  49:     // データを何処かに記録
  50:     // ここでもカウント1を記録しておく必要がある
  51: 
  52:     return true;
  53:   }
  54: 
  55:   return false;
  56: }
  57: 
  58: 
  59: //
  60: // 文字列データの場合
  61: //
  62: static bool getMetaDataString(TIFF* metatif, const TIFFField* fi )
  63: {
  64:   if (fi->field_readcount > 1) 
  65:   {
  66:     char* data;
  67:     TIFFGetField(metatif, fi->field_tag, &data);
  68:     // カウント1を記録しておく必要がある
  69:     return true;
  70:   }
  71:   
  72:   return false;
  73: }
  74: 
  75: 
  76: //
  77: // Undefinedがとんできた場合
  78: //
  79: static bool getMetadataUndefined( TIFF* metatif, const TIFFField* fi )
  80: {
  81:   size_t count = 0;
  82:   uint8* data;
  83: 
  84:   if (fi->field_readcount == TIFF_VARIABLE2 || fi->field_readcount == TIFF_VARIABLE || 
  85:       fi->field_readcount > 1) 
  86:   {
  87:     if (fi->field_readcount == TIFF_VARIABLE) 
  88:     {
  89:       uint16 gotcount = 0;
  90:       TIFFGetField(metatif, fi->field_tag, &gotcount, &data);
  91:       count = gotcount;
  92:     }
  93:     else if (fi->field_readcount == TIFF_VARIABLE2) 
  94:     {
  95:       uint32 gotcount = 0;
  96:       TIFFGetField(metatif, fi->field_tag, &gotcount, &data);
  97:       count = gotcount;
  98:     }
  99:     else 
 100:     {
 101:       TIFFGetField(metatif, fi->field_tag, &data);
 102:       count = fi->field_readcount;
 103:     }
 104: 
 105:     // ここでカウントとデータを記録する
 106: 
 107:     return true;
 108:   }
 109:   else if (fi->field_readcount == 1) 
 110:   {
 111:     TIFFGetField(metatif, fi->field_tag, &data);
 112:     
 113:     // ここでカウント1とデータを記録する
 114:     
 115:     return true;
 116:   }
 117:   return false;
 118: }
 119: 
 120: 
 121: bool GetExif( const char *pszFName )
 122: {
 123: 	TIFF *pTif = TIFFOpen( pszFName, "r" );
 124: 	if ( !pTif ) return false;
 125: 
 126: 	uint64 nReadDirOffset = 0;
 127: 	int bRet;
 128: 
 129: 	bRet = TIFFGetField( pTif, TIFFTAG_EXIFIFD, &nReadDirOffset );
 130: 
 131: 	if ( bRet )
 132: 	{
 133: 		TIFFReadEXIFDirectory( pTif, nReadDirOffset );
 134: 		int nCnt = TIFFGetTagListCount( pTif );
 135: 
 136: 		for ( int i = 0; i < nCnt; i++ )
 137: 		{
 138: 			ttag_t tag = TIFFGetTagListEntry( pTif, i );
 139: 			const TIFFField *pFieldInfo = TIFFFieldWithTag( pTif, tag );
 140: 			
 141: 			// 戻り値
 142: 			bool usedMetaData = false;
 143: 
 144: 			switch ( pFieldInfo->field_type )
 145: 			{
 146: 			case TIFF_RATIONAL:
 147: 			case TIFF_SRATIONAL:
 148: 			case TIFF_FLOAT:
 149: 				usedMetaData = getMetaData<float, double>( pTif, pFieldInfo );
 150: 				break;
 151: 
 152: 			case TIFF_SHORT:
 153: 				usedMetaData = getMetaData<uint16, int>( pTif, pFieldInfo );
 154: 				break;
 155: 
 156: 			case TIFF_LONG:
 157: 				usedMetaData = getMetaData<uint32, double>( pTif, pFieldInfo );
 158: 				break;
 159: 
 160: 			case TIFF_SBYTE:
 161: 				usedMetaData = getMetaData<int8, int>( pTif, pFieldInfo );
 162: 				break;
 163: 
 164: 			case TIFF_SSHORT:
 165: 				usedMetaData = getMetaData<int16, int>( pTif, pFieldInfo );
 166: 				break;
 167: 
 168: 			case TIFF_SLONG:
 169: 				usedMetaData = getMetaData<int32, int>( pTif, pFieldInfo );
 170: 				break;
 171: 
 172: 			case TIFF_DOUBLE:
 173: 				usedMetaData = getMetaData<double, double>( pTif, pFieldInfo );
 174: 				break;
 175: 
 176: 			case TIFF_ASCII:
 177: 				usedMetaData = getMetaDataString( pTif, pFieldInfo );
 178: 				break;
 179: 
 180: 			case TIFF_UNDEFINED:
 181: 				usedMetaData = getMetadataUndefined( pTif, pFieldInfo );
 182: 				break;
 183: 
 184: 			default:
 185: 
 186: 				break;
 187: 			}
 188: 
 189: 			if ( usedMetaData )
 190: 			{
 191: 				// 本来は各関数の引数でデータを受け取って、
 192: 				// 戻り値で保存するかどうか判断するべき?
 193: 			}
 194: 		}
 195: 	}
 196: 
 197: 	TIFFClose( pTif );
 198: 
 199: 	return true;
 200: }

EXIFのMakerNoteタグと、MakeタグとModelタグ

EXIFにはMakerNoteタグというのがあります。
これはメーカー独自の情報を記録するタグで、中身のフォーマットもそれぞれのメーカー定義のもののようです。
ExifToolなどはMakeタグとModelタグを見て中身を解析してくれたりします。
なので、対応するMakeタグとModelタグも、あれば読み込んでおいて、保存時には書き込んでおきましょう。

GPSタグ

EXIFタグはlibtiff内に定義されていましたが、GPSタグは定義されていません。
そこで、タグ情報のTIFFField型の配列を自前で作成する必要があります。
以下は筆者が作成したものですが、以下のタグは確認できていますが他は未確認です。

    • GPSLatitudeRef
    • GPSLongituideRef
    • GPSTimeStamp
    • GPSStatus
    • GPSMapDatum
    • GPSDateStamp
    • GPSDateTime
    • GPSLatitude
    • GPSLongitude
    • GPSPosition
   1: //
   2: // タグ番号
   3: // 下記のサイトの情報を元にGPSタグのものと合わせています。
   4: // http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/gps.html
   5: // 
   6: //
   7: #define GPSTAG_VERSIONID        0
   8: #define GPSTAG_LATITUDEREF      1
   9: #define GPSTAG_LATITUDE         2
  10: #define GPSTAG_LONGITUDEREF     3
  11: #define GPSTAG_LONGITUDE        4
  12: #define GPSTAG_ALTITUDEREF      5
  13: #define GPSTAG_ALTITUDE         6
  14: #define GPSTAG_TIMESTAMP        7
  15: #define GPSTAG_SATELLITES       8
  16: #define GPSTAG_STATUS           9
  17: #define GPSTAG_MEASUREMODE      10
  18: #define GPSTAG_DOP              11
  19: #define GPSTAG_SPEEDREF         12
  20: #define GPSTAG_SPEED            13
  21: #define GPSTAG_TRACKREF         14
  22: #define GPSTAG_TRACK            15
  23: #define GPSTAG_IMGDIRECTIONREF  16
  24: #define GPSTAG_IMGDIRECTION     17
  25: #define GPSTAG_MAPDATUM         18
  26: #define GPSTAG_DESTLATITUDEREF  19
  27: #define GPSTAG_DESTLATITUDE     20
  28: #define GPSTAG_DESTLONGITUDEREF 21
  29: #define GPSTAG_DESTLONGITUDE    22
  30: #define GPSTAG_DESTBEARINGREF   23
  31: #define GPSTAG_DESTBEARING      24
  32: #define GPSTAG_DESTDISTANCEREF  25
  33: #define GPSTAG_DESTDISTANCE     26
  34: #define GPSTAG_PROCESSINGMETHOD 27
  35: #define GPSTAG_AREAINFORMATION  28
  36: #define GPSTAG_DATASTAMP        29
  37: #define GPSTAG_DIFFERENTIAL     30
  38: 
  39: //
  40: // フィールド情報定義
  41: // ここがキモ
  42: //
  43: static TIFFField gpsFields[] = {
  44:   { GPSTAG_VERSIONID, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UINT8, 
          FIELD_CUSTOM, 1, 0, "GPSVersionID", NULL },
  45:   { GPSTAG_LATITUDEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_ASCII, 
          FIELD_CUSTOM, 1, 0, "GPSLatitudeRef", NULL },
  46:   { GPSTAG_LATITUDE, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_C16_FLOAT, 
          FIELD_CUSTOM, 1, 1, "GPSLatitude", NULL },
  47:   { GPSTAG_LONGITUDEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_ASCII, 
          FIELD_CUSTOM, 1, 0, "GPSLongitudeRef", NULL },
  48:   { GPSTAG_LONGITUDE, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_C16_FLOAT,
          FIELD_CUSTOM, 1, 1, "GPSLongitude", NULL },
  49:   { GPSTAG_ALTITUDEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_ASCII,
          FIELD_CUSTOM, 1, 0, "GPSAltitudeRef", NULL },
  50:   { GPSTAG_ALTITUDE, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_C16_FLOAT,
          FIELD_CUSTOM, 1, 1, "GPSAltitude", NULL },
  51:   { GPSTAG_TIMESTAMP, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_C16_FLOAT,
          FIELD_CUSTOM, 1, 1, "GPSTimeStamp", NULL },
  52:   { GPSTAG_SATELLITES, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 1, "GPSSatellites", NULL },
  53:   { GPSTAG_STATUS, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSStatus", NULL },
  54:   { GPSTAG_MEASUREMODE, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSMeasureMode", NULL },
  55:   { GPSTAG_DOP, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSDOP", NULL },
  56:   { GPSTAG_SPEEDREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSSpeedRef", NULL },
  57:   { GPSTAG_SPEED, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSSpeed", NULL },
  58:   { GPSTAG_TRACKREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSTrackRef", NULL },
  59:   { GPSTAG_TRACK, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSTrack", NULL },
  60:   { GPSTAG_IMGDIRECTIONREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSImgDirectionRef", NULL },
  61:   { GPSTAG_IMGDIRECTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSImgDirection", NULL },
  62:   { GPSTAG_MAPDATUM, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSMapDatum", NULL },
  63:   { GPSTAG_DESTLATITUDEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSDestLatitudeRef", NULL },
  64:   { GPSTAG_DESTLATITUDE, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_C16_FLOAT,
          FIELD_CUSTOM, 1, 1, "GPSDestLatitude", NULL },
  65:   { GPSTAG_DESTLONGITUDEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSDestLongitudeRef", NULL },
  66:   { GPSTAG_DESTLONGITUDE, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_C16_FLOAT,
          FIELD_CUSTOM, 1, 1, "GPSDestLongitude", NULL },
  67:   { GPSTAG_DESTBEARINGREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, 
          FIELD_CUSTOM, 1, 0, "GPSDestBearingRef", NULL },
  68:   { GPSTAG_DESTBEARING, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSDestBearing", NULL },
  69:   { GPSTAG_DESTDISTANCEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSDestDistanceRef", NULL },
  70:   { GPSTAG_DESTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSDestDistance", NULL },
  71:   { GPSTAG_PROCESSINGMETHOD, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 1, "GPSProcessingMethod", NULL },
  72:   { GPSTAG_AREAINFORMATION, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 1, "GPSAreaInformation", NULL },
  73:   { GPSTAG_DATASTAMP, 11, 11, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSDateStamp", NULL },
  74:   { GPSTAG_DIFFERENTIAL, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED,
          FIELD_CUSTOM, 1, 0, "GPSDifferential", NULL }
  75: };
  76: 
  77: //
  78: // この変数を用意して、TIFFReadCustomDirectory()に渡す
  79: //
  80: static TIFFFieldArray gpsFieldArray = { tfiatOther, 0, 31, gpsFields };
  81: 
  82: /////////////////////////////////////////////////////////////////////
  83: 
  84: bool GetGps( const char *pszFName )
  85: {
  86:   // GPS IFD
  87:   nReadDirOffset = 0;
  88:   TIFFSetDirectory( pTif, 0 );
  89:   
  90:   // GPS IFDまでのオフセットを取得
  91:   bRet = TIFFGetField( pTif, TIFFTAG_GPSIFD, &nReadDirOffset );
  92: 
  93:   if ( bRet )
  94:   {
  95: 	// カスタムディレクトリとしてGPS IFDを読み込む
  96: 	// ここで、上の変数を渡す
  97:     TIFFReadCustomDirectory( pTif, nReadDirOffset, &gpsFieldArray );
  98:     int nCnt = TIFFGetTagListCount( pTif );
  99: 
 100:     for ( int i = 0; i < nCnt; i++ )
 101:     {
 102:       ttag_t tag = TIFFGetTagListEntry( pTif, i );
 103:       const TIFFField *pFieldInfo = TIFFFieldWithTag( pTif, tag );
 104: 
 105:       // 以下はEXIFタグと同じ
 106:     

書き込み

EXIF、GPSタグの書き込みは、基本的には新しくIFDを作成してTIFFSetField()でタグを書き込み、
最後にTIFFWriteCustomDirectory()でIFDを書き込むという手順です。

ここでは書き込みの概略を示します。

   1: 	uint64 nExifDirOffset, nGpsDirOffset;
   2: 
   3: 	// EXIF
   4: 
   5: 	if ( TIFFCreateEXIFDirectory( pTif ) != 0 )
   6: 	{
   7: 		return false;
   8: 	}
   9: 
  10: 	// EXIFタグを書き込む例
  11: 	TIFFSetField( pTif, EXIFTAG_ISOSPEEDRATINGS, 200 )
  12: 	
  13: 	// EXIF IFDを書き込む
  14: 	if ( !TIFFWriteCustomDirectory( pTif, &nExifDirOffset ) )
  15: 	{
  16: 		return false;
  17: 	}
  18: 	
  19: 	// GPS
  20: 	// 変数gpsFieldArrayは上記参照
  21: 
  22: 	if ( TIFFCreateCustomDirectory( pTif, &gpsFieldArray ) )
  23: 	{
  24: 		return false;
  25: 	}
  26: 	
  27: 	// GPSタグを書き込む例
  28: 	// タグ定義は上記参照
  29: 	TIFFSetField( pTif, GPSTAG_LATITUDEREF, "N" );
  30: 
  31: 	// GPS IFDを書き込む
  32: 	if ( !TIFFWriteCustomDirectory( pTif, &nGpsDirOffset ) )
  33: 	{
  34: 		return false;
  35: 	}
  36: 
  37: 	// 先頭のIFDにEXIFIFD、GPSIFDへのオフセットタグを書き込む
  38: 	TIFFSetDirectory( pTif, 0 );
  39: 	TIFFSetField( pTif, TIFFTAG_EXIFIFD, nExifDirOffset );
  40: 	TIFFSetField( pTif, TIFFTAG_GPSIFD, nGpsDirOffset );
  41: 	

参考サイト

アーカイブ