Coverage Report

Created: 2023-12-08 06:53

/src/freeimage-svn/FreeImage/trunk/Source/Metadata/Exif.cpp
Line
Count
Source (jump to first uncovered line)
1
// ==========================================================
2
// Metadata functions implementation
3
// Exif metadata model
4
//
5
// Design and implementation by
6
// - Hervé Drolon (drolon@infonie.fr)
7
// - Mihail Naydenov (mnaydenov@users.sourceforge.net)
8
// - Garrick Meeker (garrickmeeker@users.sourceforge.net)
9
//
10
// Based on the following implementations:
11
// - metadata-extractor : http://www.drewnoakes.com/code/exif/
12
// - jhead : http://www.sentex.net/~mwandel/jhead/
13
// - ImageMagick : http://www.imagemagick.org/
14
//
15
// This file is part of FreeImage 3
16
//
17
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
18
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
19
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
20
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
21
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
22
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
23
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
24
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
25
// THIS DISCLAIMER.
26
//
27
// Use at your own risk!
28
// ==========================================================
29
30
#ifdef _MSC_VER 
31
#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
32
#endif
33
34
#include "FreeImage.h"
35
#include "Utilities.h"
36
#include "FreeImageTag.h"
37
38
// ==========================================================
39
// Exif JPEG routines
40
// ==========================================================
41
42
0
#define EXIF_NUM_FORMATS  12
43
44
0
#define TAG_EXIF_OFFSET     0x8769  // Exif IFD Pointer
45
0
#define TAG_GPS_OFFSET      0x8825  // GPS Info IFD Pointer
46
0
#define TAG_INTEROP_OFFSET    0xA005  // Interoperability IFD Pointer
47
0
#define TAG_MAKER_NOTE      0x927C  // Maker note
48
49
// CANON cameras have some funny bespoke fields that need further processing...
50
0
#define TAG_CANON_CAMERA_STATE_0x01 0x0001    // tags under tag 0x001 (CameraSettings)
51
0
#define TAG_CANON_CAMERA_STATE_0x02 0x0002    // tags under tag 0x002 (FocalLength)
52
0
#define TAG_CANON_CAMERA_STATE_0x04 0x0004    // tags under tag 0x004 (ShotInfo)
53
0
#define TAG_CANON_CAMERA_STATE_0x12 0x0012    // tags under tag 0x012 (AFInfo)
54
0
#define TAG_CANON_CAMERA_STATE_0xA0 0x00A0    // tags under tag 0x0A0 (ProcessingInfo)
55
0
#define TAG_CANON_CAMERA_STATE_0xE0 0x00E0    // tags under tag 0x0E0 (SensorInfo)
56
57
58
// =====================================================================
59
// Reimplementation of strnicmp (it is not supported on some systems)
60
// =====================================================================
61
62
/**
63
Compare characters of two strings without regard to case.
64
@param s1 Null-terminated string to compare.
65
@param s2 Null-terminated string to compare.
66
@param len Number of characters to compare
67
@return Returns 0 if s1 substring identical to s2 substring
68
*/
69
static int 
70
0
FreeImage_strnicmp(const char *s1, const char *s2, size_t len) {
71
0
  if (!s1 || !s2) {
72
0
    return -1;
73
0
  }
74
75
0
  unsigned char c1 = 0;
76
0
  unsigned char c2 = 0;
77
78
0
  if(len) {
79
0
    do {
80
0
      c1 = *s1; 
81
0
      c2 = *s2;
82
0
      s1++; 
83
0
      s2++;
84
0
      if (!c1) {
85
0
        break;
86
0
      }
87
0
      if (!c2) {
88
0
        break;
89
0
      }
90
0
      if (c1 == c2) {
91
0
        continue;
92
0
      }
93
0
      c1 = (BYTE)tolower(c1);
94
0
      c2 = (BYTE)tolower(c2);
95
0
      if (c1 != c2) {
96
0
        break;
97
0
      }
98
0
    } while (--len);
99
0
  }
100
0
  return ((int)c1 - (int)c2);
101
0
}
102
103
// ----------------------------------------------------------
104
// Little Endian / Big Endian io routines
105
// msb_order is Endianness order of the Exif file (TRUE if big-endian, FALSE if little-endian)
106
// ----------------------------------------------------------
107
108
static short 
109
0
ReadInt16(BOOL msb_order, const void *buffer) {
110
0
  short value;
111
112
0
  if(msb_order) {
113
0
    value = (short)((((BYTE*) buffer)[0] << 8) | ((BYTE*) buffer)[1]);
114
0
    return value;
115
0
    }
116
0
  value = (short)((((BYTE*) buffer)[1] << 8) | ((BYTE*) buffer)[0]);
117
0
  return value;
118
0
}
119
120
static LONG 
121
0
ReadInt32(BOOL msb_order, const void *buffer) {
122
0
  LONG value;
123
124
0
  if(msb_order) {
125
0
    value = (LONG)((((BYTE*) buffer)[0] << 24) | (((BYTE*) buffer)[1] << 16) | (((BYTE*) buffer)[2] << 8) | (((BYTE*) buffer)[3]));
126
0
    return value;
127
0
    }
128
0
  value = (LONG)((((BYTE*) buffer)[3] << 24) | (((BYTE*) buffer)[2] << 16) | (((BYTE*) buffer)[1] << 8 ) | (((BYTE*) buffer)[0]));
129
0
  return value;
130
0
}
131
132
static WORD 
133
0
ReadUint16(BOOL msb_order, const void *buffer) {
134
0
  WORD value;
135
  
136
0
  if(msb_order) {
137
0
    value = (WORD) ((((BYTE*) buffer)[0] << 8) | ((BYTE*) buffer)[1]);
138
0
    return value;
139
0
    }
140
0
  value = (WORD) ((((BYTE*) buffer)[1] << 8) | ((BYTE*) buffer)[0]);
141
0
  return value;
142
0
}
143
144
static DWORD 
145
0
ReadUint32(BOOL msb_order, const void *buffer) {
146
0
  return ((DWORD) ReadInt32(msb_order, buffer) & 0xFFFFFFFF);
147
0
}
148
149
// ----------------------------------------------------------
150
//   Exif JPEG markers routines
151
// ----------------------------------------------------------
152
153
/**
154
Process a IFD offset
155
Returns the offset and the metadata model for this tag
156
157
@param tag
158
@param pval
159
@param msb_order Endianness order of the Exif file (TRUE if big-endian, FALSE if little-endian)
160
@param subdirOffset [output] Offset into the IFD
161
@param md_model [output] Metadata model to process
162
*/
163
static void 
164
0
processIFDOffset(FITAG *tag, const char *pval, BOOL msb_order, DWORD *subdirOffset, TagLib::MDMODEL *md_model) {
165
  // get the IFD offset
166
0
  *subdirOffset = ReadUint32(msb_order, pval);
167
168
  // select a tag info table
169
0
  switch(FreeImage_GetTagID(tag)) {
170
0
    case TAG_EXIF_OFFSET:
171
0
      *md_model = TagLib::EXIF_EXIF;
172
0
      break;
173
0
    case TAG_GPS_OFFSET:
174
0
      *md_model = TagLib::EXIF_GPS;
175
0
      break;
176
0
    case TAG_INTEROP_OFFSET:
177
0
      *md_model = TagLib::EXIF_INTEROP;
178
0
      break;
179
0
    default:
180
0
      break;
181
0
  }
182
0
}
183
184
/**
185
Process a maker note IFD offset
186
Returns the offset and the metadata model for this tag
187
188
A makernote is usually structured as this
189
- a header (0 or n bytes)
190
- a standard TIFF IFD (start just after the header)
191
It can also contain
192
- a header
193
- an IFD offset
194
- a standard TIFF IFD (start at the IFD offset)
195
196
@param dib Image to be processed
197
@param pval Current Exif IFD memory pointer
198
@param msb_order Endianness order of the Exif file (TRUE if big-endian, FALSE if little-endian)
199
@param subdirOffset [output] Offset into the IFD
200
@param md_model [output] Metadata model to process
201
*/
202
static void 
203
0
processMakerNote(FIBITMAP *dib, const char *pval, BOOL msb_order, DWORD *subdirOffset, TagLib::MDMODEL *md_model) {
204
0
  FITAG *tagMake = NULL;
205
206
0
  *subdirOffset = 0;
207
0
  *md_model = TagLib::UNKNOWN;
208
209
  // Determine the camera model and makernote format
210
  // WARNING: note that Maker may be NULL sometimes so check its value before using it
211
  // (NULL pointer checking is done by FreeImage_strnicmp)
212
0
  FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "Make", &tagMake);
