File indexing completed on 2024-04-21 15:22:27
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::canWriteXmp(const QString& filePath) 0018 { 0019 #ifdef _XMP_SUPPORT_ 0020 try 0021 { 0022 #if EXIV2_TEST_VERSION(0,28,0) 0023 Exiv2::Image::UniquePtr image = 0024 #else 0025 Exiv2::Image::AutoPtr image = 0026 #endif 0027 Exiv2::ImageFactory::open((const char*) 0028 (QFile::encodeName(filePath).constData())); 0029 0030 Exiv2::AccessMode mode = image->checkMode(Exiv2::mdXmp); 0031 return (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite); 0032 } 0033 catch( Exiv2::Error& e ) 0034 { 0035 std::string s(e.what()); 0036 qCCritical(LIBKEXIV2_LOG) << "Cannot check Xmp access mode using Exiv2 (Error #" 0037 #if EXIV2_TEST_VERSION(0,28,0) 0038 << Exiv2::Error(e.code()).what() 0039 #else 0040 << e.code() << ": " << s.c_str() 0041 #endif 0042 << ")"; 0043 } 0044 catch(...) 0045 { 0046 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0047 } 0048 0049 #else 0050 0051 Q_UNUSED(filePath); 0052 0053 #endif // _XMP_SUPPORT_ 0054 0055 return false; 0056 } 0057 0058 bool KExiv2::hasXmp() const 0059 { 0060 #ifdef _XMP_SUPPORT_ 0061 0062 return !d->xmpMetadata().empty(); 0063 0064 #else 0065 0066 return false; 0067 0068 #endif // _XMP_SUPPORT_ 0069 } 0070 0071 bool KExiv2::clearXmp() const 0072 { 0073 #ifdef _XMP_SUPPORT_ 0074 0075 try 0076 { 0077 d->xmpMetadata().clear(); 0078 return true; 0079 } 0080 catch( Exiv2::Error& e ) 0081 { 0082 d->printExiv2ExceptionError(QString::fromLatin1("Cannot clear Xmp data using Exiv2 "), e); 0083 } 0084 catch(...) 0085 { 0086 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0087 } 0088 0089 #endif // _XMP_SUPPORT_ 0090 0091 return false; 0092 } 0093 0094 QByteArray KExiv2::getXmp() const 0095 { 0096 #ifdef _XMP_SUPPORT_ 0097 0098 try 0099 { 0100 if (!d->xmpMetadata().empty()) 0101 { 0102 0103 std::string xmpPacket; 0104 Exiv2::XmpParser::encode(xmpPacket, d->xmpMetadata()); 0105 QByteArray data(xmpPacket.data(), xmpPacket.size()); 0106 return data; 0107 } 0108 } 0109 catch( Exiv2::Error& e ) 0110 { 0111 if (!d->filePath.isEmpty()) 0112 0113 0114 d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Xmp data using Exiv2 "), e); 0115 } 0116 catch(...) 0117 { 0118 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0119 } 0120 0121 #endif // _XMP_SUPPORT_ 0122 0123 return QByteArray(); 0124 } 0125 0126 bool KExiv2::setXmp(const QByteArray& data) const 0127 { 0128 #ifdef _XMP_SUPPORT_ 0129 0130 try 0131 { 0132 if (!data.isEmpty()) 0133 { 0134 std::string xmpPacket; 0135 xmpPacket.assign(data.data(), data.size()); 0136 0137 if (Exiv2::XmpParser::decode(d->xmpMetadata(), xmpPacket) != 0) 0138 return false; 0139 else 0140 return true; 0141 } 0142 } 0143 catch( Exiv2::Error& e ) 0144 { 0145 if (!d->filePath.isEmpty()) 0146 qCCritical(LIBKEXIV2_LOG) << "From file " << d->filePath.toLatin1().constData(); 0147 0148 d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp data using Exiv2 "), e); 0149 } 0150 catch(...) 0151 { 0152 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0153 } 0154 0155 #else 0156 0157 Q_UNUSED(data); 0158 0159 #endif // _XMP_SUPPORT_ 0160 0161 return false; 0162 } 0163 0164 KExiv2::MetaDataMap KExiv2::getXmpTagsDataList(const QStringList& xmpKeysFilter, bool invertSelection) const 0165 { 0166 #ifdef _XMP_SUPPORT_ 0167 0168 if (d->xmpMetadata().empty()) 0169 return MetaDataMap(); 0170 0171 try 0172 { 0173 Exiv2::XmpData xmpData = d->xmpMetadata(); 0174 xmpData.sortByKey(); 0175 0176 QString ifDItemName; 0177 MetaDataMap metaDataMap; 0178 0179 for (Exiv2::XmpData::iterator md = xmpData.begin(); md != xmpData.end(); ++md) 0180 { 0181 QString key = QString::fromLatin1(md->key().c_str()); 0182 0183 // Decode the tag value with a user friendly output. 0184 std::ostringstream os; 0185 os << *md; 0186 QString value = QString::fromUtf8(os.str().c_str()); 0187 0188 // If the tag is a language alternative type, parse content to detect language. 0189 if (md->typeId() == Exiv2::langAlt) 0190 { 0191 QString lang; 0192 value = detectLanguageAlt(value, lang); 0193 } 0194 else 0195 { 0196 value = QString::fromUtf8(os.str().c_str()); 0197 } 0198 0199 // To make a string just on one line. 0200 value.replace(QString::fromLatin1("\n"), QString::fromLatin1(" ")); 0201 0202 // Some XMP key are redondancy. check if already one exist... 0203 MetaDataMap::iterator it = metaDataMap.find(key); 0204 0205 // We apply a filter to get only the XMP tags that we need. 0206 0207 if (!xmpKeysFilter.isEmpty()) 0208 { 0209 if (!invertSelection) 0210 { 0211 if (xmpKeysFilter.contains(key.section(QString::fromLatin1("."), 1, 1))) 0212 { 0213 if (it == metaDataMap.end()) 0214 { 0215 metaDataMap.insert(key, value); 0216 } 0217 else 0218 { 0219 QString v = *it; 0220 v.append(QString::fromLatin1(", ")); 0221 v.append(value); 0222 metaDataMap.insert(key, v); 0223 } 0224 } 0225 } 0226 else 0227 { 0228 if (!xmpKeysFilter.contains(key.section(QString::fromLatin1("."), 1, 1))) 0229 { 0230 if (it == metaDataMap.end()) 0231 { 0232 metaDataMap.insert(key, value); 0233 } 0234 else 0235 { 0236 QString v = *it; 0237 v.append(QString::fromLatin1(", ")); 0238 v.append(value); 0239 metaDataMap.insert(key, v); 0240 } 0241 } 0242 } 0243 } 0244 else // else no filter at all. 0245 { 0246 if (it == metaDataMap.end()) 0247 { 0248 metaDataMap.insert(key, value); 0249 } 0250 else 0251 { 0252 QString v = *it; 0253 v.append(QString::fromLatin1(", ")); 0254 v.append(value); 0255 metaDataMap.insert(key, v); 0256 } 0257 } 0258 } 0259 0260 return metaDataMap; 0261 } 0262 catch (Exiv2::Error& e) 0263 { 0264 d->printExiv2ExceptionError(QString::fromLatin1("Cannot parse Xmp metadata using Exiv2 "), e); 0265 } 0266 catch(...) 0267 { 0268 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0269 } 0270 0271 #else 0272 0273 Q_UNUSED(xmpKeysFilter); 0274 Q_UNUSED(invertSelection); 0275 0276 #endif // _XMP_SUPPORT_ 0277 0278 return MetaDataMap(); 0279 } 0280 0281 QString KExiv2::getXmpTagTitle(const char* xmpTagName) 0282 { 0283 #ifdef _XMP_SUPPORT_ 0284 0285 try 0286 { 0287 std::string xmpkey(xmpTagName); 0288 Exiv2::XmpKey xk(xmpkey); 0289 return QString::fromLocal8Bit( Exiv2::XmpProperties::propertyTitle(xk) ); 0290 } 0291 catch (Exiv2::Error& e) 0292 { 0293 d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Xmp metadata tag title using Exiv2 "), e); 0294 } 0295 catch(...) 0296 { 0297 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0298 } 0299 0300 #else 0301 0302 Q_UNUSED(xmpTagName); 0303 0304 #endif // _XMP_SUPPORT_ 0305 0306 return QString(); 0307 } 0308 0309 QString KExiv2::getXmpTagDescription(const char* xmpTagName) 0310 { 0311 #ifdef _XMP_SUPPORT_ 0312 try 0313 { 0314 std::string xmpkey(xmpTagName); 0315 Exiv2::XmpKey xk(xmpkey); 0316 return QString::fromLocal8Bit( Exiv2::XmpProperties::propertyDesc(xk) ); 0317 } 0318 catch (Exiv2::Error& e) 0319 { 0320 d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Xmp metadata tag description using Exiv2 "), e); 0321 } 0322 catch(...) 0323 { 0324 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0325 } 0326 0327 #else 0328 0329 Q_UNUSED(xmpTagName); 0330 0331 #endif // _XMP_SUPPORT_ 0332 0333 return QString(); 0334 } 0335 0336 QString KExiv2::getXmpTagString(const char* xmpTagName, bool escapeCR) const 0337 { 0338 #ifdef _XMP_SUPPORT_ 0339 0340 try 0341 { 0342 Exiv2::XmpData xmpData(d->xmpMetadata()); 0343 Exiv2::XmpKey key(xmpTagName); 0344 Exiv2::XmpData::iterator it = xmpData.findKey(key); 0345 0346 if (it != xmpData.end()) 0347 { 0348 std::ostringstream os; 0349 os << *it; 0350 QString tagValue = QString::fromUtf8(os.str().c_str()); 0351 0352 if (escapeCR) 0353 tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" ")); 0354 0355 return tagValue; 0356 } 0357 } 0358 catch( Exiv2::Error& e ) 0359 { 0360 d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Xmp key '%1' into image using Exiv2 ").arg(QString::fromLatin1(xmpTagName)), e); 0361 } 0362 catch(...) 0363 { 0364 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0365 } 0366 0367 #else 0368 0369 Q_UNUSED(xmpTagName); 0370 Q_UNUSED(escapeCR); 0371 0372 #endif // _XMP_SUPPORT_ 0373 0374 return QString(); 0375 } 0376 0377 bool KExiv2::setXmpTagString(const char* xmpTagName, const QString& value, bool setProgramName) const 0378 { 0379 #ifdef _XMP_SUPPORT_ 0380 0381 if (!setProgramId(setProgramName)) 0382 return false; 0383 0384 try 0385 { 0386 const std::string &txt(value.toUtf8().constData()); 0387 #if EXIV2_TEST_VERSION(0,28,0) 0388 Exiv2::Value::UniquePtr xmpTxtVal = Exiv2::Value::create(Exiv2::xmpText); 0389 #else 0390 Exiv2::Value::AutoPtr xmpTxtVal = Exiv2::Value::create(Exiv2::xmpText); 0391 #endif 0392 xmpTxtVal->read(txt); 0393 d->xmpMetadata()[xmpTagName].setValue(xmpTxtVal.get()); 0394 return true; 0395 } 0396 catch( Exiv2::Error& e ) 0397 { 0398 d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp tag string into image using Exiv2 "), e); 0399 } 0400 catch(...) 0401 { 0402 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0403 } 0404 0405 #else 0406 0407 Q_UNUSED(xmpTagName); 0408 Q_UNUSED(value); 0409 Q_UNUSED(setProgramName); 0410 0411 #endif // _XMP_SUPPORT_ 0412 0413 return false; 0414 } 0415 bool KExiv2::setXmpTagString(const char* xmpTagName, const QString& value, 0416 KExiv2::XmpTagType type, bool setProgramName) const 0417 { 0418 #ifdef _XMP_SUPPORT_ 0419 0420 if (!setProgramId(setProgramName)) 0421 return false; 0422 0423 try 0424 { 0425 const std::string &txt(value.toUtf8().constData()); 0426 Exiv2::XmpTextValue xmpTxtVal(""); 0427 0428 if (type == KExiv2::NormalTag) // normal type 0429 { 0430 xmpTxtVal.read(txt); 0431 d->xmpMetadata().add(Exiv2::XmpKey(xmpTagName),&xmpTxtVal); 0432 return true; 0433 } 0434 0435 if (type == KExiv2::ArrayBagTag) // xmp type = bag 0436 { 0437 xmpTxtVal.setXmpArrayType(Exiv2::XmpValue::xaBag); 0438 xmpTxtVal.read(""); 0439 d->xmpMetadata().add(Exiv2::XmpKey(xmpTagName),&xmpTxtVal); 0440 } 0441 0442 if (type == KExiv2::StructureTag) // xmp type = struct 0443 { 0444 xmpTxtVal.setXmpStruct(); 0445 d->xmpMetadata().add(Exiv2::XmpKey(xmpTagName),&xmpTxtVal); 0446 } 0447 } 0448 catch( Exiv2::Error& e ) 0449 { 0450 d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp tag string into image using Exiv2 "), e); 0451 } 0452 catch(...) 0453 { 0454 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0455 } 0456 0457 #else 0458 0459 Q_UNUSED(xmpTagName); 0460 Q_UNUSED(value); 0461 Q_UNUSED(setProgramName); 0462 0463 #endif // _XMP_SUPPORT_ 0464 0465 return false; 0466 } 0467 KExiv2::AltLangMap KExiv2::getXmpTagStringListLangAlt(const char* xmpTagName, bool escapeCR) const 0468 { 0469 #ifdef _XMP_SUPPORT_ 0470 0471 try 0472 { 0473 Exiv2::XmpData xmpData = d->xmpMetadata(); 0474 0475 for (Exiv2::XmpData::iterator it = xmpData.begin(); it != xmpData.end(); ++it) 0476 { 0477 if (it->key() == xmpTagName && it->typeId() == Exiv2::langAlt) 0478 { 0479 AltLangMap map; 0480 const Exiv2::LangAltValue &value = static_cast<const Exiv2::LangAltValue &>(it->value()); 0481 0482 for (Exiv2::LangAltValue::ValueType::const_iterator it2 = value.value_.begin(); 0483 it2 != value.value_.end(); ++it2) 0484 { 0485 QString lang = QString::fromUtf8(it2->first.c_str()); 0486 QString text = QString::fromUtf8(it2->second.c_str()); 0487 0488 if (escapeCR) 0489 text.replace(QString::fromLatin1("\n"), QString::fromLatin1(" ")); 0490 0491 map.insert(lang, text); 0492 } 0493 0494 return map; 0495 } 0496 } 0497 } 0498 catch( Exiv2::Error& e ) 0499 { 0500 d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Xmp key '%1' into image using Exiv2 ").arg(QString::fromLatin1(xmpTagName)), e); 0501 } 0502 catch(...) 0503 { 0504 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0505 } 0506 0507 #else 0508 0509 Q_UNUSED(xmpTagName); 0510 Q_UNUSED(escapeCR); 0511 0512 #endif // _XMP_SUPPORT_ 0513 0514 return AltLangMap(); 0515 } 0516 0517 bool KExiv2::setXmpTagStringListLangAlt(const char* xmpTagName, const KExiv2::AltLangMap& values, 0518 bool setProgramName) const 0519 { 0520 #ifdef _XMP_SUPPORT_ 0521 0522 if (!setProgramId(setProgramName)) 0523 return false; 0524 0525 try 0526 { 0527 // Remove old XMP alternative Language tag. 0528 removeXmpTag(xmpTagName); 0529 0530 if (!values.isEmpty()) 0531 { 0532 #if EXIV2_TEST_VERSION(0,28,0) 0533 Exiv2::Value::UniquePtr xmpTxtVal = Exiv2::Value::create(Exiv2::langAlt); 0534 #else 0535 Exiv2::Value::AutoPtr xmpTxtVal = Exiv2::Value::create(Exiv2::langAlt); 0536 #endif 0537 0538 for (AltLangMap::const_iterator it = values.constBegin(); it != values.constEnd(); ++it) 0539 { 0540 QString lang = it.key(); 0541 QString text = it.value(); 0542 QString txtLangAlt = QString::fromLatin1("lang=%1 %2").arg(lang).arg(text); 0543 const std::string &txt(txtLangAlt.toUtf8().constData()); 0544 xmpTxtVal->read(txt); 0545 } 0546 0547 // ...and add the new one instead. 0548 d->xmpMetadata().add(Exiv2::XmpKey(xmpTagName), xmpTxtVal.get()); 0549 } 0550 return true; 0551 } 0552 catch( Exiv2::Error& e ) 0553 { 0554 d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp tag string lang-alt into image using Exiv2 "), e); 0555 } 0556 catch(...) 0557 { 0558 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0559 } 0560 0561 #else 0562 0563 Q_UNUSED(xmpTagName); 0564 Q_UNUSED(values); 0565 Q_UNUSED(setProgramName); 0566 0567 #endif // _XMP_SUPPORT_ 0568 0569 return false; 0570 } 0571 0572 QString KExiv2::getXmpTagStringLangAlt(const char* xmpTagName, const QString& langAlt, bool escapeCR) const 0573 { 0574 #ifdef _XMP_SUPPORT_ 0575 0576 try 0577 { 0578 Exiv2::XmpData xmpData(d->xmpMetadata()); 0579 Exiv2::XmpKey key(xmpTagName); 0580 0581 for (Exiv2::XmpData::iterator it = xmpData.begin(); it != xmpData.end(); ++it) 0582 { 0583 if (it->key() == xmpTagName && it->typeId() == Exiv2::langAlt) 0584 { 0585 for (int i = 0; i < it->count(); i++) 0586 { 0587 std::ostringstream os; 0588 os << it->toString(i); 0589 QString lang; 0590 QString tagValue = QString::fromUtf8(os.str().c_str()); 0591 tagValue = detectLanguageAlt(tagValue, lang); 0592 0593 if (langAlt == lang) 0594 { 0595 if (escapeCR) 0596 tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" ")); 0597 0598 return tagValue; 0599 } 0600 } 0601 } 0602 } 0603 } 0604 catch( Exiv2::Error& e ) 0605 { 0606 d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Xmp key '%1' into image using Exiv2 ").arg(QString::fromLatin1(xmpTagName)), e); 0607 } 0608 catch(...) 0609 { 0610 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0611 } 0612 0613 #else 0614 0615 Q_UNUSED(xmpTagName); 0616 Q_UNUSED(langAlt); 0617 Q_UNUSED(escapeCR); 0618 0619 #endif // _XMP_SUPPORT_ 0620 0621 return QString(); 0622 } 0623 0624 bool KExiv2::setXmpTagStringLangAlt(const char* xmpTagName, const QString& value, 0625 const QString& langAlt, bool setProgramName) const 0626 { 0627 #ifdef _XMP_SUPPORT_ 0628 0629 if (!setProgramId(setProgramName)) 0630 return false; 0631 0632 try 0633 { 0634 QString language(QString::fromLatin1("x-default")); // default alternative language. 0635 0636 if (!langAlt.isEmpty()) 0637 language = langAlt; 0638 0639 QString txtLangAlt = QString(QString::fromLatin1("lang=%1 %2")).arg(language).arg(value); 0640 0641 const std::string &txt(txtLangAlt.toUtf8().constData()); 0642 #if EXIV2_TEST_VERSION(0,28,0) 0643 Exiv2::Value::UniquePtr xmpTxtVal = Exiv2::Value::create(Exiv2::langAlt); 0644 #else 0645 Exiv2::Value::AutoPtr xmpTxtVal = Exiv2::Value::create(Exiv2::langAlt); 0646 #endif 0647 0648 // Search if an Xmp tag already exist. 0649 0650 AltLangMap map = getXmpTagStringListLangAlt(xmpTagName, false); 0651 0652 if (!map.isEmpty()) 0653 { 0654 for (AltLangMap::iterator it = map.begin(); it != map.end(); ++it) 0655 { 0656 if (it.key() != langAlt) 0657 { 0658 const std::string &val((*it).toUtf8().constData()); 0659 xmpTxtVal->read(val); 0660 qCDebug(LIBKEXIV2_LOG) << *it; 0661 } 0662 } 0663 } 0664 0665 xmpTxtVal->read(txt); 0666 removeXmpTag(xmpTagName); 0667 d->xmpMetadata().add(Exiv2::XmpKey(xmpTagName), xmpTxtVal.get()); 0668 return true; 0669 } 0670 catch( Exiv2::Error& e ) 0671 { 0672 d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp tag string lang-alt into image using Exiv2 "), e); 0673 } 0674 catch(...) 0675 { 0676 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0677 } 0678 0679 #else 0680 0681 Q_UNUSED(xmpTagName); 0682 Q_UNUSED(value); 0683 Q_UNUSED(langAlt); 0684 Q_UNUSED(setProgramName); 0685 0686 #endif // _XMP_SUPPORT_ 0687 0688 return false; 0689 } 0690 0691 QStringList KExiv2::getXmpTagStringSeq(const char* xmpTagName, bool escapeCR) const 0692 { 0693 #ifdef _XMP_SUPPORT_ 0694 0695 try 0696 { 0697 Exiv2::XmpData xmpData(d->xmpMetadata()); 0698 Exiv2::XmpKey key(xmpTagName); 0699 Exiv2::XmpData::iterator it = xmpData.findKey(key); 0700 0701 if (it != xmpData.end()) 0702 { 0703 if (it->typeId() == Exiv2::xmpSeq) 0704 { 0705 QStringList seq; 0706 0707 for (int i = 0; i < it->count(); i++) 0708 { 0709 std::ostringstream os; 0710 os << it->toString(i); 0711 QString seqValue = QString::fromUtf8(os.str().c_str()); 0712 0713 if (escapeCR) 0714 seqValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" ")); 0715 0716 seq.append(seqValue); 0717 } 0718 qCDebug(LIBKEXIV2_LOG) << "XMP String Seq (" << xmpTagName << "): " << seq; 0719 0720 return seq; 0721 } 0722 } 0723 } 0724 catch( Exiv2::Error& e ) 0725 { 0726 d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Xmp key '%1' into image using Exiv2 ").arg(QString::fromLatin1(xmpTagName)), e); 0727 } 0728 catch(...) 0729 { 0730 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0731 } 0732 0733 #else 0734 0735 Q_UNUSED(xmpTagName); 0736 Q_UNUSED(escapeCR); 0737 0738 #endif // _XMP_SUPPORT_ 0739 0740 return QStringList(); 0741 } 0742 0743 bool KExiv2::setXmpTagStringSeq(const char* xmpTagName, const QStringList& seq, 0744 bool setProgramName) const 0745 { 0746 #ifdef _XMP_SUPPORT_ 0747 0748 if (!setProgramId(setProgramName)) 0749 return false; 0750 0751 try 0752 { 0753 if (seq.isEmpty()) 0754 { 0755 removeXmpTag(xmpTagName); 0756 } 0757 else 0758 { 0759 const QStringList list = seq; 0760 #if EXIV2_TEST_VERSION(0,28,0) 0761 Exiv2::Value::UniquePtr xmpTxtSeq = Exiv2::Value::create(Exiv2::xmpSeq); 0762 #else 0763 Exiv2::Value::AutoPtr xmpTxtSeq = Exiv2::Value::create(Exiv2::xmpSeq); 0764 #endif 0765 0766 for (QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it ) 0767 { 0768 const std::string &txt((*it).toUtf8().constData()); 0769 xmpTxtSeq->read(txt); 0770 } 0771 0772 d->xmpMetadata()[xmpTagName].setValue(xmpTxtSeq.get()); 0773 } 0774 return true; 0775 } 0776 catch( Exiv2::Error& e ) 0777 { 0778 d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp tag string Seq into image using Exiv2 "), e); 0779 } 0780 catch(...) 0781 { 0782 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0783 } 0784 0785 #else 0786 0787 Q_UNUSED(xmpTagName); 0788 Q_UNUSED(seq); 0789 Q_UNUSED(setProgramName); 0790 0791 #endif // _XMP_SUPPORT_ 0792 0793 return false; 0794 } 0795 0796 QStringList KExiv2::getXmpTagStringBag(const char* xmpTagName, bool escapeCR) const 0797 { 0798 #ifdef _XMP_SUPPORT_ 0799 0800 try 0801 { 0802 Exiv2::XmpData xmpData(d->xmpMetadata()); 0803 Exiv2::XmpKey key(xmpTagName); 0804 Exiv2::XmpData::iterator it = xmpData.findKey(key); 0805 0806 if (it != xmpData.end()) 0807 { 0808 if (it->typeId() == Exiv2::xmpBag) 0809 { 0810 QStringList bag; 0811 0812 for (int i = 0; i < it->count(); i++) 0813 { 0814 std::ostringstream os; 0815 os << it->toString(i); 0816 QString bagValue = QString::fromUtf8(os.str().c_str()); 0817 0818 if (escapeCR) 0819 bagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" ")); 0820 0821 bag.append(bagValue); 0822 } 0823 0824 return bag; 0825 } 0826 } 0827 } 0828 catch( Exiv2::Error& e ) 0829 { 0830 d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Xmp key '%1' into image using Exiv2 ").arg(QString::fromLatin1(xmpTagName)), e); 0831 } 0832 catch(...) 0833 { 0834 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0835 } 0836 0837 #else 0838 0839 Q_UNUSED(xmpTagName); 0840 Q_UNUSED(escapeCR); 0841 0842 #endif // _XMP_SUPPORT_ 0843 0844 return QStringList(); 0845 } 0846 0847 bool KExiv2::setXmpTagStringBag(const char* xmpTagName, const QStringList& bag, 0848 bool setProgramName) const 0849 { 0850 #ifdef _XMP_SUPPORT_ 0851 0852 if (!setProgramId(setProgramName)) 0853 return false; 0854 0855 try 0856 { 0857 if (bag.isEmpty()) 0858 { 0859 removeXmpTag(xmpTagName); 0860 } 0861 else 0862 { 0863 QStringList list = bag; 0864 #if EXIV2_TEST_VERSION(0,28,0) 0865 Exiv2::Value::UniquePtr xmpTxtBag = Exiv2::Value::create(Exiv2::xmpBag); 0866 #else 0867 Exiv2::Value::AutoPtr xmpTxtBag = Exiv2::Value::create(Exiv2::xmpBag); 0868 #endif 0869 0870 for (QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it ) 0871 { 0872 const std::string &txt((*it).toUtf8().constData()); 0873 xmpTxtBag->read(txt); 0874 } 0875 0876 d->xmpMetadata()[xmpTagName].setValue(xmpTxtBag.get()); 0877 } 0878 return true; 0879 } 0880 catch( Exiv2::Error& e ) 0881 { 0882 d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp tag string Bag into image using Exiv2 "), e); 0883 } 0884 catch(...) 0885 { 0886 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 0887 } 0888 0889 #else 0890 0891 Q_UNUSED(xmpTagName); 0892 Q_UNUSED(bag); 0893 Q_UNUSED(setProgramName); 0894 0895 #endif // _XMP_SUPPORT_ 0896 0897 return false; 0898 } 0899 0900 bool KExiv2::addToXmpTagStringBag(const char* xmpTagName, const QStringList& entriesToAdd, 0901 bool setProgramName) const 0902 { 0903 if (!setProgramId(setProgramName)) 0904 return false; 0905 0906 QStringList oldEntries = getXmpTagStringBag(xmpTagName, false); 0907 QStringList newEntries = entriesToAdd; 0908 0909 // Create a list of keywords including old one which already exists. 0910 for (QStringList::const_iterator it = oldEntries.constBegin(); it != oldEntries.constEnd(); ++it ) 0911 { 0912 if (!newEntries.contains(*it)) 0913 newEntries.append(*it); 0914 } 0915 0916 if (setXmpTagStringBag(xmpTagName, newEntries, false)) 0917 return true; 0918 0919 return false; 0920 } 0921 0922 bool KExiv2::removeFromXmpTagStringBag(const char* xmpTagName, const QStringList& entriesToRemove, 0923 bool setProgramName) const 0924 { 0925 if (!setProgramId(setProgramName)) 0926 return false; 0927 0928 QStringList currentEntries = getXmpTagStringBag(xmpTagName, false); 0929 QStringList newEntries; 0930 0931 // Create a list of current keywords except those that shall be removed 0932 for (QStringList::const_iterator it = currentEntries.constBegin(); it != currentEntries.constEnd(); ++it ) 0933 { 0934 if (!entriesToRemove.contains(*it)) 0935 newEntries.append(*it); 0936 } 0937 0938 if (setXmpTagStringBag(xmpTagName, newEntries, false)) 0939 return true; 0940 0941 return false; 0942 } 0943 0944 QVariant KExiv2::getXmpTagVariant(const char* xmpTagName, bool rationalAsListOfInts, bool stringEscapeCR) const 0945 { 0946 #ifdef _XMP_SUPPORT_ 0947 try 0948 { 0949 Exiv2::XmpData xmpData(d->xmpMetadata()); 0950 Exiv2::XmpKey key(xmpTagName); 0951 Exiv2::XmpData::iterator it = xmpData.findKey(key); 0952 0953 if (it != xmpData.end()) 0954 { 0955 switch (it->typeId()) 0956 { 0957 case Exiv2::unsignedByte: 0958 case Exiv2::unsignedShort: 0959 case Exiv2::unsignedLong: 0960 case Exiv2::signedShort: 0961 case Exiv2::signedLong: 0962 #if EXIV2_TEST_VERSION(0,28,0) 0963 return QVariant((int)it->toUint32()); 0964 #else 0965 return QVariant((int)it->toLong()); 0966 #endif 0967 case Exiv2::unsignedRational: 0968 case Exiv2::signedRational: 0969 if (rationalAsListOfInts) 0970 { 0971 QList<QVariant> list; 0972 list << (*it).toRational().first; 0973 list << (*it).toRational().second; 0974 return QVariant(list); 0975 } 0976 else 0977 { 0978 // prefer double precision 0979 double num = (*it).toRational().first; 0980 double den = (*it).toRational().second; 0981 0982 if (den == 0.0) 0983 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0984 return QVariant(QMetaType(QMetaType::Double)); 0985 #else 0986 return QVariant(QVariant::Double); 0987 #endif 0988 0989 return QVariant(num / den); 0990 } 0991 case Exiv2::date: 0992 case Exiv2::time: 0993 { 0994 QDateTime dateTime = QDateTime::fromString(QString::fromLatin1(it->toString().c_str()), Qt::ISODate); 0995 return QVariant(dateTime); 0996 } 0997 case Exiv2::asciiString: 0998 case Exiv2::comment: 0999 case Exiv2::string: 1000 { 1001 std::ostringstream os; 1002 os << *it; 1003 QString tagValue = QString::fromLocal8Bit(os.str().c_str()); 1004 1005 if (stringEscapeCR) 1006 tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" ")); 1007 1008 return QVariant(tagValue); 1009 } 1010 case Exiv2::xmpText: 1011 { 1012 std::ostringstream os; 1013 os << *it; 1014 QString tagValue = QString::fromUtf8(os.str().c_str()); 1015 1016 if (stringEscapeCR) 1017 tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" ")); 1018 1019 return tagValue; 1020 } 1021 case Exiv2::xmpBag: 1022 case Exiv2::xmpSeq: 1023 case Exiv2::xmpAlt: 1024 { 1025 QStringList list; 1026 1027 for (int i=0; i < it->count(); i++) 1028 { 1029 list << QString::fromUtf8(it->toString(i).c_str()); 1030 } 1031 1032 return list; 1033 } 1034 case Exiv2::langAlt: 1035 { 1036 // access the value directly 1037 const Exiv2::LangAltValue &value = static_cast<const Exiv2::LangAltValue &>(it->value()); 1038 QMap<QString, QVariant> map; 1039 // access the ValueType std::map< std::string, std::string> 1040 Exiv2::LangAltValue::ValueType::const_iterator i; 1041 1042 for (i = value.value_.begin(); i != value.value_.end(); ++i) 1043 { 1044 map[QString::fromUtf8(i->first.c_str())] = QString::fromUtf8(i->second.c_str()); 1045 } 1046 1047 return map; 1048 } 1049 default: 1050 break; 1051 } 1052 } 1053 } 1054 catch( Exiv2::Error& e ) 1055 { 1056 d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Xmp key '%1' into image using Exiv2 ").arg(QString::fromLatin1(xmpTagName)), e); 1057 } 1058 catch(...) 1059 { 1060 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 1061 } 1062 1063 #else 1064 1065 Q_UNUSED(xmpTagName); 1066 Q_UNUSED(rationalAsListOfInts); 1067 Q_UNUSED(stringEscapeCR); 1068 1069 #endif // _XMP_SUPPORT_ 1070 1071 return QVariant(); 1072 } 1073 1074 bool KExiv2::registerXmpNameSpace(const QString& uri, const QString& prefix) 1075 { 1076 #ifdef _XMP_SUPPORT_ 1077 1078 try 1079 { 1080 QString ns = uri; 1081 1082 if (!uri.endsWith(QString::fromLatin1("/"))) 1083 ns.append(QString::fromLatin1("/")); 1084 1085 Exiv2::XmpProperties::registerNs(ns.toLatin1().constData(), prefix.toLatin1().constData()); 1086 return true; 1087 } 1088 catch( Exiv2::Error& e ) 1089 { 1090 KExiv2Private::printExiv2ExceptionError(QString::fromLatin1("Cannot register a new Xmp namespace using Exiv2 "), e); 1091 } 1092 catch(...) 1093 { 1094 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 1095 } 1096 1097 #else 1098 1099 Q_UNUSED(uri); 1100 Q_UNUSED(prefix); 1101 1102 #endif // _XMP_SUPPORT_ 1103 1104 return false; 1105 } 1106 1107 bool KExiv2::unregisterXmpNameSpace(const QString& uri) 1108 { 1109 #ifdef _XMP_SUPPORT_ 1110 1111 try 1112 { 1113 QString ns = uri; 1114 1115 if (!uri.endsWith(QString::fromLatin1("/"))) 1116 ns.append(QString::fromLatin1("/")); 1117 1118 Exiv2::XmpProperties::unregisterNs(ns.toLatin1().constData()); 1119 return true; 1120 } 1121 catch( Exiv2::Error& e ) 1122 { 1123 KExiv2Private::printExiv2ExceptionError(QString::fromLatin1("Cannot unregister a new Xmp namespace using Exiv2 "), e); 1124 } 1125 catch(...) 1126 { 1127 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 1128 } 1129 1130 #else 1131 1132 Q_UNUSED(uri); 1133 1134 #endif // _XMP_SUPPORT_ 1135 1136 return false; 1137 } 1138 1139 bool KExiv2::removeXmpTag(const char* xmpTagName, bool setProgramName) const 1140 { 1141 #ifdef _XMP_SUPPORT_ 1142 1143 if (!setProgramId(setProgramName)) 1144 return false; 1145 1146 try 1147 { 1148 Exiv2::XmpKey xmpKey(xmpTagName); 1149 Exiv2::XmpData::iterator it = d->xmpMetadata().findKey(xmpKey); 1150 1151 if (it != d->xmpMetadata().end()) 1152 { 1153 d->xmpMetadata().erase(it); 1154 return true; 1155 } 1156 } 1157 catch( Exiv2::Error& e ) 1158 { 1159 d->printExiv2ExceptionError(QString::fromLatin1("Cannot remove Xmp tag using Exiv2 "), e); 1160 } 1161 catch(...) 1162 { 1163 qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2"; 1164 } 1165 1166 #else 1167 1168 Q_UNUSED(xmpTagName); 1169 Q_UNUSED(setProgramName); 1170 1171 #endif // _XMP_SUPPORT_ 1172 1173 return false; 1174 } 1175 1176 QStringList KExiv2::getXmpKeywords() const 1177 { 1178 return (getXmpTagStringBag("Xmp.dc.subject", false)); 1179 } 1180 1181 bool KExiv2::setXmpKeywords(const QStringList& newKeywords, bool setProgramName) const 1182 { 1183 return addToXmpTagStringBag("Xmp.dc.subject", newKeywords, setProgramName); 1184 } 1185 1186 bool KExiv2::removeXmpKeywords(const QStringList& keywordsToRemove, bool setProgramName) 1187 { 1188 return removeFromXmpTagStringBag("Xmp.dc.subject", keywordsToRemove, setProgramName); 1189 } 1190 1191 QStringList KExiv2::getXmpSubCategories() const 1192 { 1193 return (getXmpTagStringBag("Xmp.photoshop.SupplementalCategories", false)); 1194 } 1195 1196 bool KExiv2::setXmpSubCategories(const QStringList& newSubCategories, bool setProgramName) const 1197 { 1198 return addToXmpTagStringBag("Xmp.photoshop.SupplementalCategories", newSubCategories, setProgramName); 1199 } 1200 1201 bool KExiv2::removeXmpSubCategories(const QStringList& subCategoriesToRemove, bool setProgramName) 1202 { 1203 return removeFromXmpTagStringBag("Xmp.photoshop.SupplementalCategories", subCategoriesToRemove, setProgramName); 1204 } 1205 1206 QStringList KExiv2::getXmpSubjects() const 1207 { 1208 return (getXmpTagStringBag("Xmp.iptc.SubjectCode", false)); 1209 } 1210 1211 bool KExiv2::setXmpSubjects(const QStringList& newSubjects, bool setProgramName) const 1212 { 1213 return addToXmpTagStringBag("Xmp.iptc.SubjectCode", newSubjects, setProgramName); 1214 } 1215 1216 bool KExiv2::removeXmpSubjects(const QStringList& subjectsToRemove, bool setProgramName) 1217 { 1218 return removeFromXmpTagStringBag("Xmp.iptc.SubjectCode", subjectsToRemove, setProgramName); 1219 } 1220 1221 KExiv2::TagsMap KExiv2::getXmpTagsList() const 1222 { 1223 TagsMap tagsMap; 1224 d->getXMPTagsListFromPrefix(QString::fromLatin1("dc"), tagsMap); 1225 d->getXMPTagsListFromPrefix(QString::fromLatin1("digiKam"), tagsMap); 1226 d->getXMPTagsListFromPrefix(QString::fromLatin1("xmp"), tagsMap); 1227 d->getXMPTagsListFromPrefix(QString::fromLatin1("xmpRights"), tagsMap); 1228 d->getXMPTagsListFromPrefix(QString::fromLatin1("xmpMM"), tagsMap); 1229 d->getXMPTagsListFromPrefix(QString::fromLatin1("xmpBJ"), tagsMap); 1230 d->getXMPTagsListFromPrefix(QString::fromLatin1("xmpTPg"), tagsMap); 1231 d->getXMPTagsListFromPrefix(QString::fromLatin1("xmpDM"), tagsMap); 1232 d->getXMPTagsListFromPrefix(QString::fromLatin1("MicrosoftPhoto"), tagsMap); 1233 d->getXMPTagsListFromPrefix(QString::fromLatin1("pdf"), tagsMap); 1234 d->getXMPTagsListFromPrefix(QString::fromLatin1("photoshop"), tagsMap); 1235 d->getXMPTagsListFromPrefix(QString::fromLatin1("crs"), tagsMap); 1236 d->getXMPTagsListFromPrefix(QString::fromLatin1("tiff"), tagsMap); 1237 d->getXMPTagsListFromPrefix(QString::fromLatin1("exif"), tagsMap); 1238 d->getXMPTagsListFromPrefix(QString::fromLatin1("aux"), tagsMap); 1239 d->getXMPTagsListFromPrefix(QString::fromLatin1("iptc"), tagsMap); 1240 d->getXMPTagsListFromPrefix(QString::fromLatin1("iptcExt"), tagsMap); 1241 d->getXMPTagsListFromPrefix(QString::fromLatin1("plus"), tagsMap); 1242 d->getXMPTagsListFromPrefix(QString::fromLatin1("mwg-rs"), tagsMap); 1243 d->getXMPTagsListFromPrefix(QString::fromLatin1("dwc"), tagsMap); 1244 return tagsMap; 1245 } 1246 1247 } // NameSpace KExiv2Iface