Rev 13951 | Rev 19730 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4430 | cbradney | 1 | /* |
2 | For general Scribus (>=1.3.2) copyright and licensing information please refer |
||
3 | to the COPYING file provided with the program. Following this notice may exist |
||
4 | a copyright and/or license notice that predates the release of Scribus 1.3.2 |
||
5 | for which a new license (GPL+exception) is in place. |
||
6 | */ |
||
3685 | fschmid | 7 | //-------------------------------------------------------------------------- |
8 | // Program to pull the information out of various types of EFIF digital |
||
9 | // camera files and show it in a reasonably consistent way |
||
10 | // |
||
11 | // This module parses the very complicated exif structures. |
||
12 | // |
||
13 | // Matthias Wandel, Dec 1999 - August 2000 |
||
14 | //-------------------------------------------------------------------------- |
||
15 | |||
16 | |||
17 | #include "exif.h" |
||
13951 | fschmid | 18 | #include <QTransform> |
3685 | fschmid | 19 | |
20 | //-------------------------------------------------------------------------- |
||
21 | // Table of Jpeg encoding process names |
||
22 | |||
23 | #define M_SOF0 0xC0 // Start Of Frame N |
||
24 | #define M_SOF1 0xC1 // N indicates which compression process |
||
25 | #define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use |
||
26 | #define M_SOF3 0xC3 |
||
27 | #define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers |
||
28 | #define M_SOF6 0xC6 |
||
29 | #define M_SOF7 0xC7 |
||
30 | #define M_SOF9 0xC9 |
||
31 | #define M_SOF10 0xCA |
||
32 | #define M_SOF11 0xCB |
||
33 | #define M_SOF13 0xCD |
||
34 | #define M_SOF14 0xCE |
||
35 | #define M_SOF15 0xCF |
||
36 | #define M_SOI 0xD8 // Start Of Image (beginning of datastream) |
||
37 | #define M_EOI 0xD9 // End Of Image (end of datastream) |
||
38 | #define M_SOS 0xDA // Start Of Scan (begins compressed data) |
||
39 | #define M_JFIF 0xE0 // Jfif marker |
||
40 | #define M_EXIF 0xE1 // Exif marker |
||
41 | #define M_COM 0xFE // COMment |
||
42 | |||
43 | |||
10911 | fschmid | 44 | TagTable ProcessTable[] = |
45 | { |
||
46 | TagTable ( M_SOF0, "Baseline" ), |
||
47 | TagTable ( M_SOF1, "Extended sequential" ), |
||
48 | TagTable ( M_SOF2, "Progressive" ), |
||
49 | TagTable ( M_SOF3, "Lossless" ), |
||
50 | TagTable ( M_SOF5, "Differential sequential" ), |
||
51 | TagTable ( M_SOF6, "Differential progressive" ), |
||
52 | TagTable ( M_SOF7, "Differential lossless" ), |
||
53 | TagTable ( M_SOF9, "Extended sequential, arithmetic coding" ), |
||
54 | TagTable ( M_SOF10, "Progressive, arithmetic coding" ), |
||
55 | TagTable ( M_SOF11, "Lossless, arithmetic coding" ), |
||
56 | TagTable ( M_SOF13, "Differential sequential, arithmetic coding" ), |
||
57 | TagTable ( M_SOF14, "Differential progressive, arithmetic coding" ), |
||
58 | TagTable ( M_SOF15, "Differential lossless, arithmetic coding" ), |
||
59 | TagTable ( 0, "Unknown" ) |
||
60 | }; |
||
3685 | fschmid | 61 | |
62 | //-------------------------------------------------------------------------- |
||
63 | // Describes format descriptor |
||
64 | static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; |
||
65 | #define NUM_FORMATS 12 |
||
66 | |||
67 | #define FMT_BYTE 1 |
||
68 | #define FMT_STRING 2 |
||
69 | #define FMT_USHORT 3 |
||
70 | #define FMT_ULONG 4 |
||
71 | #define FMT_URATIONAL 5 |
||
72 | #define FMT_SBYTE 6 |
||
73 | #define FMT_UNDEFINED 7 |
||
74 | #define FMT_SSHORT 8 |
||
75 | #define FMT_SLONG 9 |
||
76 | #define FMT_SRATIONAL 10 |
||
77 | #define FMT_SINGLE 11 |
||
78 | #define FMT_DOUBLE 12 |
||
79 | |||
80 | //-------------------------------------------------------------------------- |
||
81 | // Describes tag values |
||
82 | |||
83 | #define TAG_EXIF_OFFSET 0x8769 |
||
84 | #define TAG_INTEROP_OFFSET 0xa005 |
||
85 | |||
86 | #define TAG_MAKE 0x010F |
||
87 | #define TAG_MODEL 0x0110 |
||
88 | #define TAG_ORIENTATION 0x0112 |
||
89 | |||
90 | #define TAG_EXPOSURETIME 0x829A |
||
91 | #define TAG_FNUMBER 0x829D |
||
92 | |||
93 | #define TAG_SHUTTERSPEED 0x9201 |
||
94 | #define TAG_APERTURE 0x9202 |
||
95 | #define TAG_MAXAPERTURE 0x9205 |
||
96 | #define TAG_FOCALLENGTH 0x920A |
||
97 | |||
98 | #define TAG_DATETIME_ORIGINAL 0x9003 |
||
99 | #define TAG_USERCOMMENT 0x9286 |
||
100 | |||
101 | #define TAG_SUBJECT_DISTANCE 0x9206 |
||
102 | #define TAG_FLASH 0x9209 |
||
103 | |||
104 | #define TAG_FOCALPLANEXRES 0xa20E |
||
105 | #define TAG_FOCALPLANEUNITS 0xa210 |
||
106 | #define TAG_EXIF_IMAGEWIDTH 0xA002 |
||
107 | #define TAG_EXIF_IMAGELENGTH 0xA003 |
||
108 | |||
109 | // the following is added 05-jan-2001 vcs |
||
110 | #define TAG_EXPOSURE_BIAS 0x9204 |
||
111 | #define TAG_WHITEBALANCE 0x9208 |
||
112 | #define TAG_METERING_MODE 0x9207 |
||
113 | #define TAG_EXPOSURE_PROGRAM 0x8822 |
||
114 | #define TAG_ISO_EQUIVALENT 0x8827 |
||
115 | #define TAG_COMPRESSION_LEVEL 0x9102 |
||
116 | |||
117 | #define TAG_THUMBNAIL_OFFSET 0x0201 |
||
118 | #define TAG_THUMBNAIL_LENGTH 0x0202 |
||
119 | |||
120 | |||
121 | /*static TagTable_t TagTable[] = { |
||
122 | { 0x100, "ImageWidth"}, |
||
123 | { 0x101, "ImageLength"}, |
||
124 | { 0x102, "BitsPerSample"}, |
||
125 | { 0x103, "Compression"}, |
||
126 | { 0x106, "PhotometricInterpretation"}, |
||
127 | { 0x10A, "FillOrder"}, |
||
128 | { 0x10D, "DocumentName"}, |
||
129 | { 0x10E, "ImageDescription"}, |
||
130 | { 0x10F, "Make"}, |
||
131 | { 0x110, "Model"}, |
||
132 | { 0x111, "StripOffsets"}, |
||
133 | { 0x112, "Orientation"}, |
||
134 | { 0x115, "SamplesPerPixel"}, |
||
135 | { 0x116, "RowsPerStrip"}, |
||
136 | { 0x117, "StripByteCounts"}, |
||
137 | { 0x11A, "XResolution"}, |
||
138 | { 0x11B, "YResolution"}, |
||
139 | { 0x11C, "PlanarConfiguration"}, |
||
140 | { 0x128, "ResolutionUnit"}, |
||
141 | { 0x12D, "TransferFunction"}, |
||
142 | { 0x131, "Software"}, |
||
143 | { 0x132, "DateTime"}, |
||
144 | { 0x13B, "Artist"}, |
||
145 | { 0x13E, "WhitePoint"}, |
||
146 | { 0x13F, "PrimaryChromaticities"}, |
||
147 | { 0x156, "TransferRange"}, |
||
148 | { 0x200, "JPEGProc"}, |
||
149 | { 0x201, "ThumbnailOffset"}, |
||
150 | { 0x202, "ThumbnailLength"}, |
||
151 | { 0x211, "YCbCrCoefficients"}, |
||
152 | { 0x212, "YCbCrSubSampling"}, |
||
153 | { 0x213, "YCbCrPositioning"}, |
||
154 | { 0x214, "ReferenceBlackWhite"}, |
||
155 | { 0x828D, "CFARepeatPatternDim"}, |
||
156 | { 0x828E, "CFAPattern"}, |
||
157 | { 0x828F, "BatteryLevel"}, |
||
158 | { 0x8298, "Copyright"}, |
||
159 | { 0x829A, "ExposureTime"}, |
||
160 | { 0x829D, "FNumber"}, |
||
161 | { 0x83BB, "IPTC/NAA"}, |
||
162 | { 0x8769, "ExifOffset"}, |
||
163 | { 0x8773, "InterColorProfile"}, |
||
164 | { 0x8822, "ExposureProgram"}, |
||
165 | { 0x8824, "SpectralSensitivity"}, |
||
166 | { 0x8825, "GPSInfo"}, |
||
167 | { 0x8827, "ISOSpeedRatings"}, |
||
168 | { 0x8828, "OECF"}, |
||
169 | { 0x9000, "ExifVersion"}, |
||
170 | { 0x9003, "DateTimeOriginal"}, |
||
171 | { 0x9004, "DateTimeDigitized"}, |
||
172 | { 0x9101, "ComponentsConfiguration"}, |
||
173 | { 0x9102, "CompressedBitsPerPixel"}, |
||
174 | { 0x9201, "ShutterSpeedValue"}, |
||
175 | { 0x9202, "ApertureValue"}, |
||
176 | { 0x9203, "BrightnessValue"}, |
||
177 | { 0x9204, "ExposureBiasValue"}, |
||
178 | { 0x9205, "MaxApertureValue"}, |
||
179 | { 0x9206, "SubjectDistance"}, |
||
180 | { 0x9207, "MeteringMode"}, |
||
181 | { 0x9208, "LightSource"}, |
||
182 | { 0x9209, "Flash"}, |
||
183 | { 0x920A, "FocalLength"}, |
||
184 | { 0x927C, "MakerNote"}, |
||
185 | { 0x9286, "UserComment"}, |
||
186 | { 0x9290, "SubSecTime"}, |
||
187 | { 0x9291, "SubSecTimeOriginal"}, |
||
188 | { 0x9292, "SubSecTimeDigitized"}, |
||
189 | { 0xA000, "FlashPixVersion"}, |
||
190 | { 0xA001, "ColorSpace"}, |
||
191 | { 0xA002, "ExifImageWidth"}, |
||
192 | { 0xA003, "ExifImageLength"}, |
||
193 | { 0xA005, "InteroperabilityOffset"}, |
||
194 | { 0xA20B, "FlashEnergy"}, // 0x920B in TIFF/EP |
||
195 | { 0xA20C, "SpatialFrequencyResponse"}, // 0x920C - - |
||
196 | { 0xA20E, "FocalPlaneXResolution"}, // 0x920E - - |
||
197 | { 0xA20F, "FocalPlaneYResolution"}, // 0x920F - - |
||
198 | { 0xA210, "FocalPlaneResolutionUnit"}, // 0x9210 - - |
||
199 | { 0xA214, "SubjectLocation"}, // 0x9214 - - |
||
200 | { 0xA215, "ExposureIndex"}, // 0x9215 - - |
||
201 | { 0xA217, "SensingMethod"}, // 0x9217 - - |
||
202 | { 0xA300, "FileSource"}, |
||
203 | { 0xA301, "SceneType"}, |
||
204 | { 0, NULL} |
||
205 | } ; |
||
206 | */ |
||
207 | |||
10911 | fschmid | 208 | int ExifData::getch ( QFile &infile ) |
10507 | fschmid | 209 | { |
10911 | fschmid | 210 | QByteArray a = infile.read ( 1 ); |
10507 | fschmid | 211 | uint r = 0; |
10911 | fschmid | 212 | r = static_cast<uint> ( a[0] ); |
10507 | fschmid | 213 | r &= 0x000000FF; |
10911 | fschmid | 214 | return static_cast<int> ( r ); |
10507 | fschmid | 215 | } |
3685 | fschmid | 216 | //-------------------------------------------------------------------------- |
217 | // Parse the marker stream until SOS or EOI is seen; |
||
218 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 219 | int ExifData::ReadJpegSections ( QFile & infile, ReadMode_t ReadMode ) |
3685 | fschmid | 220 | { |
10911 | fschmid | 221 | int a; |
12898 | fschmid | 222 | int SectionsRead; |
3685 | fschmid | 223 | |
10911 | fschmid | 224 | a = getch ( infile ); |
3685 | fschmid | 225 | |
10911 | fschmid | 226 | if ( a != 0xff || getch ( infile ) != M_SOI ) |
227 | { |
||
228 | SectionsRead = 0; |
||
229 | return false; |
||
230 | } |
||
12898 | fschmid | 231 | for ( SectionsRead = 0; SectionsRead < MAX_SECTIONS-1; SectionsRead++ ) |
10911 | fschmid | 232 | { |
233 | int marker = 0; |
||
234 | int got; |
||
235 | unsigned int ll,lh; |
||
236 | unsigned int itemlen; |
||
237 | uchar * Data; |
||
3685 | fschmid | 238 | |
10911 | fschmid | 239 | for ( a=0;a<7;a++ ) |
240 | { |
||
241 | marker = getch ( infile ); |
||
12898 | fschmid | 242 | if ( marker != 0xff ) |
243 | break; |
||
10911 | fschmid | 244 | if ( a >= 6 ) |
245 | return false; |
||
246 | } |
||
247 | if ( marker == 0xff ) |
||
248 | return false; |
||
249 | // Read the length of the section. |
||
250 | lh = ( uchar ) getch ( infile ); |
||
251 | ll = ( uchar ) getch ( infile ); |
||
252 | itemlen = ( lh << 8 ) | ll; |
||
253 | if ( itemlen < 2 ) |
||
254 | return false; |
||
255 | Data = ( uchar * ) malloc ( itemlen+1 ); // Add 1 to allow sticking a 0 at the end. |
||
3685 | fschmid | 256 | |
10911 | fschmid | 257 | // Store first two pre-read bytes. |
258 | Data[0] = ( uchar ) lh; |
||
259 | Data[1] = ( uchar ) ll; |
||
3685 | fschmid | 260 | |
10911 | fschmid | 261 | got = infile.read ( ( char* ) Data+2, itemlen-2 ); // Read the whole section. |
262 | if ( ( unsigned ) got != itemlen-2 ) |
||
263 | { |
||
12898 | fschmid | 264 | free(Data); |
10911 | fschmid | 265 | return false; |
266 | } |
||
3685 | fschmid | 267 | |
10911 | fschmid | 268 | switch ( marker ) |
269 | { |
||
3685 | fschmid | 270 | |
10911 | fschmid | 271 | case M_SOS: // stop before hitting compressed data |
12898 | fschmid | 272 | free(Data); |
10911 | fschmid | 273 | return true; |
3685 | fschmid | 274 | |
10911 | fschmid | 275 | case M_EOI: // in case it's a tables-only JPEG stream |
12898 | fschmid | 276 | free(Data); |
10911 | fschmid | 277 | return false; |
3685 | fschmid | 278 | |
10911 | fschmid | 279 | case M_COM: // Comment section |
280 | // pieczy 2002-02-12 |
||
281 | // now the User comment goes to UserComment |
||
282 | // so we can store a Comment section also in READ_EXIF mode |
||
283 | process_COM ( Data, itemlen ); |
||
284 | break; |
||
3685 | fschmid | 285 | |
10911 | fschmid | 286 | case M_JFIF: |
287 | // Regular jpegs always have this tag, exif images have the exif |
||
288 | // marker instead, althogh ACDsee will write images with both markers. |
||
289 | // this program will re-create this marker on absence of exif marker. |
||
290 | // hence no need to keep the copy from the file. |
||
291 | break; |
||
3685 | fschmid | 292 | |
10911 | fschmid | 293 | case M_EXIF: |
294 | // Seen files from some 'U-lead' software with Vivitar scanner |
||
295 | // that uses marker 31 for non exif stuff. Thus make sure |
||
296 | // it says 'Exif' in the section before treating it as exif. |
||
297 | if ( ( ReadMode & READ_EXIF ) && memcmp ( Data+2, "Exif", 4 ) == 0 ) |
||
298 | { |
||
299 | process_EXIF ( ( uchar * ) Data, itemlen ); // FIXME: This call |
||
300 | // requires Data to be array of at least 8 bytes. Code |
||
301 | // above only checks for itemlen < 2. |
||
3898 | fschmid | 302 | exifDataValid = true; |
10911 | fschmid | 303 | } |
12898 | fschmid | 304 | // else |
305 | // { |
||
306 | // // Discard this section. |
||
307 | // free ( Sections[--SectionsRead].Data ); |
||
3880 | fschmid | 308 | // return false; |
12898 | fschmid | 309 | // } |
10911 | fschmid | 310 | break; |
3685 | fschmid | 311 | |
10911 | fschmid | 312 | case M_SOF0: |
313 | case M_SOF1: |
||
314 | case M_SOF2: |
||
315 | case M_SOF3: |
||
316 | case M_SOF5: |
||
317 | case M_SOF6: |
||
318 | case M_SOF7: |
||
319 | case M_SOF9: |
||
320 | case M_SOF10: |
||
321 | case M_SOF11: |
||
322 | case M_SOF13: |
||
323 | case M_SOF14: |
||
324 | case M_SOF15: |
||
325 | process_SOFn ( Data, marker ); //FIXME: This call requires Data to |
||
326 | // be array of at least 8 bytes. Code above only checks for |
||
327 | // itemlen < 2. |
||
10914 | fschmid | 328 | break; |
10911 | fschmid | 329 | default: |
330 | break; |
||
331 | } |
||
12898 | fschmid | 332 | free(Data); |
10911 | fschmid | 333 | } |
334 | return true; |
||
3685 | fschmid | 335 | } |
336 | |||
337 | |||
338 | //-------------------------------------------------------------------------- |
||
339 | // Discard read data. |
||
340 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 341 | void ExifData::DiscardData ( void ) |
3685 | fschmid | 342 | { |
12898 | fschmid | 343 | // for ( int a=0; a < SectionsRead; a++ ) |
344 | // free ( Sections[a].Data ); |
||
345 | // SectionsRead = 0; |
||
3685 | fschmid | 346 | } |
347 | |||
348 | //-------------------------------------------------------------------------- |
||
349 | // Convert a 16 bit unsigned value from file's native byte order |
||
350 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 351 | int ExifData::Get16u ( void * Short ) |
3685 | fschmid | 352 | { |
10911 | fschmid | 353 | if ( MotorolaOrder ) |
354 | { |
||
355 | return ( ( ( uchar * ) Short ) [0] << 8 ) | ( ( uchar * ) Short ) [1]; |
||
356 | } |
||
357 | else |
||
358 | { |
||
359 | return ( ( ( uchar * ) Short ) [1] << 8 ) | ( ( uchar * ) Short ) [0]; |
||
360 | } |
||
3685 | fschmid | 361 | } |
362 | |||
363 | //-------------------------------------------------------------------------- |
||
364 | // Convert a 32 bit signed value from file's native byte order |
||
365 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 366 | int ExifData::Get32s ( void * Long ) |
3685 | fschmid | 367 | { |
10911 | fschmid | 368 | if ( MotorolaOrder ) |
369 | { |
||
370 | return ( ( ( char * ) Long ) [0] << 24 ) | ( ( ( uchar * ) Long ) [1] << 16 ) |
||
371 | | ( ( ( uchar * ) Long ) [2] << 8 ) | ( ( ( uchar * ) Long ) [3] << 0 ); |
||
372 | } |
||
373 | else |
||
374 | { |
||
375 | return ( ( ( char * ) Long ) [3] << 24 ) | ( ( ( uchar * ) Long ) [2] << 16 ) |
||
376 | | ( ( ( uchar * ) Long ) [1] << 8 ) | ( ( ( uchar * ) Long ) [0] << 0 ); |
||
377 | } |
||
3685 | fschmid | 378 | } |
379 | |||
380 | //-------------------------------------------------------------------------- |
||
381 | // Convert a 32 bit unsigned value from file's native byte order |
||
382 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 383 | unsigned ExifData::Get32u ( void * Long ) |
3685 | fschmid | 384 | { |
10911 | fschmid | 385 | return ( unsigned ) Get32s ( Long ) & 0xffffffff; |
3685 | fschmid | 386 | } |
387 | |||
388 | //-------------------------------------------------------------------------- |
||
389 | // Evaluate number, be it int, rational, or float from directory. |
||
390 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 391 | double ExifData::ConvertAnyFormat ( void * ValuePtr, int Format ) |
3685 | fschmid | 392 | { |
10911 | fschmid | 393 | double Value; |
394 | Value = 0; |
||
3685 | fschmid | 395 | |
10911 | fschmid | 396 | switch ( Format ) |
397 | { |
||
398 | case FMT_SBYTE: Value = * ( signed char * ) ValuePtr; break; |
||
399 | case FMT_BYTE: Value = * ( uchar * ) ValuePtr; break; |
||
3685 | fschmid | 400 | |
10911 | fschmid | 401 | case FMT_USHORT: Value = Get16u ( ValuePtr ); break; |
3685 | fschmid | 402 | |
10911 | fschmid | 403 | case FMT_ULONG: Value = Get32u ( ValuePtr ); break; |
3685 | fschmid | 404 | |
10911 | fschmid | 405 | case FMT_URATIONAL: |
406 | case FMT_SRATIONAL: |
||
407 | { |
||
408 | int Num,Den; |
||
409 | Num = Get32s ( ValuePtr ); |
||
410 | Den = Get32s ( 4+ ( char * ) ValuePtr ); |
||
411 | if ( Den == 0 ) |
||
412 | { |
||
413 | Value = 0; |
||
414 | } |
||
415 | else |
||
416 | { |
||
417 | Value = ( double ) Num/Den; |
||
418 | } |
||
419 | break; |
||
420 | } |
||
3685 | fschmid | 421 | |
10911 | fschmid | 422 | case FMT_SSHORT: Value = ( signed short ) Get16u ( ValuePtr ); break; |
423 | case FMT_SLONG: Value = Get32s ( ValuePtr ); break; |
||
3685 | fschmid | 424 | |
10911 | fschmid | 425 | // Not sure if this is correct (never seen float used in Exif format) |
426 | case FMT_SINGLE: Value = ( double ) * ( float * ) ValuePtr; break; |
||
427 | case FMT_DOUBLE: Value = * ( double * ) ValuePtr; break; |
||
428 | } |
||
429 | return Value; |
||
3685 | fschmid | 430 | } |
431 | |||
432 | //-------------------------------------------------------------------------- |
||
433 | // Process one of the nested EXIF directories. |
||
434 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 435 | void ExifData::ProcessExifDir ( unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength ) |
3685 | fschmid | 436 | { |
10911 | fschmid | 437 | int de; |
438 | int a; |
||
439 | int NumDirEntries; |
||
440 | unsigned ThumbnailOffset = 0; |
||
441 | unsigned ThumbnailSize = 0; |
||
442 | recurseLevel++; |
||
443 | if (recurseLevel > 3) |
||
444 | return; |
||
445 | NumDirEntries = Get16u ( DirStart ); |
||
446 | #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry)) |
||
3685 | fschmid | 447 | |
10911 | fschmid | 448 | { |
449 | unsigned char * DirEnd; |
||
450 | DirEnd = DIR_ENTRY_ADDR ( DirStart, NumDirEntries ); |
||
451 | if ( DirEnd+4 > ( OffsetBase+ExifLength ) ) |
||
452 | { |
||
453 | if ( DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength ) |
||
454 | { |
||
455 | // Version 1.3 of jhead would truncate a bit too much. |
||
456 | // This also caught later on as well. |
||
457 | } |
||
458 | else |
||
459 | { |
||
460 | // Note: Files that had thumbnails trimmed with jhead 1.3 or earlier |
||
461 | // might trigger this. |
||
462 | return; |
||
3685 | fschmid | 463 | // throw FatalError("Illegally sized directory"); |
10911 | fschmid | 464 | } |
465 | } |
||
466 | if ( DirEnd < LastExifRefd ) LastExifRefd = DirEnd; |
||
467 | } |
||
3685 | fschmid | 468 | |
10911 | fschmid | 469 | for ( de=0;de<NumDirEntries;de++ ) |
470 | { |
||
471 | int Tag, Format, Components; |
||
472 | unsigned char * ValuePtr; |
||
473 | int ByteCount; |
||
474 | char * DirEntry; |
||
475 | DirEntry = ( char * ) DIR_ENTRY_ADDR ( DirStart, de ); |
||
3685 | fschmid | 476 | |
10911 | fschmid | 477 | Tag = Get16u ( DirEntry ); |
478 | Format = Get16u ( DirEntry+2 ); |
||
479 | Components = Get32u ( DirEntry+4 ); |
||
3685 | fschmid | 480 | |
10911 | fschmid | 481 | if ( ( Format-1 ) >= NUM_FORMATS ) |
482 | { |
||
483 | // (-1) catches illegal zero case as unsigned underflows to positive large. |
||
484 | return; |
||
3685 | fschmid | 485 | // throw FatalError("Illegal format code in EXIF dir"); |
10911 | fschmid | 486 | } |
10914 | fschmid | 487 | if ((unsigned)Components > 0x10000) |
488 | continue; |
||
10911 | fschmid | 489 | ByteCount = Components * BytesPerFormat[Format]; |
3685 | fschmid | 490 | |
10911 | fschmid | 491 | if ( ByteCount > 4 ) |
492 | { |
||
493 | unsigned OffsetVal; |
||
494 | OffsetVal = Get32u ( DirEntry+8 ); |
||
495 | // If its bigger than 4 bytes, the dir entry contains an offset. |
||
496 | if ( OffsetVal+ByteCount > ExifLength ) |
||
497 | { |
||
498 | // Bogus pointer offset and / or bytecount value |
||
499 | //printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength); |
||
3685 | fschmid | 500 | |
10911 | fschmid | 501 | return ; |
3685 | fschmid | 502 | // throw FatalError("Illegal pointer offset value in EXIF"); |
10911 | fschmid | 503 | } |
504 | ValuePtr = OffsetBase+OffsetVal; |
||
505 | } |
||
506 | else |
||
507 | { |
||
508 | // 4 bytes or less and value is in the dir entry itself |
||
509 | ValuePtr = ( unsigned char * ) DirEntry+8; |
||
510 | } |
||
3685 | fschmid | 511 | |
10911 | fschmid | 512 | if ( LastExifRefd < ValuePtr+ByteCount ) |
513 | { |
||
514 | // Keep track of last byte in the exif header that was actually referenced. |
||
515 | // That way, we know where the discardable thumbnail data begins. |
||
516 | LastExifRefd = ValuePtr+ByteCount; |
||
517 | } |
||
3685 | fschmid | 518 | |
10911 | fschmid | 519 | // Extract useful components of tag |
520 | switch ( Tag ) |
||
521 | { |
||
3685 | fschmid | 522 | |
10911 | fschmid | 523 | case TAG_MAKE: |
524 | ExifData::CameraMake = QString ( ( char* ) ValuePtr ); |
||
525 | break; |
||
3685 | fschmid | 526 | |
10911 | fschmid | 527 | case TAG_MODEL: |
528 | ExifData::CameraModel = QString ( ( char* ) ValuePtr ); |
||
529 | break; |
||
3685 | fschmid | 530 | |
10911 | fschmid | 531 | case TAG_ORIENTATION: |
16438 | fschmid | 532 | if (orientationCount == 0) |
533 | { |
||
534 | Orientation = ( int ) ConvertAnyFormat ( ValuePtr, Format ); |
||
535 | orientationCount++; |
||
536 | } |
||
10911 | fschmid | 537 | break; |
3685 | fschmid | 538 | |
10911 | fschmid | 539 | case TAG_DATETIME_ORIGINAL: |
540 | DateTime = QString ( ( char* ) ValuePtr ); |
||
541 | break; |
||
3685 | fschmid | 542 | |
10911 | fschmid | 543 | case TAG_USERCOMMENT: |
544 | // Olympus has this padded with trailing spaces. Remove these first. |
||
545 | for ( a=ByteCount;; ) |
||
546 | { |
||
547 | a--; |
||
548 | if ( ( ValuePtr ) [a] == ' ' ) |
||
549 | { |
||
550 | ( ValuePtr ) [a] = '\0'; |
||
551 | } |
||
552 | else |
||
553 | { |
||
554 | break; |
||
555 | } |
||
556 | if ( a == 0 ) break; |
||
557 | } |
||
3685 | fschmid | 558 | |
10911 | fschmid | 559 | // Copy the comment |
560 | if ( memcmp ( ValuePtr, "ASCII",5 ) == 0 ) |
||
561 | { |
||
562 | for ( a=5;a<10;a++ ) |
||
563 | { |
||
564 | int c; |
||
565 | c = ( ValuePtr ) [a]; |
||
566 | if ( c != '\0' && c != ' ' ) |
||
567 | { |
||
568 | //strncpy(ImageInfo.Comments, (const char*)(a+ValuePtr), 199); |
||
569 | UserComment.sprintf ( "%s", ( const char* ) ( a+ValuePtr ) ); |
||
570 | break; |
||
571 | } |
||
572 | } |
||
573 | } |
||
574 | else |
||
575 | { |
||
576 | //strncpy(ImageInfo.Comments, (const char*)ValuePtr, 199); |
||
577 | UserComment.sprintf ( "%s", ( const char* ) ValuePtr ); |
||
578 | } |
||
579 | break; |
||
3685 | fschmid | 580 | |
10911 | fschmid | 581 | case TAG_FNUMBER: |
582 | // Simplest way of expressing aperture, so I trust it the most. |
||
583 | // (overwrite previously computd value if there is one) |
||
584 | ExifData::ApertureFNumber = ( float ) ConvertAnyFormat ( ValuePtr, Format ); |
||
585 | break; |
||
3685 | fschmid | 586 | |
10911 | fschmid | 587 | case TAG_APERTURE: |
588 | case TAG_MAXAPERTURE: |
||
589 | // More relevant info always comes earlier, so only use this field if we don't |
||
590 | // have appropriate aperture information yet. |
||
591 | if ( ExifData::ApertureFNumber == 0 ) |
||
592 | { |
||
593 | ExifData::ApertureFNumber |
||
594 | = ( float ) exp ( ConvertAnyFormat ( ValuePtr, Format ) *log ( 2.0 ) *0.5 ); |
||
595 | } |
||
596 | break; |
||
3685 | fschmid | 597 | |
10911 | fschmid | 598 | case TAG_FOCALLENGTH: |
599 | // Nice digital cameras actually save the focal length as a function |
||
600 | // of how far they are zoomed in. |
||
601 | ExifData::FocalLength = ( float ) ConvertAnyFormat ( ValuePtr, Format ); |
||
602 | break; |
||
3685 | fschmid | 603 | |
10911 | fschmid | 604 | case TAG_SUBJECT_DISTANCE: |
605 | // Inidcates the distacne the autofocus camera is focused to. |
||
606 | // Tends to be less accurate as distance increases. |
||
607 | ExifData::Distance = ( float ) ConvertAnyFormat ( ValuePtr, Format ); |
||
608 | break; |
||
3685 | fschmid | 609 | |
10911 | fschmid | 610 | case TAG_EXPOSURETIME: |
611 | // Simplest way of expressing exposure time, so I trust it most. |
||
612 | // (overwrite previously computd value if there is one) |
||
613 | ExifData::ExposureTime = ( float ) ConvertAnyFormat ( ValuePtr, Format ); |
||
614 | break; |
||
3685 | fschmid | 615 | |
10911 | fschmid | 616 | case TAG_SHUTTERSPEED: |
617 | // More complicated way of expressing exposure time, so only use |
||
618 | // this value if we don't already have it from somewhere else. |
||
619 | if ( ExifData::ExposureTime == 0 ) |
||
620 | { |
||
621 | ExifData::ExposureTime |
||
622 | = ( float ) ( 1/exp ( ConvertAnyFormat ( ValuePtr, Format ) *log ( 2.0 ) ) ); |
||
623 | } |
||
624 | break; |
||
3685 | fschmid | 625 | |
10911 | fschmid | 626 | case TAG_FLASH: |
627 | ExifData::FlashUsed = ( int ) ConvertAnyFormat ( ValuePtr, Format ); |
||
628 | break; |
||
3685 | fschmid | 629 | |
10911 | fschmid | 630 | case TAG_EXIF_IMAGELENGTH: |
631 | ExifImageLength = ( int ) ConvertAnyFormat ( ValuePtr, Format ); |
||
632 | break; |
||
3685 | fschmid | 633 | |
10911 | fschmid | 634 | case TAG_EXIF_IMAGEWIDTH: |
635 | ExifImageWidth = ( int ) ConvertAnyFormat ( ValuePtr, Format ); |
||
636 | break; |
||
3685 | fschmid | 637 | |
10911 | fschmid | 638 | case TAG_FOCALPLANEXRES: |
639 | FocalplaneXRes = ConvertAnyFormat ( ValuePtr, Format ); |
||
640 | break; |
||
3685 | fschmid | 641 | |
10911 | fschmid | 642 | case TAG_FOCALPLANEUNITS: |
643 | switch ( ( int ) ConvertAnyFormat ( ValuePtr, Format ) ) |
||
644 | { |
||
645 | case 1: FocalplaneUnits = 25.4; break; // inch |
||
646 | case 2: |
||
647 | // According to the information I was using, 2 means meters. |
||
648 | // But looking at the Cannon powershot's files, inches is the only |
||
649 | // sensible value. |
||
650 | FocalplaneUnits = 25.4; |
||
651 | break; |
||
3685 | fschmid | 652 | |
10911 | fschmid | 653 | case 3: FocalplaneUnits = 10; break; // centimeter |
654 | case 4: FocalplaneUnits = 1; break; // milimeter |
||
655 | case 5: FocalplaneUnits = .001; break; // micrometer |
||
656 | } |
||
657 | break; |
||
3685 | fschmid | 658 | |
10911 | fschmid | 659 | // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de) |
3685 | fschmid | 660 | |
10911 | fschmid | 661 | case TAG_EXPOSURE_BIAS: |
662 | ExifData::ExposureBias = ( float ) ConvertAnyFormat ( ValuePtr, Format ); |
||
663 | break; |
||
3685 | fschmid | 664 | |
10911 | fschmid | 665 | case TAG_WHITEBALANCE: |
666 | ExifData::Whitebalance = ( int ) ConvertAnyFormat ( ValuePtr, Format ); |
||
667 | break; |
||
3685 | fschmid | 668 | |
10911 | fschmid | 669 | case TAG_METERING_MODE: |
670 | ExifData::MeteringMode = ( int ) ConvertAnyFormat ( ValuePtr, Format ); |
||
671 | break; |
||
3685 | fschmid | 672 | |
10911 | fschmid | 673 | case TAG_EXPOSURE_PROGRAM: |
674 | ExifData::ExposureProgram = ( int ) ConvertAnyFormat ( ValuePtr, Format ); |
||
675 | break; |
||
3685 | fschmid | 676 | |
10911 | fschmid | 677 | case TAG_ISO_EQUIVALENT: |
678 | ExifData::ISOequivalent = ( int ) ConvertAnyFormat ( ValuePtr, Format ); |
||
679 | if ( ExifData::ISOequivalent < 50 ) ExifData::ISOequivalent *= 200; |
||
680 | break; |
||
3685 | fschmid | 681 | |
10911 | fschmid | 682 | case TAG_COMPRESSION_LEVEL: |
683 | ExifData::CompressionLevel = ( int ) ConvertAnyFormat ( ValuePtr, Format ); |
||
684 | break; |
||
3685 | fschmid | 685 | |
10911 | fschmid | 686 | case TAG_THUMBNAIL_OFFSET: |
687 | ThumbnailOffset = ( unsigned ) ConvertAnyFormat ( ValuePtr, Format ); |
||
688 | break; |
||
3685 | fschmid | 689 | |
10911 | fschmid | 690 | case TAG_THUMBNAIL_LENGTH: |
691 | ThumbnailSize = ( unsigned ) ConvertAnyFormat ( ValuePtr, Format ); |
||
692 | break; |
||
693 | } |
||
3685 | fschmid | 694 | |
10911 | fschmid | 695 | if ( Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET ) |
696 | { |
||
697 | unsigned char * SubdirStart; |
||
698 | SubdirStart = OffsetBase + Get32u ( ValuePtr ); |
||
12898 | fschmid | 699 | if ( (SubdirStart < OffsetBase) || (SubdirStart > OffsetBase+ExifLength) ) |
10911 | fschmid | 700 | { |
701 | return ; |
||
3685 | fschmid | 702 | // throw FatalError("Illegal subdirectory link"); |
10911 | fschmid | 703 | } |
704 | ProcessExifDir ( SubdirStart, OffsetBase, ExifLength ); |
||
705 | recurseLevel--; |
||
706 | continue; |
||
707 | } |
||
708 | } |
||
3685 | fschmid | 709 | |
10911 | fschmid | 710 | { |
711 | // In addition to linking to subdirectories via exif tags, |
||
712 | // there's also a potential link to another directory at the end of each |
||
713 | // directory. this has got to be the result of a comitee! |
||
714 | unsigned char * SubdirStart; |
||
715 | unsigned Offset; |
||
3685 | fschmid | 716 | |
10911 | fschmid | 717 | if ( DIR_ENTRY_ADDR ( DirStart, NumDirEntries ) + 4 <= OffsetBase+ExifLength ) |
718 | { |
||
719 | Offset = Get32u ( DIR_ENTRY_ADDR ( DirStart, NumDirEntries ) ); |
||
720 | // There is at least one jpeg from an HP camera having an Offset of almost MAXUINT. |
||
721 | // Adding OffsetBase to it produces an overflow, so compare with ExifLength here. |
||
722 | // See http://bugs.kde.org/show_bug.cgi?id=54542 |
||
723 | if ( Offset && Offset < ExifLength ) |
||
724 | { |
||
725 | SubdirStart = OffsetBase + Offset; |
||
726 | if ( SubdirStart > OffsetBase+ExifLength ) |
||
727 | { |
||
728 | if ( SubdirStart < OffsetBase+ExifLength+20 ) |
||
729 | { |
||
730 | // Jhead 1.3 or earlier would crop the whole directory! |
||
731 | // As Jhead produces this form of format incorrectness, |
||
732 | // I'll just let it pass silently |
||
11645 | fschmid | 733 | // qDebug ( "Thumbnail removed with Jhead 1.3 or earlier" ); |
10911 | fschmid | 734 | } |
735 | else |
||
736 | { |
||
737 | return ; |
||
738 | // throw FatalError("Illegal subdirectory link 2"); |
||
739 | } |
||
740 | } |
||
741 | else |
||
742 | { |
||
743 | if ( SubdirStart <= OffsetBase+ExifLength ) |
||
744 | { |
||
745 | ProcessExifDir ( SubdirStart, OffsetBase, ExifLength ); |
||
746 | recurseLevel--; |
||
747 | } |
||
748 | } |
||
749 | } |
||
750 | } |
||
751 | else |
||
752 | { |
||
753 | // The exif header ends before the last next directory pointer. |
||
754 | } |
||
755 | } |
||
3685 | fschmid | 756 | |
10911 | fschmid | 757 | if ( ThumbnailSize && ThumbnailOffset ) |
758 | { |
||
759 | if ( ThumbnailSize + ThumbnailOffset <= ExifLength ) |
||
760 | { |
||
761 | // The thumbnail pointer appears to be valid. Store it. |
||
762 | Thumbnail.loadFromData ( OffsetBase + ThumbnailOffset, ThumbnailSize, "JPEG" ); |
||
763 | } |
||
764 | } |
||
3685 | fschmid | 765 | } |
766 | |||
767 | //-------------------------------------------------------------------------- |
||
768 | // Process a COM marker. We want to leave the bytes unchanged. The |
||
769 | // progam that displays this text may decide to remove blanks, convert |
||
770 | // newlines, or otherwise modify the text. In particular we want to be |
||
771 | // safe for passing utf-8 text. |
||
772 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 773 | void ExifData::process_COM ( const uchar * Data, int length ) |
3685 | fschmid | 774 | { |
10911 | fschmid | 775 | Comment = QString::fromUtf8 ( ( char * ) Data+2, ( length-2 ) ); |
3685 | fschmid | 776 | } |
777 | |||
778 | |||
779 | //-------------------------------------------------------------------------- |
||
780 | // Process a SOFn marker. This is useful for the image dimensions |
||
781 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 782 | void ExifData::process_SOFn ( const uchar * Data, int marker ) |
3685 | fschmid | 783 | { |
10911 | fschmid | 784 | int data_precision, num_components; |
3685 | fschmid | 785 | |
10911 | fschmid | 786 | data_precision = Data[2]; |
787 | ExifData::Height = Get16m ( Data+3 ); |
||
788 | ExifData::Width = Get16m ( Data+5 ); |
||
789 | num_components = Data[7]; |
||
3685 | fschmid | 790 | |
10911 | fschmid | 791 | if ( num_components == 3 ) |
792 | ExifData::IsColor = 1; |
||
793 | else |
||
794 | ExifData::IsColor = 0; |
||
3685 | fschmid | 795 | |
10911 | fschmid | 796 | ExifData::Process = marker; |
3685 | fschmid | 797 | |
798 | } |
||
799 | |||
800 | //-------------------------------------------------------------------------- |
||
801 | // Get 16 bits motorola order (always) for jpeg header stuff. |
||
802 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 803 | int ExifData::Get16m ( const void * Short ) |
3685 | fschmid | 804 | { |
10911 | fschmid | 805 | return ( ( ( uchar * ) Short ) [0] << 8 ) | ( ( uchar * ) Short ) [1]; |
3685 | fschmid | 806 | } |
807 | |||
808 | |||
809 | //-------------------------------------------------------------------------- |
||
810 | // Process a EXIF marker |
||
811 | // Describes all the drivel that most digital cameras include... |
||
812 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 813 | void ExifData::process_EXIF ( unsigned char * CharBuf, unsigned int length ) |
3685 | fschmid | 814 | { |
10911 | fschmid | 815 | ExifData::FlashUsed = 0; // If it s from a digicam, and it used flash, it says so. |
3685 | fschmid | 816 | |
10911 | fschmid | 817 | FocalplaneXRes = 0; |
818 | FocalplaneUnits = 0; |
||
819 | ExifImageWidth = 0; |
||
820 | ExifImageLength = 0; |
||
3685 | fschmid | 821 | |
12898 | fschmid | 822 | // Check the EXIF header component |
823 | static const uchar ExifHeader[] = "Exif\0\0"; |
||
824 | if ( memcmp ( CharBuf+2, ExifHeader,6 ) ) |
||
825 | return ; |
||
3685 | fschmid | 826 | |
10911 | fschmid | 827 | if ( memcmp ( CharBuf+8,"II",2 ) == 0 ) |
828 | MotorolaOrder = 0; |
||
829 | else |
||
830 | { |
||
831 | if ( memcmp ( CharBuf+8,"MM",2 ) == 0 ) |
||
832 | MotorolaOrder = 1; |
||
833 | else |
||
834 | return ; |
||
835 | } |
||
3685 | fschmid | 836 | |
10911 | fschmid | 837 | // Check the next two values for correctness. |
10914 | fschmid | 838 | if ( Get16u ( CharBuf+10 ) != 0x2a || Get32u ( CharBuf+12 ) != 0x08 ) |
10911 | fschmid | 839 | return ; |
10914 | fschmid | 840 | long IFDoffset = Get32u(CharBuf+12); |
10911 | fschmid | 841 | LastExifRefd = CharBuf; |
3685 | fschmid | 842 | |
10911 | fschmid | 843 | // First directory starts 16 bytes in. Offsets start at 8 bytes in. |
10914 | fschmid | 844 | ProcessExifDir(&CharBuf[8+IFDoffset], CharBuf+8, length-6); |
10911 | fschmid | 845 | recurseLevel--; |
846 | // This is how far the interesting (non thumbnail) part of the exif went. |
||
847 | ExifSettingsLength = LastExifRefd - CharBuf; |
||
3685 | fschmid | 848 | |
10911 | fschmid | 849 | // Compute the CCD width, in milimeters. |
850 | if ( FocalplaneXRes != 0 ) |
||
851 | { |
||
852 | ExifData::CCDWidth = ( float ) ( ExifImageWidth * FocalplaneUnits / FocalplaneXRes ); |
||
853 | } |
||
3685 | fschmid | 854 | } |
855 | |||
856 | //-------------------------------------------------------------------------- |
||
857 | // Convert exif time to Unix time structure |
||
858 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 859 | int ExifData::Exif2tm ( struct tm * timeptr, char * ExifTime ) |
3685 | fschmid | 860 | { |
10911 | fschmid | 861 | int a; |
3685 | fschmid | 862 | |
10911 | fschmid | 863 | timeptr->tm_wday = -1; |
3685 | fschmid | 864 | |
10911 | fschmid | 865 | // Check for format: YYYY:MM:DD HH:MM:SS format. |
866 | a = sscanf ( ExifTime, "%d:%d:%d %d:%d:%d", |
||
867 | &timeptr->tm_year, &timeptr->tm_mon, &timeptr->tm_mday, |
||
868 | &timeptr->tm_hour, &timeptr->tm_min, &timeptr->tm_sec ); |
||
3685 | fschmid | 869 | |
10911 | fschmid | 870 | if ( a == 6 ) |
871 | { |
||
872 | timeptr->tm_isdst = -1; |
||
873 | timeptr->tm_mon -= 1; // Adjust for unix zero-based months |
||
874 | timeptr->tm_year -= 1900; // Adjust for year starting at 1900 |
||
875 | return true; // worked. |
||
876 | } |
||
3685 | fschmid | 877 | |
10911 | fschmid | 878 | return false; // Wasn't in Exif date format. |
3685 | fschmid | 879 | } |
880 | |||
881 | //-------------------------------------------------------------------------- |
||
882 | // Contructor for initialising |
||
883 | //-------------------------------------------------------------------------- |
||
884 | ExifData::ExifData() |
||
885 | { |
||
10911 | fschmid | 886 | ExifData::Whitebalance = -1; |
887 | ExifData::MeteringMode = -1; |
||
888 | ExifData::FlashUsed = 0; |
||
889 | Orientation = 0; |
||
890 | Height = 0; |
||
891 | Width = 0; |
||
892 | IsColor = 0; |
||
893 | Process = 0; |
||
894 | FocalLength = 0; |
||
895 | ExposureTime = 0; |
||
896 | ApertureFNumber = 0; |
||
897 | Distance = 0; |
||
898 | CCDWidth = 0; |
||
899 | ExposureBias = 0; |
||
900 | ExposureProgram = 0; |
||
901 | ISOequivalent = 0; |
||
902 | CompressionLevel = 0; |
||
3898 | fschmid | 903 | exifDataValid = false; |
10911 | fschmid | 904 | recurseLevel = 0; |
16438 | fschmid | 905 | orientationCount = 0; |
3685 | fschmid | 906 | } |
907 | |||
908 | //-------------------------------------------------------------------------- |
||
909 | // process a EXIF jpeg file |
||
910 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 911 | bool ExifData::scan ( const QString & path ) |
3685 | fschmid | 912 | { |
10911 | fschmid | 913 | int ret; |
3685 | fschmid | 914 | |
10911 | fschmid | 915 | QFile f ( path ); |
916 | if ( !f.open ( QIODevice::ReadOnly ) ) |
||
917 | return false; |
||
918 | ret = ReadJpegSections ( f, READ_EXIF ); |
||
919 | if ( ret == false ) |
||
920 | { |
||
921 | f.close(); |
||
922 | return false; |
||
923 | } |
||
924 | f.close(); |
||
3685 | fschmid | 925 | |
10911 | fschmid | 926 | //now make the strings clean, |
927 | // for exmaple my Casio is a "QV-4000 " |
||
10394 | cbradney | 928 | CameraMake = CameraMake.trimmed(); |
929 | CameraModel = CameraModel.trimmed(); |
||
930 | UserComment = UserComment.trimmed(); |
||
931 | Comment = Comment.trimmed(); |
||
10911 | fschmid | 932 | return true; |
3685 | fschmid | 933 | } |
934 | |||
935 | //-------------------------------------------------------------------------- |
||
936 | // Does the embedded thumbnail match the jpeg image? |
||
937 | //-------------------------------------------------------------------------- |
||
938 | #ifndef JPEG_TOL |
||
939 | #define JPEG_TOL 0.02 |
||
940 | #endif |
||
10911 | fschmid | 941 | bool ExifData::isThumbnailSane() |
942 | { |
||
943 | bool ret = true; |
||
944 | if ( Thumbnail.isNull() ) |
||
945 | ret = false; |
||
3685 | fschmid | 946 | |
10911 | fschmid | 947 | // check whether thumbnail dimensions match the image |
948 | // not foolproof, but catches some altered images (jpegtran -rotate) |
||
949 | if ( ExifImageLength != 0 && ExifImageLength != Height ) |
||
950 | ret = false; |
||
951 | if ( ExifImageWidth != 0 && ExifImageWidth != Width ) |
||
952 | ret = false; |
||
953 | if ( Thumbnail.width() == 0 || Thumbnail.height() == 0 ) |
||
954 | ret = false; |
||
955 | if ( Height == 0 || Width == 0 ) |
||
956 | ret = false; |
||
957 | double d = ( double ) Height/Width*Thumbnail.width() /Thumbnail.height(); |
||
958 | if (!(( 1-JPEG_TOL < d ) && ( d < 1+JPEG_TOL ))) |
||
959 | ret = false; |
||
960 | exifDataValid = ret; |
||
961 | return ret; |
||
3685 | fschmid | 962 | } |
963 | |||
964 | |||
965 | //-------------------------------------------------------------------------- |
||
966 | // return a thumbnail that respects the orientation flag |
||
967 | // only if it seems sane |
||
968 | //-------------------------------------------------------------------------- |
||
10911 | fschmid | 969 | QImage ExifData::getThumbnail() |
970 | { |
||
16438 | fschmid | 971 | if ( Thumbnail.isNull() ) |
972 | return QImage(); // Qt4 NULL->QImage() is it sane? |
||
973 | if (orientationCount > 1) |
||
974 | return Thumbnail; |
||
975 | if ( !Orientation || Orientation == 1 ) |
||
976 | return Thumbnail; |
||
10911 | fschmid | 977 | // now fix orientation |
13951 | fschmid | 978 | QTransform M; |
979 | QTransform flip = QTransform ( -1,0,0,1,0,0 ); |
||
10911 | fschmid | 980 | switch ( Orientation ) |
981 | { // notice intentional fallthroughs |
||
982 | case 2: M = flip; break; |
||
983 | case 4: M = flip; |
||
984 | case 3: M.rotate ( 180 ); break; |
||
985 | case 5: M = flip; |
||
986 | case 6: M.rotate ( 90 ); break; |
||
987 | case 7: M = flip; |
||
988 | case 8: M.rotate ( 270 ); break; |
||
989 | default: break; // should never happen |
||
990 | } |
||
991 | return Thumbnail.transformed ( M ); |
||
3685 | fschmid | 992 | } |