Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

opieexif.cpp

Go to the documentation of this file.
00001 #include "opieexif.h"
00002 
00003 /* OPIE */
00004 #include <opie2/odebug.h>
00005 #include <qpe/timestring.h>
00006 /* QT */
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 //static int HaveAll;
00024 
00025 //--------------------------------------------------------------------------
00026 // Table of Jpeg encoding process names
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 // Describes format descriptor
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 // Describes tag values
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 // the following is added 05-jan-2001 vcs
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 // Parse the marker stream until SOS or EOI is seen;
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             // 0xff is legal padding, but if we get that many, something's wrong.
00171             return false;
00172         }
00173 
00174         Sections[SectionsRead].Type = marker;
00175 
00176         // Read the length of the section.
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); // Add 1 to allow sticking a 0 at the end.
00189         Sections[SectionsRead].Data = Data;
00190 
00191         // Store first two pre-read bytes.
00192         Data[0] = (uchar)lh;
00193         Data[1] = (uchar)ll;
00194 
00195         got = infile.readBlock((char*)Data+2, itemlen-2); // Read the whole section.
00196         if (( unsigned ) got != itemlen-2){
00197             return false;
00198         }
00199         SectionsRead++;
00200 
00201         switch(marker){
00202 
00203             case M_SOS:   // stop before hitting compressed data
00204                 // If reading entire image is requested, read the rest of the data.
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                     //HaveAll = 1;
00224                 }
00225                 return true;
00226 
00227             case M_EOI:   // in case it's a tables-only JPEG stream
00228                 owarn << "No image in jpeg!" << oendl;
00229                 return false;
00230 
00231             case M_COM: // Comment section
00232         // pieczy 2002-02-12
00233         // now the User comment goes to UserComment
00234         // so we can store a Comment section also in READ_EXIF mode
00235         process_COM(Data, itemlen);
00236                 break;
00237 
00238             case M_JFIF:
00239                 // Regular jpegs always have this tag, exif images have the exif
00240                 // marker instead, althogh ACDsee will write images with both markers.
00241                 // this program will re-create this marker on absence of exif marker.
00242                 // hence no need to keep the copy from the file.
00243                 free(Sections[--SectionsRead].Data);
00244                 break;
00245 
00246             case M_EXIF:
00247                 // Seen files from some 'U-lead' software with Vivitar scanner
00248                 // that uses marker 31 for non exif stuff.  Thus make sure
00249                 // it says 'Exif' in the section before treating it as exif.
00250                 if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){
00251                     process_EXIF((uchar *)Data, itemlen);
00252                 }else{
00253                     // Discard this section.
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 // Discard read data.
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 // Convert a 16 bit unsigned value from file's native byte order
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 // Convert a 32 bit signed value from file's native byte order
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 // Convert a 32 bit unsigned value from file's native byte order
00318 //--------------------------------------------------------------------------
00319 unsigned ExifData::Get32u(void * Long)
00320 {
00321     return (unsigned)Get32s(Long) & 0xffffffff;
00322 }
00323 
00324 //--------------------------------------------------------------------------
00325 // Evaluate number, be it int, rational, or float from directory.
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         // Not sure if this is correct (never seen float used in Exif format)
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 // Process one of the nested EXIF directories.
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                 // Version 1.3 of jhead would truncate a bit too much.
00384                 // This also caught later on as well.
00385             }else{
00386                 // Note: Files that had thumbnails trimmed with jhead 1.3 or earlier
00387                 // might trigger this.
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             // (-1) catches illegal zero case as unsigned underflows to positive large.
00407             return;
00408         }
00409 
00410         ByteCount = Components * BytesPerFormat[Format];
00411 
00412         if (ByteCount > 4){
00413             unsigned OffsetVal;
00414             OffsetVal = Get32u(DirEntry+8);
00415             // If its bigger than 4 bytes, the dir entry contains an offset.
00416             if (OffsetVal+ByteCount > ExifLength){
00417                 // Bogus pointer offset and / or bytecount value
00418                 //printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength);
00419 
00420                 return;
00421             }
00422             ValuePtr = OffsetBase+OffsetVal;
00423         }else{
00424             // 4 bytes or less and value is in the dir entry itself
00425             ValuePtr = (unsigned char *)DirEntry+8;
00426         }
00427 
00428         if (LastExifRefd < ValuePtr+ByteCount){
00429             // Keep track of last byte in the exif header that was actually referenced.
00430             // That way, we know where the discardable thumbnail data begins.
00431             LastExifRefd = ValuePtr+ByteCount;
00432         }
00433 
00434         // Extract useful components of tag
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                 // Olympus has this padded with trailing spaces.  Remove these first.
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                 // Copy the comment
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                             //strncpy(ImageInfo.Comments, (const char*)(a+ValuePtr), 199);
00472                             UserComment.sprintf("%s", (const char*)(a+ValuePtr));
00473                             break;
00474                         }
00475                     }
00476                 }else{
00477                     //strncpy(ImageInfo.Comments, (const char*)ValuePtr, 199);
00478                     UserComment.sprintf("%s", (const char*)ValuePtr);
00479                 }
00480                 break;
00481 
00482             case TAG_FNUMBER:
00483                 // Simplest way of expressing aperture, so I trust it the most.
00484                 // (overwrite previously computd value if there is one)
00485         ExifData::ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
00486                 break;
00487 
00488             case TAG_APERTURE:
00489             case TAG_MAXAPERTURE:
00490                 // More relevant info always comes earlier, so only use this field if we don't
00491                 // have appropriate aperture information yet.
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                 // Nice digital cameras actually save the focal length as a function
00500                 // of how farthey are zoomed in.
00501                 ExifData::FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
00502                 break;
00503 
00504             case TAG_SUBJECT_DISTANCE:
00505                 // Inidcates the distacne the autofocus camera is focused to.
00506                 // Tends to be less accurate as distance increases.
00507                 ExifData::Distance = (float)ConvertAnyFormat(ValuePtr, Format);
00508                 break;
00509 
00510             case TAG_EXPOSURETIME:
00511                 // Simplest way of expressing exposure time, so I trust it most.
00512                 // (overwrite previously computd value if there is one)
00513                 ExifData::ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
00514                 break;
00515 
00516             case TAG_SHUTTERSPEED:
00517                 // More complicated way of expressing exposure time, so only use
00518                 // this value if we don't already have it from somewhere else.
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; // inch
00546                     case 2:
00547                         // According to the information I was using, 2 means meters.
00548                         // But looking at the Cannon powershot's files, inches is the only
00549                         // sensible value.
00550                         FocalplaneUnits = 25.4;
00551                         break;
00552 
00553                     case 3: FocalplaneUnits = 10;   break;  // centimeter
00554                     case 4: FocalplaneUnits = 1;    break;  // milimeter
00555                     case 5: FocalplaneUnits = .001; break;  // micrometer
00556                 }
00557                 break;
00558 
00559                 // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de)
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         // In addition to linking to subdirectories via exif tags,
00609         // there's also a potential link to another directory at the end of each
00610         // directory.  this has got to be the result of a comitee!
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         // There is at least one jpeg from an HP camera having an Offset of almost MAXUINT.
00617         // Adding OffsetBase to it produces an overflow, so compare with ExifLength here.
00618         // See http://bugs.kde.org/show_bug.cgi?id=54542
00619         if (Offset && Offset < ExifLength){
00620                 SubdirStart = OffsetBase + Offset;
00621                 if (SubdirStart > OffsetBase+ExifLength){
00622                     if (SubdirStart < OffsetBase+ExifLength+20){
00623                         // Jhead 1.3 or earlier would crop the whole directory!
00624                         // As Jhead produces this form of format incorrectness,
00625                         // I'll just let it pass silently
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             // The exif header ends before the last next directory pointer.
00638         }
00639     }
00640 
00641     if (ThumbnailSize && ThumbnailOffset){
00642         if (ThumbnailSize + ThumbnailOffset <= ExifLength){
00643             // The thumbnail pointer appears to be valid.  Store it.
00644         Thumbnail.loadFromData(OffsetBase + ThumbnailOffset, ThumbnailSize, "JPEG");
00645         }
00646     }
00647 }
00648 
00649 //--------------------------------------------------------------------------
00650 // Process a COM marker.  We want to leave the bytes unchanged.  The
00651 // progam that displays this text may decide to remove blanks, convert
00652 // newlines, or otherwise modify the text.  In particular we want to be
00653 // safe for passing utf-8 text.
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;                     // Remove nulls
00663         Comment.append(ch);
00664     }
00665 }
00666 
00667 
00668 //--------------------------------------------------------------------------
00669 // Process a SOFn marker.  This is useful for the image dimensions
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 // Get 16 bits motorola order (always) for jpeg header stuff.
00692 //--------------------------------------------------------------------------
00693 int ExifData::Get16m(const void * Short)
00694 {
00695     return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
00696 }
00697 
00698 
00699 //--------------------------------------------------------------------------
00700 // Process a EXIF marker
00701 // Describes all the drivel that most digital cameras include...
00702 //--------------------------------------------------------------------------
00703 void ExifData::process_EXIF(unsigned char * CharBuf, unsigned int length)
00704 {
00705     ExifData::FlashUsed = 0; // If it s from a digicam, and it used flash, it says so.
00706 
00707     FocalplaneXRes = 0;
00708     FocalplaneUnits = 0;
00709     ExifImageWidth = 0;
00710     ExifImageLength = 0;
00711 
00712     {   // Check the EXIF header component
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         // printf("Exif section in Intel order\n");
00721         MotorolaOrder = 0;
00722     }else{
00723         if (memcmp(CharBuf+8,"MM",2) == 0){
00724             // printf("Exif section in Motorola order\n");
00725             MotorolaOrder = 1;
00726         }else{
00727             return;
00728         }
00729     }
00730 
00731     // Check the next two values for correctness.
00732     if (Get16u(CharBuf+10) != 0x2a
00733       || Get32u(CharBuf+12) != 0x08){
00734         return;
00735     }
00736 
00737     LastExifRefd = CharBuf;
00738 
00739     // First directory starts 16 bytes in.  Offsets start at 8 bytes in.
00740     ProcessExifDir(CharBuf+16, CharBuf+8, length-6);
00741 
00742     // This is how far the interesting (non thumbnail) part of the exif went.
00743     ExifSettingsLength = LastExifRefd - CharBuf;
00744 
00745     // Compute the CCD width, in milimeters.
00746     if (FocalplaneXRes != 0){
00747         ExifData::CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
00748     }
00749 }
00750 
00751 //--------------------------------------------------------------------------
00752 // Convert exif time to Unix time structure
00753 //--------------------------------------------------------------------------
00754 int ExifData::Exif2tm(struct ::tm * timeptr, char * ExifTime)
00755 {
00756     int a;
00757 
00758     timeptr->tm_wday = -1;
00759 
00760     // Check for format: YYYY:MM:DD HH:MM:SS format.
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;      // Adjust for unix zero-based months
00768         timeptr->tm_year -= 1900;  // Adjust for year starting at 1900
00769         return true; // worked.
00770     }
00771 
00772     return false; // Wasn't in Exif date format.
00773 }
00774 
00775 //--------------------------------------------------------------------------
00776 // Contructor for initialising
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 // process a EXIF jpeg file
00806 //--------------------------------------------------------------------------
00807 bool ExifData::scan(const QString & path)
00808 {
00809     int ret;
00810 
00811     QFile f(path);
00812     f.open(IO_ReadOnly);
00813 
00814     // Scan the JPEG headers.
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     //now make the strings clean,
00827     // for exmaple my Casio is a "QV-4000   "
00828     CameraMake = CameraMake.stripWhiteSpace();
00829     CameraModel = CameraModel.stripWhiteSpace();
00830     UserComment = UserComment.stripWhiteSpace();
00831     Comment = Comment.stripWhiteSpace();
00832     return true;
00833 }
00834 
00835 //--------------------------------------------------------------------------
00836 // Does the embedded thumbnail match the jpeg image?
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   // check whether thumbnail dimensions match the image
00845   // not foolproof, but catches some altered images (jpegtran -rotate)
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 // return a thumbnail that respects the orientation flag
00863 // only if it seems sane
00864 //--------------------------------------------------------------------------
00865 QImage ExifData::getThumbnail() {
00866   if (!isThumbnailSane()) return NULL;
00867   if (!Orientation || Orientation == 1) return Thumbnail;
00868 
00869   // now fix orientation
00870 
00871   QImage dest = Thumbnail;
00872   switch (Orientation) {  // notice intentional fallthroughs
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; // should never happen
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; // we're not threaded anyway
00897 static unsigned char *srcData8, *destData8; // 8 bit is char
00898 static unsigned int *srcTable,  *destTable; // destination table
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 } // namespace MM
01151 } // namespace OPIE

Generated on Sat Nov 5 16:16:11 2005 for OPIE by  doxygen 1.4.2