Bug 113997

Summary: wish: option to store tags in image
Product: [Applications] digikam Reporter: Stuart Prescott <bugs.kde.org>
Component: Tags-EngineAssignee: Digikam Developers <digikam-bugs-null>
Status: RESOLVED FIXED    
Severity: wishlist CC: gschintgen, stephen.thompson
Priority: NOR    
Version: 0.7.2   
Target Milestone: ---   
Platform: Debian stable   
OS: Linux   
Latest Commit: Version Fixed In: 0.9.0
Sentry Crash Report:

Description Stuart Prescott 2005-10-07 05:59:27 UTC
Version:           0.7.2 (using KDE KDE 3.3.2)
Installed from:    Debian stable Packages

I'd like to be able to store the tag information in the images themselves (exif, jfif, whereever!) rather than in digikam's binary database. I know that this would be slower, I know that it would not be everyone's cup of tea, but it would be a big advantage for many users. 

The reasons are:

* I love digikam *now* but will I always use it? Storing the tags in a database makes it very difficult to migrate to a different application. (did someone say vendor lock-in?  :)

* Saving the tags in the images removes the single point of failure for the .db file, making the data safer

* It makes editing the tags by scripts, other programs etc easier 

* Operations done to images outside digikam (cpying/symlinking, editing, cropping) would preserve the tags.

* It makes moving images from one computer to another much easier (which I see in bugzilla is an oft-requested feature) as all the data about the images is just in the images.

I know that this is a non-trivial request -- but it is certainly on my wishlist :) For example a method by which tags could be changed or the tag heirarchy rearranged is much easier to do in the .db than in individual files... but it is still possible to do in the individual files, just a bit slower!

BTW I currently use Digikam's option of saving my comments in the jfif header and that is quite snappy for the 5k images that I already have in Digikam -- this means that I can at least already move much of the information about the images around with the files themselves. Tags would be more of a problem as you have to scan all Albums, but it would be easy to *cache* this information in digikam.db only updating it as needs be (say, if either the checksum has changed (a la kimdaba) or perhaps if the flastmod has changed.)

Have thoughts... and I'm happy to help out where I can with this one (having never looked under the hood of digiKam, but willing to do so!)
Comment 1 Gerhard Kulzer 2005-10-07 07:09:00 UTC
I would like that functionality too, but not as a default behavior. The data saving into the files  could be well an action called from a menu, and possibly per album or selection.
Comment 2 caulier.gilles 2006-03-30 21:34:23 UTC
From digiKam 0.9.0-svn, "Rating Tag" is now stored in IPTC tags named "Iptc.Application2.FixtureId". Let's me hear if this choose is right for you.

Image comments is now stored in :

-JPEG COM section for JPEG file.
-Exif Comments tag.
-IPTC caption tag.

digiKam Tags will be stored in the same way in another IPTC tag named "Iptc.Application2.Keywords" (not yet implemented). It will be separed by a space (like its recommended on iptc spec.).I need your viewpoint about this choose !

All tags are always stored in the database!

Gilles Caulier
Comment 3 caulier.gilles 2006-04-03 14:46:15 UTC
From svn trunk, digiKam  Tags are now stored in 'Keyword' IPTC tags like a simple keywords string.

Note : this tags is limited duing IPTC restrictions.

Give me feedback

Gilles
Comment 4 caulier.gilles 2006-04-04 12:48:44 UTC
*** Bug 122194 has been marked as a duplicate of this bug. ***
Comment 5 caulier.gilles 2006-04-06 14:37:33 UTC
SVN commit 526983 by cgilles:

digikam from trunk : IPTC and digiKam tags :

- Tags are saved in IPTC Keywords, but this tag can be redondant. This is want mean that each digiKam tag will be saved in a IPTC keywords tag, each one limited to 64 characters (before all digiKam tags been saved in only one IPTC Keywords tag). It's more powerfull (:=)))...

- Rating are now saved in IPTC Urgency tag, not FixtureId tag. This way is used by other photo management programs, like mapivi for example.

CCMAIL: digikam-devel@kde.org
CCBUGS: 103201, 113997

CCMAIL: digikam-devel@kde.org

 M  +107 -55   dmetadata.cpp  


--- trunk/extragear/graphics/digikam/libs/dmetadata/dmetadata.cpp #526982:526983
@@ -669,6 +669,22 @@
     return false;
 }
 
