File better-exif.patch of Package kdegraphics3

--- kfile-plugins/jpeg/kfile_jpeg.cpp
+++ kfile-plugins/jpeg/kfile_jpeg.cpp
@@ -19,7 +19,6 @@
  *
  */
 
-
 #include <stdlib.h>
 #include "kfile_jpeg.h"
 
@@ -35,8 +34,11 @@
 #include <qdict.h>
 #include <qvalidator.h>
 #include <qimage.h>
+#include <qwmatrix.h>
 
-#include "exif.h"
+#include <exiv2/image.hpp>
+#include <exiv2/exif.hpp>
+#include <exiv2/tags.hpp>
 
 #define EXIFGROUP "Jpeg EXIF Data"
 
@@ -58,98 +60,35 @@ KJpegPlugin::KJpegPlugin(QObject *parent
                                                           i18n("JPEG Exif") );
   KFileMimeTypeInfo::ItemInfo* item;
 
-  item = addItemInfo( exifGroup, "Comment", i18n("Comment"), QVariant::String);
+  item = addItemInfo( exifGroup, "UserComment", i18n("Comment"), QVariant::String);
   setAttributes( item,
-                 KFileMimeTypeInfo::Modifiable |
-                 KFileMimeTypeInfo::Addable |
+//                 KFileMimeTypeInfo::Modifiable |
+//                 KFileMimeTypeInfo::Addable |
                  KFileMimeTypeInfo::MultiLine );
 
-  item = addItemInfo( exifGroup, "Manufacturer", i18n("Camera Manufacturer"),
-                      QVariant::String );
-
-  item = addItemInfo( exifGroup, "Model", i18n("Camera Model"),
-                      QVariant::String );
-
-  item = addItemInfo( exifGroup, "Date/time", i18n("Date/Time"),
-                      QVariant::DateTime );
-
-  item = addItemInfo( exifGroup, "CreationDate", i18n("Creation Date"),
-                      QVariant::Date );
-
-  item = addItemInfo( exifGroup, "CreationTime", i18n("Creation Time"),
-                      QVariant::Time );
-
   item = addItemInfo( exifGroup, "Dimensions", i18n("Dimensions"),
                       QVariant::Size );
   setHint( item, KFileMimeTypeInfo::Size );
   setUnit( item, KFileMimeTypeInfo::Pixels );
 
-  item = addItemInfo( exifGroup, "Orientation", i18n("Orientation"),
-                      QVariant::Int );
-
-  item = addItemInfo( exifGroup, "ColorMode", i18n("Color Mode"),
-                      QVariant::String );
-
-  item = addItemInfo( exifGroup, "Flash used", i18n("Flash Used"),
-                      QVariant::String );
-  item = addItemInfo( exifGroup, "Focal length", i18n("Focal Length"),
-                      QVariant::String );
-  setUnit( item, KFileMimeTypeInfo::Millimeters );
-
-  item = addItemInfo( exifGroup, "35mm equivalent", i18n("35mm Equivalent"),
-                      QVariant::Int );
-  setUnit( item, KFileMimeTypeInfo::Millimeters );
-
-  item = addItemInfo( exifGroup, "CCD width", i18n("CCD Width"),
-                      QVariant::String );
-  setUnit( item, KFileMimeTypeInfo::Millimeters );
-
-  item = addItemInfo( exifGroup, "Exposure time", i18n("Exposure Time"),
-                      QVariant::String );
-  setHint( item, KFileMimeTypeInfo::Seconds );
-
-  item = addItemInfo( exifGroup, "Aperture", i18n("Aperture"),
-                      QVariant::String );
-
-  item = addItemInfo( exifGroup, "Focus dist.", i18n("Focus Dist."),
-                      QVariant::String );
-
-  item = addItemInfo( exifGroup, "Exposure bias", i18n("Exposure Bias"),
-                      QVariant::String );
-
-  item = addItemInfo( exifGroup, "Whitebalance", i18n("Whitebalance"),
-                      QVariant::String );
-
-  item = addItemInfo( exifGroup, "Metering mode", i18n("Metering Mode"),
-                      QVariant::String );
-
-  item = addItemInfo( exifGroup, "Exposure", i18n("Exposure"),
-                      QVariant::String );
-
-  item = addItemInfo( exifGroup, "ISO equiv.", i18n("ISO Equiv."),
-                      QVariant::String );
-
-  item = addItemInfo( exifGroup, "JPEG quality", i18n("JPEG Quality"),
-                      QVariant::String );
-
-  item = addItemInfo( exifGroup, "User comment", i18n("User Comment"),
-                      QVariant::String );
-  setHint(item,  KFileMimeTypeInfo::Description);
-
-  item = addItemInfo( exifGroup, "JPEG process", i18n("JPEG Process"),
-                      QVariant::String );
-
   item = addItemInfo( exifGroup, "Thumbnail", i18n("Thumbnail"),
                       QVariant::Image );
   setHint( item, KFileMimeTypeInfo::Thumbnail );
 
