/src/freeimage-svn/FreeImage/trunk/Source/Metadata/Exif.cpp
Line  | Count  | Source  | 
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  | }  |