/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 | } |