summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opiemm/opieexif.cpp54
-rw-r--r--libopie2/opiemm/opieexif.h7
2 files changed, 12 insertions, 49 deletions
diff --git a/libopie2/opiemm/opieexif.cpp b/libopie2/opiemm/opieexif.cpp
index 0860ea8..de49937 100644
--- a/libopie2/opiemm/opieexif.cpp
+++ b/libopie2/opiemm/opieexif.cpp
@@ -88,385 +88,384 @@ static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
88#define TAG_SUBJECT_DISTANCE 0x9206 88#define TAG_SUBJECT_DISTANCE 0x9206
89#define TAG_FLASH 0x9209 89#define TAG_FLASH 0x9209
90 90
91#define TAG_FOCALPLANEXRES 0xa20E 91#define TAG_FOCALPLANEXRES 0xa20E
92#define TAG_FOCALPLANEUNITS 0xa210 92#define TAG_FOCALPLANEUNITS 0xa210
93#define TAG_EXIF_IMAGEWIDTH 0xA002 93#define TAG_EXIF_IMAGEWIDTH 0xA002
94#define TAG_EXIF_IMAGELENGTH 0xA003 94#define TAG_EXIF_IMAGELENGTH 0xA003
95 95
96// the following is added 05-jan-2001 vcs 96// the following is added 05-jan-2001 vcs
97#define TAG_EXPOSURE_BIAS 0x9204 97#define TAG_EXPOSURE_BIAS 0x9204
98#define TAG_WHITEBALANCE 0x9208 98#define TAG_WHITEBALANCE 0x9208
99#define TAG_METERING_MODE 0x9207 99#define TAG_METERING_MODE 0x9207
100#define TAG_EXPOSURE_PROGRAM 0x8822 100#define TAG_EXPOSURE_PROGRAM 0x8822
101#define TAG_ISO_EQUIVALENT 0x8827 101#define TAG_ISO_EQUIVALENT 0x8827
102#define TAG_COMPRESSION_LEVEL 0x9102 102#define TAG_COMPRESSION_LEVEL 0x9102
103 103
104#define TAG_THUMBNAIL_OFFSET 0x0201 104#define TAG_THUMBNAIL_OFFSET 0x0201
105#define TAG_THUMBNAIL_LENGTH 0x0202 105#define TAG_THUMBNAIL_LENGTH 0x0202
106 106
107 107
108 108
109namespace Opie { 109namespace Opie {
110 110
111namespace MM { 111namespace MM {
112 112
113class FatalError { 113class FatalError {
114 const char* ex; 114 const char* ex;
115public: 115public:
116 FatalError(const char* s) { ex = s; } 116 FatalError(const char* s) { ex = s; }
117 void debug_print() const { owarn << "exception: " << ex << "" << oendl; } 117 void debug_print() const { owarn << "exception: " << ex << "" << oendl; }
118}; 118};
119 119
120ExifData::TagTable_t ProcessTable[] = { 120ExifData::TagTable_t ProcessTable[] = {
121 { M_SOF0, "Baseline"}, 121 { M_SOF0, "Baseline"},
122 { M_SOF1, "Extended sequential"}, 122 { M_SOF1, "Extended sequential"},
123 { M_SOF2, "Progressive"}, 123 { M_SOF2, "Progressive"},
124 { M_SOF3, "Lossless"}, 124 { M_SOF3, "Lossless"},
125 { M_SOF5, "Differential sequential"}, 125 { M_SOF5, "Differential sequential"},
126 { M_SOF6, "Differential progressive"}, 126 { M_SOF6, "Differential progressive"},
127 { M_SOF7, "Differential lossless"}, 127 { M_SOF7, "Differential lossless"},
128 { M_SOF9, "Extended sequential, arithmetic coding"}, 128 { M_SOF9, "Extended sequential, arithmetic coding"},
129 { M_SOF10, "Progressive, arithmetic coding"}, 129 { M_SOF10, "Progressive, arithmetic coding"},
130 { M_SOF11, "Lossless, arithmetic coding"}, 130 { M_SOF11, "Lossless, arithmetic coding"},
131 { M_SOF13, "Differential sequential, arithmetic coding"}, 131 { M_SOF13, "Differential sequential, arithmetic coding"},
132 { M_SOF14, "Differential progressive, arithmetic coding"}, 132 { M_SOF14, "Differential progressive, arithmetic coding"},
133 { M_SOF15, "Differential lossless, arithmetic coding"}, 133 { M_SOF15, "Differential lossless, arithmetic coding"},
134 { 0, "Unknown"} 134 { 0, "Unknown"}
135}; 135};
136 136
137//-------------------------------------------------------------------------- 137//--------------------------------------------------------------------------
138// Parse the marker stream until SOS or EOI is seen; 138// Parse the marker stream until SOS or EOI is seen;
139//-------------------------------------------------------------------------- 139//--------------------------------------------------------------------------
140int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode) 140int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode)
141{ 141{
142 int a; 142 int a;
143 143
144 a = infile.getch(); 144 a = infile.getch();
145 145
146 if (a != 0xff || infile.getch() != M_SOI) { 146 if (a != 0xff || infile.getch() != M_SOI) {
147 SectionsRead = 0; 147 SectionsRead = 0;
148 return false; 148 return false;
149 } 149 }
150 for(SectionsRead = 0; SectionsRead < MAX_SECTIONS-1; ){ 150 for(SectionsRead = 0; SectionsRead < MAX_SECTIONS-1; ){
151 int marker = 0; 151 int marker = 0;
152 int got; 152 int got;
153 unsigned int ll,lh; 153 unsigned int ll,lh;
154 unsigned int itemlen; 154 unsigned int itemlen;
155 uchar * Data; 155 uchar * Data;
156 156
157 for (a=0;a<7;a++){ 157 for (a=0;a<7;a++){
158 marker = infile.getch(); 158 marker = infile.getch();
159 if (marker != 0xff) break; 159 if (marker != 0xff) break;
160 160
161 if (a >= 6){ 161 if (a >= 6){
162 162
163 owarn << "too many padding bytes" << oendl; 163 owarn << "too many padding bytes" << oendl;
164 return false; 164 return false;
165 165
166 } 166 }
167 } 167 }
168 168
169 if (marker == 0xff){ 169 if (marker == 0xff){
170 // 0xff is legal padding, but if we get that many, something's wrong. 170 // 0xff is legal padding, but if we get that many, something's wrong.
171 return false; 171 return false;
172 } 172 }
173 173
174 Sections[SectionsRead].Type = marker; 174 Sections[SectionsRead].Type = marker;
175 175
176 // Read the length of the section. 176 // Read the length of the section.
177 lh = (uchar) infile.getch(); 177 lh = (uchar) infile.getch();
178 ll = (uchar) infile.getch(); 178 ll = (uchar) infile.getch();
179 179
180 itemlen = (lh << 8) | ll; 180 itemlen = (lh << 8) | ll;
181 181
182 if (itemlen < 2) { 182 if (itemlen < 2) {
183 return false;; 183 return false;;
184 } 184 }
185 185
186 Sections[SectionsRead].Size = itemlen; 186 Sections[SectionsRead].Size = itemlen;
187 187
188 Data = (uchar *)malloc(itemlen+1); // Add 1 to allow sticking a 0 at the end. 188 Data = (uchar *)malloc(itemlen+1); // Add 1 to allow sticking a 0 at the end.
189 Sections[SectionsRead].Data = Data; 189 Sections[SectionsRead].Data = Data;
190 190
191 // Store first two pre-read bytes. 191 // Store first two pre-read bytes.
192 Data[0] = (uchar)lh; 192 Data[0] = (uchar)lh;
193 Data[1] = (uchar)ll; 193 Data[1] = (uchar)ll;
194 194
195 got = infile.readBlock((char*)Data+2, itemlen-2); // Read the whole section. 195 got = infile.readBlock((char*)Data+2, itemlen-2); // Read the whole section.
196 if (( unsigned ) got != itemlen-2){ 196 if (( unsigned ) got != itemlen-2){
197 return false; 197 return false;
198 } 198 }
199 SectionsRead++; 199 SectionsRead++;
200 200
201 switch(marker){ 201 switch(marker){
202 202
203 case M_SOS: // stop before hitting compressed data 203 case M_SOS: // stop before hitting compressed data
204 // If reading entire image is requested, read the rest of the data. 204 // If reading entire image is requested, read the rest of the data.
205 if (ReadMode & READ_IMAGE){ 205 if (ReadMode & READ_IMAGE){
206 unsigned long size; 206 unsigned long size;
207 207
208 size = QMAX( 0ul, infile.size()-infile.at() ); 208 size = QMAX( 0ul, infile.size()-infile.at() );
209 Data = (uchar *)malloc(size); 209 Data = (uchar *)malloc(size);
210 if (Data == NULL){ 210 if (Data == NULL){
211 return false; 211 return false;
212 } 212 }
213 213
214 got = infile.readBlock((char*)Data, size); 214 got = infile.readBlock((char*)Data, size);
215 if (( unsigned ) got != size){ 215 if (( unsigned ) got != size){
216 return false; 216 return false;
217 } 217 }
218 218
219 Sections[SectionsRead].Data = Data; 219 Sections[SectionsRead].Data = Data;
220 Sections[SectionsRead].Size = size; 220 Sections[SectionsRead].Size = size;
221 Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER; 221 Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;
222 SectionsRead ++; 222 SectionsRead ++;
223 //HaveAll = 1; 223 //HaveAll = 1;
224 } 224 }
225 return true; 225 return true;
226 226
227 case M_EOI: // in case it's a tables-only JPEG stream 227 case M_EOI: // in case it's a tables-only JPEG stream
228 owarn << "No image in jpeg!" << oendl; 228 owarn << "No image in jpeg!" << oendl;
229 return false; 229 return false;
230 230
231 case M_COM: // Comment section 231 case M_COM: // Comment section
232 // pieczy 2002-02-12 232 // pieczy 2002-02-12
233 // now the User comment goes to UserComment 233 // now the User comment goes to UserComment
234 // so we can store a Comment section also in READ_EXIF mode 234 // so we can store a Comment section also in READ_EXIF mode
235 process_COM(Data, itemlen); 235 process_COM(Data, itemlen);
236 break; 236 break;
237 237
238 case M_JFIF: 238 case M_JFIF:
239 // Regular jpegs always have this tag, exif images have the exif 239 // Regular jpegs always have this tag, exif images have the exif
240 // marker instead, althogh ACDsee will write images with both markers. 240 // marker instead, althogh ACDsee will write images with both markers.
241 // this program will re-create this marker on absence of exif marker. 241 // this program will re-create this marker on absence of exif marker.
242 // hence no need to keep the copy from the file. 242 // hence no need to keep the copy from the file.
243 free(Sections[--SectionsRead].Data); 243 free(Sections[--SectionsRead].Data);
244 break; 244 break;
245 245
246 case M_EXIF: 246 case M_EXIF:
247 // Seen files from some 'U-lead' software with Vivitar scanner 247 // Seen files from some 'U-lead' software with Vivitar scanner
248 // that uses marker 31 for non exif stuff. Thus make sure 248 // that uses marker 31 for non exif stuff. Thus make sure
249 // it says 'Exif' in the section before treating it as exif. 249 // it says 'Exif' in the section before treating it as exif.
250 if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){ 250 if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){
251 process_EXIF((uchar *)Data, itemlen); 251 process_EXIF((uchar *)Data, itemlen);
252 }else{ 252 }else{
253 // Discard this section. 253 // Discard this section.
254 free(Sections[--SectionsRead].Data); 254 free(Sections[--SectionsRead].Data);
255 } 255 }
256 break; 256 break;
257 257
258 case M_SOF0: 258 case M_SOF0:
259 case M_SOF1: 259 case M_SOF1:
260 case M_SOF2: 260 case M_SOF2:
261 case M_SOF3: 261 case M_SOF3:
262 case M_SOF5: 262 case M_SOF5:
263 case M_SOF6: 263 case M_SOF6:
264 case M_SOF7: 264 case M_SOF7:
265 case M_SOF9: 265 case M_SOF9:
266 case M_SOF10: 266 case M_SOF10:
267 case M_SOF11: 267 case M_SOF11:
268 case M_SOF13: 268 case M_SOF13:
269 case M_SOF14: 269 case M_SOF14:
270 case M_SOF15: 270 case M_SOF15:
271 process_SOFn(Data, marker); 271 process_SOFn(Data, marker);
272 default: 272 default:
273 break; 273 break;
274 break; 274 break;
275 } 275 }
276 } 276 }
277 return true; 277 return true;
278} 278}
279 279
280
281//-------------------------------------------------------------------------- 280//--------------------------------------------------------------------------
282// Discard read data. 281// Discard read data.
283//-------------------------------------------------------------------------- 282//--------------------------------------------------------------------------
284void ExifData::DiscardData(void) 283void ExifData::DiscardData(void)
285{ 284{
286 for (int a=0; a < SectionsRead; a++) 285 for (int a=0; a < SectionsRead; a++)
287 free(Sections[a].Data); 286 free(Sections[a].Data);
288 SectionsRead = 0; 287 SectionsRead = 0;
289} 288}
290 289
291//-------------------------------------------------------------------------- 290//--------------------------------------------------------------------------
292// Convert a 16 bit unsigned value from file's native byte order 291// Convert a 16 bit unsigned value from file's native byte order
293//-------------------------------------------------------------------------- 292//--------------------------------------------------------------------------
294int ExifData::Get16u(void * Short) 293int ExifData::Get16u(void * Short)
295{ 294{
296 if (MotorolaOrder){ 295 if (MotorolaOrder){
297 return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1]; 296 return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
298 }else{ 297 }else{
299 return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0]; 298 return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0];
300 } 299 }
301} 300}
302 301
303//-------------------------------------------------------------------------- 302//--------------------------------------------------------------------------
304// Convert a 32 bit signed value from file's native byte order 303// Convert a 32 bit signed value from file's native byte order
305//-------------------------------------------------------------------------- 304//--------------------------------------------------------------------------
306int ExifData::Get32s(void * Long) 305int ExifData::Get32s(void * Long)
307{ 306{
308 if (MotorolaOrder){ 307 if (MotorolaOrder){
309 return ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16) 308 return ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16)
310 | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 ); 309 | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 );
311 }else{ 310 }else{
312 return ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16) 311 return ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16)
313 | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 ); 312 | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 );
314 } 313 }
315} 314}
316 315
317//-------------------------------------------------------------------------- 316//--------------------------------------------------------------------------
318// Convert a 32 bit unsigned value from file's native byte order 317// Convert a 32 bit unsigned value from file's native byte order
319//-------------------------------------------------------------------------- 318//--------------------------------------------------------------------------
320unsigned ExifData::Get32u(void * Long) 319unsigned ExifData::Get32u(void * Long)
321{ 320{
322 return (unsigned)Get32s(Long) & 0xffffffff; 321 return (unsigned)Get32s(Long) & 0xffffffff;
323} 322}
324 323
325//-------------------------------------------------------------------------- 324//--------------------------------------------------------------------------
326// Evaluate number, be it int, rational, or float from directory. 325// Evaluate number, be it int, rational, or float from directory.
327//-------------------------------------------------------------------------- 326//--------------------------------------------------------------------------
328double ExifData::ConvertAnyFormat(void * ValuePtr, int Format) 327double ExifData::ConvertAnyFormat(void * ValuePtr, int Format)
329{ 328{
330 double Value; 329 double Value;
331 Value = 0; 330 Value = 0;
332 331
333 switch(Format){ 332 switch(Format){
334 case FMT_SBYTE: Value = *(signed char *)ValuePtr; break; 333 case FMT_SBYTE: Value = *(signed char *)ValuePtr; break;
335 case FMT_BYTE: Value = *(uchar *)ValuePtr; break; 334 case FMT_BYTE: Value = *(uchar *)ValuePtr; break;
336 335
337 case FMT_USHORT: Value = Get16u(ValuePtr); break; 336 case FMT_USHORT: Value = Get16u(ValuePtr); break;
338 337
339 case FMT_ULONG: Value = Get32u(ValuePtr); break; 338 case FMT_ULONG: Value = Get32u(ValuePtr); break;
340 339
341 case FMT_URATIONAL: 340 case FMT_URATIONAL:
342 case FMT_SRATIONAL: 341 case FMT_SRATIONAL:
343 { 342 {
344 int Num,Den; 343 int Num,Den;
345 Num = Get32s(ValuePtr); 344 Num = Get32s(ValuePtr);
346 Den = Get32s(4+(char *)ValuePtr); 345 Den = Get32s(4+(char *)ValuePtr);
347 if (Den == 0){ 346 if (Den == 0){
348 Value = 0; 347 Value = 0;
349 }else{ 348 }else{
350 Value = (double)Num/Den; 349 Value = (double)Num/Den;
351 } 350 }
352 break; 351 break;
353 } 352 }
354 353
355 case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break; 354 case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break;
356 case FMT_SLONG: Value = Get32s(ValuePtr); break; 355 case FMT_SLONG: Value = Get32s(ValuePtr); break;
357 356
358 // Not sure if this is correct (never seen float used in Exif format) 357 // Not sure if this is correct (never seen float used in Exif format)
359 case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break; 358 case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;
360 case FMT_DOUBLE: Value = *(double *)ValuePtr; break; 359 case FMT_DOUBLE: Value = *(double *)ValuePtr; break;
361 } 360 }
362 return Value; 361 return Value;
363} 362}
364 363
365//-------------------------------------------------------------------------- 364//--------------------------------------------------------------------------
366// Process one of the nested EXIF directories. 365// Process one of the nested EXIF directories.
367//-------------------------------------------------------------------------- 366//--------------------------------------------------------------------------
368void ExifData::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength) 367void ExifData::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength)
369{ 368{
370 int de; 369 int de;
371 int a; 370 int a;
372 int NumDirEntries; 371 int NumDirEntries;
373 unsigned ThumbnailOffset = 0; 372 unsigned ThumbnailOffset = 0;
374 unsigned ThumbnailSize = 0; 373 unsigned ThumbnailSize = 0;
375 374
376 NumDirEntries = Get16u(DirStart); 375 NumDirEntries = Get16u(DirStart);
377 #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry)) 376 #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
378 377
379 { 378 {
380 unsigned char * DirEnd; 379 unsigned char * DirEnd;
381 DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries); 380 DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
382 if (DirEnd+4 > (OffsetBase+ExifLength)){ 381 if (DirEnd+4 > (OffsetBase+ExifLength)){
383 if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){ 382 if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){
384 // Version 1.3 of jhead would truncate a bit too much. 383 // Version 1.3 of jhead would truncate a bit too much.
385 // This also caught later on as well. 384 // This also caught later on as well.
386 }else{ 385 }else{
387 // Note: Files that had thumbnails trimmed with jhead 1.3 or earlier 386 // Note: Files that had thumbnails trimmed with jhead 1.3 or earlier
388 // might trigger this. 387 // might trigger this.
389 return; 388 return;
390 } 389 }
391 } 390 }
392 if (DirEnd < LastExifRefd) LastExifRefd = DirEnd; 391 if (DirEnd < LastExifRefd) LastExifRefd = DirEnd;
393 } 392 }
394 393
395 for (de=0;de<NumDirEntries;de++){ 394 for (de=0;de<NumDirEntries;de++){
396 int Tag, Format, Components; 395 int Tag, Format, Components;
397 unsigned char * ValuePtr; 396 unsigned char * ValuePtr;
398 int ByteCount; 397 int ByteCount;
399 char * DirEntry; 398 char * DirEntry;
400 DirEntry = (char *)DIR_ENTRY_ADDR(DirStart, de); 399 DirEntry = (char *)DIR_ENTRY_ADDR(DirStart, de);
401 400
402 Tag = Get16u(DirEntry); 401 Tag = Get16u(DirEntry);
403 Format = Get16u(DirEntry+2); 402 Format = Get16u(DirEntry+2);
404 Components = Get32u(DirEntry+4); 403 Components = Get32u(DirEntry+4);
405 404
406 if ((Format-1) >= NUM_FORMATS) { 405 if ((Format-1) >= NUM_FORMATS) {
407 // (-1) catches illegal zero case as unsigned underflows to positive large. 406 // (-1) catches illegal zero case as unsigned underflows to positive large.
408 return; 407 return;
409 } 408 }
410 409
411 ByteCount = Components * BytesPerFormat[Format]; 410 ByteCount = Components * BytesPerFormat[Format];
412 411
413 if (ByteCount > 4){ 412 if (ByteCount > 4){
414 unsigned OffsetVal; 413 unsigned OffsetVal;
415 OffsetVal = Get32u(DirEntry+8); 414 OffsetVal = Get32u(DirEntry+8);
416 // If its bigger than 4 bytes, the dir entry contains an offset. 415 // If its bigger than 4 bytes, the dir entry contains an offset.
417 if (OffsetVal+ByteCount > ExifLength){ 416 if (OffsetVal+ByteCount > ExifLength){
418 // Bogus pointer offset and / or bytecount value 417 // Bogus pointer offset and / or bytecount value
419 //printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength); 418 //printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength);
420 419
421 return; 420 return;
422 } 421 }
423 ValuePtr = OffsetBase+OffsetVal; 422 ValuePtr = OffsetBase+OffsetVal;
424 }else{ 423 }else{
425 // 4 bytes or less and value is in the dir entry itself 424 // 4 bytes or less and value is in the dir entry itself
426 ValuePtr = (unsigned char *)DirEntry+8; 425 ValuePtr = (unsigned char *)DirEntry+8;
427 } 426 }
428 427
429 if (LastExifRefd < ValuePtr+ByteCount){ 428 if (LastExifRefd < ValuePtr+ByteCount){
430 // Keep track of last byte in the exif header that was actually referenced. 429 // Keep track of last byte in the exif header that was actually referenced.
431 // That way, we know where the discardable thumbnail data begins. 430 // That way, we know where the discardable thumbnail data begins.
432 LastExifRefd = ValuePtr+ByteCount; 431 LastExifRefd = ValuePtr+ByteCount;
433 } 432 }
434 433
435 // Extract useful components of tag 434 // Extract useful components of tag
436 switch(Tag){ 435 switch(Tag){
437 436
438 case TAG_MAKE: 437 case TAG_MAKE:
439 ExifData::CameraMake = QString((char*)ValuePtr); 438 ExifData::CameraMake = QString((char*)ValuePtr);
440 break; 439 break;
441 440
442 case TAG_MODEL: 441 case TAG_MODEL:
443 ExifData::CameraModel = QString((char*)ValuePtr); 442 ExifData::CameraModel = QString((char*)ValuePtr);
444 break; 443 break;
445 444
446 case TAG_ORIENTATION: 445 case TAG_ORIENTATION:
447 Orientation = (int)ConvertAnyFormat(ValuePtr, Format); 446 Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
448 break; 447 break;
449 448
450 case TAG_DATETIME_ORIGINAL: 449 case TAG_DATETIME_ORIGINAL:
451 DateTime = QString((char*)ValuePtr); 450 DateTime = QString((char*)ValuePtr);
452 break; 451 break;
453 452
454 case TAG_USERCOMMENT: 453 case TAG_USERCOMMENT:
455 // Olympus has this padded with trailing spaces. Remove these first. 454 // Olympus has this padded with trailing spaces. Remove these first.
456 for (a=ByteCount;;){ 455 for (a=ByteCount;;){
457 a--; 456 a--;
458 if ((ValuePtr)[a] == ' '){ 457 if ((ValuePtr)[a] == ' '){
459 (ValuePtr)[a] = '\0'; 458 (ValuePtr)[a] = '\0';
460 }else{ 459 }else{
461 break; 460 break;
462 } 461 }
463 if (a == 0) break; 462 if (a == 0) break;
464 } 463 }
465 464
466 // Copy the comment 465 // Copy the comment
467 if (memcmp(ValuePtr, "ASCII",5) == 0){ 466 if (memcmp(ValuePtr, "ASCII",5) == 0){
468 for (a=5;a<10;a++){ 467 for (a=5;a<10;a++){
469 int c; 468 int c;
470 c = (ValuePtr)[a]; 469 c = (ValuePtr)[a];
471 if (c != '\0' && c != ' '){ 470 if (c != '\0' && c != ' '){
472 //strncpy(ImageInfo.Comments, (const char*)(a+ValuePtr), 199); 471 //strncpy(ImageInfo.Comments, (const char*)(a+ValuePtr), 199);
@@ -820,376 +819,333 @@ bool ExifData::scan(const QString & path)
820 DiscardData(); 819 DiscardData();
821 f.close(); 820 f.close();
822 return false; 821 return false;
823 } 822 }
824 f.close(); 823 f.close();
825 DiscardData(); 824 DiscardData();
826 825
827 //now make the strings clean, 826 //now make the strings clean,
828 // for exmaple my Casio is a "QV-4000 " 827 // for exmaple my Casio is a "QV-4000 "
829 CameraMake = CameraMake.stripWhiteSpace(); 828 CameraMake = CameraMake.stripWhiteSpace();
830 CameraModel = CameraModel.stripWhiteSpace(); 829 CameraModel = CameraModel.stripWhiteSpace();
831 UserComment = UserComment.stripWhiteSpace(); 830 UserComment = UserComment.stripWhiteSpace();
832 Comment = Comment.stripWhiteSpace(); 831 Comment = Comment.stripWhiteSpace();
833 return true; 832 return true;
834} 833}
835 834
836//-------------------------------------------------------------------------- 835//--------------------------------------------------------------------------
837// Does the embedded thumbnail match the jpeg image? 836// Does the embedded thumbnail match the jpeg image?
838//-------------------------------------------------------------------------- 837//--------------------------------------------------------------------------
839#ifndef JPEG_TOL 838#ifndef JPEG_TOL
840#define JPEG_TOL 0.02 839#define JPEG_TOL 0.02
841#endif 840#endif
842bool ExifData::isThumbnailSane() { 841bool ExifData::isThumbnailSane() {
843 if (Thumbnail.isNull()) return false; 842 if (Thumbnail.isNull()) return false;
844 843
845 // check whether thumbnail dimensions match the image 844 // check whether thumbnail dimensions match the image
846 // not foolproof, but catches some altered images (jpegtran -rotate) 845 // not foolproof, but catches some altered images (jpegtran -rotate)
847 if (ExifImageLength != 0 && ExifImageLength != Height) return false; 846 if (ExifImageLength != 0 && ExifImageLength != Height) return false;
848 if (ExifImageWidth != 0 && ExifImageWidth != Width) return false; 847 if (ExifImageWidth != 0 && ExifImageWidth != Width) return false;
849 if (Thumbnail.width() == 0 || Thumbnail.height() == 0) return false; 848 if (Thumbnail.width() == 0 || Thumbnail.height() == 0) return false;
850 if (Height == 0 || Width == 0) return false; 849 if (Height == 0 || Width == 0) return false;
851 double d = (double)Height/Width*Thumbnail.width()/Thumbnail.height(); 850 double d = (double)Height/Width*Thumbnail.width()/Thumbnail.height();
852 return (1-JPEG_TOL < d) && (d < 1+JPEG_TOL); 851 return (1-JPEG_TOL < d) && (d < 1+JPEG_TOL);
853} 852}
854 853
855 854
856 855
857static QImage flip_image( const QImage& img ); 856static QImage flip_image( const QImage& img );
858static QImage rotate_90( const QImage& img ); 857static QImage rotate_90( const QImage& img );
859static QImage rotate_180( const QImage& ); 858static QImage rotate_180( const QImage& );
860static QImage rotate_270( const QImage& ); 859static QImage rotate_270( const QImage& );
861 860
862//-------------------------------------------------------------------------- 861//--------------------------------------------------------------------------
863// return a thumbnail that respects the orientation flag 862// return a thumbnail that respects the orientation flag
864// only if it seems sane 863// only if it seems sane
865//-------------------------------------------------------------------------- 864//--------------------------------------------------------------------------
866QImage ExifData::getThumbnail() { 865QImage ExifData::getThumbnail() {
867 if (!isThumbnailSane()) return NULL; 866 if (!isThumbnailSane()) return NULL;
868 if (!Orientation || Orientation == 1) return Thumbnail; 867 if (!Orientation || Orientation == 1) return Thumbnail;
869 868
870 // now fix orientation 869 // now fix orientation
871 870
872 QImage dest = Thumbnail; 871 QImage dest = Thumbnail;
873 switch (Orientation) { // notice intentional fallthroughs 872 switch (Orientation) { // notice intentional fallthroughs
874 case 2: dest = flip_image( dest ); break; 873 case 2: dest = flip_image( dest ); break;
875 case 4: dest = flip_image( dest ); 874 case 4: dest = flip_image( dest );
876 case 3: dest =rotate_180( dest ); break; 875 case 3: dest =rotate_180( dest ); break;
877 case 5: dest = flip_image( dest ); 876 case 5: dest = flip_image( dest );
878 case 6: dest = rotate_90( dest ); break; 877 case 6: dest = rotate_90( dest ); break;
879 case 7: dest = flip_image( dest ); 878 case 7: dest = flip_image( dest );
880 case 8: dest = rotate_270( dest ); break; 879 case 8: dest = rotate_270( dest ); break;
881 default: break; // should never happen 880 default: break; // should never happen
882 } 881 }
883 return dest; 882 return dest;
884} 883}
885 884
886 885
887/* 886/*
888 * 887 *
889 */ 888 */
890static QImage flip_image( const QImage& img ) { 889static QImage flip_image( const QImage& img ) {
891 return img.mirror( TRUE, FALSE ); 890 return img.mirror( TRUE, FALSE );
892} 891}
893 892
894 893
895static QImage dest; 894static QImage dest;
896static int x, y; 895static int x, y;
897static unsigned int *srcData, *destData; // we're not threaded anyway 896static unsigned int *srcData, *destData; // we're not threaded anyway
898static unsigned char *srcData8, *destData8; // 8 bit is char 897static unsigned char *srcData8, *destData8; // 8 bit is char
899static unsigned int *srcTable, *destTable; // destination table 898static unsigned int *srcTable, *destTable; // destination table
900 899
901 900
902static QImage rotate_90_8( const QImage &img ) { 901static QImage rotate_90_8( const QImage &img ) {
903 dest.create(img.height(), img.width(), img.depth()); 902 dest.create(img.height(), img.width(), img.depth());
904 dest.setNumColors(img.numColors()); 903 dest.setNumColors(img.numColors());
905 srcTable = (unsigned int *)img.colorTable(); 904 srcTable = (unsigned int *)img.colorTable();
906 destTable = (unsigned int *)dest.colorTable(); 905 destTable = (unsigned int *)dest.colorTable();
907 for ( x=0; x < img.numColors(); ++x ) 906 for ( x=0; x < img.numColors(); ++x )
908 destTable[x] = srcTable[x]; 907 destTable[x] = srcTable[x];
909 for ( y=0; y < img.height(); ++y ){ 908 for ( y=0; y < img.height(); ++y ){
910 srcData8 = (unsigned char *)img.scanLine(y); 909 srcData8 = (unsigned char *)img.scanLine(y);
911 for ( x=0; x < img.width(); ++x ){ 910 for ( x=0; x < img.width(); ++x ){
912 destData8 = (unsigned char *)dest.scanLine(x); 911 destData8 = (unsigned char *)dest.scanLine(x);
913 destData8[img.height()-y-1] = srcData8[x]; 912 destData8[img.height()-y-1] = srcData8[x];
914 } 913 }
915 } 914 }
916 return dest; 915 return dest;
917} 916}
918 917
919static QImage rotate_90_all( const QImage& img ) { 918static QImage rotate_90_all( const QImage& img ) {
920 dest.create(img.height(), img.width(), img.depth()); 919 dest.create(img.height(), img.width(), img.depth());
921 for ( y=0; y < img.height(); ++y ) { 920 for ( y=0; y < img.height(); ++y ) {
922 srcData = (unsigned int *)img.scanLine(y); 921 srcData = (unsigned int *)img.scanLine(y);
923 for ( x=0; x < img.width(); ++x ) { 922 for ( x=0; x < img.width(); ++x ) {
924 destData = (unsigned int *)dest.scanLine(x); 923 destData = (unsigned int *)dest.scanLine(x);
925 destData[img.height()-y-1] = srcData[x]; 924 destData[img.height()-y-1] = srcData[x];
926 } 925 }
927 } 926 }
928 927
929 return dest; 928 return dest;
930} 929}
931 930
932 931
933static QImage rotate_90( const QImage & img ) { 932static QImage rotate_90( const QImage & img ) {
934 if ( img.depth() > 8) 933 if ( img.depth() > 8)
935 return rotate_90_all( img ); 934 return rotate_90_all( img );
936 else 935 else
937 return rotate_90_8( img ); 936 return rotate_90_8( img );
938} 937}
939 938
940static QImage rotate_180_all( const QImage& img ) { 939static QImage rotate_180_all( const QImage& img ) {
941 dest.create(img.width(), img.height(), img.depth()); 940 dest.create(img.width(), img.height(), img.depth());
942 for ( y=0; y < img.height(); ++y ){ 941 for ( y=0; y < img.height(); ++y ){
943 srcData = (unsigned int *)img.scanLine(y); 942 srcData = (unsigned int *)img.scanLine(y);
944 destData = (unsigned int *)dest.scanLine(img.height()-y-1); 943 destData = (unsigned int *)dest.scanLine(img.height()-y-1);
945 for ( x=0; x < img.width(); ++x ) 944 for ( x=0; x < img.width(); ++x )
946 destData[img.width()-x-1] = srcData[x]; 945 destData[img.width()-x-1] = srcData[x];
947 } 946 }
948 return dest; 947 return dest;
949} 948}
950 949
951static QImage rotate_180_8( const QImage& img ) { 950static QImage rotate_180_8( const QImage& img ) {
952 dest.create(img.width(), img.height(), img.depth()); 951 dest.create(img.width(), img.height(), img.depth());
953 dest.setNumColors(img.numColors()); 952 dest.setNumColors(img.numColors());
954 srcTable = (unsigned int *)img.colorTable(); 953 srcTable = (unsigned int *)img.colorTable();
955 destTable = (unsigned int *)dest.colorTable(); 954 destTable = (unsigned int *)dest.colorTable();
956 for ( x=0; x < img.numColors(); ++x ) 955 for ( x=0; x < img.numColors(); ++x )
957 destTable[x] = srcTable[x]; 956 destTable[x] = srcTable[x];
958 for ( y=0; y < img.height(); ++y ){ 957 for ( y=0; y < img.height(); ++y ){
959 srcData8 = (unsigned char *)img.scanLine(y); 958 srcData8 = (unsigned char *)img.scanLine(y);
960 destData8 = (unsigned char *)dest.scanLine(img.height()-y-1); 959 destData8 = (unsigned char *)dest.scanLine(img.height()-y-1);
961 for ( x=0; x < img.width(); ++x ) 960 for ( x=0; x < img.width(); ++x )
962 destData8[img.width()-x-1] = srcData8[x]; 961 destData8[img.width()-x-1] = srcData8[x];
963 } 962 }
964 return dest; 963 return dest;
965} 964}
966 965
967static QImage rotate_180( const QImage& img ) { 966static QImage rotate_180( const QImage& img ) {
968 if ( img.depth() > 8 ) 967 if ( img.depth() > 8 )
969 return rotate_180_all( img ); 968 return rotate_180_all( img );
970 else 969 else
971 return rotate_180_8( img ); 970 return rotate_180_8( img );
972} 971}
973 972
974 973
975static QImage rotate_270_8( const QImage& img ) { 974static QImage rotate_270_8( const QImage& img ) {
976 dest.create(img.height(), img.width(), img.depth()); 975 dest.create(img.height(), img.width(), img.depth());
977 dest.setNumColors(img.numColors()); 976 dest.setNumColors(img.numColors());
978 srcTable = (unsigned int *)img.colorTable(); 977 srcTable = (unsigned int *)img.colorTable();
979 destTable = (unsigned int *)dest.colorTable(); 978 destTable = (unsigned int *)dest.colorTable();
980 for ( x=0; x < img.numColors(); ++x ) 979 for ( x=0; x < img.numColors(); ++x )
981 destTable[x] = srcTable[x]; 980 destTable[x] = srcTable[x];
982 for ( y=0; y < img.height(); ++y ){ 981 for ( y=0; y < img.height(); ++y ){
983 srcData8 = (unsigned char *)img.scanLine(y); 982 srcData8 = (unsigned char *)img.scanLine(y);
984 for ( x=0; x < img.width(); ++x ){ 983 for ( x=0; x < img.width(); ++x ){
985 destData8 = (unsigned char *)dest.scanLine(img.width()-x-1); 984 destData8 = (unsigned char *)dest.scanLine(img.width()-x-1);
986 destData8[y] = srcData8[x]; 985 destData8[y] = srcData8[x];
987 } 986 }
988 } 987 }
989 988
990 return dest; 989 return dest;
991} 990}
992 991
993static QImage rotate_270_all( const QImage& img ) { 992static QImage rotate_270_all( const QImage& img ) {
994 dest.create(img.height(), img.width(), img.depth()); 993 dest.create(img.height(), img.width(), img.depth());
995 for ( y=0; y < img.height(); ++y ){ 994 for ( y=0; y < img.height(); ++y ){
996 srcData = (unsigned int *)img.scanLine(y); 995 srcData = (unsigned int *)img.scanLine(y);
997 for ( x=0; x < img.width(); ++x ){ 996 for ( x=0; x < img.width(); ++x ){
998 destData = (unsigned int *)dest.scanLine(img.width()-x-1); 997 destData = (unsigned int *)dest.scanLine(img.width()-x-1);
999 destData[y] = srcData[x]; 998 destData[y] = srcData[x];
1000 } 999 }
1001 } 1000 }
1002 return dest; 1001 return dest;
1003} 1002}
1004 1003
1005static QImage rotate_270( const QImage& img ) { 1004static QImage rotate_270( const QImage& img ) {
1006 if ( img.depth() > 8 ) 1005 if ( img.depth() > 8 )
1007 return rotate_270_all( img ); 1006 return rotate_270_all( img );
1008 else 1007 else
1009 return rotate_270_8( img ); 1008 return rotate_270_8( img );
1010} 1009}
1011 1010
1012 1011QString ExifData::color_mode_to_string( bool b ) {
1013static QString color_mode_to_string( bool b ) {
1014 return b ? QObject::tr( "Colormode: Color\n" ) : QObject::tr( "Colormode: Black and white\n" ); 1012 return b ? QObject::tr( "Colormode: Color\n" ) : QObject::tr( "Colormode: Black and white\n" );
1015} 1013}
1016 1014
1017static QString compression_to_string( int level ) { 1015QString ExifData::compression_to_string( int level ) {
1018 QString str; 1016 QString str;
1019 switch( level ) { 1017 switch( level ) {
1020 case 1: 1018 case 1:
1021 str = QObject::tr( "Basic" ); 1019 str = QObject::tr( "Basic" );
1022 break; 1020 break;
1023 case 2: 1021 case 2:
1024 str = QObject::tr( "Normal" ); 1022 str = QObject::tr( "Normal" );
1025 break; 1023 break;
1026 case 4: 1024 case 4:
1027 str = QObject::tr( "Fine" ); 1025 str = QObject::tr( "Fine" );
1028 break; 1026 break;
1029 default: 1027 default:
1030 str = QObject::tr( "Unknown" ); 1028 str = QObject::tr( "Unknown" );
1031 1029
1032 } 1030 }
1033 return QObject::tr("Quality: %1\n").arg(str); 1031 return QObject::tr("Quality: %1\n").arg(str);
1034} 1032}
1035 1033
1036 1034QString ExifData::white_balance_string( int i ) {
1037static QDateTime parseDateTime( const QString& string )
1038{
1039 QDateTime dt;
1040 if ( string.length() != 19 )
1041 return dt;
1042
1043 QString year = string.left( 4 );
1044 QString month = string.mid( 5, 2 );
1045 QString day = string.mid( 8, 2 );
1046 QString hour = string.mid( 11, 2 );
1047 QString minute = string.mid( 14, 2 );
1048 QString seconds = string.mid( 18, 2 );
1049
1050 bool ok;
1051 bool allOk = true;
1052 int y = year.toInt( &ok );
1053 allOk &= ok;
1054
1055 int mo = month.toInt( &ok );
1056 allOk &= ok;
1057
1058 int d = day.toInt( &ok );
1059 allOk &= ok;
1060
1061 int h = hour.toInt( &ok );
1062 allOk &= ok;
1063
1064 int mi = minute.toInt( &ok );
1065 allOk &= ok;
1066
1067 int s = seconds.toInt( &ok );
1068 allOk &= ok;
1069
1070 if ( allOk ) {
1071 dt.setDate( QDate( y, mo, d ) );
1072 dt.setTime( QTime( h, mi, s ) );
1073 }
1074
1075 return dt;
1076}
1077
1078static QString white_balance_string( int i ) {
1079 QString balance; 1035 QString balance;
1080 switch ( i ) { 1036 switch ( i ) {
1081 case 0: 1037 case 0:
1082 balance = QObject::tr( "Unknown" ); 1038 balance = QObject::tr( "Unknown" );
1083 break; 1039 break;
1084 case 1: 1040 case 1:
1085 balance = QObject::tr( "Daylight" ); 1041 balance = QObject::tr( "Daylight" );
1086 break; 1042 break;
1087 case 2: 1043 case 2:
1088 balance = QObject::tr( "Fluorescent" ); 1044 balance = QObject::tr( "Fluorescent" );
1089 break; 1045 break;
1090 case 3: 1046 case 3:
1091 balance = QObject::tr( "Tungsten" ); 1047 balance = QObject::tr( "Tungsten" );
1092 break; 1048 break;
1093 case 17: 1049 case 17:
1094 balance = QObject::tr( "Standard light A" ); 1050 balance = QObject::tr( "Standard light A" );
1095 break; 1051 break;
1096 case 18: 1052 case 18:
1097 balance = QObject::tr( "Standard light B" ); 1053 balance = QObject::tr( "Standard light B" );
1098 break; 1054 break;
1099 case 19: 1055 case 19:
1100 balance = QObject::tr( "Standard light C" ); 1056 balance = QObject::tr( "Standard light C" );
1101 break; 1057 break;
1102 case 20: 1058 case 20:
1103 balance = QObject::tr( "D55" ); 1059 balance = QObject::tr( "D55" );
1104 break; 1060 break;
1105 case 21: 1061 case 21:
1106 balance = QObject::tr( "D65" ); 1062 balance = QObject::tr( "D65" );
1107 break; 1063 break;
1108 case 22: 1064 case 22:
1109 balance = QObject::tr( "D75" ); 1065 balance = QObject::tr( "D75" );
1110 break; 1066 break;
1111 case 255: 1067 case 255:
1112 balance = QObject::tr( "Other" ); 1068 balance = QObject::tr( "Other" );
1113 break; 1069 break;
1114 default: 1070 default:
1115 balance = QObject::tr( "Unknown" ); 1071 balance = QObject::tr( "Unknown" );
1116 } 1072 }
1117 return QObject::tr( "White Balance: %1\n" ).arg( balance ); 1073 return QObject::tr( "White Balance: %1\n" ).arg( balance );
1118 1074
1119} 1075}
1120 1076
1121 1077
1122static QString metering_mode( int i) { 1078QString ExifData::metering_mode( int i) {
1123 QString meter; 1079 QString meter;
1124 switch( i ) { 1080 switch( i ) {
1125 case 0: 1081 case 0:
1126 meter = QObject::tr( "Unknown" ); 1082 meter = QObject::tr( "Unknown" );
1127 break; 1083 break;
1128 case 1: 1084 case 1:
1129 meter = QObject::tr( "Average" ); 1085 meter = QObject::tr( "Average" );
1130 break; 1086 break;
1131 case 2: 1087 case 2:
1132 meter = QObject::tr( "Center weighted average" ); 1088 meter = QObject::tr( "Center weighted average" );
1133 break; 1089 break;
1134 case 3: 1090 case 3:
1135 meter = QObject::tr( "Spot" ); 1091 meter = QObject::tr( "Spot" );
1136 break; 1092 break;
1137 case 4: 1093 case 4:
1138 meter = QObject::tr( "MultiSpot" ); 1094 meter = QObject::tr( "MultiSpot" );
1139 break; 1095 break;
1140 case 5: 1096 case 5:
1141 meter = QObject::tr( "Pattern" ); 1097 meter = QObject::tr( "Pattern" );
1142 break; 1098 break;
1143 case 6: 1099 case 6:
1144 meter = QObject::tr( "Partial" ); 1100 meter = QObject::tr( "Partial" );
1145 break; 1101 break;
1146 case 255: 1102 case 255:
1147 meter = QObject::tr( "Other" ); 1103 meter = QObject::tr( "Other" );
1148 break; 1104 break;
1149 default: 1105 default:
1150 meter = QObject::tr( "Unknown" ); 1106 meter = QObject::tr( "Unknown" );
1151 } 1107 }
1152 1108
1153 return QObject::tr( "Metering Mode: %1\n" ).arg( meter ); 1109 return QObject::tr( "Metering Mode: %1\n" ).arg( meter );
1154} 1110}
1155 1111
1156 1112
1157static QString exposure_program( int i ) { 1113QString ExifData::exposure_program( int i ) {
1158 QString exp; 1114 QString exp;
1159 switch( i ) { 1115 switch( i ) {
1160 case 0: 1116 case 0:
1161 exp = QObject::tr( "Not defined" ); 1117 exp = QObject::tr( "Not defined" );
1162 break; 1118 break;
1163 case 1: 1119 case 1:
1164 exp = QObject::tr( "Manual" ); 1120 exp = QObject::tr( "Manual" );
1165 break; 1121 break;
1166 case 2: 1122 case 2:
1167 exp = QObject::tr( "Normal progam" ); 1123 exp = QObject::tr( "Normal progam" );
1168 break; 1124 break;
1169 case 3: 1125 case 3:
1170 exp = QObject::tr( "Aperture priority" ); 1126 exp = QObject::tr( "Aperture priority" );
1171 break; 1127 break;
1172 case 4: 1128 case 4:
1173 exp = QObject::tr( "Shutter priority" ); 1129 exp = QObject::tr( "Shutter priority" );
1174 break; 1130 break;
1175 case 5: 1131 case 5:
1176 exp = QObject::tr( "Creative progam\n(biased toward fast shutter speed" ); 1132 exp = QObject::tr( "Creative progam\n(biased toward fast shutter speed" );
1177 break; 1133 break;
1178 case 6: 1134 case 6:
1179 exp = QObject::tr( "Action progam\n(biased toward fast shutter speed)" ); 1135 exp = QObject::tr( "Action progam\n(biased toward fast shutter speed)" );
1180 break; 1136 break;
1181 case 7: 1137 case 7:
1182 exp = QObject::tr( "Portrait mode\n(for closeup photos with the background out of focus)" ); 1138 exp = QObject::tr( "Portrait mode\n(for closeup photos with the background out of focus)" );
1183 break; 1139 break;
1184 case 8: 1140 case 8:
1185 exp = QObject::tr( "Landscape mode\n(for landscape photos with the background in focus)" ); 1141 exp = QObject::tr( "Landscape mode\n(for landscape photos with the background in focus)" );
1186 break; 1142 break;
1187 default: 1143 default:
1188 exp = QObject::tr( "Unknown" ); 1144 exp = QObject::tr( "Unknown" );
1189 } 1145 }
1190 1146
1191 return QObject::tr( "Exposure Program: %1\n" ).arg( exp ); 1147 return QObject::tr( "Exposure Program: %1\n" ).arg( exp );
1192} 1148}
1193 1149
1194} // namespace MM 1150} // namespace MM
1195} // namespace OPIE 1151} // namespace OPIE
diff --git a/libopie2/opiemm/opieexif.h b/libopie2/opiemm/opieexif.h
index efaed71..fb06bf8 100644
--- a/libopie2/opiemm/opieexif.h
+++ b/libopie2/opiemm/opieexif.h
@@ -1,139 +1,146 @@
1#ifndef _OPIE_EXIF_H 1#ifndef _OPIE_EXIF_H
2#define _OPIE_EXIF_H 2#define _OPIE_EXIF_H
3 3
4#include <qt.h> 4#include <qt.h>
5#include <qstring.h> 5#include <qstring.h>
6#include <qimage.h> 6#include <qimage.h>
7#include <qfile.h> 7#include <qfile.h>
8 8
9#include <time.h> 9#include <time.h>
10 10
11namespace Opie { namespace MM { 11namespace Opie { namespace MM {
12 12
13#ifndef uchar 13#ifndef uchar
14typedef unsigned char uchar; 14typedef unsigned char uchar;
15#endif 15#endif
16 16
17//#define MAX_SECTIONS 20 17//#define MAX_SECTIONS 20
18//#define PSEUDO_IMAGE_MARKER 0x123; // Extra value. 18//#define PSEUDO_IMAGE_MARKER 0x123; // Extra value.
19 19
20//! Class for reading exif data from images 20//! Class for reading exif data from images
21/*! 21/*!
22 * This class is mostly used inside OImageScrollView for testing jpegs headers for a faster 22 * This class is mostly used inside OImageScrollView for testing jpegs headers for a faster
23 * loading and scaling. It is taken from libexif and converted into an C++ structure. 23 * loading and scaling. It is taken from libexif and converted into an C++ structure.
24 * 24 *
25 * \see OImageScrollView 25 * \see OImageScrollView
26 * \since 1.2 26 * \since 1.2
27 */ 27 */
28class ExifData { 28class ExifData {
29public: 29public:
30 enum ReadMode_t { 30 enum ReadMode_t {
31 READ_EXIF = 1, 31 READ_EXIF = 1,
32 READ_IMAGE = 2, 32 READ_IMAGE = 2,
33 READ_ALL = 3 33 READ_ALL = 3
34 }; 34 };
35 35
36 //-------------------------------------------------------------------------- 36 //--------------------------------------------------------------------------
37 // This structure is used to store jpeg file sections in memory. 37 // This structure is used to store jpeg file sections in memory.
38 struct Section_t { 38 struct Section_t {
39 uchar * Data; 39 uchar * Data;
40 int Type; 40 int Type;
41 unsigned Size; 41 unsigned Size;
42 }; 42 };
43 43
44 struct TagTable_t { 44 struct TagTable_t {
45 unsigned short Tag; 45 unsigned short Tag;
46 const char*const Desc; 46 const char*const Desc;
47 }; 47 };
48 48
49private: 49private:
50 static const int MAX_SECTIONS=20; 50 static const int MAX_SECTIONS=20;
51 static const unsigned int PSEUDO_IMAGE_MARKER=0x123; 51 static const unsigned int PSEUDO_IMAGE_MARKER=0x123;
52 Section_t Sections[MAX_SECTIONS]; 52 Section_t Sections[MAX_SECTIONS];
53 53
54 QString CameraMake; 54 QString CameraMake;
55 QString CameraModel; 55 QString CameraModel;
56 QString DateTime; 56 QString DateTime;
57 int Orientation; 57 int Orientation;
58 int Height, Width; 58 int Height, Width;
59 int ExifImageLength, ExifImageWidth; 59 int ExifImageLength, ExifImageWidth;
60 int IsColor; 60 int IsColor;
61 int Process; 61 int Process;
62 int FlashUsed; 62 int FlashUsed;
63 float FocalLength; 63 float FocalLength;
64 float ExposureTime; 64 float ExposureTime;
65 float ApertureFNumber; 65 float ApertureFNumber;
66 float Distance; 66 float Distance;
67 int Whitebalance; 67 int Whitebalance;
68 int MeteringMode; 68 int MeteringMode;
69 float CCDWidth; 69 float CCDWidth;
70 float ExposureBias; 70 float ExposureBias;
71 int ExposureProgram; 71 int ExposureProgram;
72 int ISOequivalent; 72 int ISOequivalent;
73 int CompressionLevel; 73 int CompressionLevel;
74 QString UserComment; 74 QString UserComment;
75 QString Comment; 75 QString Comment;
76 QImage Thumbnail; 76 QImage Thumbnail;
77 77
78 unsigned char * LastExifRefd; 78 unsigned char * LastExifRefd;
79 int ExifSettingsLength; 79 int ExifSettingsLength;
80 double FocalplaneXRes; 80 double FocalplaneXRes;
81 double FocalplaneUnits; 81 double FocalplaneUnits;
82 int MotorolaOrder; 82 int MotorolaOrder;
83 int SectionsRead; 83 int SectionsRead;
84 84
85 int ReadJpegSections (QFile & infile, ReadMode_t ReadMode); 85 int ReadJpegSections (QFile & infile, ReadMode_t ReadMode);
86 void DiscardData(void); 86 void DiscardData(void);
87 int Get16u(void * Short); 87 int Get16u(void * Short);
88 int Get32s(void * Long); 88 int Get32s(void * Long);
89 unsigned Get32u(void * Long); 89 unsigned Get32u(void * Long);
90 double ConvertAnyFormat(void * ValuePtr, int Format); 90 double ConvertAnyFormat(void * ValuePtr, int Format);
91 void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength); 91 void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength);
92 void process_COM (const uchar * Data, int length); 92 void process_COM (const uchar * Data, int length);
93 void process_SOFn (const uchar * Data, int marker); 93 void process_SOFn (const uchar * Data, int marker);
94 int Get16m(const void * Short); 94 int Get16m(const void * Short);
95 void process_EXIF(unsigned char * CharBuf, unsigned int length); 95 void process_EXIF(unsigned char * CharBuf, unsigned int length);
96 int Exif2tm(struct ::tm * timeptr, char * ExifTime); 96 int Exif2tm(struct ::tm * timeptr, char * ExifTime);
97 97
98public: 98public:
99 //! Contructor for initialising 99 //! Contructor for initialising
100 ExifData(); 100 ExifData();
101 //! destructor 101 //! destructor
102 virtual ~ExifData(); 102 virtual ~ExifData();
103 //! scan a given file 103 //! scan a given file
104 /*! 104 /*!
105 * try to scan the EXIF data of a image file 105 * try to scan the EXIF data of a image file
106 * \param aFile the file to scan 106 * \param aFile the file to scan
107 * \return true if success, otherwise false 107 * \return true if success, otherwise false
108 */ 108 */
109 bool scan(const QString &aFile); 109 bool scan(const QString &aFile);
110 QString getCameraMake() { return CameraMake; } 110 QString getCameraMake() { return CameraMake; }
111 QString getCameraModel() { return CameraModel; } 111 QString getCameraModel() { return CameraModel; }
112 QString getDateTime() { return DateTime; } 112 QString getDateTime() { return DateTime; }
113 int getOrientation() { return Orientation; } 113 int getOrientation() { return Orientation; }
114 int getHeight() { return Height; } 114 int getHeight() { return Height; }
115 int getWidth() { return Width; } 115 int getWidth() { return Width; }
116 int getIsColor() { return IsColor; } 116 int getIsColor() { return IsColor; }
117 int getProcess() { return Process; } 117 int getProcess() { return Process; }
118 int getFlashUsed() { return FlashUsed; } 118 int getFlashUsed() { return FlashUsed; }
119 float getFocalLength() { return FocalLength; } 119 float getFocalLength() { return FocalLength; }
120 float getExposureTime() { return ExposureTime; } 120 float getExposureTime() { return ExposureTime; }
121 float getApertureFNumber() { return ApertureFNumber; } 121 float getApertureFNumber() { return ApertureFNumber; }
122 float getDistance() { return Distance; } 122 float getDistance() { return Distance; }
123 int getWhitebalance() { return Whitebalance; } 123 int getWhitebalance() { return Whitebalance; }
124 int getMeteringMode() { return MeteringMode; } 124 int getMeteringMode() { return MeteringMode; }
125 float getCCDWidth() { return CCDWidth; } 125 float getCCDWidth() { return CCDWidth; }
126 float getExposureBias() { return ExposureBias; } 126 float getExposureBias() { return ExposureBias; }
127 int getExposureProgram() { return ExposureProgram; } 127 int getExposureProgram() { return ExposureProgram; }
128 int getISOequivalent() { return ISOequivalent; } 128 int getISOequivalent() { return ISOequivalent; }
129 int getCompressionLevel() { return CompressionLevel; } 129 int getCompressionLevel() { return CompressionLevel; }
130 QString getUserComment() { return UserComment; } 130 QString getUserComment() { return UserComment; }
131 QString getComment() { return Comment; } 131 QString getComment() { return Comment; }
132 QImage getThumbnail(); 132 QImage getThumbnail();
133 bool isThumbnailSane(); 133 bool isThumbnailSane();
134 bool isNullThumbnail() { return !isThumbnailSane(); } 134 bool isNullThumbnail() { return !isThumbnailSane(); }
135
136 // some helpers
137 static QString color_mode_to_string( bool b );
138 static QString compression_to_string( int level );
139 static QString white_balance_string( int i );
140 static QString metering_mode( int i);
141 static QString exposure_program( int i );
135}; 142};
136 143
137} 144}
138} 145}
139#endif 146#endif