+/*
+Iptc.Application2.Urgency <==> digiKam Rating links:
+
+digiKam     IPTC
+Rating      Urgency
+
+0 star  <=>  8          // Least important
+1 star  <=>  7
+1 star  <==  6
+2 star  <=>  5
+3 star  <=>  4
+4 star  <==  3
+4 star  <=>  2
+5 star  <=>  1          // Most important
+*/
+
 int DMetadata::getImageRating() const
 {
     try
@@ -680,25 +696,29 @@
         {
             Exiv2::IptcData iptcData;
             iptcData.load((const Exiv2::byte*)m_iptcMetadata.data(), m_iptcMetadata.size());
-            Exiv2::IptcKey key("Iptc.Application2.FixtureId");
+            Exiv2::IptcKey key("Iptc.Application2.Urgency");
             Exiv2::IptcData::iterator it = iptcData.findKey(key);
             
             if (it != iptcData.end())
             {
-                QString IptcComment(it->toString().c_str());
+                QString IptcUrgency(it->toString().c_str());
     
-                if (IptcComment == QString("digiKamRating=0"))
+                if (IptcUrgency == QString("1"))
+                    return 5;
+                else if (IptcUrgency == QString("2"))
+                    return 4;
+                else if (IptcUrgency == QString("3"))
+                    return 4;
+                else if (IptcUrgency == QString("4"))
+                    return 3;
+                else if (IptcUrgency == QString("5"))
+                    return 2;
+                else if (IptcUrgency == QString("6"))
+                    return 1;
+                else if (IptcUrgency == QString("7"))
+                    return 1;
+                else if (IptcUrgency == QString("8"))
                     return 0;
-                else if (IptcComment == QString("digiKamRating=1"))
-                    return 1;
-                else if (IptcComment == QString("digiKamRating=2"))
-                    return 2;
-                else if (IptcComment == QString("digiKamRating=3"))
-                    return 3;
-                else if (IptcComment == QString("digiKamRating=4"))
-                    return 4;
-                else if (IptcComment == QString("digiKamRating=5"))
-                    return 5;
             }
         }
     }
@@ -729,12 +749,31 @@
             iptcData.load((const Exiv2::byte*)m_iptcMetadata.data(), m_iptcMetadata.size());
 
         setImageProgramId(iptcData);
+        QString urgencyTag;
         
-        QString temp;
-        QString ratingString("digiKamRating=");
-        ratingString.append(temp.setNum(rating));
+        switch(rating)
+        {
+            case 0:
+                urgencyTag = QString("8");
+                break;
+            case 1:
+                urgencyTag = QString("7");
+                break;
+            case 2:
+                urgencyTag = QString("5");
+                break;
+            case 3:
+                urgencyTag = QString("4");
+                break;
+            case 4:
+                urgencyTag = QString("3");
+                break;
+            case 5:
+                urgencyTag = QString("1");
+                break;
+        }
         
-        iptcData["Iptc.Application2.FixtureId"] = ratingString.latin1();
+        iptcData["Iptc.Application2.Urgency"] = urgencyTag.ascii();
         setIptc(iptcData.copy());
 
         return true;
@@ -749,6 +788,41 @@
     return false;
 }
 
+// Warning: this method haven't be tested yet!
+QStringList DMetadata::getImageKeywords() const
+{
+    try
+    {    
+        if (m_iptcMetadata.isEmpty())
+        {
+            Exiv2::IptcData iptcData;
+            iptcData.load((const Exiv2::byte*)m_iptcMetadata.data(), m_iptcMetadata.size());
+            QStringList keywords;
+            
+            for (Exiv2::IptcData::iterator it = iptcData.begin(); it != iptcData.end(); ++it)
+            {
+                QString key = QString::fromLocal8Bit(it->key().c_str());
+                
+                if (key == QString("Iptc.Application2.Keywords"))
+                {
+                    QString val(it->toString().c_str());
+                    keywords.append(val);
+                }
+            }
+            
+            return keywords;
+        }
+    }
+    catch( Exiv2::Error &e )
+    {
+        kdDebug() << "Cannot get Keywords from image using Exiv2 (" 
+                  << QString::fromLocal8Bit(e.what().c_str())
+                  << ")" << endl;
+    }        
+    
+    return QString();
+}
+
 bool DMetadata::setImageKeywords(const QStringList& keywords)
 {
     try
@@ -756,18 +830,28 @@
         if (keywords.isEmpty())
             return false;
 
+        QStringList keys = keywords;
+        
         Exiv2::IptcData iptcData;
         if (!m_iptcMetadata.isEmpty())
             iptcData.load((const Exiv2::byte*)m_iptcMetadata.data(), m_iptcMetadata.size());
         
         setImageProgramId(iptcData);
-
-        // Keywords IPTC tag is limited to 64 char.
-        QString keywordsString = keywords.join(" ");
-        keywordsString.truncate(64);
-        kdDebug() << m_filePath << " ==> Keywords: " << keywordsString << endl;
+        kdDebug() << m_filePath << " ==> Keywords: " << keywords << endl;
         
-        iptcData["Iptc.Application2.Keywords"] = keywordsString.latin1();
+        // Keywords IPTC tag is limited to 64 char but can be redondancy.
+        
+        for (QStringList::iterator it = keys.begin(); it != keys.end(); ++it)
+        {
+            QString key = *it;
+            key.truncate(64);
+            Exiv2::IptcKey iptcTag("Iptc.Application2.Keywords");
+            
+            Exiv2::Value::AutoPtr val = Exiv2::Value::create(Exiv2::asciiString);
+            val->read(key.latin1());
+            iptcData.add(iptcTag, val.get());        
+        }
+        
         setIptc(iptcData.copy());
         return true;
     }
