00001 #include "opieexif.h"
00002
00003
00004 #include <opie2/odebug.h>
00005 #include <qpe/timestring.h>
00006
00007 #include <qobject.h>
00008 #include <qimage.h>
00009
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <math.h>
00017 #include <time.h>
00018
00019 #include <qstring.h>
00020 #include <qfile.h>
00021 #include <qimage.h>
00022
00023
00024
00025
00026
00027
00028 #define M_SOF0 0xC0 // Start Of Frame N
00029 #define M_SOF1 0xC1 // N indicates which compression process
00030 #define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use
00031 #define M_SOF3 0xC3
00032 #define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers
00033 #define M_SOF6 0xC6
00034 #define M_SOF7 0xC7
00035 #define M_SOF9 0xC9
00036 #define M_SOF10 0xCA
00037 #define M_SOF11 0xCB
00038 #define M_SOF13 0xCD
00039 #define M_SOF14 0xCE
00040 #define M_SOF15 0xCF
00041 #define M_SOI 0xD8 // Start Of Image (beginning of datastream)
00042 #define M_EOI 0xD9 // End Of Image (end of datastream)
00043 #define M_SOS 0xDA // Start Of Scan (begins compressed data)
00044 #define M_JFIF 0xE0 // Jfif marker
00045 #define M_EXIF 0xE1 // Exif marker
00046 #define M_COM 0xFE // COMment
00047
00048
00049
00050
00051 static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
00052 #define NUM_FORMATS 12
00053
00054 #define FMT_BYTE 1
00055 #define FMT_STRING 2
00056 #define FMT_USHORT 3
00057 #define FMT_ULONG 4
00058 #define FMT_URATIONAL 5
00059 #define FMT_SBYTE 6
00060 #define FMT_UNDEFINED 7
00061 #define FMT_SSHORT 8
00062 #define FMT_SLONG 9
00063 #define FMT_SRATIONAL 10
00064 #define FMT_SINGLE 11
00065 #define FMT_DOUBLE 12
00066
00067
00068
00069
00070 #define TAG_EXIF_OFFSET 0x8769
00071 #define TAG_INTEROP_OFFSET 0xa005
00072
00073 #define TAG_MAKE 0x010F
00074 #define TAG_MODEL 0x0110
00075 #define TAG_ORIENTATION 0x0112
00076
00077 #define TAG_EXPOSURETIME 0x829A
00078 #define TAG_FNUMBER 0x829D
00079
00080 #define TAG_SHUTTERSPEED 0x9201
00081 #define TAG_APERTURE 0x9202
00082 #define TAG_MAXAPERTURE 0x9205
00083 #define TAG_FOCALLENGTH 0x920A
00084
00085 #define TAG_DATETIME_ORIGINAL 0x9003
00086 #define TAG_USERCOMMENT 0x9286
00087
00088 #define TAG_SUBJECT_DISTANCE 0x9206
00089 #define TAG_FLASH 0x9209
00090
00091 #define TAG_FOCALPLANEXRES 0xa20E
00092 #define TAG_FOCALPLANEUNITS 0xa210
00093 #define TAG_EXIF_IMAGEWIDTH 0xA002
00094 #define TAG_EXIF_IMAGELENGTH 0xA003
00095
00096
00097 #define TAG_EXPOSURE_BIAS 0x9204
00098 #define TAG_WHITEBALANCE 0x9208
00099 #define TAG_METERING_MODE 0x9207
00100 #define TAG_EXPOSURE_PROGRAM 0x8822
00101 #define TAG_ISO_EQUIVALENT 0x8827
00102 #define TAG_COMPRESSION_LEVEL 0x9102
00103
00104 #define TAG_THUMBNAIL_OFFSET 0x0201
00105 #define TAG_THUMBNAIL_LENGTH 0x0202
00106
00107
00108
00109 namespace Opie {
00110
00111 namespace MM {
00112
00113 class FatalError {
00114 const char* ex;
00115 public:
00116 FatalError(const char* s) { ex = s; }
00117 void debug_print() const { owarn << "exception: " << ex << "" << oendl; }
00118 };
00119
00120 ExifData::TagTable_t ProcessTable[] = {
00121 { M_SOF0, "Baseline"},
00122 { M_SOF1, "Extended sequential"},
00123 { M_SOF2, "Progressive"},
00124 { M_SOF3, "Lossless"},
00125 { M_SOF5, "Differential sequential"},
00126 { M_SOF6, "Differential progressive"},
00127 { M_SOF7, "Differential lossless"},
00128 { M_SOF9, "Extended sequential, arithmetic coding"},
00129 { M_SOF10, "Progressive, arithmetic coding"},
00130 { M_SOF11, "Lossless, arithmetic coding"},
00131 { M_SOF13, "Differential sequential, arithmetic coding"},
00132 { M_SOF14, "Differential progressive, arithmetic coding"},
00133 { M_SOF15, "Differential lossless, arithmetic coding"},
00134 { 0, "Unknown"}
00135 };
00136
00137
00138
00139
00140 int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode)
00141 {
00142 int a;
00143
00144 a = infile.getch();
00145
00146 if (a != 0xff || infile.getch() != M_SOI) {
00147 SectionsRead = 0;
00148 return false;
00149 }
00150 for(SectionsRead = 0; SectionsRead < MAX_SECTIONS-1; ){
00151 int marker = 0;
00152 int got;
00153 unsigned int ll,lh;
00154 unsigned int itemlen;
00155 uchar * Data;
00156
00157 for (a=0;a<7;a++){
00158 marker = infile.getch();
00159 if (marker != 0xff) break;
00160
00161 if (a >= 6){
00162
00163 owarn << "too many padding bytes" << oendl;
00164 return false;
00165
00166 }
00167 }
00168
00169 if (marker == 0xff){
00170
00171 return false;
00172 }
00173
00174 Sections[SectionsRead].Type = marker;
00175
00176
00177 lh = (uchar) infile.getch();
00178 ll = (uchar) infile.getch();
00179
00180 itemlen = (lh << 8) | ll;
00181
00182 if (itemlen < 2) {
00183 return false;;
00184 }
00185
00186 Sections[SectionsRead].Size = itemlen;
00187
00188 Data = (uchar *)malloc(itemlen+1);
00189 Sections[SectionsRead].Data = Data;
00190
00191
00192 Data[0] = (uchar)lh;
00193 Data[1] = (uchar)ll;
00194
00195 got = infile.readBlock((char*)Data+2, itemlen-2);
00196 if (( unsigned ) got != itemlen-2){
00197 return false;
00198 }
00199 SectionsRead++;
00200
00201 switch(marker){
00202
00203 case M_SOS:
00204
00205 if (ReadMode & READ_IMAGE){
00206 unsigned long size;
00207
00208 size = QMAX( 0ul, infile.size()-infile.at() );
00209 Data = (uchar *)malloc(size);
00210 if (Data == NULL){
00211 return false;
00212 }
00213
00214 got = infile.readBlock((char*)Data, size);
00215 if (( unsigned ) got != size){
00216 return false;
00217 }
00218
00219 Sections[SectionsRead].Data = Data;
00220 Sections[SectionsRead].Size = size;
00221 Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;
00222 SectionsRead ++;
00223
00224 }
00225 return true;
00226
00227 case M_EOI:
00228 owarn << "No image in jpeg!" << oendl;
00229 return false;
00230
00231 case M_COM:
00232
00233
00234
00235 process_COM(Data, itemlen);
00236 break;
00237
00238 case M_JFIF:
00239
00240
00241
00242
00243 free(Sections[--SectionsRead].Data);
00244 break;
00245
00246 case M_EXIF:
00247
00248
00249
00250 if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){
00251 process_EXIF((uchar *)Data, itemlen);
00252 }else{
00253
00254 free(Sections[--SectionsRead].Data);
00255 }
00256 break;
00257
00258 case M_SOF0:
00259 case M_SOF1:
00260 case M_SOF2:
00261 case M_SOF3:
00262 case M_SOF5:
00263 case M_SOF6:
00264 case M_SOF7:
00265 case M_SOF9:
00266 case M_SOF10:
00267 case M_SOF11:
00268 case M_SOF13:
00269 case M_SOF14:
00270 case M_SOF15:
00271 process_SOFn(Data, marker);
00272 default:
00273 break;
00274 break;
00275 }
00276 }
00277 return true;
00278 }
00279
00280
00281
00282
00283 void ExifData::DiscardData(void)
00284 {
00285 for (int a=0; a < SectionsRead; a++)
00286 free(Sections[a].Data);
00287 SectionsRead = 0;
00288 }
00289
00290
00291
00292
00293 int ExifData::Get16u(void * Short)
00294 {
00295 if (MotorolaOrder){
00296 return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
00297 }else{
00298 return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0];
00299 }
00300 }
00301
00302
00303
00304
00305 int ExifData::Get32s(void * Long)
00306 {
00307 if (MotorolaOrder){
00308 return ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16)
00309 | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 );
00310 }else{
00311 return ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16)
00312 | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 );
00313 }
00314 }
00315
00316
00317
00318
00319 unsigned ExifData::Get32u(void * Long)
00320 {
00321 return (unsigned)Get32s(Long) & 0xffffffff;
00322 }
00323
00324
00325
00326
00327 double ExifData::ConvertAnyFormat(void * ValuePtr, int Format)
00328 {
00329 double Value;
00330 Value = 0;
00331
00332 switch(Format){
00333 case FMT_SBYTE: Value = *(signed char *)ValuePtr; break;
00334 case FMT_BYTE: Value = *(uchar *)ValuePtr; break;
00335
00336 case FMT_USHORT: Value = Get16u(ValuePtr); break;
00337
00338 case FMT_ULONG: Value = Get32u(ValuePtr); break;
00339
00340 case FMT_URATIONAL:
00341 case FMT_SRATIONAL:
00342 {
00343 int Num,Den;
00344 Num = Get32s(ValuePtr);
00345 Den = Get32s(4+(char *)ValuePtr);
00346 if (Den == 0){
00347 Value = 0;
00348 }else{
00349 Value = (double)Num/Den;
00350 }
00351 break;
00352 }
00353
00354 case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break;
00355 case FMT_SLONG: Value = Get32s(ValuePtr); break;
00356
00357
00358 case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;
00359 case FMT_DOUBLE: Value = *(double *)ValuePtr; break;
00360 }
00361 return Value;
00362 }
00363
00364
00365
00366
00367 void ExifData::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength)
00368 {
00369 int de;
00370 int a;
00371 int NumDirEntries;
00372 unsigned ThumbnailOffset = 0;
00373 unsigned ThumbnailSize = 0;
00374
00375 NumDirEntries = Get16u(DirStart);
00376 #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
00377
00378 {
00379 unsigned char * DirEnd;
00380 DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
00381 if (DirEnd+4 > (OffsetBase+ExifLength)){
00382 if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){
00383
00384
00385 }else{
00386
00387
00388 return;
00389 }
00390 }
00391 if (DirEnd < LastExifRefd) LastExifRefd = DirEnd;
00392 }
00393
00394 for (de=0;de<NumDirEntries;de++){
00395 int Tag, Format, Components;
00396 unsigned char * ValuePtr;
00397 int ByteCount;
00398 char * DirEntry;
00399 DirEntry = (char *)DIR_ENTRY_ADDR(DirStart, de);
00400
00401 Tag = Get16u(DirEntry);
00402 Format = Get16u(DirEntry+2);
00403 Components = Get32u(DirEntry+4);
00404
00405 if ((Format-1) >= NUM_FORMATS) {
00406
00407 return;
00408 }
00409
00410 ByteCount = Components * BytesPerFormat[Format];
00411
00412 if (ByteCount > 4){
00413 unsigned OffsetVal;
00414 OffsetVal = Get32u(DirEntry+8);
00415
00416 if (OffsetVal+ByteCount > ExifLength){
00417
00418
00419
00420 return;
00421 }
00422 ValuePtr = OffsetBase+OffsetVal;
00423 }else{
00424
00425 ValuePtr = (unsigned char *)DirEntry+8;
00426 }
00427
00428 if (LastExifRefd < ValuePtr+ByteCount){
00429
00430
00431 LastExifRefd = ValuePtr+ByteCount;
00432 }
00433
00434
00435 switch(Tag){
00436
00437 case TAG_MAKE:
00438 ExifData::CameraMake = QString((char*)ValuePtr);
00439 break;
00440
00441 case TAG_MODEL:
00442 ExifData::CameraModel = QString((char*)ValuePtr);
00443 break;
00444
00445 case TAG_ORIENTATION:
00446 Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
00447 break;
00448
00449 case TAG_DATETIME_ORIGINAL:
00450 DateTime = QString((char*)ValuePtr);
00451 break;
00452
00453 case TAG_USERCOMMENT:
00454
00455 for (a=ByteCount;;){
00456 a--;
00457 if ((ValuePtr)[a] == ' '){
00458 (ValuePtr)[a] = '\0';
00459 }else{
00460 break;
00461 }
00462 if (a == 0) break;
00463 }
00464
00465
00466 if (memcmp(ValuePtr, "ASCII",5) == 0){
00467 for (a=5;a<10;a++){
00468 int c;
00469 c = (ValuePtr)[a];
00470 if (c != '\0' && c != ' '){
00471
00472 UserComment.sprintf("%s", (const char*)(a+ValuePtr));
00473 break;
00474 }
00475 }
00476 }else{
00477
00478 UserComment.sprintf("%s", (const char*)ValuePtr);
00479 }
00480 break;
00481
00482 case TAG_FNUMBER:
00483
00484
00485 ExifData::ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
00486 break;
00487
00488 case TAG_APERTURE:
00489 case TAG_MAXAPERTURE:
00490
00491
00492 if (ExifData::ApertureFNumber == 0){
00493 ExifData::ApertureFNumber
00494 = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
00495 }
00496 break;
00497
00498 case TAG_FOCALLENGTH:
00499
00500
00501 ExifData::FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
00502 break;
00503
00504 case TAG_SUBJECT_DISTANCE:
00505
00506
00507 ExifData::Distance = (float)ConvertAnyFormat(ValuePtr, Format);
00508 break;
00509
00510 case TAG_EXPOSURETIME:
00511
00512
00513 ExifData::ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
00514 break;
00515
00516 case TAG_SHUTTERSPEED:
00517
00518
00519 if (ExifData::ExposureTime == 0){
00520 ExifData::ExposureTime
00521 = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
00522 }
00523 break;
00524
00525 case TAG_FLASH:
00526 if (ConvertAnyFormat(ValuePtr, Format)){
00527 ExifData::FlashUsed = 1;
00528 }
00529 break;
00530
00531 case TAG_EXIF_IMAGELENGTH:
00532 ExifImageLength = (int)ConvertAnyFormat(ValuePtr, Format);
00533 break;
00534
00535 case TAG_EXIF_IMAGEWIDTH:
00536 ExifImageWidth = (int)ConvertAnyFormat(ValuePtr, Format);
00537 break;
00538
00539 case TAG_FOCALPLANEXRES:
00540 FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
00541 break;
00542
00543 case TAG_FOCALPLANEUNITS:
00544 switch((int)ConvertAnyFormat(ValuePtr, Format)){
00545 case 1: FocalplaneUnits = 25.4; break;
00546 case 2:
00547
00548
00549
00550 FocalplaneUnits = 25.4;
00551 break;
00552
00553 case 3: FocalplaneUnits = 10; break;
00554 case 4: FocalplaneUnits = 1; break;
00555 case 5: FocalplaneUnits = .001; break;
00556 }
00557 break;
00558
00559
00560
00561 case TAG_EXPOSURE_BIAS:
00562 ExifData::ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
00563 break;
00564
00565 case TAG_WHITEBALANCE:
00566 ExifData::Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
00567 break;
00568
00569 case TAG_METERING_MODE:
00570 ExifData::MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
00571 break;
00572
00573 case TAG_EXPOSURE_PROGRAM:
00574 ExifData::ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
00575 break;
00576
00577 case TAG_ISO_EQUIVALENT:
00578 ExifData::ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
00579 if ( ExifData::ISOequivalent < 50 ) ExifData::ISOequivalent *= 200;
00580 break;
00581
00582 case TAG_COMPRESSION_LEVEL:
00583 ExifData::CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format);
00584 break;
00585
00586 case TAG_THUMBNAIL_OFFSET:
00587 ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
00588 break;
00589
00590 case TAG_THUMBNAIL_LENGTH:
00591 ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
00592 break;
00593
00594 }
00595
00596 if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){
00597 unsigned char * SubdirStart;
00598 SubdirStart = OffsetBase + Get32u(ValuePtr);
00599 if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
00600 return;
00601 }
00602 ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
00603 continue;
00604 }
00605 }
00606
00607 {
00608
00609
00610
00611 unsigned char * SubdirStart;
00612 unsigned Offset;
00613
00614 if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){
00615 Offset = Get32u(DIR_ENTRY_ADDR(DirStart, NumDirEntries));
00616
00617
00618
00619 if (Offset && Offset < ExifLength){
00620 SubdirStart = OffsetBase + Offset;
00621 if (SubdirStart > OffsetBase+ExifLength){
00622 if (SubdirStart < OffsetBase+ExifLength+20){
00623
00624
00625
00626 owarn << "Thumbnail removed with Jhead 1.3 or earlier" << oendl;
00627 }else{
00628 return;
00629 }
00630 }else{
00631 if (SubdirStart <= OffsetBase+ExifLength){
00632 ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
00633 }
00634 }
00635 }
00636 }else{
00637
00638 }
00639 }
00640
00641 if (ThumbnailSize && ThumbnailOffset){
00642 if (ThumbnailSize + ThumbnailOffset <= ExifLength){
00643
00644 Thumbnail.loadFromData(OffsetBase + ThumbnailOffset, ThumbnailSize, "JPEG");
00645 }
00646 }
00647 }
00648
00649
00650
00651
00652
00653
00654
00655 void ExifData::process_COM (const uchar * Data, int length)
00656 {
00657 QChar ch;
00658 int a;
00659
00660 for (a=2;a<length;a++){
00661 ch = Data[a];
00662 if (ch == '\000') continue;
00663 Comment.append(ch);
00664 }
00665 }
00666
00667
00668
00669
00670
00671 void ExifData::process_SOFn (const uchar * Data, int marker)
00672 {
00673 int data_precision, num_components;
00674
00675 data_precision = Data[2];
00676 ExifData::Height = Get16m(Data+3);
00677 ExifData::Width = Get16m(Data+5);
00678 num_components = Data[7];
00679
00680 if (num_components == 3){
00681 ExifData::IsColor = 1;
00682 }else{
00683 ExifData::IsColor = 0;
00684 }
00685
00686 ExifData::Process = marker;
00687
00688 }
00689
00690
00691
00692
00693 int ExifData::Get16m(const void * Short)
00694 {
00695 return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
00696 }
00697
00698
00699
00700
00701
00702
00703 void ExifData::process_EXIF(unsigned char * CharBuf, unsigned int length)
00704 {
00705 ExifData::FlashUsed = 0;
00706
00707 FocalplaneXRes = 0;
00708 FocalplaneUnits = 0;
00709 ExifImageWidth = 0;
00710 ExifImageLength = 0;
00711
00712 {
00713 static const uchar ExifHeader[] = "Exif\0\0";
00714 if (memcmp(CharBuf+2, ExifHeader,6)){
00715 return;
00716 }
00717 }
00718
00719 if (memcmp(CharBuf+8,"II",2) == 0){
00720
00721 MotorolaOrder = 0;
00722 }else{
00723 if (memcmp(CharBuf+8,"MM",2) == 0){
00724
00725 MotorolaOrder = 1;
00726 }else{
00727 return;
00728 }
00729 }
00730
00731
00732 if (Get16u(CharBuf+10) != 0x2a
00733 || Get32u(CharBuf+12) != 0x08){
00734 return;
00735 }
00736
00737 LastExifRefd = CharBuf;
00738
00739
00740 ProcessExifDir(CharBuf+16, CharBuf+8, length-6);
00741
00742
00743 ExifSettingsLength = LastExifRefd - CharBuf;
00744
00745
00746 if (FocalplaneXRes != 0){
00747 ExifData::CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
00748 }
00749 }
00750
00751
00752
00753
00754 int ExifData::Exif2tm(struct ::tm * timeptr, char * ExifTime)
00755 {
00756 int a;
00757
00758 timeptr->tm_wday = -1;
00759
00760
00761 a = sscanf(ExifTime, "%d:%d:%d %d:%d:%d",
00762 &timeptr->tm_year, &timeptr->tm_mon, &timeptr->tm_mday,
00763 &timeptr->tm_hour, &timeptr->tm_min, &timeptr->tm_sec);
00764
00765 if (a == 6){
00766 timeptr->tm_isdst = -1;
00767 timeptr->tm_mon -= 1;
00768 timeptr->tm_year -= 1900;
00769 return true;
00770 }
00771
00772 return false;
00773 }
00774
00775
00776
00777
00778 ExifData::ExifData()
00779 {
00780 ExifData::Whitebalance = -1;
00781 ExifData::MeteringMode = -1;
00782 ExifData::FlashUsed = -1;
00783 Orientation = 0;
00784 Height = 0;
00785 Width = 0;
00786 IsColor = 0;
00787 Process = 0;
00788 FocalLength = 0;
00789 ExposureTime = 0;
00790 ApertureFNumber = 0;
00791 Distance = 0;
00792 CCDWidth = 0;
00793 ExposureBias = 0;
00794 ExposureProgram = 0;
00795 ISOequivalent = 0;
00796 CompressionLevel = 0;
00797 MotorolaOrder = 0;
00798 }
00799
00800 ExifData::~ExifData()
00801 {
00802 }
00803
00804
00805
00806
00807 bool ExifData::scan(const QString & path)
00808 {
00809 int ret;
00810
00811 QFile f(path);
00812 f.open(IO_ReadOnly);
00813
00814
00815 ret = ReadJpegSections(f, READ_EXIF);
00816
00817 if (ret == false){
00818 owarn << "Not JPEG file!" << oendl;
00819 DiscardData();
00820 f.close();
00821 return false;
00822 }
00823 f.close();
00824 DiscardData();
00825
00826
00827
00828 CameraMake = CameraMake.stripWhiteSpace();
00829 CameraModel = CameraModel.stripWhiteSpace();
00830 UserComment = UserComment.stripWhiteSpace();
00831 Comment = Comment.stripWhiteSpace();
00832 return true;
00833 }
00834
00835
00836
00837
00838 #ifndef JPEG_TOL
00839 #define JPEG_TOL 0.02
00840 #endif
00841 bool ExifData::isThumbnailSane() {
00842 if (Thumbnail.isNull()) return false;
00843
00844
00845
00846 if (ExifImageLength != 0 && ExifImageLength != Height) return false;
00847 if (ExifImageWidth != 0 && ExifImageWidth != Width) return false;
00848 if (Thumbnail.width() == 0 || Thumbnail.height() == 0) return false;
00849 if (Height == 0 || Width == 0) return false;
00850 double d = (double)Height/Width*Thumbnail.width()/Thumbnail.height();
00851 return (1-JPEG_TOL < d) && (d < 1+JPEG_TOL);
00852 }
00853
00854
00855
00856 static QImage flip_image( const QImage& img );
00857 static QImage rotate_90( const QImage& img );
00858 static QImage rotate_180( const QImage& );
00859 static QImage rotate_270( const QImage& );
00860
00861
00862
00863
00864
00865 QImage ExifData::getThumbnail() {
00866 if (!isThumbnailSane()) return NULL;
00867 if (!Orientation || Orientation == 1) return Thumbnail;
00868
00869
00870
00871 QImage dest = Thumbnail;
00872 switch (Orientation) {
00873 case 2: dest = flip_image( dest ); break;
00874 case 4: dest = flip_image( dest );
00875 case 3: dest =rotate_180( dest ); break;
00876 case 5: dest = flip_image( dest );
00877 case 6: dest = rotate_90( dest ); break;
00878 case 7: dest = flip_image( dest );
00879 case 8: dest = rotate_270( dest ); break;
00880 default: break;
00881 }
00882 return dest;
00883 }
00884
00885
00886
00887
00888
00889 static QImage flip_image( const QImage& img ) {
00890 return img.mirror( TRUE, FALSE );
00891 }
00892
00893
00894 static QImage dest;
00895 static int x, y;
00896 static unsigned int *srcData, *destData;
00897 static unsigned char *srcData8, *destData8;
00898 static unsigned int *srcTable, *destTable;
00899
00900
00901 static QImage rotate_90_8( const QImage &img ) {
00902 dest.create(img.height(), img.width(), img.depth());
00903 dest.setNumColors(img.numColors());
00904 srcTable = (unsigned int *)img.colorTable();
00905 destTable = (unsigned int *)dest.colorTable();
00906 for ( x=0; x < img.numColors(); ++x )
00907 destTable[x] = srcTable[x];
00908 for ( y=0; y < img.height(); ++y ){
00909 srcData8 = (unsigned char *)img.scanLine(y);
00910 for ( x=0; x < img.width(); ++x ){
00911 destData8 = (unsigned char *)dest.scanLine(x);
00912 destData8[img.height()-y-1] = srcData8[x];
00913 }
00914 }
00915 return dest;
00916 }
00917
00918 static QImage rotate_90_all( const QImage& img ) {
00919 dest.create(img.height(), img.width(), img.depth());
00920 for ( y=0; y < img.height(); ++y ) {
00921 srcData = (unsigned int *)img.scanLine(y);
00922 for ( x=0; x < img.width(); ++x ) {
00923 destData = (unsigned int *)dest.scanLine(x);
00924 destData[img.height()-y-1] = srcData[x];
00925 }
00926 }
00927
00928 return dest;
00929 }
00930
00931
00932 static QImage rotate_90( const QImage & img ) {
00933 if ( img.depth() > 8)
00934 return rotate_90_all( img );
00935 else
00936 return rotate_90_8( img );
00937 }
00938
00939 static QImage rotate_180_all( const QImage& img ) {
00940 dest.create(img.width(), img.height(), img.depth());
00941 for ( y=0; y < img.height(); ++y ){
00942 srcData = (unsigned int *)img.scanLine(y);
00943 destData = (unsigned int *)dest.scanLine(img.height()-y-1);
00944 for ( x=0; x < img.width(); ++x )
00945 destData[img.width()-x-1] = srcData[x];
00946 }
00947 return dest;
00948 }
00949
00950 static QImage rotate_180_8( const QImage& img ) {
00951 dest.create(img.width(), img.height(), img.depth());
00952 dest.setNumColors(img.numColors());
00953 srcTable = (unsigned int *)img.colorTable();
00954 destTable = (unsigned int *)dest.colorTable();
00955 for ( x=0; x < img.numColors(); ++x )
00956 destTable[x] = srcTable[x];
00957 for ( y=0; y < img.height(); ++y ){
00958 srcData8 = (unsigned char *)img.scanLine(y);
00959 destData8 = (unsigned char *)dest.scanLine(img.height()-y-1);
00960 for ( x=0; x < img.width(); ++x )
00961 destData8[img.width()-x-1] = srcData8[x];
00962 }
00963 return dest;
00964 }
00965
00966 static QImage rotate_180( const QImage& img ) {
00967 if ( img.depth() > 8 )
00968 return rotate_180_all( img );
00969 else
00970 return rotate_180_8( img );
00971 }
00972
00973
00974 static QImage rotate_270_8( const QImage& img ) {
00975 dest.create(img.height(), img.width(), img.depth());
00976 dest.setNumColors(img.numColors());
00977 srcTable = (unsigned int *)img.colorTable();
00978 destTable = (unsigned int *)dest.colorTable();
00979 for ( x=0; x < img.numColors(); ++x )
00980 destTable[x] = srcTable[x];
00981 for ( y=0; y < img.height(); ++y ){
00982 srcData8 = (unsigned char *)img.scanLine(y);
00983 for ( x=0; x < img.width(); ++x ){
00984 destData8 = (unsigned char *)dest.scanLine(img.width()-x-1);
00985 destData8[y] = srcData8[x];
00986 }
00987 }
00988
00989 return dest;
00990 }
00991
00992 static QImage rotate_270_all( const QImage& img ) {
00993 dest.create(img.height(), img.width(), img.depth());
00994 for ( y=0; y < img.height(); ++y ){
00995 srcData = (unsigned int *)img.scanLine(y);
00996 for ( x=0; x < img.width(); ++x ){
00997 destData = (unsigned int *)dest.scanLine(img.width()-x-1);
00998 destData[y] = srcData[x];
00999 }
01000 }
01001 return dest;
01002 }
01003
01004 static QImage rotate_270( const QImage& img ) {
01005 if ( img.depth() > 8 )
01006 return rotate_270_all( img );
01007 else
01008 return rotate_270_8( img );
01009 }
01010
01011 QString ExifData::color_mode_to_string( bool b ) {
01012 return b ? QObject::tr( "Colormode: Color\n" ) : QObject::tr( "Colormode: Black and white\n" );
01013 }
01014
01015 QString ExifData::compression_to_string( int level ) {
01016 QString str;
01017 switch( level ) {
01018 case 1:
01019 str = QObject::tr( "Basic" );
01020 break;
01021 case 2:
01022 str = QObject::tr( "Normal" );
01023 break;
01024 case 4:
01025 str = QObject::tr( "Fine" );
01026 break;
01027 default:
01028 str = QObject::tr( "Unknown" );
01029
01030 }
01031 return QObject::tr("Quality: %1\n").arg(str);
01032 }
01033
01034 QString ExifData::white_balance_string( int i ) {
01035 QString balance;
01036 switch ( i ) {
01037 case 0:
01038 balance = QObject::tr( "Unknown" );
01039 break;
01040 case 1:
01041 balance = QObject::tr( "Daylight" );
01042 break;
01043 case 2:
01044 balance = QObject::tr( "Fluorescent" );
01045 break;
01046 case 3:
01047 balance = QObject::tr( "Tungsten" );
01048 break;
01049 case 17:
01050 balance = QObject::tr( "Standard light A" );
01051 break;
01052 case 18:
01053 balance = QObject::tr( "Standard light B" );
01054 break;
01055 case 19:
01056 balance = QObject::tr( "Standard light C" );
01057 break;
01058 case 20:
01059 balance = QObject::tr( "D55" );
01060 break;
01061 case 21:
01062 balance = QObject::tr( "D65" );
01063 break;
01064 case 22:
01065 balance = QObject::tr( "D75" );
01066 break;
01067 case 255:
01068 balance = QObject::tr( "Other" );
01069 break;
01070 default:
01071 balance = QObject::tr( "Unknown" );
01072 }
01073 return QObject::tr( "White Balance: %1\n" ).arg( balance );
01074
01075 }
01076
01077
01078 QString ExifData::metering_mode( int i) {
01079 QString meter;
01080 switch( i ) {
01081 case 0:
01082 meter = QObject::tr( "Unknown" );
01083 break;
01084 case 1:
01085 meter = QObject::tr( "Average" );
01086 break;
01087 case 2:
01088 meter = QObject::tr( "Center weighted average" );
01089 break;
01090 case 3:
01091 meter = QObject::tr( "Spot" );
01092 break;
01093 case 4:
01094 meter = QObject::tr( "MultiSpot" );
01095 break;
01096 case 5:
01097 meter = QObject::tr( "Pattern" );
01098 break;
01099 case 6:
01100 meter = QObject::tr( "Partial" );
01101 break;
01102 case 255:
01103 meter = QObject::tr( "Other" );
01104 break;
01105 default:
01106 meter = QObject::tr( "Unknown" );
01107 }
01108
01109 return QObject::tr( "Metering Mode: %1\n" ).arg( meter );
01110 }
01111
01112
01113 QString ExifData::exposure_program( int i ) {
01114 QString exp;
01115 switch( i ) {
01116 case 0:
01117 exp = QObject::tr( "Not defined" );
01118 break;
01119 case 1:
01120 exp = QObject::tr( "Manual" );
01121 break;
01122 case 2:
01123 exp = QObject::tr( "Normal progam" );
01124 break;
01125 case 3:
01126 exp = QObject::tr( "Aperture priority" );
01127 break;
01128 case 4:
01129 exp = QObject::tr( "Shutter priority" );
01130 break;
01131 case 5:
01132 exp = QObject::tr( "Creative progam\n(biased toward fast shutter speed" );
01133 break;
01134 case 6:
01135 exp = QObject::tr( "Action progam\n(biased toward fast shutter speed)" );
01136 break;
01137 case 7:
01138 exp = QObject::tr( "Portrait mode\n(for closeup photos with the background out of focus)" );
01139 break;
01140 case 8:
01141 exp = QObject::tr( "Landscape mode\n(for landscape photos with the background in focus)" );
01142 break;
01143 default:
01144 exp = QObject::tr( "Unknown" );
01145 }
01146
01147 return QObject::tr( "Exposure Program: %1\n" ).arg( exp );
01148 }
01149
01150 }
01151 }