213
0
  const char *Maker = (char*)FreeImage_GetTagValue(tagMake);
214
215
0
  if((memcmp("OLYMP\x00\x01", pval, 7) == 0) || (memcmp("OLYMP\x00\x02", pval, 7) == 0) || (memcmp("EPSON", pval, 5) == 0) || (memcmp("AGFA", pval, 4) == 0)) {
216
    // Olympus Type 1 Makernote
217
    // Epson and Agfa use Olympus maker note standard, 
218
    // see: http://www.ozhiker.com/electronics/pjmt/jpeg_info/
219
0
    *md_model = TagLib::EXIF_MAKERNOTE_OLYMPUSTYPE1;
220
0
    *subdirOffset = 8;
221
0
  } 
222
0
  else if(memcmp("OLYMPUS\x00\x49\x49\x03\x00", pval, 12) == 0) {
223
    // Olympus Type 2 Makernote
224
    // !!! NOT YET SUPPORTED !!!
225
0
    *md_model = TagLib::UNKNOWN;
226
0
    *subdirOffset = 0;
227
0
  }
228
0
  else if(memcmp("Nikon", pval, 5) == 0) {
229
    /* There are two scenarios here:
230
     * Type 1:
231
     * :0000: 4E 69 6B 6F 6E 00 01 00-05 00 02 00 02 00 06 00 Nikon...........
232
     * :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................
233
     * Type 3:
234
     * :0000: 4E 69 6B 6F 6E 00 02 00-00 00 4D 4D 00 2A 00 00 Nikon....MM.*...
235
     * :0010: 00 08 00 1E 00 01 00 07-00 00 00 04 30 32 30 30 ............0200
236
     */
237
0
    if (pval[6] == 1) {
238
      // Nikon type 1 Makernote
239
0
      *md_model = TagLib::EXIF_MAKERNOTE_NIKONTYPE1;
240
0
      *subdirOffset = 8;
241
0
        } else if (pval[6] == 2) {
242
            // Nikon type 3 Makernote
243
0
      *md_model = TagLib::EXIF_MAKERNOTE_NIKONTYPE3;
244
0
      *subdirOffset = 18;
245
0
    } else {
246
      // Unsupported makernote data ignored
247
0
      *md_model = TagLib::UNKNOWN;
248
0
      *subdirOffset = 0;
249
0
    }
250
0
  } else if(Maker && (FreeImage_strnicmp("NIKON", Maker, 5) == 0)) {
251
    // Nikon type 2 Makernote
252
0
    *md_model = TagLib::EXIF_MAKERNOTE_NIKONTYPE2;
253
0
    *subdirOffset = 0;
254
0
  } else if(Maker && (FreeImage_strnicmp("Canon", Maker, 5) == 0)) {
255
        // Canon Makernote
256
0
    *md_model = TagLib::EXIF_MAKERNOTE_CANON;
257
0
    *subdirOffset = 0;
258
0
  } else if(Maker && (FreeImage_strnicmp("Casio", Maker, 5) == 0)) {
259
        // Casio Makernote
260
0
    if(memcmp("QVC\x00\x00\x00", pval, 6) == 0) {
261
      // Casio Type 2 Makernote
262
0
      *md_model = TagLib::EXIF_MAKERNOTE_CASIOTYPE2;
263
0
      *subdirOffset = 6;
264
0
    } else {
265
      // Casio Type 1 Makernote
266
0
      *md_model = TagLib::EXIF_MAKERNOTE_CASIOTYPE1;
267
0
      *subdirOffset = 0;
268
0
    }
269
0
  } else if ((memcmp("FUJIFILM", pval, 8) == 0) || (Maker && (FreeImage_strnicmp("Fujifilm", Maker, 8) == 0))) {
270
        // Fujifile Makernote
271
    // Fujifilm's Makernote always use little-endian order altough the Exif section maybe in little-endian order or in big-endian order. 
272
    // If msb_order == TRUE, the Makernote won't be read: 
273
    // the value of ifdStart will be 0x0c000000 instead of 0x0000000c and the MakerNote section will be 
274
    // discarded later in jpeg_read_exif_dir because the IFD is too high
275
0
    *md_model = TagLib::EXIF_MAKERNOTE_FUJIFILM;
276
0
        DWORD ifdStart = ReadUint32(msb_order, pval + 8);
277
0
    *subdirOffset = ifdStart;
278
0
    }
279
0
  else if(memcmp("KYOCERA\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x00\x00\x00", pval, 22) == 0) {
280
0
    *md_model = TagLib::EXIF_MAKERNOTE_KYOCERA;
281
0
    *subdirOffset = 22;
282
0
  }
283
0
  else if(Maker && (FreeImage_strnicmp("Minolta", Maker, 7) == 0)) {
284
    // Minolta maker note
285
0
    *md_model = TagLib::EXIF_MAKERNOTE_MINOLTA;
286
0
    *subdirOffset = 0;
287
0
  }
288
0
  else if(memcmp("Panasonic\x00\x00\x00", pval, 12) == 0) {
289
    // Panasonic maker note
290
0
    *md_model = TagLib::EXIF_MAKERNOTE_PANASONIC;
291
0
    *subdirOffset = 12;
292
0
  }
293
0
  else if(Maker && (FreeImage_strnicmp("LEICA", Maker, 5) == 0)) {
294
    // Leica maker note
295
0
    if(memcmp("LEICA\x00\x00\x00", pval, 8) == 0) {
296
      // not yet supported makernote data ignored
297
0
      *md_model = TagLib::UNKNOWN;
298
0
      *subdirOffset = 0;
299
0
    }
300
0
  }
301
0
  else if(Maker && ((FreeImage_strnicmp("Pentax", Maker, 6) == 0) || (FreeImage_strnicmp("Asahi", Maker, 5) == 0))) {
302
    // Pentax maker note
303
0
    if(memcmp("AOC\x00", pval, 4) == 0) {
304
      // Type 2 Pentax Makernote
305
0
      *md_model = TagLib::EXIF_MAKERNOTE_PENTAX;
306
0
      *subdirOffset = 6;
307
0
    } else {
308
      // Type 1 Pentax Makernote
309
0
      *md_model = TagLib::EXIF_MAKERNOTE_ASAHI;
310
0
      *subdirOffset = 0;
311
0
    }
312
0
  } 
313
0
  else if((memcmp("SONY CAM\x20\x00\x00\x00", pval, 12) == 0) || (memcmp("SONY DSC\x20\x00\x00\x00", pval, 12) == 0)) {
314
0
    *md_model = TagLib::EXIF_MAKERNOTE_SONY;
315
0
    *subdirOffset = 12;
316
0
  }
317
0
  else if((memcmp("SIGMA\x00\x00\x00", pval, 8) == 0) || (memcmp("FOVEON\x00\x00", pval, 8) == 0)) {
318
0
    FITAG *tagModel = NULL;
319
0
    FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "Model", &tagModel);
320
0
    const char *Model = (char*)FreeImage_GetTagValue(tagModel);
321
0
    if(Model && (memcmp("SIGMA SD1\x00", Model, 10) == 0)) {
322
      // Sigma SD1 maker note
323
0
      *md_model = TagLib::EXIF_MAKERNOTE_SIGMA_SD1;
324
0
      *subdirOffset = 10;
325
0
    } else {
326
      // Sigma / Foveon makernote
327
0
      *md_model = TagLib::EXIF_MAKERNOTE_SIGMA_FOVEON;
328
0
      *subdirOffset = 10;
329
0
    }
