[Digikam-devel] [Bug 120241] utf8 display and edit

Marcel Wiesweg marcel.wiesweg at gmx.de
Fri May 5 22:17:30 BST 2006


------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.
         
http://bugs.kde.org/show_bug.cgi?id=120241         




------- Additional Comments From marcel.wiesweg gmx de  2006-05-05 23:17 -------
SVN commit 537807 by mwiesweg:

Unicode support for JFIF and EXIF comments:

- use UTF8 for JFIF comment
- use Unicode (UCS-2) to write JPEG UserComment,
  support charset specification when reading the UserComment
   - add convertCommentValue method to DMetaData

Using UTF8 for JFIF is simple and easy and should work.

The UCS-2 support needs testing (and a decision if we
always want to write Unicode, or a way to find out when we need to
and when we can as well write ASCII)

CCBUG: 120241 114211


 M  +84 -28    dmetadata/dmetadata.cpp  
 M  +3 -0      dmetadata/dmetadata.h  
 M  +11 -3     widgets/metadata/exifwidget.cpp  


--- trunk/extragear/graphics/digikam/libs/dmetadata/dmetadata.cpp #537806:537807
 @ -28,6 +28,7  @
 // Qt includes.
 
 #include <qfile.h>
+#include <qtextcodec.h>
 #include <qwmatrix.h>
 
 // KDE includes.
 @ -635,43 +636,46  @
 QString DMetadata::getImageComment() const
 {
     try
-    {    
+    {
+        if (d->filePath.isEmpty())
+            return QString();
+
         // In first we trying to get image comments, outside of Exif and IPTC.
 
-        QString comments(d->imageComments.c_str());
-        
+        QString comments = QString::fromUtf8(d->imageComments.c_str());
+
         if (!comments.isEmpty())
-           return comments;
-           
-        // In second, we trying to get Exif comments   
-                
+            return comments;
+
+        // In second, we trying to get Exif comments
+
         if (!d->exifMetadata.empty())
         {
             Exiv2::ExifKey key("Exif.Photo.UserComment");
             Exiv2::ExifData exifData(d->exifMetadata);
             Exiv2::ExifData::iterator it = exifData.findKey(key);
-            
+
             if (it != exifData.end())
             {
-                QString ExifComment(it->toString().c_str());
-    
-                if (!ExifComment.isEmpty())
-                  return ExifComment;
+                QString exifComment = convertCommentValue(*it);
+
+                if (!exifComment.isEmpty())
+                  return exifComment;
             }
         }
-        
-        // In third, we trying to get IPTC comments   
-                
+
+        // In third, we trying to get IPTC comments
+
         if (!d->iptcMetadata.empty())
         {
             Exiv2::IptcKey key("Iptc.Application2.Caption");
             Exiv2::IptcData iptcData(d->iptcMetadata);
             Exiv2::IptcData::iterator it = iptcData.findKey(key);
-            
+
             if (it != iptcData.end())
             {
-                QString IptcComment(it->toString().c_str());
-    
+                QString IptcComment = QString::fromLatin1(it->toString().c_str());
+
                 if (!IptcComment.isEmpty())
                   return IptcComment;
             }
 @ -683,15 +687,15  @
         kdDebug() << "Cannot get Image comments using Exiv2 (" 
                   << QString::fromLocal8Bit(e.what().c_str())
                   << ")" << endl;
-    }        
-    
+    }
+
     return QString();
 }
 
 bool DMetadata::setImageComment(const QString& comment)
 {
     try
-    {    
+    {
         if (comment.isEmpty())
             return false;
 
 @ -699,13 +703,21  @
 
         // In first we trying to set image comments, outside of Exif and IPTC.
 
-        const std::string str(comment.latin1());
+        const std::string str(comment.utf8());
         d->imageComments = str;
 
         // In Second we write comments into Exif.
-                
-        d->exifMetadata["Exif.Photo.UserComment"] = comment.latin1();
-        
+
+        // Be aware that we are dealing with a UCS-2 string.
+        // Null termination means \0\0, strlen does not work,
+        // do not use any const-char*-only methods,
+        // pass a std::string and not a const char * to ExifDatum::operator=().
+        const unsigned short *ucs2 = comment.ucs2();
+        std::string exifComment("charset=\"Unicode\" ");
+        exifComment.append((const char*)ucs2, sizeof(unsigned short) * comment.length());
+        d->exifMetadata["Exif.Photo.UserComment"] = exifComment;
+        //d->exifMetadata["Exif.Photo.UserComment"] = comment.latin1();
+
         // In Third we write comments into Iptc. Note that Caption IPTC tag is limited to 2000 char.
 
         setImageProgramId();
 @ -713,7 +725,7  @
         QString commentIptc = comment;
         commentIptc.truncate(2000);
         d->iptcMetadata["Iptc.Application2.Caption"] = commentIptc.latin1();
-    
+
         return true;
     }
     catch( Exiv2::Error &e )
 @ -721,11 +733,55  @
         kdDebug() << "Cannot set Comment into image using Exiv2 (" 
                   << QString::fromLocal8Bit(e.what().c_str())
                   << ")" << endl;
-    }        
-    
+    }
+
     return false;
 }
 