-//  ###
-//   exifGroup.setSupportsVariableKeys(true);
+  for (const Exiv2::TagInfo* taglist = Exiv2::ExifTags::ifdTagList();
+       taglist->tag_ != 0xffff; taglist++)
+      addItemInfo (exifGroup, taglist->name_, taglist->title_, QVariant::String);
+
+  for (const Exiv2::TagInfo* taglist = Exiv2::ExifTags::exifTagList();
+       taglist->tag_ != 0xffff; taglist++)
+      addItemInfo (exifGroup, taglist->name_, taglist->title_, QVariant::String);
+
+   //exifGroup->setSupportsVariableKeys(true);
 }
 
 QValidator* KJpegPlugin::createValidator(const KFileMetaInfoItem& /*item*/,
-                                        QObject */*parent*/,
-                                         const char */*name*/ ) const
+                                        QObject* /*parent*/,
+                                         const char* /*name*/ ) const
 {
     // no need to return a validator that validates everything as OK :)
 //     if (item.isEditable())
@@ -161,30 +100,48 @@ QValidator* KJpegPlugin::createValidator
 bool KJpegPlugin::writeInfo( const KFileMetaInfo& info ) const
 {
     QString comment = info[EXIFGROUP].value("Comment").toString();
-    QString path    = info.path();
 
     kdDebug(7034) << "exif writeInfo: " << info.path() << " \"" << comment << "\"\n";
+#if 0
+    try {
+        Exiv2::Image::AutoPtr image =
+            Exiv2::ImageFactory::open(QFile::encodeName(info.path()).data());
+        image->readMetadata();
+        Exiv2::ExifData &exifData = image->exifData();
+ 
+     /*
+       Exiv2 uses a CommentValue for Exif user comments. The format of the
+       comment string includes an optional charset specification at the beginning:
+ 
+       [charset=["]Ascii|Jis|Unicode|Undefined["] ]comment
+ 
+       Undefined is used as a default if the comment doesn't start with a charset
+       definition.
+ 
+       Following are a few examples of valid comments. The last one is written to
+       the file.
+      */
+     exifData["Exif.Photo.UserComment"]
+         = "charset=\"Unicode\" An Unicode Exif comment added with Exiv2";
+     exifData["Exif.Photo.UserComment"]
+         = "charset=\"Undefined\" An undefined Exif comment added with Exiv2";
+     exifData["Exif.Photo.UserComment"]
+         = "Another undefined Exif comment added with Exiv2";
+     exifData["Exif.Photo.UserComment"]
+         = "charset=Ascii An ASCII Exif comment added with Exiv2";
 
-    /*
-        Do a strictly safe insertion of the comment:
+     exifData["Exif.Photo.UserComment"] 
+         = std::string("charset=\"Unicode\" ") + std::string(comment.utf8().data());
 
-        Scan original to verify it's a proper jpeg
-        Open a unique temporary file in this directory
-        Write temporary, replacing all COM blocks with this one.
-        Scan temporary, to verify it's a proper jpeg
-        Rename original to another unique name
-        Rename temporary to original
-        Unlink original
-    */
-    /*
-        The jpeg standard does not regulate the contents of the COM block.
-        I'm assuming the best thing to do here is write as unicode utf-8,
-        which is fully backwards compatible with readers expecting ascii.
-        Readers expecting a national character set are out of luck...
-    */
-    if( safe_copy_and_modify( QFile::encodeName( path ), comment.utf8() ) ) {
-            return false;
-        }
+     image->writeMetadata();
+    }
+    catch (Exiv2::AnyError& e)
+    {
+        return false;
+    }
+#else
+    return false;
+#endif
     return true;
 }
 
@@ -194,292 +151,79 @@ bool KJpegPlugin::readInfo( KFileMetaInf
     if ( path.isEmpty() ) // remote file
         return false;
 
-    QString tag;
-    ExifData ImageInfo;
+    std::string tag;
 
-    // parse the jpeg file now
     try {
-        if ( !ImageInfo.scan(info.path()) ) {
-            kdDebug(7034) << "Not a JPEG file!\n";
+        Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(info.path().utf8().data());
+        if (!image.get())
             return false;
-        }
-    }
-    catch (FatalError& e) { // malformed exif data?
-        kdDebug(7034) << "Exception caught while parsing Exif data of: " << info.path() << endl;
-        e.debug_print();
-        return false;
-    }
+        image->readMetadata();
+        Exiv2::ExifData& ImageInfo = image->exifData();
 
-    KFileMetaInfoGroup exifGroup = appendGroup( info, EXIFGROUP );
+        KFileMetaInfoGroup exifGroup = appendGroup( info, EXIFGROUP );
 
-    tag = ImageInfo.getComment();
-    if ( tag.length() ) {
-        kdDebug(7034) << "exif inserting Comment: " << tag << "\n";
-        appendItem( exifGroup, "Comment", tag );
-    } else {
-        appendItem( exifGroup, "Comment", tag );    // So user can add new comment
-    }
-
-    tag = ImageInfo.getCameraMake();
-    if (tag.length())
-    	appendItem( exifGroup, "Manufacturer", tag );
-
-    tag = ImageInfo.getCameraModel();
-    if (tag.length())
-        appendItem( exifGroup, "Model", tag );
-
-    tag = ImageInfo.getDateTime();
-    if (tag.length()){
-        QDateTime dt = parseDateTime( tag.stripWhiteSpace() );
-        if ( dt.isValid() ) {
-            appendItem( exifGroup, "Date/time", dt );
-            appendItem( exifGroup, "CreationDate", dt.date() );
-            appendItem( exifGroup, "CreationTime", dt.time() );
+        tag = image->comment();
+        if ( tag.length() ) {
+            kdDebug(7034) << "exif inserting Comment: " << tag.c_str() << "\n";
+            appendItem( exifGroup, "UserComment", QString::fromUtf8(tag.c_str()) );
+        } else {
+            appendItem( exifGroup, "UserComment", QString::null);    // So user can add new comment
         }
-    }
-
-    appendItem( exifGroup,"Dimensions", QSize( ImageInfo.getWidth(),
-                                               ImageInfo.getHeight() ) );
-
-    if ( ImageInfo.getOrientation() )
-        appendItem( exifGroup, "Orientation", ImageInfo.getOrientation() );
-
-    appendItem( exifGroup, "ColorMode", ImageInfo.getIsColor() ?
-                i18n("Color") : i18n("Black and white") );
 
-    int flashUsed = ImageInfo.getFlashUsed(); // -1, <set>
-    if ( flashUsed >= 0 ) {
-	 QString flash = i18n("Flash", "(unknown)");
-         switch ( flashUsed ) {
-         case 0: flash = i18n("Flash", "No");
-             break;
-         case 1:
-         case 5:
-         case 7:
-             flash = i18n("Flash", "Fired");
-             break;
-         case 9:
-         case 13:
-         case 15:
-             flash = i18n( "Flash", "Fill Fired" );
-             break;
-         case 16:
-             flash = i18n( "Flash", "Off" );
-             break;
-         case 24:
-             flash = i18n( "Flash", "Auto Off" );
-             break;
-         case 25:
-         case 29:
-         case 31:
-             flash = i18n( "Flash", "Auto Fired" );
-             break;
-         case 32:
-             flash = i18n( "Flash", "Not Available" );
-             break;
-         default:
-             break;
+        for (Exiv2::ExifData::const_iterator i = ImageInfo.begin();
+             i != ImageInfo.end(); ++i) {
+            std::ostringstream str;
+            str << *i;
+            QString dt = QString::fromUtf8( str.str().c_str());
+            dt = convertDateTime( dt ); // exiv2 doesn't seem to convert to normal date/time, check
+            appendItem(exifGroup, QString::fromUtf8(i->tagName().c_str()), dt );
         }
-        appendItem( exifGroup, "Flash used",
-                    flash );
-    }
-
-    if (ImageInfo.getFocalLength()){
-    	appendItem( exifGroup, "Focal length",
-                    QString().sprintf("%4.1f", ImageInfo.getFocalLength()) );
-
-        if (ImageInfo.getCCDWidth()){
-            appendItem( exifGroup, "35mm equivalent",
-                        (int)(ImageInfo.getFocalLength()/ImageInfo.getCCDWidth()*35 + 0.5) );
-	}
-    }
 
-    if (ImageInfo.getCCDWidth()){
-	appendItem( exifGroup, "CCD width",
-                    QString().sprintf("%4.2f", ImageInfo.getCCDWidth()) );
-    }
-
-    if (ImageInfo.getExposureTime()){
-        tag=QString().sprintf("%6.3f", ImageInfo.getExposureTime());
-        float exposureTime = ImageInfo.getExposureTime();
-	if (exposureTime > 0 && exposureTime <= 0.5){
-            tag+=QString().sprintf(" (1/%d)", (int)(0.5 + 1/exposureTime) );
-	}
-	appendItem( exifGroup, "Exposure time", tag );
-    }
-
-    if (ImageInfo.getApertureFNumber()){
-	appendItem( exifGroup, "Aperture",
-                    QString().sprintf("f/%3.1f",
-                                      (double)ImageInfo.getApertureFNumber()));
-    }
-
-    if (ImageInfo.getDistance()){
-        if (ImageInfo.getDistance() < 0){
-	    tag=i18n("Infinite");
-        }else{
-	    tag=QString().sprintf("%5.2fm",(double)ImageInfo.getDistance());
+        Exiv2::ExifData::const_iterator iw =
+            ImageInfo.findKey(Exiv2::ExifKey("Exif.Image.ImageWidth"));
+        if (iw == ImageInfo.end())
+            iw = ImageInfo.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension"));
+        Exiv2::ExifData::const_iterator ih =
+            ImageInfo.findKey(Exiv2::ExifKey("Exif.Image.ImageLength"));
+        if (ih == ImageInfo.end())
+            ih = ImageInfo.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension"));
+
+        if (iw != ImageInfo.end() && ih != ImageInfo.end())
+            appendItem( exifGroup,"Dimensions", QSize( iw->toLong(), ih->toLong()));
+
+        if ( what & KFileMetaInfo::Thumbnail ) {
+            Exiv2::ExifThumbC thumb(ImageInfo);  Exiv2::DataBuf thumbnail = thumb.copy();
+	    QImage image;
+            image.loadFromData(thumbnail.pData_, thumbnail.size_);
+            // if there's no thumbnail in the jpeg, create a thumbnail from the file itself,
+            // so that orientation is applied correctly (kio_thumbnail doesn't handle it)
+            if( image.isNull())
+                image.load( info.path());
+            if( !image.isNull()) {
+                Exiv2::ExifData::const_iterator ort = ImageInfo.findKey(Exiv2::ExifKey("Exif.Image.Orientation"));
+                if (ort != ImageInfo.end()) {
+                    QWMatrix m;
+                    QWMatrix flip= QWMatrix(-1,0,0,1,0,0);
+                    switch( ort->toLong()) { // notice intentional fallthroughs
+                        case 2: m = flip; break;
+                        case 4: m = flip;
+                        case 3: m.rotate(180); break;
+                        case 5: m = flip;
+                        case 6: m.rotate(90); break;
+                        case 7: m = flip;
+                        case 8: m.rotate(270); break;
+                        default: break; // should never happen
+                    }
+                    if( !m.isIdentity())
+                        image = image.xForm( m );
+                }
+                appendItem( exifGroup, "Thumbnail", image );
+            }
         }
-    	appendItem( exifGroup, "Focus dist.", tag );
-    }
-
-    if (ImageInfo.getExposureBias()){
-	appendItem( exifGroup, "Exposure bias",
-                    QString().sprintf("%4.2f",
-                                      (double)ImageInfo.getExposureBias()) );
     }
-
-    if (ImageInfo.getWhitebalance() != -1){
-        switch(ImageInfo.getWhitebalance()) {
-	case 0:
-	    tag=i18n("Unknown");
-	    break;
-	case 1:
-	    tag=i18n("Daylight");
-	    break;
-	case 2:
-	    tag=i18n("Fluorescent");
-	    break;
-	case 3:
-	    //tag=i18n("incandescent");
-	    tag=i18n("Tungsten");
-	    break;
-	case 17:
-	    tag=i18n("Standard light A");
-	    break;
-	case 18:
-	    tag=i18n("Standard light B");
-	    break;
-	case 19:
-	    tag=i18n("Standard light C");
-	    break;
-	case 20:
-	    tag=i18n("D55");
-	    break;
-	case 21:
-	    tag=i18n("D65");
-	    break;
-	case 22:
-	    tag=i18n("D75");
-	    break;
-	case 255:
-	    tag=i18n("Other");
-	    break;
-	default:
-            //23 to 254 = reserved
-	    tag=i18n("Unknown");
-	}
-  	appendItem( exifGroup, "Whitebalance", tag );
-    }
-
-    if (ImageInfo.getMeteringMode() != -1){
-        switch(ImageInfo.getMeteringMode()) {
-	case 0:
-	    tag=i18n("Unknown");
-	    break;
-	case 1:
-	    tag=i18n("Average");
-	    break;
-	case 2:
-	    tag=i18n("Center weighted average");
-	    break;
-	case 3:
-	    tag=i18n("Spot");
-	    break;
-	case 4:
-	    tag=i18n("MultiSpot");
-	    break;
-	case 5:
-	    tag=i18n("Pattern");
-	    break;
-	case 6:
-	    tag=i18n("Partial");
-	    break;
-	case 255:
-	    tag=i18n("Other");
-	    break;
-	default:
-	    // 7 to 254 = reserved
-	    tag=i18n("Unknown");
-	}
-	appendItem( exifGroup, "Metering mode", tag );
-    }
-
-    if (ImageInfo.getExposureProgram()){
-        switch(ImageInfo.getExposureProgram()) {
-	case 0:
-	    tag=i18n("Not defined");
-	    break;
-	case 1:
-	    tag=i18n("Manual");
-	    break;
-	case 2:
-	    tag=i18n("Normal program");
-	    break;
-	case 3:
-	    tag=i18n("Aperture priority");
-	    break;
-	case 4:
-	    tag=i18n("Shutter priority");
-	    break;
-	case 5:
-	    tag=i18n("Creative program\n(biased toward fast shutter speed)");
-	    break;
-	case 6:
-	    tag=i18n("Action program\n(biased toward fast shutter speed)");
-	    break;
-	case 7:
-	    tag=i18n("Portrait mode\n(for closeup photos with the background out of focus)");
-	    break;
-	case 8:
-	    tag=i18n("Landscape mode\n(for landscape photos with the background in focus)");
-	    break;
-	default:
-	    // 9 to 255 = reserved
-	    tag=i18n("Unknown");
-	}
-	appendItem( exifGroup, "Exposure", tag );
-    }
-
-    if (ImageInfo.getISOequivalent()){
-	appendItem( exifGroup, "ISO equiv.",
-                    QString().sprintf("%2d",
-                                      (int)ImageInfo.getISOequivalent()) );
-    }
-
-    if (ImageInfo.getCompressionLevel()){
-	switch(ImageInfo.getCompressionLevel()) {
-	case 1:
-	    tag=i18n("Basic");
-            break;
-	case 2:
-	    tag=i18n("Normal");
-	    break;
-        case 4:
-	    tag=i18n("Fine");
-	    break;
-	default:
-	    tag=i18n("Unknown");
-	}
-	appendItem( exifGroup, "JPEG quality", tag );
-    }
-
-    tag = ImageInfo.getUserComment();
-    if (tag.length()){
-	appendItem( exifGroup, "EXIF comment", tag );
-    }
-
-    int a;
-    for (a=0;;a++){
-        if (ProcessTable[a].Tag == ImageInfo.getProcess() || ProcessTable[a].Tag == 0){
-    	    appendItem( exifGroup, "JPEG process",
-                        QString::fromUtf8( ProcessTable[a].Desc) );
-            break;
-        }
-    }
-
-    if ( what & KFileMetaInfo::Thumbnail && !ImageInfo.isNullThumbnail() ){
-        appendItem( exifGroup, "Thumbnail", ImageInfo.getThumbnail() );
+    catch (Exiv2::AnyError& e) {
+        kdDebug(7034) << "Caught Exiv2 exception" << endl;
+        return false;
     }
 
   return true;
@@ -487,11 +231,10 @@ bool KJpegPlugin::readInfo( KFileMetaInf
 
 // format of the string is:
 // YYYY:MM:DD HH:MM:SS
-QDateTime KJpegPlugin::parseDateTime( const QString& string )
+QString KJpegPlugin::convertDateTime( const QString& string )
 {
-    QDateTime dt;
     if ( string.length() != 19 )
-        return dt;
+        return string;
 
     QString year    = string.left( 4 );
     QString month   = string.mid( 5, 2 );
@@ -521,11 +264,13 @@ QDateTime KJpegPlugin::parseDateTime( co
     allOk &= ok;
 
     if ( allOk ) {
+        QDateTime dt;
         dt.setDate( QDate( y, mo, d ) );
         dt.setTime( QTime( h, mi, s ) );
+        return KGlobal::locale()->formatDateTime( dt, true, true ); // short format, seconds
     }
 
-    return dt;
+    return string;
 }
 
 #include "kfile_jpeg.moc"
--- kfile-plugins/jpeg/kfile_jpeg.desktop
+++ kfile-plugins/jpeg/kfile_jpeg.desktop
@@ -60,5 +60,5 @@ Name[zu]=Ulwazi lwe-JPEG EXIF
 ServiceTypes=KFilePlugin
 X-KDE-Library=kfile_jpeg
 MimeType=image/jpeg
-PreferredItems=User comment,CreationDate,CreationTime,Dimensions,Exposure time,JPEG quality,Comment
+PreferredItems=UserComment,Dimensions,DateTime,DateTimeOriginal,Flash,ExposureTime,Orientation,ApertureValue
 SupportsThumbnail=true
--- kfile-plugins/jpeg/kfile_jpeg.h
+++ kfile-plugins/jpeg/kfile_jpeg.h
@@ -37,7 +37,7 @@ public:
                                          QObject* parent, const char* name) const;
     
 private:
-    QDateTime parseDateTime( const QString& string ); 
+    QString convertDateTime( const QString& string ); 
 };
 
 #endif
--- kfile-plugins/jpeg/Makefile.am
+++ kfile-plugins/jpeg/Makefile.am
@@ -6,13 +6,13 @@ KDE_CXXFLAGS = $(USE_EXCEPTIONS)
 INCLUDES         = $(all_includes)
 
 # these are the headers for your project
-noinst_HEADERS   = kfile_jpeg.h exif.h
+noinst_HEADERS   = kfile_jpeg.h
 
 kde_module_LTLIBRARIES = kfile_jpeg.la
 
-kfile_jpeg_la_SOURCES = kfile_jpeg.cpp exif.cpp kfile_setcomment.cpp
+kfile_jpeg_la_SOURCES = kfile_jpeg.cpp kfile_setcomment.cpp
 kfile_jpeg_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
-kfile_jpeg_la_LIBADD = $(LIB_KIO)
+kfile_jpeg_la_LIBADD = $(LIB_KIO) -lexiv2
 
 # let automoc handle all of the meta source files (moc)
 METASOURCES = AUTO
openSUSE Build Service is sponsored by