330
0
  }
331
0
  else if (Maker && (FreeImage_strnicmp("Apple", Maker, 5) == 0)) {
332
    // Apple maker note
333
0
    if (memcmp("Apple iOS", pval, 9) == 0) {
334
      // Apple iOS Makernote
335
0
      *md_model = TagLib::EXIF_MAKERNOTE_APPLE_IOS;
336
0
      *subdirOffset = 14;
337
0
    }
338
0
  }
339
0
}
340
341
/**
342
Process a Canon maker note tag. 
343
A single Canon tag may contain many other tags within.
344
345
@param dib Image to be processed
346
@param tag MakerNote Exif tag
347
@return Returns TRUE if successful, returns FALSE otherwise
348
*/
349
static BOOL 
350
0
processCanonMakerNoteTag(FIBITMAP *dib, FITAG *tag) {
351
0
  char defaultKey[16];
352
0
  DWORD startIndex = 0;
353
0
  TagLib& s = TagLib::instance();
354
355
0
  WORD tag_id = FreeImage_GetTagID(tag);
356
357
0
  int subTagTypeBase = 0;
358
359
0
  switch(tag_id) {
360
0
    case TAG_CANON_CAMERA_STATE_0x01:
361
0
      subTagTypeBase = 0xC100;
362
0
      startIndex = 1;
363
0
      break;
364
0
    case TAG_CANON_CAMERA_STATE_0x02:
365
0
      subTagTypeBase = 0xC200;
366
0
      startIndex = 0;
367
0
      break;
368
0
    case TAG_CANON_CAMERA_STATE_0x04:
369
0
      subTagTypeBase = 0xC400;
370
0
      startIndex = 1;
371
0
      break;
372
0
    case TAG_CANON_CAMERA_STATE_0x12:
373
0
      subTagTypeBase = 0x1200;
374
0
      startIndex = 0;
375
0
      break;
376
0
    case TAG_CANON_CAMERA_STATE_0xA0:
377
0
      subTagTypeBase = 0xCA00;
378
0
      startIndex = 1;
379
0
      break;
380
0
    case TAG_CANON_CAMERA_STATE_0xE0:
381
0
      subTagTypeBase = 0xCE00;
382
0
      startIndex = 1;
383
0
      break;
384
385
0
    default:
386
0
    {
387
      // process as a normal tag
388
389
      // get the tag key and description
390
0
      const char *key = s.getTagFieldName(TagLib::EXIF_MAKERNOTE_CANON, tag_id, defaultKey);
391
0
      FreeImage_SetTagKey(tag, key);
392
0
      const char *description = s.getTagDescription(TagLib::EXIF_MAKERNOTE_CANON, tag_id);
393
0
      FreeImage_SetTagDescription(tag, description);
394
395
      // store the tag
396
0
      if(key) {
397
0
        FreeImage_SetMetadata(FIMD_EXIF_MAKERNOTE, dib, key, tag);
398
0
      }
399
400
0
      return TRUE;
401
0
    }
402
0
    break;
403
404
0
  }
405
406
0
  WORD *pvalue = (WORD*)FreeImage_GetTagValue(tag);
407
408
  // create a tag
409
0
  FITAG *canonTag = FreeImage_CreateTag();
410
0
  if(!canonTag) return FALSE;
411
412
  // we intentionally skip the first array member (if needed)
413
0
    for (DWORD i = startIndex; i < FreeImage_GetTagCount(tag); i++) {
414
415
0
    tag_id = (WORD)(subTagTypeBase + i);
416
417
0
    FreeImage_SetTagID(canonTag, tag_id);
418
0
    FreeImage_SetTagType(canonTag, FIDT_SHORT);
419
0
    FreeImage_SetTagCount(canonTag, 1);
420
0
    FreeImage_SetTagLength(canonTag, 2);
421
0
    FreeImage_SetTagValue(canonTag, &pvalue[i]);
422
423
    // get the tag key and description
424
0
    const char *key = s.getTagFieldName(TagLib::EXIF_MAKERNOTE_CANON, tag_id, defaultKey);
425
0
    FreeImage_SetTagKey(canonTag, key);
426
0
    const char *description = s.getTagDescription(TagLib::EXIF_MAKERNOTE_CANON, tag_id);
427
0
    FreeImage_SetTagDescription(canonTag, description);
428
429
    // store the tag
430
0
    if(key) {
431
0
      FreeImage_SetMetadata(FIMD_EXIF_MAKERNOTE, dib, key, canonTag);
432
0
    }
433
0
  }
434
435
  // delete the tag
436
0
  FreeImage_DeleteTag(canonTag);
437
438
0
  return TRUE;
439
0
}
440
441
/**
442
Process a standard Exif tag
443
444
@param dib Image to be processed
445
@param tag
446
@param pval
447
@param msb_order Endianness order of the Exif file (TRUE if big-endian, FALSE if little-endian)
448
@param md_model
449
*/
450
static void 
451
0
processExifTag(FIBITMAP *dib, FITAG *tag, char *pval, BOOL msb_order, TagLib::MDMODEL md_model) {
452
0
  char defaultKey[16];
453
0
  int n;
454
0
  DWORD i;
455
456
  // allocate a buffer to store the tag value
457
0
  BYTE *exif_value = (BYTE*)malloc(FreeImage_GetTagLength(tag) * sizeof(BYTE));
458
0
  if(NULL == exif_value) {
459
    // out of memory ...
460
0
    return;
461
0
  }
462
0
  memset(exif_value, 0, FreeImage_GetTagLength(tag) * sizeof(BYTE));
463
464
  // get the tag value
465
0
  switch(FreeImage_GetTagType(tag)) {
466
467
0
    case FIDT_SHORT:
468
0
    {
469
0
      WORD *value = (WORD*)&exif_value[0];
470
0
      for(i = 0; i < FreeImage_GetTagCount(tag); i++) {
471
0
        value[i] = ReadUint16(msb_order, pval + i * sizeof(WORD));
472
0
      }
473
0
      FreeImage_SetTagValue(tag, value);
474
0
      break;
475
0
    }
476
0
    case FIDT_SSHORT:
477
0
    {
478
0
      short *value = (short*)&exif_value[0];
479
0
      for(i = 0; i < FreeImage_GetTagCount(tag); i++) {
480
0
        value[i] = ReadInt16(msb_order, pval + i * sizeof(short));
481
0
      }
482
0
      FreeImage_SetTagValue(tag, value);
483
0
      break;
484
0
    }
485
0
    case FIDT_LONG:
486
0
    {
487
0
      DWORD *value = (DWORD*)&exif_value[0];
488
0
      for(i = 0; i < FreeImage_GetTagCount(tag); i++) {
489
0
        value[i] = ReadUint32(msb_order, pval + i * sizeof(DWORD));
490
0
      }
491
0
      FreeImage_SetTagValue(tag, value);
492
0
      break;
493
0
    }
494
0
    case FIDT_SLONG:
495
0
    {
496
0
      LONG *value = (LONG*)&exif_value[0];
497
0
      for(i = 0; i < FreeImage_GetTagCount(tag); i++) {
498
0
        value[i] = ReadInt32(msb_order, pval + i * sizeof(LONG));
499
0
      }
500
0
      FreeImage_SetTagValue(tag, value);
501
0
      break;
502
0
    }
503
0
    case FIDT_RATIONAL:
504
0
    {
505
0
      n = sizeof(DWORD);
506
507
0
      DWORD *value = (DWORD*)&exif_value[0];            
508
0
      for(i = 0; i < 2 * FreeImage_GetTagCount(tag); i++) {
509
        // read a sequence of (numerator, denominator)
510
0
        value[i] = ReadUint32(msb_order, n*i + (char*)pval);
511
0
      }
512
0
      FreeImage_SetTagValue(tag, value);
513
0
      break;
514
0
    }
515
0
    case FIDT_SRATIONAL:
516
0
    {
517
0
      n = sizeof(LONG);
518
519
0
      LONG *value = (LONG*)&exif_value[0];
520
0
      for(i = 0; i < 2 * FreeImage_GetTagCount(tag); i++) {
521
        // read a sequence of (numerator, denominator)
522
0
        value[i] = ReadInt32(msb_order, n*i + (char*)pval);
523
0
      }
524
0
      FreeImage_SetTagValue(tag, value);
525
0
      break;
526
0
    }
527
0
    case FIDT_BYTE:
528
0
    case FIDT_ASCII:
529
0
    case FIDT_SBYTE:
530
0
    case FIDT_UNDEFINED:
531
0
    case FIDT_FLOAT:
532
0
    case FIDT_DOUBLE:
533
0
    default:
534
0
      FreeImage_SetTagValue(tag, pval);
535
0
      break;
536
0
  }
537
538
0
  if(md_model == TagLib::EXIF_MAKERNOTE_CANON) {
539
    // A single Canon tag can have multiple values within
540
0
    processCanonMakerNoteTag(dib, tag);
541
0
  }
542
0
  else {
543
0
    TagLib& s = TagLib::instance();
544
545
0
    WORD tag_id = FreeImage_GetTagID(tag);
546
547
    // get the tag key and description
548
0
    const char *key = s.getTagFieldName(md_model, tag_id, defaultKey);
549
0
    FreeImage_SetTagKey(tag, key);
550
0
    const char *description = s.getTagDescription(md_model, tag_id);
551
0
    FreeImage_SetTagDescription(tag, description);
552
553
    // store the tag
554
0
    if(key) {
555
0
      FreeImage_SetMetadata(s.getFreeImageModel(md_model), dib, key, tag);
556
0
    }
557
0
  }
558
  
559
560
  // free the temporary buffer
561
0
  free(exif_value);
562
0
}
563
564
// --------------------------------------------------------------------------
565
566
/**
567
Process Exif directory
568
569
@param dib Image to be processed
570
@param tiffp Pointer to the TIFF header
571
@param dwOffsetIfd0 Offset to the 0th IFD (first IFD)
572
@param dwLength Length of the Exif file
573
@param dwProfileOffset File offset to be used when reading 'offset/value' tags
574
@param msb_order Endianness order of the Exif file (TRUE if big-endian, FALSE if little-endian)
575
@param starting_md_model Metadata model of the IFD (should be TagLib::EXIF_MAIN for a jpeg)
576
@return Returns TRUE if sucessful, returns FALSE otherwise
577
*/
578
static BOOL 
579
0
jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, DWORD dwOffsetIfd0, DWORD dwLength, DWORD dwProfileOffset, BOOL msb_order, TagLib::MDMODEL starting_md_model) {
580
0
  WORD de, nde;
581
582
0
  std::stack<WORD>      destack;  // directory entries stack
583
0
  std::stack<const BYTE*>   ifdstack; // IFD stack
584
0
  std::stack<TagLib::MDMODEL> modelstack; // metadata model stack
585
586
  // Keep a list of already visited IFD to avoid stack overflows 
587
  // when recursive/cyclic directory structures exist. 
588
  // This kind of recursive Exif file was encountered with Kodak images coming from 
589
  // KODAK PROFESSIONAL DCS Photo Desk JPEG Export v3.2 W
590
0
  std::map<DWORD, int> visitedIFD;
591
592
  /*
593
  "An Image File Directory (IFD) consists of a 2-byte count of the number of directory
594
  entries (i.e. the number of fields), followed by a sequence of 12-byte field
595
  entries, followed by a 4-byte offset of the next IFD (or 0 if none)."
596
  The "next IFD" (1st IFD) is the thumbnail.
597
  */
598
0
  #define DIR_ENTRY_ADDR(_start, _entry) (_start + 2 + (12 * _entry))
599
600
  // set the metadata model to Exif
601
602
0
  TagLib::MDMODEL md_model = starting_md_model;
603
604
  // set the pointer to the first IFD (0th IFD) and follow it were it leads.
605
606
0
  const BYTE *ifd0th = (BYTE*)tiffp + (size_t)dwOffsetIfd0;
607
608
0
  const BYTE *ifdp = ifd0th;
609
610
0
  de = 0;
611
612
0
  do {
613
    // if there is anything on the stack then pop it off
614
0
    if(!destack.empty()) {
615
0
      ifdp    = ifdstack.top(); ifdstack.pop();
616
0
      de      = destack.top();  destack.pop();
617
0
      md_model  = modelstack.top(); modelstack.pop();
618
0
    }
619
620
    // remember that we've visited this directory and entry so that we don't visit it again later
621
0
    DWORD visited = (DWORD)( (((size_t)ifdp & 0xFFFF) << 16) | (size_t)de );
622
0
    if(visitedIFD.find(visited) != visitedIFD.end()) {
623
0
      continue;
624
0
    } else {
625
0
      visitedIFD[visited] = 1;  // processed
626
0
    }
627
628
    // determine how many entries there are in the current IFD
629
0
    nde = ReadUint16(msb_order, ifdp);
630
0
    if (((size_t)(ifdp - tiffp) + 12 * nde) > (size_t)dwLength) {
631
      // suspicious IFD offset, ignore
632
0
      continue;
633
0
    }
634
635
0
    for(; de < nde; de++) {
636
0
      char *pde = NULL; // pointer to the directory entry
637
0
      char *pval = NULL;  // pointer to the tag value
638
      
639
      // create a tag
640
0
      FITAG *tag = FreeImage_CreateTag();
641
0
      if (!tag) {
642
0
        return FALSE;
643
0
      }
644
645
      // point to the directory entry
646
0
      pde = (char*) DIR_ENTRY_ADDR(ifdp, de);
647
648
      // get the tag ID
649
0
      WORD tag_id = ReadUint16(msb_order, pde);
650
0
      FreeImage_SetTagID(tag, tag_id);
651
652
      // get the tag type
653
0
      WORD tag_type = (WORD)ReadUint16(msb_order, pde + 2);
654
0
            if((tag_type - 1) >= EXIF_NUM_FORMATS) {
655
                // a problem occured : delete the tag (not free'd after)
656
0
          FreeImage_DeleteTag(tag);
657
        // break out of the for loop
658
0
        break;
659
0
            }
660
0
      FreeImage_SetTagType(tag, (FREE_IMAGE_MDTYPE)tag_type);
661
662
      // get number of components
663
0
      DWORD tag_count = ReadUint32(msb_order, pde + 4);
664
0
      FreeImage_SetTagCount(tag, tag_count);
665
666
            // check that tag length (size of the tag value in bytes) will fit in a DWORD
667
0
            unsigned tag_data_width = FreeImage_TagDataWidth(FreeImage_GetTagType(tag));
668
0
            if (tag_data_width != 0 && FreeImage_GetTagCount(tag) > ~(DWORD)0 / tag_data_width) {
669
0
                FreeImage_DeleteTag(tag);
670
                // jump to next entry
671
0
                continue;
672
0
            }
673
0
      FreeImage_SetTagLength(tag, FreeImage_GetTagCount(tag) * tag_data_width);
674
675
0
      if(FreeImage_GetTagLength(tag) <= 4) {
676
        // 4 bytes or less and value is in the dir entry itself
677
0
        pval = pde + 8;
678
0
      } else {
679
        // if its bigger than 4 bytes, the directory entry contains an offset       
680
0
        DWORD offset_value = ReadUint32(msb_order, pde + 8);
681
        // the offset can be relative to tiffp or to an external reference (see JPEG-XR)
682
0
        if(dwProfileOffset) {
683
0
          offset_value -= dwProfileOffset;
684
0
        }
685
        // first check if offset exceeds buffer, at this stage FreeImage_GetTagLength may return invalid data
686
0
        if(offset_value > dwLength) {
687
          // a problem occured : delete the tag (not free'd after)
688
0
          FreeImage_DeleteTag(tag);
689
          // jump to next entry
690
0
          continue;
691
0
        }
692
        // now check that length does not exceed the buffer size
693
0
        if(FreeImage_GetTagLength(tag) > (dwLength - offset_value)){
694
          // a problem occured : delete the tag (not free'd after)
695
0
          FreeImage_DeleteTag(tag);
696
          // jump to next entry
697
0
          continue;
698
0
        }
699
0
        pval = (char*)(tiffp + offset_value);
700
0
      }
701
702
      // check for a IFD offset
703
0
      BOOL isIFDOffset = FALSE;
704
0
      switch(FreeImage_GetTagID(tag)) {
705
0
        case TAG_EXIF_OFFSET:
706
0
        case TAG_GPS_OFFSET:
707
0
        case TAG_INTEROP_OFFSET:
708
0
        case TAG_MAKER_NOTE:
709
0
          isIFDOffset = TRUE;
710
0
          break;
711
0
      }
712
0
      if(isIFDOffset) {
713
0
        DWORD sub_offset = 0;
714
0
        TagLib::MDMODEL next_mdmodel = md_model;
715
0
        const BYTE *next_ifd = ifdp;
716
        
717
        // get offset and metadata model
718
0
        if (FreeImage_GetTagID(tag) == TAG_MAKER_NOTE) {
719
0
          processMakerNote(dib, pval, msb_order, &sub_offset, &next_mdmodel);
720
0
          next_ifd = (BYTE*)pval + sub_offset;
721
0
        } else {
722
0
          processIFDOffset(tag, pval, msb_order, &sub_offset, &next_mdmodel);
723
0
          next_ifd = (BYTE*)tiffp + sub_offset;
724
0
        }
725
726
0
        if((sub_offset < dwLength) && (next_mdmodel != TagLib::UNKNOWN)) {
727
          // push our current directory state onto the stack
728
0
          ifdstack.push(ifdp);
729
          // jump to the next entry
730
0
          de++;
731
0
          destack.push(de);
732
733
          // push our current metadata model
734
0
          modelstack.push(md_model);
735
736
          // push new state onto of stack to cause a jump
737
0
          ifdstack.push(next_ifd);
738
0
          destack.push(0);
739
740
          // select a new metadata model
741
0
          modelstack.push(next_mdmodel);
742
          
743
          // delete the tag as it won't be stored nor deleted in the for() loop
744
0
          FreeImage_DeleteTag(tag);
745
          
746
0
          break; // break out of the for loop
747
0
        }
748
0
        else {
749
          // unsupported camera model, canon maker tag or something unknown
750
          // process as a standard tag
751
0
          processExifTag(dib, tag, pval, msb_order, md_model);
752
0
        }     
753
754
0
      } else {
755
        // process as a standard tag
756
0
        processExifTag(dib, tag, pval, msb_order, md_model);
757
0
      }
758
      
759
      // delete the tag
760
0
      FreeImage_DeleteTag(tag);
761
762
0
        } // for(nde)
763
764
    // additional thumbnail data is skipped
765
766
0
    } while (!destack.empty()); 
767
768
  //
769
  // --- handle thumbnail data ---
770
  //
771
772
0
  const WORD entriesCount0th = ReadUint16(msb_order, ifd0th);
773
  
774
0
  DWORD next_offset = ReadUint32(msb_order, DIR_ENTRY_ADDR(ifd0th, entriesCount0th));
775
0
  if((next_offset == 0) || (next_offset >= dwLength)) {
776
0
    return TRUE; //< no thumbnail
777
0
  }
778
  
779
0
  const BYTE* const ifd1st = (BYTE*)tiffp + next_offset;
780
0
  const WORD entriesCount1st = ReadUint16(msb_order, ifd1st);
781
  
782
0
  unsigned thCompression = 0;
783
0
  unsigned thOffset = 0; 
784
0
  unsigned thSize = 0; 
785
  
786
0
  for(int e = 0; e < entriesCount1st; e++) {
787
788
    // point to the directory entry
789
0
    const BYTE* base = DIR_ENTRY_ADDR(ifd1st, e);
790
    
791
    // check for buffer overflow
792
0
    const size_t remaining = (size_t)base + 12 - (size_t)tiffp;
793
0
    if(remaining >= dwLength) {
794
      // bad IFD1 directory, ignore it
795
0
      return FALSE;
796
0
    }
797
798
    // get the tag ID
799
0
    WORD tag = ReadUint16(msb_order, base);
800
    // get the tag type
801
0
    /*WORD type = */ReadUint16(msb_order, base + sizeof(WORD));
802
    // get number of components
803
0
    /*DWORD count = */ReadUint32(msb_order, base + sizeof(WORD) + sizeof(WORD));
804
    // get the tag value
805
0
    DWORD offset = ReadUint32(msb_order, base + sizeof(WORD) + sizeof(WORD) + sizeof(DWORD));
806
807
0
    switch(tag) {
808
0
      case TAG_COMPRESSION:
809
        // Tiff Compression Tag (should be COMPRESSION_OJPEG (6), but is not always respected)
810
0
        thCompression = offset;
811
0
        break;
812
0
      case TAG_JPEG_INTERCHANGE_FORMAT:
813
        // Tiff JPEGInterchangeFormat Tag
814
0
        thOffset = offset;
815
0
        break;
816
0
      case TAG_JPEG_INTERCHANGE_FORMAT_LENGTH:
817
        // Tiff JPEGInterchangeFormatLength Tag
818
0
        thSize = offset;
819
0
        break;
820
      // ### X and Y Resolution ignored, orientation ignored
821
0
      case TAG_X_RESOLUTION:   // XResolution
822
0
      case TAG_Y_RESOLUTION:   // YResolution
823
0
      case TAG_RESOLUTION_UNIT: // ResolutionUnit
824
0
      case TAG_ORIENTATION:   // Orientation
825
0
        break;
826
0
      default:
827
0
        break;
828
0
    }
829
0
  }
830
  
831
0
  if(/*thCompression != 6 ||*/ thOffset == 0 || thSize == 0) {
832
0
    return TRUE;
833
0
  }
834
  
835
0
  if(thOffset + thSize > dwLength) {
836
0
    return TRUE;
837
0
  }
838
  
839
  // load the thumbnail
840
841
0
  const BYTE *thLocation = tiffp + thOffset;
842
  
843
0
  FIMEMORY* hmem = FreeImage_OpenMemory(const_cast<BYTE*>(thLocation), thSize);
844
0
  FIBITMAP* thumbnail = FreeImage_LoadFromMemory(FIF_JPEG, hmem);
845
0
  FreeImage_CloseMemory(hmem);
846
  
847
  // store the thumbnail
848
0
  FreeImage_SetThumbnail(dib, thumbnail);
849
  // then delete it
850
0
  FreeImage_Unload(thumbnail);
851
852
0
  return TRUE;
853
0
}
854
855
// --------------------------------------------------------------------------
856
857
/**
858
Read and decode JPEG_APP1 marker (Exif profile)
859
@param dib Image to be processed
860
@param data Pointer to the APP1 marker
861
@param length APP1 marker length
862
@return Returns TRUE if successful, FALSE otherwise
863
*/
864
BOOL  
865
0
jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *data, unsigned length) {
866
    // marker identifying string for Exif = "Exif\0\0"
867
0
    BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
868
0
  BYTE lsb_first[4] = { 0x49, 0x49, 0x2A, 0x00 };   // Classic TIFF signature - little-endian order
869
0
  BYTE msb_first[4] = { 0x4D, 0x4D, 0x00, 0x2A };   // Classic TIFF signature - big-endian order
870
871
  // profile size is up to 32-bit
872
0
  DWORD dwProfileLength = (DWORD)length;
873
0
  BYTE *pbProfile = (BYTE*)data;
874
875
  // verify the identifying string
876
0
  if(memcmp(exif_signature, pbProfile, sizeof(exif_signature)) == 0) {
877
    // This is an Exif profile
878
    // should contain a TIFF header with up to 2 IFDs (IFD stands for 'Image File Directory')
879
    // 0th IFD : the image attributes, 1st IFD : may be used for thumbnail
880
881
0
    pbProfile += sizeof(exif_signature);
882
0
    dwProfileLength -= sizeof(exif_signature);
883
884
    // read the TIFF header (8 bytes)
885
886
    // check the endianess order
887
    
888
0
    BOOL bBigEndian = TRUE;
889
890
0
    if(memcmp(pbProfile, lsb_first, sizeof(lsb_first)) == 0) {
891
      // Exif section is in little-endian order
892
0
      bBigEndian = FALSE;
893
0
    } else {
894
0
      if(memcmp(pbProfile, msb_first, sizeof(msb_first)) == 0) {
895
        // Exif section is in big-endian order
896
0
        bBigEndian = TRUE;
897
0
      } else {
898
        // Invalid Exif alignment marker
899
0
        return FALSE;
900
0
      }
901
0
    }
902
903
    // this is the offset to the first IFD (Image File Directory)
904
0
    DWORD dwFirstOffset = ReadUint32(bBigEndian, pbProfile + 4);
905
0
    if (dwFirstOffset > dwProfileLength) {
906
      // bad Exif data
907
0
      return FALSE;
908
0
    }
909
910
    /*
911
    Note: as FreeImage 3.14.0, this test is no longer needed for images with similar suspicious offset
912
    => tested with Pentax Optio 230, FujiFilm SP-2500 and Canon EOS 300D
913
    if (dwFirstOffset < 8 || dwFirstOffset > 16) {
914
      // This is usually set to 8
915
      // but PENTAX Optio 230 has it set differently, and uses it as offset. 
916
      FreeImage_OutputMessageProc(FIF_JPEG, "Exif: Suspicious offset of first IFD value");
917
      return FALSE;
918
    }
919
    */
920
921
    // process Exif directories, starting with Exif-TIFF IFD
922
0
    return jpeg_read_exif_dir(dib, pbProfile, dwFirstOffset, dwProfileLength, 0, bBigEndian, TagLib::EXIF_MAIN);
923
0
  }
924
925
0
  return FALSE;
926
0
}
927
928
// ==========================================================
929
// Exif JPEG helper routines
930
// ==========================================================
931
932
/**
933
Read JPEG_APP1 marker (Exif profile)
934
@param dib Image to be processed
935
@param dataptr Pointer to the APP1 marker
936
@param datalen APP1 marker length
937
@return Returns TRUE if successful, FALSE otherwise
938
*/
939
BOOL  
940
0
jpeg_read_exif_profile_raw(FIBITMAP *dib, const BYTE *profile, unsigned length) {
941
    // marker identifying string for Exif = "Exif\0\0"
942
0
    BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
943
944
  // verify the identifying string
945
0
  if(memcmp(exif_signature, profile, sizeof(exif_signature)) != 0) {
946
    // not an Exif profile
947
0
    return FALSE;
948
0
  }
949
950
  // create a tag
951
0
  FITAG *tag = FreeImage_CreateTag();
952
0
  if(tag) {
953
0
    FreeImage_SetTagKey(tag, g_TagLib_ExifRawFieldName);
954
0
    FreeImage_SetTagLength(tag, (DWORD)length);
955
0
    FreeImage_SetTagCount(tag, (DWORD)length);
956
0
    FreeImage_SetTagType(tag, FIDT_BYTE);
957
0
    FreeImage_SetTagValue(tag, profile);
958
959
    // store the tag
960
0
    FreeImage_SetMetadata(FIMD_EXIF_RAW, dib, FreeImage_GetTagKey(tag), tag);
961
962
    // destroy the tag
963
0
    FreeImage_DeleteTag(tag);
964
965
0
    return TRUE;
966
0
  }
967
968
0
  return FALSE;
969
0
}
970
971
// ==========================================================
972
// Exif JPEG-XR helper routines
973
// ==========================================================
974
975
/**
976
Read and decode JPEG-XR Exif IFD
977
@param dib Image to be processed
978
@param profile Pointer to the Exif marker
979
@param length Exif marker length
980
@param file_offset Reference offset in the original file of each tag value whose length is > 4
981
@return Returns TRUE if successful, FALSE otherwise
982
*/
983
BOOL  
984
0
jpegxr_read_exif_profile(FIBITMAP *dib, const BYTE *profile, unsigned length, unsigned file_offset) {
985
  // assume Little Endian order
986
0
  BOOL bBigEndian = FALSE;
987
  
988
  // process Exif specific IFD
989
0
  return jpeg_read_exif_dir(dib, profile, 0, length, file_offset, bBigEndian, TagLib::EXIF_EXIF);
990
0
}
991
992
/**
993
Read and decode JPEG-XR Exif-GPS IFD
994
@param dib Image to be processed
995
@param profile Pointer to the Exif-GPS profile
996
@param length Exif-GPS profile length
997
@param file_offset Reference offset in the original file of each tag value whose length is > 4
998
@return Returns TRUE if successful, FALSE otherwise
999
*/
1000
BOOL  
1001
0
jpegxr_read_exif_gps_profile(FIBITMAP *dib, const BYTE *profile, unsigned length, unsigned file_offset) {
1002
  // assume Little Endian order
1003
0
  BOOL bBigEndian = FALSE;
1004
  
1005
  // process Exif GPS IFD
1006
0
  return jpeg_read_exif_dir(dib, profile, 0, length, file_offset, bBigEndian, TagLib::EXIF_GPS);
1007
0
}
1008
1009
// ==========================================================
1010
// Exif common helper routines
1011
// ==========================================================
1012
1013
/**
1014
Rotate a dib according to Exif info
1015
@param dib Input / Output dib to rotate
1016
@see PluginJPEG.cpp
1017
*/
1018
void 
1019
0
RotateExif(FIBITMAP **dib) {
1020
  // check for Exif rotation
1021
0
  if(FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, *dib)) {
1022
0
    FIBITMAP *rotated = NULL;
1023
    // process Exif rotation
1024
0
    FITAG *tag = NULL;
1025
0
    FreeImage_GetMetadata(FIMD_EXIF_MAIN, *dib, "Orientation", &tag);
1026
0
    if((tag != NULL) && (FreeImage_GetTagID(tag) == TAG_ORIENTATION)) {
1027
0
      const WORD orientation = *((WORD *)FreeImage_GetTagValue(tag));
1028
0
      switch (orientation) {
1029
0
        case 1:   // "top, left side" => 0°
1030
0
          break;
1031
0
        case 2:   // "top, right side" => flip left-right
1032
0
          FreeImage_FlipHorizontal(*dib);
1033
0
          break;
1034
0
        case 3:   // "bottom, right side" => -180°
1035
0
          rotated = FreeImage_Rotate(*dib, 180);
1036
0
          FreeImage_Unload(*dib);
1037
0
          *dib = rotated;
1038
0
          break;
1039
0
        case 4:   // "bottom, left side" => flip up-down
1040
0
          FreeImage_FlipVertical(*dib);
1041
0
          break;
1042
0
        case 5:   // "left side, top" => +90° + flip up-down
1043
0
          rotated = FreeImage_Rotate(*dib, 90);
1044
0
          FreeImage_Unload(*dib);
1045
0
          *dib = rotated;
1046
0
          FreeImage_FlipVertical(*dib);
1047
0
          break;
1048
0
        case 6:   // "right side, top" => -90°
1049
0
          rotated = FreeImage_Rotate(*dib, -90);
1050
0
          FreeImage_Unload(*dib);
1051
0
          *dib = rotated;
1052
0
          break;
1053
0
        case 7:   // "right side, bottom" => -90° + flip up-down
1054
0
          rotated = FreeImage_Rotate(*dib, -90);
1055
0
          FreeImage_Unload(*dib);
1056
0
          *dib = rotated;
1057
0
          FreeImage_FlipVertical(*dib);
1058
0
          break;
1059
0
        case 8:   // "left side, bottom" => +90°
1060
0
          rotated = FreeImage_Rotate(*dib, 90);
1061
0
          FreeImage_Unload(*dib);
1062
0
          *dib = rotated;
1063
0
          break;
1064
0
        default:
1065
0
          break;
1066
0
      }
1067
0
    }
1068
0
  }