+QString DMetadata::convertCommentValue(const Exiv2::Exifdatum &exifDatum)
+{
+    std::string comment = exifDatum.toString();
+    std::string charset;
+
+    // libexiv2 will prepend "charset=\"SomeCharset\" " if charset is specified
+    // Before conversion to QString, we must know the charset, so we stay with std::string for a while
+    if (comment.length() > 8 && comment.substr(0, 8) == "charset=")
+    {
+        // the prepended charset specification is followed by a blank
+        std::string::size_type pos = comment.find_first_of(' ');
+        if (pos != std::string::npos)
+        {
+            // extract string between the = and the blank
+            charset = comment.substr(8, pos-8);
+            // get the rest of the string after the charset specification
+            comment = comment.substr(pos+1);
+        }
+    }
+
+    if (charset == "\"Unicode\"")
+    {
+        // QString expects a null-terminated UCS-2 string.
+        // Is it already null terminated? In any case, add termination for safety.
+        comment += "\0\0";
+        return QString::fromUcs2((unsigned short *)comment.data());
+    }
+    else if (charset == "\"Jis\"")
+    {
+        QTextCodec *codec = QTextCodec::codecForName("JIS7");
+        return codec->toUnicode(comment.c_str());
+    }
+    else if (charset == "\"Ascii\"")
+    {
+        return QString::fromLatin1(comment.c_str());
+    }
+    else
+    {
+        // or from local8bit ??
+        return QString::fromLatin1(comment.c_str());
+    }
+}
+
+
 /*
 Iptc.Application2.Urgency <==> digiKam Rating links:
 
--- trunk/extragear/graphics/digikam/libs/dmetadata/dmetadata.h #537806:537807
 @ -30,6 +30,7  @
 // Exiv2 includes.
 
 #include <exiv2/types.hpp>
+#include <exiv2/exif.hpp>
 
 // Local includes.
 
 @ -104,6 +105,8  @
 
     PhotoInfoContainer getPhotographInformations() const;
 
+    static QString convertCommentValue(const Exiv2::Exifdatum &comment);
+
 private:
 
     DImg::FORMAT fileFormat(const QString& filePath);
--- trunk/extragear/graphics/digikam/libs/widgets/metadata/exifwidget.cpp #537806:537807
 @ -155,9 +155,17  @
             QString key = QString::fromLocal8Bit(md->key().c_str());
 
             // Decode the tag value with a user friendly output.
-            std::ostringstream os;
-            os << *md;
-            QString tagValue = QString::fromLocal8Bit(os.str().c_str());
+            QString tagValue;
+            if (key == "Exif.Photo.UserComment")
+            {
+                tagValue = DMetadata::convertCommentValue(*md);
+            }
+            else
+            {
+                std::ostringstream os;
+                os << *md;
+                tagValue = QString::fromLocal8Bit(os.str().c_str());
+            }
             tagValue.replace("\n", " ");
 
             // We apply a filter to get only standard Exif tags, not maker notes.



More information about the Digikam-devel mailing list