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