1069
0
}
1070
1071
// ==========================================================
1072
// Exif TIFF JPEG-XR helper routines
1073
// ==========================================================
1074
1075
class PredicateTagIDCompare {
1076
public:
1077
0
  bool operator()(FITAG *a, FITAG *b) {
1078
0
    WORD tag_id_a = FreeImage_GetTagID(a);
1079
0
    WORD tag_id_b = FreeImage_GetTagID(b);
1080
0
    return (tag_id_a < tag_id_b);
1081
0
  }
1082
};
1083
1084
/**
1085
Write a metadata model as a TIF IFD to a FIMEMORY handle.
1086
The entries in the TIF IFD are sorted in ascending order by tag id. 
1087
The last entry is written as 0 (4 bytes) which means no more IFD to follow. 
1088
Supported metadata models are
1089
<ul>
1090
<li>FIMD_EXIF_MAIN
1091
<li>FIMD_EXIF_EXIF
1092
<li>FIMD_EXIF_GPS
1093
<li>FIMD_EXIF_INTEROP
1094
</ul>
1095
The end of the buffer is filled with 4 bytes equal to 0 (end of IFD offset)
1096
1097
@param dib Input FIBITMAP
1098
@param md_model Metadata model to write
1099
@param hmem Memory handle
1100
@return Returns TRUE if successful, FALSE otherwise
1101
@see tiff_get_ifd_profile
1102
*/
1103
static BOOL
1104
0
tiff_write_ifd(FIBITMAP *dib, FREE_IMAGE_MDMODEL md_model, FIMEMORY *hmem) {
1105
0
  FITAG *tag = NULL;
1106
0
  FIMETADATA *mdhandle = NULL;
1107
0
  std::vector<FITAG*> vTagList;
1108
0
  TagLib::MDMODEL internal_md_model;
1109
1110
0
  DWORD ifd_offset = 0; // WORD-aligned IFD value offset
1111
1112
0
  const BYTE empty_byte = 0;
1113
1114
  // start of the file
1115
0
  const long start_of_file = FreeImage_TellMemory(hmem);
1116
1117
  // get the metadata count
1118
0
  unsigned metadata_count = FreeImage_GetMetadataCount(md_model, dib);
1119
0
  if(metadata_count == 0) {
1120
0
    return FALSE;
1121
0
  }
1122
1123
0
  TagLib& s = TagLib::instance();
1124
1125
  // check for supported metadata models
1126
0
  switch(md_model) {
1127
0
    case FIMD_EXIF_MAIN:
1128
0
      internal_md_model = TagLib::EXIF_MAIN;
1129
0
      break;
1130
0
    case FIMD_EXIF_EXIF:
1131
0
      internal_md_model = TagLib::EXIF_EXIF;
1132
0
      break;
1133
0
    case FIMD_EXIF_GPS:
1134
0
      internal_md_model = TagLib::EXIF_GPS;
1135
0
      break;
1136
0
    case FIMD_EXIF_INTEROP:
1137
0
      internal_md_model = TagLib::EXIF_INTEROP;
1138
0
      break;
1139
0
    default:
1140
0
      return FALSE;
1141
0
  }
1142
1143
0
  try {
1144
    // 1) according to the TIFF specifications, 
1145
    // the entries in a TIF IFD must be sorted in ascending order by tag id
1146
1147
    // store the tags into a vector
1148
0
    vTagList.reserve(metadata_count);
1149
0
    mdhandle = FreeImage_FindFirstMetadata(md_model, dib, &tag);
1150
0
    if(mdhandle) {
1151
      // parse the tags and store them inside vTagList
1152
0
      do {
1153
        // rewrite the tag id using FreeImage internal database
1154
        // (in case the tag id is wrong or missing)
1155
0
        const char *key = FreeImage_GetTagKey(tag);
1156
0
        int tag_id = s.getTagID(internal_md_model, key);
1157
0
        if(tag_id != -1) {
1158
          // this is a known tag, set the tag ID
1159
0
          FreeImage_SetTagID(tag, (WORD)tag_id);
1160
          // record the tag
1161
0
          vTagList.push_back(tag);
1162
0
        }
1163
        // else ignore this tag
1164
0
      } while(FreeImage_FindNextMetadata(mdhandle, &tag));
1165
1166
0
      FreeImage_FindCloseMetadata(mdhandle);
1167
1168
      // sort the vector by tag id
1169
0
      std::sort(vTagList.begin(), vTagList.end(), PredicateTagIDCompare());
1170
1171
      // update the metadata_count
1172
0
      metadata_count = (unsigned)vTagList.size();
1173
1174
0
    } else {
1175
0
      throw(1);
1176
0
    }
1177
1178
    // 2) prepare the place for each IFD entries.
1179
1180
    /*
1181
    An Image File Directory (IFD) consists of a 2-byte count of the number of directory entries (i.e., the number of fields), 
1182
    followed by a sequence of 12-byte field entries, 
1183
    followed by a 4-byte offset of the next IFD (or 0 if none). Do not forget to write the 4 bytes of 0 after the last IFD.
1184
    */
1185
1186
0
    {   
1187
      // prepare place for 2 bytes for number of entries + 12 bytes for each entry
1188
0
      unsigned ifd_size = 2 + 12 * metadata_count;
1189
0
      FreeImage_WriteMemory(&empty_byte, 1, ifd_size, hmem);
1190
      // record the offset used to write values > 4-bytes
1191
0
      ifd_offset = FreeImage_TellMemory(hmem);
1192
      // rewind
1193
0
      FreeImage_SeekMemory(hmem, start_of_file, SEEK_SET);
1194
0
    }
1195
1196
    // 3) write each IFD entry in tag id ascending order
1197
1198
    // number of directory entries
1199
0
    WORD nde = (WORD)metadata_count;
1200
0
    FreeImage_WriteMemory(&nde, 1, 2, hmem);
1201
1202
    // for each entry ...
1203
0
    for(unsigned i = 0; i < metadata_count; i++) {
1204
0
      FITAG *tag = vTagList[i];
1205
      // tag id
1206
0
      WORD tag_id = FreeImage_GetTagID(tag);
1207
0
      FreeImage_WriteMemory(&tag_id, 1, 2, hmem);
1208
      // tag type (compliant with TIFF specification)
1209
0
      WORD tag_type = (WORD)FreeImage_GetTagType(tag);
1210
0
      FreeImage_WriteMemory(&tag_type, 1, 2, hmem);
1211
      // tag count
1212
0
      DWORD tag_count = FreeImage_GetTagCount(tag);
1213
0
      FreeImage_WriteMemory(&tag_count, 1, 4, hmem);
1214
      // tag value or offset (results are in BYTE's units)
1215
0
      unsigned tag_length = FreeImage_GetTagLength(tag);
1216
0
      if(tag_length <= 4) {
1217
        // 4 bytes or less, write the value (left justified)
1218
0
        const BYTE *tag_value = (BYTE*)FreeImage_GetTagValue(tag);
1219
0
        FreeImage_WriteMemory(tag_value, 1, tag_length, hmem);
1220
0
        for(unsigned k = tag_length; k < 4; k++) {
1221
0
          FreeImage_WriteMemory(&empty_byte, 1, 1, hmem);
1222
0
        }
1223
0
      } else {
1224
        // write an offset
1225
0
        FreeImage_WriteMemory(&ifd_offset, 1, 4, hmem);
1226
        // write the value
1227
0
        long current_position = FreeImage_TellMemory(hmem);
1228
0
        FreeImage_SeekMemory(hmem, ifd_offset, SEEK_SET);
1229
0
        FreeImage_WriteMemory(FreeImage_GetTagValue(tag), 1, tag_length, hmem);
1230
0
        if(tag_length & 1) {
1231
          // align to the next WORD boundary
1232
0
          FreeImage_WriteMemory(&empty_byte, 1, 1, hmem);
1233
0
        }
1234
        // next offset to use
1235
0
        ifd_offset = FreeImage_TellMemory(hmem);
1236
        // rewind
1237
0
        FreeImage_SeekMemory(hmem, current_position, SEEK_SET);
1238
0
      }
1239
0
    }
1240
1241
    // end-of-IFD or next IFD (0 == none)
1242
0
    FreeImage_SeekMemory(hmem, ifd_offset, SEEK_SET);
1243
0
    FreeImage_WriteMemory(&empty_byte, 1, 4, hmem);
1244
1245
0
    return TRUE;
1246
0
  }
1247
0
  catch(int) {
1248
0
    return FALSE;
1249
0
  }
1250
0
}
1251
1252
/**
1253
Write a metadata model as a TIF IFD, returns the IFD as a buffer.
1254
The buffer is allocated by the function and must be freed by the caller, using 'free'.
1255
@param dib Input FIBITMAP
1256
@param md_model Metadata model to write
1257
@param ppbProfile Returned buffer
1258
@param uProfileLength Returned buffer size
1259
@return Returns TRUE if successful, FALSE otherwise
1260
@see tiff_write_ifd
1261
*/
1262
BOOL
1263
0
tiff_get_ifd_profile(FIBITMAP *dib, FREE_IMAGE_MDMODEL md_model, BYTE **ppbProfile, unsigned *uProfileLength) {
1264
0
  FIMEMORY *hmem = NULL;
1265
1266
0
  try {
1267
    // open a memory stream
1268
0
    hmem = FreeImage_OpenMemory(NULL, 0);
1269
0
    if(!hmem) {
1270
0
      throw(1);
1271
0
    }
1272
1273
    // write the metadata model as a TIF IFD
1274
0
    BOOL bResult = tiff_write_ifd(dib, md_model, hmem);
1275
1276
0
    if(bResult) {
1277
0
      BYTE *data = NULL;
1278
0
      DWORD size_in_bytes = 0;
1279
1280
      // get a pointer to the stream buffer
1281
0
      FreeImage_AcquireMemory(hmem, &data, &size_in_bytes);
1282
      
1283
      // (re-)allocate output buffer
1284
0
      BYTE *pbProfile = *ppbProfile;
1285
0
      pbProfile = (BYTE*)realloc(pbProfile, size_in_bytes);
1286
0
      if(!pbProfile) {
1287
0
        throw(1);
1288
0
      } else {
1289
        // copy IFD
1290
0
        memcpy(pbProfile, data, size_in_bytes);
1291
0
        *ppbProfile = pbProfile;
1292
0
        *uProfileLength = size_in_bytes;
1293
0
      }
1294
0
    }
1295
1296
    // free the memory stream
1297
0
    FreeImage_CloseMemory(hmem);
1298
1299
0
    return bResult;
1300
1301
0
  } catch(int) {
1302
0
    FreeImage_CloseMemory(hmem);
1303
0
    return FALSE;
1304
0
  }
1305
0
}
1306
1307
// ----------------------------------------------------------
1308
//   Exif PSD routines
1309
// ----------------------------------------------------------
1310
1311
/**
1312
Read and decode PSD image resource (Exif profile)
1313
@param dib Input FIBITMAP
1314
@param data Pointer to the resource data
1315
@param length Resource length
1316
@return Returns TRUE if successful, FALSE otherwise
1317
*/
1318
BOOL
1319
0
psd_read_exif_profile(FIBITMAP *dib, const BYTE *data, unsigned int length) {
1320
0
  BYTE lsb_first[4] = { 0x49, 0x49, 0x2A, 0x00 };   // Classic TIFF signature - little-endian order
1321
0
  BYTE msb_first[4] = { 0x4D, 0x4D, 0x00, 0x2A };   // Classic TIFF signature - big-endian order
1322
1323
  // profile size is up to 32-bit
1324
0
  DWORD dwProfileLength = (DWORD)length;
1325
0
  BYTE *pbProfile = (BYTE*)data;
1326
1327
  // This is an Exif profile
1328
  // should contain a TIFF header with up to 2 IFDs (IFD stands for 'Image File Directory')
1329
  // 0th IFD : the image attributes, 1st IFD : may be used for thumbnail
1330
1331
  // read the TIFF header (8 bytes)
1332
1333
  // check the endianess order
1334
1335
0
  BOOL bBigEndian = TRUE;
1336
1337
0
  if(memcmp(pbProfile, lsb_first, sizeof(lsb_first)) == 0) {
1338
    // Exif section is in little-endian order
1339
0
    bBigEndian = FALSE;
1340
0
  } else {
1341
0
    if(memcmp(pbProfile, msb_first, sizeof(msb_first)) == 0) {
1342
      // Exif section is in big-endian order
1343
0
      bBigEndian = TRUE;
1344
0
    } else {
1345
      // Invalid Exif alignment marker
1346
0
      return FALSE;
1347
0
    }
1348
0
  }
1349
1350
  // this is the offset to the first IFD (Image File Directory)
1351
0
  DWORD dwFirstOffset = ReadUint32(bBigEndian, pbProfile + 4);
1352
0
  if (dwFirstOffset > dwProfileLength) {
1353
    // bad Exif data
1354
0
    return FALSE;
1355
0
  }
1356
1357
  // process Exif directories, starting with Exif-TIFF IFD
1358
0
  return jpeg_read_exif_dir(dib, pbProfile, dwFirstOffset, dwProfileLength, 0, bBigEndian, TagLib::EXIF_MAIN);
1359
0
}
1360
1361
/**
1362
Read PSD image resource (Exif profile)
1363
@param dib Input FIBITMAP
1364
@param dataptr Pointer to the resource data
1365
@param datalen Resource length
1366
@return Returns TRUE if successful, FALSE otherwise
1367
*/
1368
BOOL
1369
0
psd_read_exif_profile_raw(FIBITMAP *dib, const BYTE *profile, unsigned length) {
1370
    // marker identifying string for Exif = "Exif\0\0"
1371
  // used by JPEG not PSD
1372
0
    BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
1373
1374
0
  if(NULL == profile || length == 0) {
1375
0
    return FALSE;
1376
0
  }
1377
1378
0
  DWORD dwProfileLength = (DWORD)length + sizeof(exif_signature);
1379
0
  BYTE *pbProfile = (BYTE*)malloc(dwProfileLength);
1380
0
  if(NULL == pbProfile) {
1381
    // out of memory ...
1382
0
    return FALSE;
1383
0
  }
1384
0
  memcpy(pbProfile, exif_signature, sizeof(exif_signature));
1385
0
  memcpy(pbProfile + sizeof(exif_signature), profile, length);
1386
1387
  // create a tag
1388
0
  FITAG *tag = FreeImage_CreateTag();
1389
0
  BOOL bSuccess = FALSE;
1390
0
  if(tag) {
1391
0
    FreeImage_SetTagKey(tag, g_TagLib_ExifRawFieldName);
1392
0
    FreeImage_SetTagLength(tag, dwProfileLength);
1393
0
    FreeImage_SetTagCount(tag, dwProfileLength);
1394
0
    FreeImage_SetTagType(tag, FIDT_BYTE);
1395
0
    FreeImage_SetTagValue(tag, pbProfile);
1396
1397
    // store the tag
1398
0
    FreeImage_SetMetadata(FIMD_EXIF_RAW, dib, FreeImage_GetTagKey(tag), tag);
1399
1400
    // destroy the tag
1401
0
    FreeImage_DeleteTag(tag);
1402
1403
0
    bSuccess = TRUE;
1404
0
  }
1405
0
  free(pbProfile);
1406
1407
0
  return bSuccess;
1408
0
}