-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 @@ -906,524 +906,532 @@ ExifData::ExifData() //-------------------------------------------------------------------------- // 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 ); } } |