File indexing completed on 2024-04-21 15:22:26

0001 /*
0002     SPDX-FileCopyrightText: 2006-2015 Gilles Caulier <caulier dot gilles at gmail dot com>
0003     SPDX-FileCopyrightText: 2006-2012 Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 // Local includes
0009 
0010 #include "kexiv2.h"
0011 #include "kexiv2_p.h"
0012 #include "libkexiv2_debug.h"
0013 
0014 namespace KExiv2Iface
0015 {
0016 
0017 bool KExiv2::canWriteIptc(const QString& filePath)
0018 {
0019     try
0020     {
0021 #if EXIV2_TEST_VERSION(0,28,0)
0022         Exiv2::Image::UniquePtr image = 
0023 #else
0024         Exiv2::Image::AutoPtr image = 
0025 #endif
0026                                       Exiv2::ImageFactory::open((const char*)
0027                                       (QFile::encodeName(filePath).constData()));
0028 
0029         Exiv2::AccessMode mode = image->checkMode(Exiv2::mdIptc);
0030         return (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite);
0031     }
0032     catch(Exiv2::Error& e)
0033     {
0034         std::string s(e.what());
0035         qCCritical(LIBKEXIV2_LOG) << "Cannot check Iptc access mode using Exiv2 (Error #"
0036 #if EXIV2_TEST_VERSION(0,28,0)
0037                                   << Exiv2::Error(e.code()).what()
0038 #else
0039                                   << e.code() << ": " << s.c_str()
0040 #endif
0041                                   << ")";
0042     }
0043     catch(...)
0044     {
0045         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0046     }
0047 
0048     return false;
0049 }
0050 
0051 bool KExiv2::hasIptc() const
0052 {
0053     return !d->iptcMetadata().empty();
0054 }
0055 
0056 bool KExiv2::clearIptc() const
0057 {
0058     try
0059     {
0060         d->iptcMetadata().clear();
0061         return true;
0062     }
0063     catch(Exiv2::Error& e)
0064     {
0065         d->printExiv2ExceptionError(QString::fromLatin1("Cannot clear Iptc data using Exiv2 "), e);
0066     }
0067     catch(...)
0068     {
0069         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0070     }
0071 
0072     return false;
0073 }
0074 
0075 QByteArray KExiv2::getIptc(bool addIrbHeader) const
0076 {
0077     try
0078     {
0079         if (!d->iptcMetadata().empty())
0080         {
0081             Exiv2::IptcData& iptc = d->iptcMetadata();
0082             Exiv2::DataBuf c2;
0083 
0084             if (addIrbHeader)
0085             {
0086                 c2 = Exiv2::Photoshop::setIptcIrb(nullptr, 0, iptc);
0087             }
0088             else
0089             {
0090                 c2 = Exiv2::IptcParser::encode(d->iptcMetadata());
0091             }
0092 
0093 #if EXIV2_TEST_VERSION(0,28,0)
0094             QByteArray data((const char*)c2.c_data(), c2.size());
0095 #else
0096             QByteArray data((const char*)c2.pData_, c2.size_);
0097 #endif
0098             return data;
0099 
0100         }
0101     }
0102     catch(Exiv2::Error& e)
0103     {
0104         if (!d->filePath.isEmpty())
0105         {
0106             qCCritical(LIBKEXIV2_LOG) << "From file " << d->filePath.toLatin1().constData();
0107         }
0108 
0109         d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Iptc data using Exiv2 "), e);
0110     }
0111     catch(...)
0112     {
0113         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0114     }
0115 
0116     return QByteArray();
0117 }
0118 
0119 bool KExiv2::setIptc(const QByteArray& data) const
0120 {
0121     try
0122     {
0123         if (!data.isEmpty())
0124         {
0125             Exiv2::IptcParser::decode(d->iptcMetadata(), (const Exiv2::byte*)data.data(), data.size());
0126             return (!d->iptcMetadata().empty());
0127         }
0128     }
0129     catch(Exiv2::Error& e)
0130     {
0131         if (!d->filePath.isEmpty())
0132         {
0133             qCCritical(LIBKEXIV2_LOG) << "From file " << d->filePath.toLatin1().constData();
0134         }
0135 
0136         d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc data using Exiv2 "), e);
0137     }
0138     catch(...)
0139     {
0140         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0141     }
0142 
0143     return false;
0144 }
0145 
0146 KExiv2::MetaDataMap KExiv2::getIptcTagsDataList(const QStringList& iptcKeysFilter, bool invertSelection) const
0147 {
0148     if (d->iptcMetadata().empty())
0149        return MetaDataMap();
0150 
0151     try
0152     {
0153         Exiv2::IptcData iptcData = d->iptcMetadata();
0154         iptcData.sortByKey();
0155 
0156         QString     ifDItemName;
0157         MetaDataMap metaDataMap;
0158 
0159         for (Exiv2::IptcData::iterator md = iptcData.begin(); md != iptcData.end(); ++md)
0160         {
0161             QString key = QString::fromLocal8Bit(md->key().c_str());
0162 
0163             // Decode the tag value with a user friendly output.
0164             std::ostringstream os;
0165             os << *md;
0166 
0167             QString value;
0168 
0169             if (key == QString::fromLatin1("Iptc.Envelope.CharacterSet"))
0170             {
0171                 value = QString::fromLatin1(iptcData.detectCharset());
0172             }
0173             else 
0174             {
0175                 value = QString::fromUtf8(os.str().c_str());
0176             }
0177 
0178             // To make a string just on one line.
0179             value.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
0180 
0181             // Some Iptc key are redondancy. check if already one exist...
0182             MetaDataMap::iterator it = metaDataMap.find(key);
0183 
0184             // We apply a filter to get only the Iptc tags that we need.
0185 
0186             if (!iptcKeysFilter.isEmpty())
0187             {
0188                 if (!invertSelection)
0189                 {
0190                     if (iptcKeysFilter.contains(key.section(QString::fromLatin1("."), 1, 1)))
0191                     {
0192                         if (it == metaDataMap.end())
0193                         {
0194                             metaDataMap.insert(key, value);
0195                         }
0196                         else
0197                         {
0198                             QString v = *it;
0199                             v.append(QString::fromLatin1(", "));
0200                             v.append(value);
0201                             metaDataMap.insert(key, v);
0202                         }
0203                     }
0204                 }
0205                 else
0206                 {
0207                     if (!iptcKeysFilter.contains(key.section(QString::fromLatin1("."), 1, 1)))
0208                     {
0209                         if (it == metaDataMap.end())
0210                         {
0211                             metaDataMap.insert(key, value);
0212                         }
0213                         else
0214                         {
0215                             QString v = *it;
0216                             v.append(QString::fromLatin1(", "));
0217                             v.append(value);
0218                             metaDataMap.insert(key, v);
0219                         }
0220                     }
0221                 }
0222             }
0223             else // else no filter at all.
0224             {
0225                 if (it == metaDataMap.end())
0226                 {
0227                     metaDataMap.insert(key, value);
0228                 }
0229                 else
0230                 {
0231                     QString v = *it;
0232                     v.append(QString::fromLatin1(", "));
0233                     v.append(value);
0234                     metaDataMap.insert(key, v);
0235                     }
0236             }
0237 
0238         }
0239 
0240         return metaDataMap;
0241     }
0242     catch (Exiv2::Error& e)
0243     {
0244         d->printExiv2ExceptionError(QString::fromLatin1("Cannot parse Iptc metadata using Exiv2 "), e);
0245     }
0246     catch(...)
0247     {
0248         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0249     }
0250 
0251     return MetaDataMap();
0252 }
0253 
0254 QString KExiv2::getIptcTagTitle(const char* iptcTagName)
0255 {
0256     try
0257     {
0258         std::string iptckey(iptcTagName);
0259         Exiv2::IptcKey ik(iptckey);
0260         return QString::fromLocal8Bit( Exiv2::IptcDataSets::dataSetTitle(ik.tag(), ik.record()) );
0261     }
0262     catch (Exiv2::Error& e)
0263     {
0264         d->printExiv2ExceptionError(QString::fromLatin1("Cannot get metadata tag title using Exiv2 "), e);
0265     }
0266     catch(...)
0267     {
0268         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0269     }
0270 
0271     return QString();
0272 }
0273 
0274 QString KExiv2::getIptcTagDescription(const char* iptcTagName)
0275 {
0276     try
0277     {
0278         std::string iptckey(iptcTagName);
0279         Exiv2::IptcKey ik(iptckey);
0280         return QString::fromLocal8Bit( Exiv2::IptcDataSets::dataSetDesc(ik.tag(), ik.record()) );
0281     }
0282     catch (Exiv2::Error& e)
0283     {
0284         d->printExiv2ExceptionError(QString::fromLatin1("Cannot get metadata tag description using Exiv2 "), e);
0285     }
0286     catch(...)
0287     {
0288         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0289     }
0290 
0291     return QString();
0292 }
0293 
0294 bool KExiv2::removeIptcTag(const char* iptcTagName, bool setProgramName) const
0295 {
0296     if (!setProgramId(setProgramName))
0297         return false;
0298 
0299     try
0300     {
0301         Exiv2::IptcData::iterator it = d->iptcMetadata().begin();
0302         int i                        = 0;
0303 
0304         while(it != d->iptcMetadata().end())
0305         {
0306             QString key = QString::fromLocal8Bit(it->key().c_str());
0307 
0308             if (key == QString::fromLatin1(iptcTagName))
0309             {
0310                 it = d->iptcMetadata().erase(it);
0311                 ++i;
0312             }
0313             else
0314             {
0315                 ++it;
0316             }
0317         };
0318 
0319         if (i > 0)
0320             return true;
0321     }
0322     catch(Exiv2::Error& e)
0323     {
0324         d->printExiv2ExceptionError(QString::fromLatin1("Cannot remove Iptc tag using Exiv2 "), e);
0325     }
0326     catch(...)
0327     {
0328         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0329     }
0330 
0331     return false;
0332 }
0333 
0334 bool KExiv2::setIptcTagData(const char* iptcTagName, const QByteArray& data, bool setProgramName) const
0335 {
0336     if (data.isEmpty())
0337         return false;
0338 
0339     if (!setProgramId(setProgramName))
0340         return false;
0341 
0342     try
0343     {
0344         Exiv2::DataValue val((Exiv2::byte *)data.data(), data.size());
0345         d->iptcMetadata()[iptcTagName] = val;
0346         return true;
0347     }
0348     catch(Exiv2::Error& e)
0349     {
0350         d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc tag data into image using Exiv2 "), e);
0351     }
0352     catch(...)
0353     {
0354         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0355     }
0356 
0357     return false;
0358 }
0359 
0360 QByteArray KExiv2::getIptcTagData(const char* iptcTagName) const
0361 {
0362     try
0363     {
0364         Exiv2::IptcKey  iptcKey(iptcTagName);
0365         Exiv2::IptcData iptcData(d->iptcMetadata());
0366         Exiv2::IptcData::iterator it = iptcData.findKey(iptcKey);
0367 
0368         if (it != iptcData.end())
0369         {
0370             char* const s = new char[(*it).size()];
0371             (*it).copy((Exiv2::byte*)s, Exiv2::bigEndian);
0372             QByteArray data(s, (*it).size());
0373             delete [] s;
0374             return data;
0375         }
0376     }
0377     catch(Exiv2::Error& e)
0378     {
0379         d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Iptc key '%1' into image using Exiv2 ").arg(QString::fromLatin1(iptcTagName)), e);
0380     }
0381     catch(...)
0382     {
0383         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0384     }
0385 
0386     return QByteArray();
0387 }
0388 
0389 QString KExiv2::getIptcTagString(const char* iptcTagName, bool escapeCR) const
0390 {
0391     try
0392     {
0393         Exiv2::IptcKey  iptcKey(iptcTagName);
0394         Exiv2::IptcData iptcData(d->iptcMetadata());
0395         Exiv2::IptcData::iterator it = iptcData.findKey(iptcKey);
0396 
0397         if (it != iptcData.end())
0398         {
0399             std::ostringstream os;
0400             os << *it;
0401             QString tagValue(QString::fromLatin1(os.str().c_str()));
0402 
0403             if (escapeCR)
0404                 tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
0405 
0406             return tagValue;
0407         }
0408     }
0409     catch(Exiv2::Error& e)
0410     {
0411         d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Iptc key '%1' into image using Exiv2 ").arg(QString::fromLatin1(iptcTagName)), e);
0412     }
0413     catch(...)
0414     {
0415         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0416     }
0417 
0418     return QString();
0419 }
0420 
0421 bool KExiv2::setIptcTagString(const char* iptcTagName, const QString& value, bool setProgramName) const
0422 {
0423     if (!setProgramId(setProgramName))
0424         return false;
0425 
0426     try
0427     {
0428         d->iptcMetadata()[iptcTagName] = std::string(value.toUtf8().constData());
0429 
0430         // Make sure we have set the charset to UTF-8
0431         d->iptcMetadata()["Iptc.Envelope.CharacterSet"] = "\33%G";
0432         return true;
0433     }
0434     catch(Exiv2::Error& e)
0435     {
0436         d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc tag string into image using Exiv2 "), e);
0437     }
0438     catch(...)
0439     {
0440         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0441     }
0442 
0443     return false;
0444 }
0445 
0446 QStringList KExiv2::getIptcTagsStringList(const char* iptcTagName, bool escapeCR) const
0447 {
0448     try
0449     {
0450         if (!d->iptcMetadata().empty())
0451         {
0452             QStringList values;
0453             Exiv2::IptcData iptcData(d->iptcMetadata());
0454 
0455             for (Exiv2::IptcData::iterator it = iptcData.begin(); it != iptcData.end(); ++it)
0456             {
0457                 QString key = QString::fromLocal8Bit(it->key().c_str());
0458 
0459                 if (key == QString::fromLatin1(iptcTagName))
0460                 {
0461                     QString tagValue = QString::fromUtf8(it->toString().c_str());
0462 
0463                     if (escapeCR)
0464                         tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
0465 
0466                     values.append(tagValue);
0467                 }
0468             }
0469 
0470             return values;
0471         }
0472     }
0473     catch(Exiv2::Error& e)
0474     {
0475         d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Iptc key '%1' into image using Exiv2 ").arg(QString::fromLatin1(iptcTagName)), e);
0476     }
0477     catch(...)
0478     {
0479         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0480     }
0481 
0482     return QStringList();
0483 }
0484 
0485 bool KExiv2::setIptcTagsStringList(const char* iptcTagName, int maxSize,
0486                                    const QStringList& oldValues, const QStringList& newValues,
0487                                    bool setProgramName) const
0488 {
0489     if (!setProgramId(setProgramName))
0490         return false;
0491 
0492     try
0493     {
0494         QStringList oldvals = oldValues;
0495         QStringList newvals = newValues;
0496 
0497         qCDebug(LIBKEXIV2_LOG) << d->filePath.toLatin1().constData() << " : " << iptcTagName
0498                  << " => " << newvals.join(QString::fromLatin1(",")).toLatin1().constData();
0499 
0500         // Remove all old values.
0501         Exiv2::IptcData iptcData(d->iptcMetadata());
0502         Exiv2::IptcData::iterator it = iptcData.begin();
0503 
0504         while(it != iptcData.end())
0505         {
0506             QString key = QString::fromLocal8Bit(it->key().c_str());
0507             QString val = QString::fromUtf8(it->toString().c_str());
0508 
0509             // Also remove new values to avoid duplicates. They will be added again below.
0510             if ( key == QString::fromLatin1(iptcTagName) &&
0511                  (oldvals.contains(val) || newvals.contains(val))
0512                )
0513                 it = iptcData.erase(it);
0514             else
0515                 ++it;
0516         };
0517 
0518         // Add new values.
0519 
0520         Exiv2::IptcKey iptcTag(iptcTagName);
0521 
0522         for (QStringList::iterator it = newvals.begin(); it != newvals.end(); ++it)
0523         {
0524             QString key = *it;
0525             key.truncate(maxSize);
0526 
0527 #if EXIV2_TEST_VERSION(0,28,0)
0528             Exiv2::Value::UniquePtr val = Exiv2::Value::create(Exiv2::string);
0529 #else
0530             Exiv2::Value::AutoPtr val = Exiv2::Value::create(Exiv2::string);
0531 #endif
0532             val->read(key.toUtf8().constData());
0533             iptcData.add(iptcTag, val.get());
0534         }
0535 
0536         d->iptcMetadata() = iptcData;
0537 
0538         // Make sure character set is UTF-8
0539         setIptcTagString("Iptc.Envelope.CharacterSet", QString::fromLatin1("\33%G"), false);
0540 
0541         return true;
0542     }
0543     catch(Exiv2::Error& e)
0544     {
0545         d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc key '%1' into image using Exiv2 ").arg(QString::fromLatin1(iptcTagName)), e);
0546     }
0547     catch(...)
0548     {
0549         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0550     }
0551 
0552     return false;
0553 }
0554 
0555 QStringList KExiv2::getIptcKeywords() const
0556 {
0557     try
0558     {
0559         if (!d->iptcMetadata().empty())
0560         {
0561             QStringList keywords;
0562             Exiv2::IptcData iptcData(d->iptcMetadata());
0563 
0564             for (Exiv2::IptcData::iterator it = iptcData.begin(); it != iptcData.end(); ++it)
0565             {
0566                 QString key = QString::fromLocal8Bit(it->key().c_str());
0567 
0568                 if (key == QString::fromLatin1("Iptc.Application2.Keywords"))
0569                 {
0570                     QString val = QString::fromUtf8(it->toString().c_str());
0571                     keywords.append(val);
0572                 }
0573             }
0574 
0575             qCDebug(LIBKEXIV2_LOG) << d->filePath << " ==> Read Iptc Keywords: " << keywords;
0576 
0577             return keywords;
0578         }
0579     }
0580     catch(Exiv2::Error& e)
0581     {
0582         d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Iptc Keywords from image using Exiv2 "), e);
0583     }
0584     catch(...)
0585     {
0586         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0587     }
0588 
0589     return QStringList();
0590 }
0591 
0592 bool KExiv2::setIptcKeywords(const QStringList& oldKeywords, const QStringList& newKeywords,
0593                              bool setProgramName) const
0594 {
0595     if (!setProgramId(setProgramName))
0596         return false;
0597 
0598     try
0599     {
0600         QStringList oldkeys = oldKeywords;
0601         QStringList newkeys = newKeywords;
0602 
0603         qCDebug(LIBKEXIV2_LOG) << d->filePath << " ==> New Iptc Keywords: " << newkeys;
0604 
0605         // Remove all old keywords.
0606         Exiv2::IptcData iptcData(d->iptcMetadata());
0607         Exiv2::IptcData::iterator it = iptcData.begin();
0608 
0609         while(it != iptcData.end())
0610         {
0611             QString key = QString::fromLocal8Bit(it->key().c_str());
0612             QString val = QString::fromUtf8(it->toString().c_str());
0613 
0614             // Also remove new keywords to avoid duplicates. They will be added again below.
0615             if ( key == QString::fromLatin1("Iptc.Application2.Keywords") &&
0616                  (oldKeywords.contains(val) || newKeywords.contains(val))
0617                )
0618                 it = iptcData.erase(it);
0619             else
0620                 ++it;
0621         };
0622 
0623         // Add new keywords. Note that Keywords Iptc tag is limited to 64 char but can be redondant.
0624 
0625         Exiv2::IptcKey iptcTag("Iptc.Application2.Keywords");
0626 
0627         for (QStringList::iterator it = newkeys.begin(); it != newkeys.end(); ++it)
0628         {
0629             QString key = *it;
0630             key.truncate(64);
0631 
0632 #if EXIV2_TEST_VERSION(0,28,0)
0633             Exiv2::Value::UniquePtr val = Exiv2::Value::create(Exiv2::string);
0634 #else
0635             Exiv2::Value::AutoPtr val = Exiv2::Value::create(Exiv2::string);
0636 #endif
0637             val->read(key.toUtf8().constData());
0638             iptcData.add(iptcTag, val.get());
0639         }
0640 
0641         d->iptcMetadata() = iptcData;
0642 
0643         // Make sure character set is UTF-8
0644         setIptcTagString("Iptc.Envelope.CharacterSet", QString::fromLatin1("\33%G"), false);
0645 
0646         return true;
0647     }
0648     catch(Exiv2::Error& e)
0649     {
0650         d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc Keywords into image using Exiv2 "), e);
0651     }
0652     catch(...)
0653     {
0654         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0655     }
0656 
0657     return false;
0658 }
0659 
0660 QStringList KExiv2::getIptcSubjects() const
0661 {
0662     try
0663     {
0664         if (!d->iptcMetadata().empty())
0665         {
0666             QStringList subjects;
0667             Exiv2::IptcData iptcData(d->iptcMetadata());
0668 
0669             for (Exiv2::IptcData::iterator it = iptcData.begin(); it != iptcData.end(); ++it)
0670             {
0671                 QString key = QString::fromLocal8Bit(it->key().c_str());
0672 
0673                 if (key == QString::fromLatin1("Iptc.Application2.Subject"))
0674                 {
0675                     QString val(QString::fromLatin1(it->toString().c_str()));
0676                     subjects.append(val);
0677                 }
0678             }
0679 
0680             return subjects;
0681         }
0682     }
0683     catch(Exiv2::Error& e)
0684     {
0685         d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Iptc Subjects from image using Exiv2 "), e);
0686     }
0687     catch(...)
0688     {
0689         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0690     }
0691 
0692     return QStringList();
0693 }
0694 
0695 bool KExiv2::setIptcSubjects(const QStringList& oldSubjects, const QStringList& newSubjects,
0696                              bool setProgramName) const
0697 {
0698     if (!setProgramId(setProgramName))
0699         return false;
0700 
0701     try
0702     {
0703         QStringList oldDef = oldSubjects;
0704         QStringList newDef = newSubjects;
0705 
0706         // Remove all old subjects.
0707         Exiv2::IptcData iptcData(d->iptcMetadata());
0708         Exiv2::IptcData::iterator it = iptcData.begin();
0709 
0710         while(it != iptcData.end())
0711         {
0712             QString key = QString::fromLocal8Bit(it->key().c_str());
0713             QString val = QString::fromUtf8(it->toString().c_str());
0714 
0715             if (key == QString::fromLatin1("Iptc.Application2.Subject") && oldDef.contains(val))
0716                 it = iptcData.erase(it);
0717             else
0718                 ++it;
0719         };
0720 
0721         // Add new subjects. Note that Keywords Iptc tag is limited to 236 char but can be redondant.
0722 
0723         Exiv2::IptcKey iptcTag("Iptc.Application2.Subject");
0724 
0725         for (QStringList::iterator it = newDef.begin(); it != newDef.end(); ++it)
0726         {
0727             QString key = *it;
0728             key.truncate(236);
0729 
0730 #if EXIV2_TEST_VERSION(0,28,0)
0731             Exiv2::Value::UniquePtr val = Exiv2::Value::create(Exiv2::string);
0732 #else
0733             Exiv2::Value::AutoPtr val = Exiv2::Value::create(Exiv2::string);
0734 #endif
0735             val->read(key.toUtf8().constData());
0736             iptcData.add(iptcTag, val.get());
0737         }
0738 
0739         d->iptcMetadata() = iptcData;
0740 
0741         // Make sure character set is UTF-8
0742         setIptcTagString("Iptc.Envelope.CharacterSet", QString::fromLatin1("\33%G"), false);
0743 
0744         return true;
0745     }
0746     catch(Exiv2::Error& e)
0747     {
0748         d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc Subjects into image using Exiv2 "), e);
0749     }
0750     catch(...)
0751     {
0752         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0753     }
0754 
0755     return false;
0756 }
0757 
0758 QStringList KExiv2::getIptcSubCategories() const
0759 {
0760     try
0761     {
0762         if (!d->iptcMetadata().empty())
0763         {
0764             QStringList subCategories;
0765             Exiv2::IptcData iptcData(d->iptcMetadata());
0766 
0767             for (Exiv2::IptcData::iterator it = iptcData.begin(); it != iptcData.end(); ++it)
0768             {
0769                 QString key = QString::fromLocal8Bit(it->key().c_str());
0770 
0771                 if (key == QString::fromLatin1("Iptc.Application2.SuppCategory"))
0772                 {
0773                     QString val(QString::fromLatin1(it->toString().c_str()));
0774                     subCategories.append(val);
0775                 }
0776             }
0777 
0778             return subCategories;
0779         }
0780     }
0781     catch(Exiv2::Error& e)
0782     {
0783         d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Iptc Sub Categories from image using Exiv2 "), e);
0784     }
0785     catch(...)
0786     {
0787         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0788     }
0789 
0790     return QStringList();
0791 }
0792 
0793 bool KExiv2::setIptcSubCategories(const QStringList& oldSubCategories, const QStringList& newSubCategories,
0794                                   bool setProgramName) const
0795 {
0796     if (!setProgramId(setProgramName))
0797         return false;
0798 
0799     try
0800     {
0801         QStringList oldkeys = oldSubCategories;
0802         QStringList newkeys = newSubCategories;
0803 
0804         // Remove all old Sub Categories.
0805         Exiv2::IptcData iptcData(d->iptcMetadata());
0806         Exiv2::IptcData::iterator it = iptcData.begin();
0807 
0808         while(it != iptcData.end())
0809         {
0810             QString key = QString::fromLocal8Bit(it->key().c_str());
0811             QString val = QString::fromUtf8(it->toString().c_str());
0812 
0813             if (key == QString::fromLatin1("Iptc.Application2.SuppCategory") && oldSubCategories.contains(val))
0814                 it = iptcData.erase(it);
0815             else
0816                 ++it;
0817         };
0818 
0819         // Add new Sub Categories. Note that SubCategories Iptc tag is limited to 32
0820         // characters but can be redondant.
0821 
0822         Exiv2::IptcKey iptcTag("Iptc.Application2.SuppCategory");
0823 
0824         for (QStringList::iterator it = newkeys.begin(); it != newkeys.end(); ++it)
0825         {
0826             QString key = *it;
0827             key.truncate(32);
0828 
0829 #if EXIV2_TEST_VERSION(0,28,0)
0830             Exiv2::Value::UniquePtr val = Exiv2::Value::create(Exiv2::string);
0831 #else
0832             Exiv2::Value::AutoPtr val = Exiv2::Value::create(Exiv2::string);
0833 #endif
0834             val->read(key.toUtf8().constData());
0835             iptcData.add(iptcTag, val.get());
0836         }
0837 
0838         d->iptcMetadata() = iptcData;
0839 
0840         // Make sure character set is UTF-8
0841         setIptcTagString("Iptc.Envelope.CharacterSet", QString::fromLatin1("\33%G"), false);
0842 
0843         return true;
0844     }
0845     catch(Exiv2::Error& e)
0846     {
0847         d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc Sub Categories into image using Exiv2 "), e);
0848     }
0849     catch(...)
0850     {
0851         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0852     }
0853 
0854     return false;
0855 }
0856 
0857 KExiv2::TagsMap KExiv2::getIptcTagsList() const
0858 {
0859     try
0860     {
0861         QList<const Exiv2::DataSet*> tags;
0862         tags << Exiv2::IptcDataSets::envelopeRecordList()
0863              << Exiv2::IptcDataSets::application2RecordList();
0864 
0865         TagsMap tagsMap;
0866 
0867         for (QList<const Exiv2::DataSet*>::iterator it = tags.begin(); it != tags.end(); ++it)
0868         {
0869             do
0870             {
0871                 QString     key = QLatin1String( Exiv2::IptcKey( (*it)->number_, (*it)->recordId_ ).key().c_str() );
0872                 QStringList values;
0873                 values << QString::fromLatin1((*it)->name_) << QString::fromLatin1((*it)->title_) << QString::fromLatin1((*it)->desc_);
0874                 tagsMap.insert(key, values);
0875                 ++(*it);
0876             }
0877             while((*it)->number_ != 0xffff);
0878         }
0879 
0880         return tagsMap;
0881     }
0882     catch(Exiv2::Error& e)
0883     {
0884         d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Iptc Tags list using Exiv2 "), e);
0885     }
0886     catch(...)
0887     {
0888         qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
0889     }
0890 
0891     return TagsMap();
0892 }
0893 
0894 }  // NameSpace KExiv2Iface