author | alwin <alwin> | 2004-11-01 13:33:51 (UTC) |
---|---|---|
committer | alwin <alwin> | 2004-11-01 13:33:51 (UTC) |
commit | 915af02212ea80e43da5bcc24415e3e48778bea9 (patch) (side-by-side diff) | |
tree | eff6dbcc2f1e62dfbb8f6ababe183306fe2077e1 | |
parent | b3153506a1be76a386f23a3af44f84042d148111 (diff) | |
download | opie-915af02212ea80e43da5bcc24415e3e48778bea9.zip opie-915af02212ea80e43da5bcc24415e3e48778bea9.tar.gz opie-915af02212ea80e43da5bcc24415e3e48778bea9.tar.bz2 |
when jpeg image is smaller than requested thumbsize it will not use
scaled loading
-rw-r--r-- | noncore/graphics/opie-eye/slave/jpeg_slave.cpp | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/noncore/graphics/opie-eye/slave/jpeg_slave.cpp b/noncore/graphics/opie-eye/slave/jpeg_slave.cpp index fb7d5de..1bb81d9 100644 --- a/noncore/graphics/opie-eye/slave/jpeg_slave.cpp +++ b/noncore/graphics/opie-eye/slave/jpeg_slave.cpp @@ -394,1036 +394,1044 @@ void ExifData::DiscardData(void) SectionsRead = 0; } //-------------------------------------------------------------------------- // Convert a 16 bit unsigned value from file's native byte order //-------------------------------------------------------------------------- int ExifData::Get16u(void * Short) { if (MotorolaOrder){ return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1]; }else{ return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0]; } } //-------------------------------------------------------------------------- // Convert a 32 bit signed value from file's native byte order //-------------------------------------------------------------------------- int ExifData::Get32s(void * Long) { if (MotorolaOrder){ return ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16) | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 ); }else{ return ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16) | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 ); } } //-------------------------------------------------------------------------- // Convert a 32 bit unsigned value from file's native byte order //-------------------------------------------------------------------------- unsigned ExifData::Get32u(void * Long) { return (unsigned)Get32s(Long) & 0xffffffff; } //-------------------------------------------------------------------------- // Evaluate number, be it int, rational, or float from directory. //-------------------------------------------------------------------------- double ExifData::ConvertAnyFormat(void * ValuePtr, int Format) { double Value; Value = 0; switch(Format){ case FMT_SBYTE: Value = *(signed char *)ValuePtr; break; case FMT_BYTE: Value = *(uchar *)ValuePtr; break; case FMT_USHORT: Value = Get16u(ValuePtr); break; case FMT_ULONG: Value = Get32u(ValuePtr); break; case FMT_URATIONAL: case FMT_SRATIONAL: { int Num,Den; Num = Get32s(ValuePtr); Den = Get32s(4+(char *)ValuePtr); if (Den == 0){ Value = 0; }else{ Value = (double)Num/Den; } break; } case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break; case FMT_SLONG: Value = Get32s(ValuePtr); break; // Not sure if this is correct (never seen float used in Exif format) case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break; case FMT_DOUBLE: Value = *(double *)ValuePtr; break; } return Value; } //-------------------------------------------------------------------------- // Process one of the nested EXIF directories. //-------------------------------------------------------------------------- void ExifData::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength) { int de; int a; int NumDirEntries; unsigned ThumbnailOffset = 0; unsigned ThumbnailSize = 0; NumDirEntries = Get16u(DirStart); #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry)) { unsigned char * DirEnd; DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries); if (DirEnd+4 > (OffsetBase+ExifLength)){ if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){ // Version 1.3 of jhead would truncate a bit too much. // This also caught later on as well. }else{ // Note: Files that had thumbnails trimmed with jhead 1.3 or earlier // might trigger this. return; } } if (DirEnd < LastExifRefd) LastExifRefd = DirEnd; } for (de=0;de<NumDirEntries;de++){ int Tag, Format, Components; unsigned char * ValuePtr; int ByteCount; char * DirEntry; DirEntry = (char *)DIR_ENTRY_ADDR(DirStart, de); Tag = Get16u(DirEntry); Format = Get16u(DirEntry+2); Components = Get32u(DirEntry+4); if ((Format-1) >= NUM_FORMATS) { // (-1) catches illegal zero case as unsigned underflows to positive large. return; } ByteCount = Components * BytesPerFormat[Format]; if (ByteCount > 4){ unsigned OffsetVal; OffsetVal = Get32u(DirEntry+8); // If its bigger than 4 bytes, the dir entry contains an offset. if (OffsetVal+ByteCount > ExifLength){ // Bogus pointer offset and / or bytecount value //printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength); return; } ValuePtr = OffsetBase+OffsetVal; }else{ // 4 bytes or less and value is in the dir entry itself ValuePtr = (unsigned char *)DirEntry+8; } if (LastExifRefd < ValuePtr+ByteCount){ // Keep track of last byte in the exif header that was actually referenced. // That way, we know where the discardable thumbnail data begins. LastExifRefd = ValuePtr+ByteCount; } // Extract useful components of tag switch(Tag){ case TAG_MAKE: ExifData::CameraMake = QString((char*)ValuePtr); break; case TAG_MODEL: ExifData::CameraModel = QString((char*)ValuePtr); break; case TAG_ORIENTATION: Orientation = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_DATETIME_ORIGINAL: DateTime = QString((char*)ValuePtr); break; case TAG_USERCOMMENT: // Olympus has this padded with trailing spaces. Remove these first. for (a=ByteCount;;){ a--; if ((ValuePtr)[a] == ' '){ (ValuePtr)[a] = '\0'; }else{ break; } if (a == 0) break; } // Copy the comment if (memcmp(ValuePtr, "ASCII",5) == 0){ for (a=5;a<10;a++){ int c; c = (ValuePtr)[a]; if (c != '\0' && c != ' '){ //strncpy(ImageInfo.Comments, (const char*)(a+ValuePtr), 199); UserComment.sprintf("%s", (const char*)(a+ValuePtr)); break; } } }else{ //strncpy(ImageInfo.Comments, (const char*)ValuePtr, 199); UserComment.sprintf("%s", (const char*)ValuePtr); } break; case TAG_FNUMBER: // Simplest way of expressing aperture, so I trust it the most. // (overwrite previously computd value if there is one) ExifData::ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format); break; case TAG_APERTURE: case TAG_MAXAPERTURE: // More relevant info always comes earlier, so only use this field if we don't // have appropriate aperture information yet. if (ExifData::ApertureFNumber == 0){ ExifData::ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5); } break; case TAG_FOCALLENGTH: // Nice digital cameras actually save the focal length as a function // of how farthey are zoomed in. ExifData::FocalLength = (float)ConvertAnyFormat(ValuePtr, Format); break; case TAG_SUBJECT_DISTANCE: // Inidcates the distacne the autofocus camera is focused to. // Tends to be less accurate as distance increases. ExifData::Distance = (float)ConvertAnyFormat(ValuePtr, Format); break; case TAG_EXPOSURETIME: // Simplest way of expressing exposure time, so I trust it most. // (overwrite previously computd value if there is one) ExifData::ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format); break; case TAG_SHUTTERSPEED: // More complicated way of expressing exposure time, so only use // this value if we don't already have it from somewhere else. if (ExifData::ExposureTime == 0){ ExifData::ExposureTime = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2))); } break; case TAG_FLASH: if (ConvertAnyFormat(ValuePtr, Format)){ ExifData::FlashUsed = 1; } break; case TAG_EXIF_IMAGELENGTH: ExifImageLength = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_EXIF_IMAGEWIDTH: ExifImageWidth = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_FOCALPLANEXRES: FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format); break; case TAG_FOCALPLANEUNITS: switch((int)ConvertAnyFormat(ValuePtr, Format)){ case 1: FocalplaneUnits = 25.4; break; // inch case 2: // According to the information I was using, 2 means meters. // But looking at the Cannon powershot's files, inches is the only // sensible value. FocalplaneUnits = 25.4; break; case 3: FocalplaneUnits = 10; break; // centimeter case 4: FocalplaneUnits = 1; break; // milimeter case 5: FocalplaneUnits = .001; break; // micrometer } break; // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de) case TAG_EXPOSURE_BIAS: ExifData::ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format); break; case TAG_WHITEBALANCE: ExifData::Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_METERING_MODE: ExifData::MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_EXPOSURE_PROGRAM: ExifData::ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_ISO_EQUIVALENT: ExifData::ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); if ( ExifData::ISOequivalent < 50 ) ExifData::ISOequivalent *= 200; break; case TAG_COMPRESSION_LEVEL: ExifData::CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_THUMBNAIL_OFFSET: ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); break; case TAG_THUMBNAIL_LENGTH: ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); break; } if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){ unsigned char * SubdirStart; SubdirStart = OffsetBase + Get32u(ValuePtr); if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){ return; } ProcessExifDir(SubdirStart, OffsetBase, ExifLength); continue; } } { // In addition to linking to subdirectories via exif tags, // there's also a potential link to another directory at the end of each // directory. this has got to be the result of a comitee! unsigned char * SubdirStart; unsigned Offset; if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){ Offset = Get32u(DIR_ENTRY_ADDR(DirStart, NumDirEntries)); // There is at least one jpeg from an HP camera having an Offset of almost MAXUINT. // Adding OffsetBase to it produces an overflow, so compare with ExifLength here. // See http://bugs.kde.org/show_bug.cgi?id=54542 if (Offset && Offset < ExifLength){ SubdirStart = OffsetBase + Offset; if (SubdirStart > OffsetBase+ExifLength){ if (SubdirStart < OffsetBase+ExifLength+20){ // Jhead 1.3 or earlier would crop the whole directory! // As Jhead produces this form of format incorrectness, // I'll just let it pass silently owarn << "Thumbnail removed with Jhead 1.3 or earlier" << oendl; }else{ return; } }else{ if (SubdirStart <= OffsetBase+ExifLength){ ProcessExifDir(SubdirStart, OffsetBase, ExifLength); } } } }else{ // The exif header ends before the last next directory pointer. } } if (ThumbnailSize && ThumbnailOffset){ if (ThumbnailSize + ThumbnailOffset <= ExifLength){ // The thumbnail pointer appears to be valid. Store it. Thumbnail.loadFromData(OffsetBase + ThumbnailOffset, ThumbnailSize, "JPEG"); } } } //-------------------------------------------------------------------------- // Process a COM marker. We want to leave the bytes unchanged. The // progam that displays this text may decide to remove blanks, convert // newlines, or otherwise modify the text. In particular we want to be // safe for passing utf-8 text. //-------------------------------------------------------------------------- void ExifData::process_COM (const uchar * Data, int length) { QChar ch; int a; for (a=2;a<length;a++){ ch = Data[a]; if (ch == '\000') continue; // Remove nulls Comment.append(ch); } } //-------------------------------------------------------------------------- // Process a SOFn marker. This is useful for the image dimensions //-------------------------------------------------------------------------- void ExifData::process_SOFn (const uchar * Data, int marker) { int data_precision, num_components; data_precision = Data[2]; ExifData::Height = Get16m(Data+3); ExifData::Width = Get16m(Data+5); num_components = Data[7]; if (num_components == 3){ ExifData::IsColor = 1; }else{ ExifData::IsColor = 0; } ExifData::Process = marker; } //-------------------------------------------------------------------------- // Get 16 bits motorola order (always) for jpeg header stuff. //-------------------------------------------------------------------------- int ExifData::Get16m(const void * Short) { return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1]; } //-------------------------------------------------------------------------- // Process a EXIF marker // Describes all the drivel that most digital cameras include... //-------------------------------------------------------------------------- void ExifData::process_EXIF(unsigned char * CharBuf, unsigned int length) { ExifData::FlashUsed = 0; // If it s from a digicam, and it used flash, it says so. FocalplaneXRes = 0; FocalplaneUnits = 0; ExifImageWidth = 0; ExifImageLength = 0; { // Check the EXIF header component static const uchar ExifHeader[] = "Exif\0\0"; if (memcmp(CharBuf+2, ExifHeader,6)){ return; } } if (memcmp(CharBuf+8,"II",2) == 0){ // printf("Exif section in Intel order\n"); MotorolaOrder = 0; }else{ if (memcmp(CharBuf+8,"MM",2) == 0){ // printf("Exif section in Motorola order\n"); MotorolaOrder = 1; }else{ return; } } // Check the next two values for correctness. if (Get16u(CharBuf+10) != 0x2a || Get32u(CharBuf+12) != 0x08){ return; } LastExifRefd = CharBuf; // First directory starts 16 bytes in. Offsets start at 8 bytes in. ProcessExifDir(CharBuf+16, CharBuf+8, length-6); // This is how far the interesting (non thumbnail) part of the exif went. ExifSettingsLength = LastExifRefd - CharBuf; // Compute the CCD width, in milimeters. if (FocalplaneXRes != 0){ ExifData::CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes); } } //-------------------------------------------------------------------------- // Convert exif time to Unix time structure //-------------------------------------------------------------------------- int ExifData::Exif2tm(struct tm * timeptr, char * ExifTime) { int a; timeptr->tm_wday = -1; // Check for format: YYYY:MM:DD HH:MM:SS format. a = sscanf(ExifTime, "%d:%d:%d %d:%d:%d", &timeptr->tm_year, &timeptr->tm_mon, &timeptr->tm_mday, &timeptr->tm_hour, &timeptr->tm_min, &timeptr->tm_sec); if (a == 6){ timeptr->tm_isdst = -1; timeptr->tm_mon -= 1; // Adjust for unix zero-based months timeptr->tm_year -= 1900; // Adjust for year starting at 1900 return true; // worked. } return false; // Wasn't in Exif date format. } //-------------------------------------------------------------------------- // Contructor for initialising //-------------------------------------------------------------------------- ExifData::ExifData() { ExifData::Whitebalance = -1; ExifData::MeteringMode = -1; ExifData::FlashUsed = -1; Orientation = 0; Height = 0; Width = 0; IsColor = 0; Process = 0; FocalLength = 0; ExposureTime = 0; ApertureFNumber = 0; Distance = 0; CCDWidth = 0; ExposureBias = 0; ExposureProgram = 0; ISOequivalent = 0; CompressionLevel = 0; } //-------------------------------------------------------------------------- // process a EXIF jpeg file //-------------------------------------------------------------------------- bool ExifData::scan(const QString & path) { int ret; QFile f(path); f.open(IO_ReadOnly); // Scan the JPEG headers. ret = ReadJpegSections(f, READ_EXIF); if (ret == false){ owarn << "Not JPEG file!" << oendl; DiscardData(); f.close(); return false; } f.close(); DiscardData(); //now make the strings clean, // for exmaple my Casio is a "QV-4000 " CameraMake = CameraMake.stripWhiteSpace(); CameraModel = CameraModel.stripWhiteSpace(); UserComment = UserComment.stripWhiteSpace(); Comment = Comment.stripWhiteSpace(); return true; } //-------------------------------------------------------------------------- // Does the embedded thumbnail match the jpeg image? //-------------------------------------------------------------------------- #ifndef JPEG_TOL #define JPEG_TOL 0.02 #endif bool ExifData::isThumbnailSane() { if (Thumbnail.isNull()) return false; // check whether thumbnail dimensions match the image // not foolproof, but catches some altered images (jpegtran -rotate) if (ExifImageLength != 0 && ExifImageLength != Height) return false; if (ExifImageWidth != 0 && ExifImageWidth != Width) return false; if (Thumbnail.width() == 0 || Thumbnail.height() == 0) return false; if (Height == 0 || Width == 0) return false; double d = (double)Height/Width*Thumbnail.width()/Thumbnail.height(); return (1-JPEG_TOL < d) && (d < 1+JPEG_TOL); } static QImage flip_image( const QImage& img ); static QImage rotate_90( const QImage& img ); static QImage rotate_180( const QImage& ); static QImage rotate_270( const QImage& ); //-------------------------------------------------------------------------- // return a thumbnail that respects the orientation flag // only if it seems sane //-------------------------------------------------------------------------- QImage ExifData::getThumbnail() { if (!isThumbnailSane()) return NULL; if (!Orientation || Orientation == 1) return Thumbnail; // now fix orientation QImage dest = Thumbnail; switch (Orientation) { // notice intentional fallthroughs case 2: dest = flip_image( dest ); break; case 4: dest = flip_image( dest ); case 3: dest =rotate_180( dest ); break; case 5: dest = flip_image( dest ); case 6: dest = rotate_90( dest ); break; case 7: dest = flip_image( dest ); case 8: dest = rotate_270( dest ); break; default: break; // should never happen } return dest; } /* * */ static QImage flip_image( const QImage& img ) { return img.mirror( TRUE, FALSE ); } static QImage dest; static int x, y; static unsigned int *srcData, *destData; // we're not threaded anyway static unsigned char *srcData8, *destData8; // 8 bit is char static unsigned int *srcTable, *destTable; // destination table static QImage rotate_90_8( const QImage &img ) { dest.create(img.height(), img.width(), img.depth()); dest.setNumColors(img.numColors()); srcTable = (unsigned int *)img.colorTable(); destTable = (unsigned int *)dest.colorTable(); for ( x=0; x < img.numColors(); ++x ) destTable[x] = srcTable[x]; for ( y=0; y < img.height(); ++y ){ srcData8 = (unsigned char *)img.scanLine(y); for ( x=0; x < img.width(); ++x ){ destData8 = (unsigned char *)dest.scanLine(x); destData8[img.height()-y-1] = srcData8[x]; } } return dest; } static QImage rotate_90_all( const QImage& img ) { dest.create(img.height(), img.width(), img.depth()); for ( y=0; y < img.height(); ++y ) { srcData = (unsigned int *)img.scanLine(y); for ( x=0; x < img.width(); ++x ) { destData = (unsigned int *)dest.scanLine(x); destData[img.height()-y-1] = srcData[x]; } } return dest; } static QImage rotate_90( const QImage & img ) { if ( img.depth() > 8) return rotate_90_all( img ); else return rotate_90_8( img ); } static QImage rotate_180_all( const QImage& img ) { dest.create(img.width(), img.height(), img.depth()); for ( y=0; y < img.height(); ++y ){ srcData = (unsigned int *)img.scanLine(y); destData = (unsigned int *)dest.scanLine(img.height()-y-1); for ( x=0; x < img.width(); ++x ) destData[img.width()-x-1] = srcData[x]; } return dest; } static QImage rotate_180_8( const QImage& img ) { dest.create(img.width(), img.height(), img.depth()); dest.setNumColors(img.numColors()); srcTable = (unsigned int *)img.colorTable(); destTable = (unsigned int *)dest.colorTable(); for ( x=0; x < img.numColors(); ++x ) destTable[x] = srcTable[x]; for ( y=0; y < img.height(); ++y ){ srcData8 = (unsigned char *)img.scanLine(y); destData8 = (unsigned char *)dest.scanLine(img.height()-y-1); for ( x=0; x < img.width(); ++x ) destData8[img.width()-x-1] = srcData8[x]; } return dest; } static QImage rotate_180( const QImage& img ) { if ( img.depth() > 8 ) return rotate_180_all( img ); else return rotate_180_8( img ); } static QImage rotate_270_8( const QImage& img ) { dest.create(img.height(), img.width(), img.depth()); dest.setNumColors(img.numColors()); srcTable = (unsigned int *)img.colorTable(); destTable = (unsigned int *)dest.colorTable(); for ( x=0; x < img.numColors(); ++x ) destTable[x] = srcTable[x]; for ( y=0; y < img.height(); ++y ){ srcData8 = (unsigned char *)img.scanLine(y); for ( x=0; x < img.width(); ++x ){ destData8 = (unsigned char *)dest.scanLine(img.width()-x-1); destData8[y] = srcData8[x]; } } return dest; } static QImage rotate_270_all( const QImage& img ) { dest.create(img.height(), img.width(), img.depth()); for ( y=0; y < img.height(); ++y ){ srcData = (unsigned int *)img.scanLine(y); for ( x=0; x < img.width(); ++x ){ destData = (unsigned int *)dest.scanLine(img.width()-x-1); destData[y] = srcData[x]; } } return dest; } static QImage rotate_270( const QImage& img ) { if ( img.depth() > 8 ) return rotate_270_all( img ); else return rotate_270_8( img ); } static QString color_mode_to_string( bool b ) { return b ? QObject::tr( "Colormode: Color\n" ) : QObject::tr( "Colormode: Black and white\n" ); } static QString compression_to_string( int level ) { QString str; switch( level ) { case 1: str = QObject::tr( "Basic" ); break; case 2: str = QObject::tr( "Normal" ); break; case 4: str = QObject::tr( "Fine" ); break; default: str = QObject::tr( "Unknown" ); } return QObject::tr("Quality: %1\n").arg(str); } static QDateTime parseDateTime( const QString& string ) { QDateTime dt; if ( string.length() != 19 ) return dt; QString year = string.left( 4 ); QString month = string.mid( 5, 2 ); QString day = string.mid( 8, 2 ); QString hour = string.mid( 11, 2 ); QString minute = string.mid( 14, 2 ); QString seconds = string.mid( 18, 2 ); bool ok; bool allOk = true; int y = year.toInt( &ok ); allOk &= ok; int mo = month.toInt( &ok ); allOk &= ok; int d = day.toInt( &ok ); allOk &= ok; int h = hour.toInt( &ok ); allOk &= ok; int mi = minute.toInt( &ok ); allOk &= ok; int s = seconds.toInt( &ok ); allOk &= ok; if ( allOk ) { dt.setDate( QDate( y, mo, d ) ); dt.setTime( QTime( h, mi, s ) ); } return dt; } static QString white_balance_string( int i ) { QString balance; switch ( i ) { case 0: balance = QObject::tr( "Unknown" ); break; case 1: balance = QObject::tr( "Daylight" ); break; case 2: balance = QObject::tr( "Fluorescent" ); break; case 3: balance = QObject::tr( "Tungsten" ); break; case 17: balance = QObject::tr( "Standard light A" ); break; case 18: balance = QObject::tr( "Standard light B" ); break; case 19: balance = QObject::tr( "Standard light C" ); break; case 20: balance = QObject::tr( "D55" ); break; case 21: balance = QObject::tr( "D65" ); break; case 22: balance = QObject::tr( "D75" ); break; case 255: balance = QObject::tr( "Other" ); break; default: balance = QObject::tr( "Unknown" ); } return QObject::tr( "White Balance: %1\n" ).arg( balance ); } static QString metering_mode( int i) { QString meter; switch( i ) { case 0: meter = QObject::tr( "Unknown" ); break; case 1: meter = QObject::tr( "Average" ); break; case 2: meter = QObject::tr( "Center weighted average" ); break; case 3: meter = QObject::tr( "Spot" ); break; case 4: meter = QObject::tr( "MultiSpot" ); break; case 5: meter = QObject::tr( "Pattern" ); break; case 6: meter = QObject::tr( "Partial" ); break; case 255: meter = QObject::tr( "Other" ); break; default: meter = QObject::tr( "Unknown" ); } return QObject::tr( "Metering Mode: %1\n" ).arg( meter ); } static QString exposure_program( int i ) { QString exp; switch( i ) { case 0: exp = QObject::tr( "Not defined" ); break; case 1: exp = QObject::tr( "Manual" ); break; case 2: exp = QObject::tr( "Normal progam" ); break; case 3: exp = QObject::tr( "Aperture priority" ); break; case 4: exp = QObject::tr( "Shutter priority" ); break; case 5: exp = QObject::tr( "Creative progam\n(biased toward fast shutter speed" ); break; case 6: exp = QObject::tr( "Action progam\n(biased toward fast shutter speed)" ); break; case 7: exp = QObject::tr( "Portrait mode\n(for closeup photos with the background out of focus)" ); break; case 8: exp = QObject::tr( "Landscape mode\n(for landscape photos with the background in focus)" ); break; default: exp = QObject::tr( "Unknown" ); } return QObject::tr( "Exposure Program: %1\n" ).arg( exp ); } JpegSlave::JpegSlave() : SlaveInterface( QStringList::split( " ", "jpeg jpg" ) ) {} JpegSlave::~JpegSlave() {} QString JpegSlave::iconViewName( const QString& path) { ExifData ImageInfo; if ( !ImageInfo.scan( path ) ) return QString::null; QString tag; tag = QObject::tr( "Comment: %1\n" ).arg( ImageInfo.getComment() ); { // ODP fixme QString timestring = TimeString::dateString( parseDateTime( ImageInfo.getDateTime() ), FALSE ); tag += QObject::tr( "Date/Time: %1\n" ).arg( timestring ); } tag += QObject::tr( "Dimensions: %1x%2\n" ).arg(ImageInfo.getWidth()) .arg(ImageInfo.getHeight() ); tag += color_mode_to_string( ImageInfo.getIsColor() ); tag += compression_to_string( ImageInfo.getCompressionLevel() ); return tag; } /* * messy messy string creation */ QString JpegSlave::fullImageInfo( const QString& path) { ExifData ImageInfo; if ( !ImageInfo.scan( path ) ) return QString::null; QString tag, tmp; tag = QObject::tr( "<qt>Comment: %1\n" ).arg( ImageInfo.getComment() ); tmp = ImageInfo.getCameraMake(); if ( tmp.length() ) tag += QObject::tr( "Manufacturer: %1\n" ).arg( tmp ); tmp = ImageInfo.getCameraModel(); if ( tmp.length() ) tag += QObject::tr( "Model: %1\n" ).arg( tmp ); { // ODP fixme tmp = TimeString::dateString( parseDateTime( ImageInfo.getDateTime() ), FALSE ); tag += QObject::tr( "Date/Time: %1\n" ).arg( tmp ); } tag += QObject::tr( "Dimensions: %1x%2\n" ).arg(ImageInfo.getWidth()) .arg(ImageInfo.getHeight() ); tag += color_mode_to_string( ImageInfo.getIsColor() ); tag += compression_to_string( ImageInfo.getCompressionLevel() ); if ( ImageInfo.getOrientation() ) tag += QObject::tr( "Orientation: %1\n" ).arg(ImageInfo.getOrientation() ); { int flash_used = ImageInfo.getFlashUsed(); if ( flash_used >= 0 ) tag += QObject::tr( "Flash used\n" ); } if ( ImageInfo.getFocalLength() ) { tag += QObject::tr( "Focal length: %1\n" ).arg( QString().sprintf( "%4.1f", ImageInfo.getFocalLength() ) ); if ( ImageInfo.getCCDWidth() ) tag += QObject::tr( "35mm equivalent: %1\n" ).arg( (int)(ImageInfo.getFocalLength()/ImageInfo.getCCDWidth()*35 + 0.5) ); } if ( ImageInfo.getCCDWidth() ) tag += QObject::tr( "CCD width: %1" ).arg( ImageInfo.getCCDWidth() ); if ( ImageInfo.getExposureTime() ) { tmp = QString().sprintf("%4.2f", ImageInfo.getExposureTime() ); float exposureTime = ImageInfo.getExposureTime(); if ( exposureTime > 0 && exposureTime <= 0.5 ) tmp += QString().sprintf(" (1/%d)", (int)(0.5 +1/exposureTime) ); tag += QObject::tr( "Exposure time: %1\n" ).arg( tmp ); } if ( ImageInfo.getApertureFNumber() ) tag += QObject::tr( "Aperture: %1\n" ).arg( QString().sprintf("f/%3.1f", (double)ImageInfo.getApertureFNumber() ) ); if ( ImageInfo.getDistance() ) { if ( ImageInfo.getDistance() < 0 ) tag += QObject::tr( "Distance: %1\n" ).arg( QObject::tr( "Infinite" ) ); else tag += QObject::tr( "Distance: %1\n" ).arg( QString().sprintf( "%5.2fm", (double)ImageInfo.getDistance() ) ); } if ( ImageInfo.getExposureBias() ) { tag += QObject::tr( "Exposure bias: %1\n", QString().sprintf("%4.2f", (double)ImageInfo.getExposureBias() ) ); } if ( ImageInfo.getWhitebalance() != -1 ) tag += white_balance_string( ImageInfo.getWhitebalance() ); if( ImageInfo.getMeteringMode() != -1 ) tag += metering_mode( ImageInfo.getMeteringMode() ); if ( ImageInfo.getExposureProgram() ) tag += exposure_program( ImageInfo.getExposureProgram() ); if ( ImageInfo.getISOequivalent() ) tag += QObject::tr( "ISO equivalent: %1\n" ).arg( QString().sprintf("%2d", ImageInfo.getISOequivalent() ) ); tmp = ImageInfo.getUserComment(); if ( tmp.length() ) tag += QObject::tr( "EXIF comment: %1" ).arg( tmp ); tag += QObject::tr( "</qt>" ); return tag; } QPixmap JpegSlave::pixmap( const QString& path, int wid, int hei) { ExifData ImageInfo; + /* + */ if ( !ImageInfo.scan( path ) || ImageInfo.isNullThumbnail() ) { QImage img; QImageIO iio( path, 0l ); + if (wid < ImageInfo.getWidth() || hei<ImageInfo.getHeight()) { + odebug << "Scaling "<<ImageInfo.getWidth()<<"x"<<ImageInfo.getHeight() + << " to "<<wid<<"x"<<hei<< " ("<<path<<")"<<oendl; QString str = QString( "Fast Shrink( 4 ) Scale( %1, %2, ScaleFree)" ).arg( wid ).arg( hei ); iio.setParameters( str.latin1() );// will be strdupped anyway + } else { + odebug << "Not scaling "<<ImageInfo.getWidth()<<"x"<<ImageInfo.getHeight()<< " ("<<path<<")"<<oendl; + } img = iio.read() ? iio.image() : QImage(); return ThumbNailTool::scaleImage( img, wid,hei ); }else{ QImage img = ImageInfo.getThumbnail(); return ThumbNailTool::scaleImage( img, wid,hei ); } } |