@@ -853,36 +937,4 @@
     return false;
 }
 
-// -- METHODS BELOW ARE UNTESTED ---------------------------------
-
-QStringList DMetadata::getImageKeywords() const
-{
-    try
-    {    
-        if (m_iptcMetadata.isEmpty())
-        {
-            Exiv2::IptcData iptcData;
-            iptcData.load((const Exiv2::byte*)m_iptcMetadata.data(), m_iptcMetadata.size());
-            Exiv2::IptcKey key("Iptc.Application2.Keywords");
-            Exiv2::IptcData::iterator it = iptcData.findKey(key);
-            
-            if (it != iptcData.end())
-            {
-                QStringList keywords;
-                QString keywordsString(it->toString().c_str());
-                keywords.split(" ", keywordsString);
-                return keywords;
-            }
-        }
-    }
-    catch( Exiv2::Error &e )
-    {
-        kdDebug() << "Cannot get Keywords from image using Exiv2 (" 
-                  << QString::fromLocal8Bit(e.what().c_str())
-                  << ")" << endl;
-    }        
-    
-    return QString();
-}
-
 }  // NameSpace Digikam
Comment 6 caulier.gilles 2006-04-06 14:48:09 UTC
All editable informations from Comments & tags sidebar tab are stored in JPEG images now :

- Time stamp : Exif and IPTC tags are changed accordinly.
- Comments : JFIF section, Exif UserComment tag and IPTC Caption tag
- Rating : IPTC Urgency tag.
- digiKam tags : like multiple IPTC keywords tags.

Nota : This code depand of Exiv2 library. If other image file formats are supported by this lib in the future (like TIFF and NEF images witch are under development - http://dev.robotbattle.com/cmtinfo_svn.php?r=10), digikam will use it automaticly !!!

I close this file now.

Gilles Caulier
Comment 7 Wim Meeussen 2006-04-06 14:56:01 UTC
This is a wonderful feature! So, all editable information from comments and tags are now stored in the jpeg images AND in the digikam database? 
Thanks a lot Gilles!!
Comment 8 caulier.gilles 2006-04-06 14:57:37 UTC
Yes, of course. Database is unchanged.

Gilles
Comment 9 Fabrice Deydier 2006-04-06 15:15:28 UTC
What digiKam doing when I change the IPTC data value in the photo file with an other application ?

Where is the "true" value : in the photo file or in the digiKam database ?

How the digikam database will be updated ? in case of :
- adding an information (like adding a tag value)
- changing an information (like the comment or the date-time value)
- deleting an information (like deleting a tag)

Fabrice from Bordeaux
Comment 10 caulier.gilles 2006-04-06 15:21:11 UTC
The database will be updated at next digiKam session during startup, if you have enable file parsing option.

Actually, only Comments and date stamp are updated. Rating is easy to do, Tags more difficult. This is releavant of another B.K.O entry.

Gilles
Comment 11 Fabrice Deydier 2006-04-06 15:33:28 UTC
Bonjour

Une p'tite aide pour le newbie que je suis...
Que signifie "B.K.O." ?

A+ / F.

Et f
Comment 12 Maxime Delorme 2006-04-06 15:39:15 UTC
b.k.o =  bugs.kde.org 
Comment 13 Fabrice Deydier 2006-04-06 15:42:56 UTC
Thank's.

Oup's, sorry for the cross-posting (in french).

F.
Comment 14 caulier.gilles 2006-04-06 15:53:10 UTC
Like i said about new file formats supported by current Exiv2 implementation, i have tested it with DNG and NEF file. It works fine !!! Look here :

http://digikam3rdparty.free.fr/Screenshots/NEF-DNG-metadata.png

My pleasure to use Exiv2 lib (:=)))

Gilles
Comment 15 caulier.gilles 2006-04-06 21:57:55 UTC
SVN commit 527080 by cgilles:

digikam from trunk : 

- Assign digiKam tags and rating can be done using keboard shortcuts and contextual menu. Toggle IPTC tags relevant accordinly.
- Cleanup IPTC keywords tags before to apply any changes relevent of digiKam taging to prevent dupplicate entries.

CCMAIL: digikam-devel@kde.org 
CCBUGS: 113997

 M  +52 -11    digikam/albumiconview.cpp  
 M  +23 -10    libs/dmetadata/dmetadata.cpp  
 M  +2 -1      libs/dmetadata/dmetadata.h  
 M  +2 -3      libs/imageproperties/imagedescedittab.cpp  
 M  +2 -2      utilities/imageeditor/editor/Makefile.am  
 M  +31 -2     utilities/imageeditor/editor/imagewindow.cpp  
Comment 16 caulier.gilles 2006-04-07 09:31:04 UTC
About improvement of database update at startup, please use this file now for your comments :
 
http://bugs.kde.org/show_bug.cgi?id=91811

Gilles Caulier