KExiv2

kexiv2xmp.cpp
Go to the documentation of this file.
1 
28 // Local includes
29 
30 #include "kexiv2.h"
31 #include "kexiv2_p.h"
32 #include "libkexiv2_debug.h"
33 
34 namespace KExiv2Iface
35 {
36 
37 bool KExiv2::canWriteXmp(const QString& filePath)
38 {
39 #ifdef _XMP_SUPPORT_
40  try
41  {
42  Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open((const char*)
43  (QFile::encodeName(filePath).constData()));
44 
45  Exiv2::AccessMode mode = image->checkMode(Exiv2::mdXmp);
46  return (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite);
47  }
48  catch( Exiv2::Error& e )
49  {
50  std::string s(e.what());
51  qCCritical(LIBKEXIV2_LOG) << "Cannot check Xmp access mode using Exiv2 (Error #"
52  << e.code() << ": " << s.c_str() << ")";
53  }
54  catch(...)
55  {
56  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
57  }
58 
59 #else
60 
61  Q_UNUSED(filePath);
62 
63 #endif // _XMP_SUPPORT_
64 
65  return false;
66 }
67 
68 bool KExiv2::hasXmp() const
69 {
70 #ifdef _XMP_SUPPORT_
71 
72  return !d->xmpMetadata().empty();
73 
74 #else
75 
76  return false;
77 
78 #endif // _XMP_SUPPORT_
79 }
80 
81 bool KExiv2::clearXmp() const
82 {
83 #ifdef _XMP_SUPPORT_
84 
85  try
86  {
87  d->xmpMetadata().clear();
88  return true;
89  }
90  catch( Exiv2::Error& e )
91  {
92  d->printExiv2ExceptionError(QString::fromLatin1("Cannot clear Xmp data using Exiv2 "), e);
93  }
94  catch(...)
95  {
96  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
97  }
98 
99 #endif // _XMP_SUPPORT_
100 
101  return false;
102 }
103 
105 {
106 #ifdef _XMP_SUPPORT_
107 
108  try
109  {
110  if (!d->xmpMetadata().empty())
111  {
112 
113  std::string xmpPacket;
114  Exiv2::XmpParser::encode(xmpPacket, d->xmpMetadata());
115  QByteArray data(xmpPacket.data(), xmpPacket.size());
116  return data;
117  }
118  }
119  catch( Exiv2::Error& e )
120  {
121  if (!d->filePath.isEmpty())
122 
123 
124  d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Xmp data using Exiv2 "), e);
125  }
126  catch(...)
127  {
128  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
129  }
130 
131 #endif // _XMP_SUPPORT_
132 
133  return QByteArray();
134 }
135 
136 bool KExiv2::setXmp(const QByteArray& data) const
137 {
138 #ifdef _XMP_SUPPORT_
139 
140  try
141  {
142  if (!data.isEmpty())
143  {
144  std::string xmpPacket;
145  xmpPacket.assign(data.data(), data.size());
146 
147  if (Exiv2::XmpParser::decode(d->xmpMetadata(), xmpPacket) != 0)
148  return false;
149  else
150  return true;
151  }
152  }
153  catch( Exiv2::Error& e )
154  {
155  if (!d->filePath.isEmpty())
156  qCCritical(LIBKEXIV2_LOG) << "From file " << d->filePath.toLatin1().constData();
157 
158  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp data using Exiv2 "), e);
159  }
160  catch(...)
161  {
162  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
163  }
164 
165 #else
166 
167  Q_UNUSED(data);
168 
169 #endif // _XMP_SUPPORT_
170 
171  return false;
172 }
173 
174 KExiv2::MetaDataMap KExiv2::getXmpTagsDataList(const QStringList& xmpKeysFilter, bool invertSelection) const
175 {
176 #ifdef _XMP_SUPPORT_
177 
178  if (d->xmpMetadata().empty())
179  return MetaDataMap();
180 
181  try
182  {
183  Exiv2::XmpData xmpData = d->xmpMetadata();
184  xmpData.sortByKey();
185 
186  QString ifDItemName;
187  MetaDataMap metaDataMap;
188 
189  for (Exiv2::XmpData::iterator md = xmpData.begin(); md != xmpData.end(); ++md)
190  {
191  QString key = QString::fromLatin1(md->key().c_str());
192 
193  // Decode the tag value with a user friendly output.
194  std::ostringstream os;
195  os << *md;
196  QString value = QString::fromUtf8(os.str().c_str());
197 
198  // If the tag is a language alternative type, parse content to detect language.
199  if (md->typeId() == Exiv2::langAlt)
200  {
201  QString lang;
202  value = detectLanguageAlt(value, lang);
203  }
204  else
205  {
206  value = QString::fromUtf8(os.str().c_str());
207  }
208 
209  // To make a string just on one line.
211 
212  // Some XMP key are redondancy. check if already one exist...
213  MetaDataMap::iterator it = metaDataMap.find(key);
214 
215  // We apply a filter to get only the XMP tags that we need.
216 
217  if (!xmpKeysFilter.isEmpty())
218  {
219  if (!invertSelection)
220  {
221  if (xmpKeysFilter.contains(key.section(QString::fromLatin1("."), 1, 1)))
222  {
223  if (it == metaDataMap.end())
224  {
225  metaDataMap.insert(key, value);
226  }
227  else
228  {
229  QString v = *it;
230  v.append(QString::fromLatin1(", "));
231  v.append(value);
232  metaDataMap.insert(key, v);
233  }
234  }
235  }
236  else
237  {
238  if (!xmpKeysFilter.contains(key.section(QString::fromLatin1("."), 1, 1)))
239  {
240  if (it == metaDataMap.end())
241  {
242  metaDataMap.insert(key, value);
243  }
244  else
245  {
246  QString v = *it;
247  v.append(QString::fromLatin1(", "));
248  v.append(value);
249  metaDataMap.insert(key, v);
250  }
251  }
252  }
253  }
254  else // else no filter at all.
255  {
256  if (it == metaDataMap.end())
257  {
258  metaDataMap.insert(key, value);
259  }
260  else
261  {
262  QString v = *it;
263  v.append(QString::fromLatin1(", "));
264  v.append(value);
265  metaDataMap.insert(key, v);
266  }
267  }
268  }
269 
270  return metaDataMap;
271  }
272  catch (Exiv2::Error& e)
273  {
274  d->printExiv2ExceptionError(QString::fromLatin1("Cannot parse Xmp metadata using Exiv2 "), e);
275  }
276  catch(...)
277  {
278  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
279  }
280 
281 #else
282 
283  Q_UNUSED(xmpKeysFilter);
284  Q_UNUSED(invertSelection);
285 
286 #endif // _XMP_SUPPORT_
287 
288  return MetaDataMap();
289 }
290 
291 QString KExiv2::getXmpTagTitle(const char* xmpTagName)
292 {
293 #ifdef _XMP_SUPPORT_
294 
295  try
296  {
297  std::string xmpkey(xmpTagName);
298  Exiv2::XmpKey xk(xmpkey);
299  return QString::fromLocal8Bit( Exiv2::XmpProperties::propertyTitle(xk) );
300  }
301  catch (Exiv2::Error& e)
302  {
303  d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Xmp metadata tag title using Exiv2 "), e);
304  }
305  catch(...)
306  {
307  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
308  }
309 
310 #else
311 
312  Q_UNUSED(xmpTagName);
313 
314 #endif // _XMP_SUPPORT_
315 
316  return QString();
317 }
318 
319 QString KExiv2::getXmpTagDescription(const char* xmpTagName)
320 {
321 #ifdef _XMP_SUPPORT_
322  try
323  {
324  std::string xmpkey(xmpTagName);
325  Exiv2::XmpKey xk(xmpkey);
326  return QString::fromLocal8Bit( Exiv2::XmpProperties::propertyDesc(xk) );
327  }
328  catch (Exiv2::Error& e)
329  {
330  d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Xmp metadata tag description using Exiv2 "), e);
331  }
332  catch(...)
333  {
334  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
335  }
336 
337 #else
338 
339  Q_UNUSED(xmpTagName);
340 
341 #endif // _XMP_SUPPORT_
342 
343  return QString();
344 }
345 
346 QString KExiv2::getXmpTagString(const char* xmpTagName, bool escapeCR) const
347 {
348 #ifdef _XMP_SUPPORT_
349 
350  try
351  {
352  Exiv2::XmpData xmpData(d->xmpMetadata());
353  Exiv2::XmpKey key(xmpTagName);
354  Exiv2::XmpData::iterator it = xmpData.findKey(key);
355 
356  if (it != xmpData.end())
357  {
358  std::ostringstream os;
359  os << *it;
360  QString tagValue = QString::fromUtf8(os.str().c_str());
361 
362  if (escapeCR)
363  tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
364 
365  return tagValue;
366  }
367  }
368  catch( Exiv2::Error& e )
369  {
370  d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Xmp key '%1' into image using Exiv2 ").arg(QString::fromLatin1(xmpTagName)), e);
371  }
372  catch(...)
373  {
374  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
375  }
376 
377 #else
378 
379  Q_UNUSED(xmpTagName);
380  Q_UNUSED(escapeCR);
381 
382 #endif // _XMP_SUPPORT_
383 
384  return QString();
385 }
386 
387 bool KExiv2::setXmpTagString(const char* xmpTagName, const QString& value, bool setProgramName) const
388 {
389 #ifdef _XMP_SUPPORT_
390 
391  if (!setProgramId(setProgramName))
392  return false;
393 
394  try
395  {
396  const std::string &txt(value.toUtf8().constData());
397  Exiv2::Value::AutoPtr xmpTxtVal = Exiv2::Value::create(Exiv2::xmpText);
398  xmpTxtVal->read(txt);
399  d->xmpMetadata()[xmpTagName].setValue(xmpTxtVal.get());
400  return true;
401  }
402  catch( Exiv2::Error& e )
403  {
404  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp tag string into image using Exiv2 "), e);
405  }
406  catch(...)
407  {
408  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
409  }
410 
411 #else
412 
413  Q_UNUSED(xmpTagName);
414  Q_UNUSED(value);
415  Q_UNUSED(setProgramName);
416 
417 #endif // _XMP_SUPPORT_
418 
419  return false;
420 }
421 bool KExiv2::setXmpTagString(const char* xmpTagName, const QString& value,
422  KExiv2::XmpTagType type, bool setProgramName) const
423 {
424 #ifdef _XMP_SUPPORT_
425 
426  if (!setProgramId(setProgramName))
427  return false;
428 
429  try
430  {
431  const std::string &txt(value.toUtf8().constData());
432  Exiv2::XmpTextValue xmpTxtVal("");
433 
434  if (type == KExiv2::NormalTag) // normal type
435  {
436  xmpTxtVal.read(txt);
437  d->xmpMetadata().add(Exiv2::XmpKey(xmpTagName),&xmpTxtVal);
438  return true;
439  }
440 
441  if (type == KExiv2::ArrayBagTag) // xmp type = bag
442  {
443  xmpTxtVal.setXmpArrayType(Exiv2::XmpValue::xaBag);
444  xmpTxtVal.read("");
445  d->xmpMetadata().add(Exiv2::XmpKey(xmpTagName),&xmpTxtVal);
446  }
447 
448  if (type == KExiv2::StructureTag) // xmp type = struct
449  {
450  xmpTxtVal.setXmpStruct();
451  d->xmpMetadata().add(Exiv2::XmpKey(xmpTagName),&xmpTxtVal);
452  }
453  }
454  catch( Exiv2::Error& e )
455  {
456  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp tag string into image using Exiv2 "), e);
457  }
458  catch(...)
459  {
460  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
461  }
462 
463 #else
464 
465  Q_UNUSED(xmpTagName);
466  Q_UNUSED(value);
467  Q_UNUSED(setProgramName);
468 
469 #endif // _XMP_SUPPORT_
470 
471  return false;
472 }
473 KExiv2::AltLangMap KExiv2::getXmpTagStringListLangAlt(const char* xmpTagName, bool escapeCR) const
474 {
475 #ifdef _XMP_SUPPORT_
476 
477  try
478  {
479  Exiv2::XmpData xmpData = d->xmpMetadata();
480 
481  for (Exiv2::XmpData::iterator it = xmpData.begin(); it != xmpData.end(); ++it)
482  {
483  if (it->key() == xmpTagName && it->typeId() == Exiv2::langAlt)
484  {
485  AltLangMap map;
486  const Exiv2::LangAltValue &value = static_cast<const Exiv2::LangAltValue &>(it->value());
487 
488  for (Exiv2::LangAltValue::ValueType::const_iterator it2 = value.value_.begin();
489  it2 != value.value_.end(); ++it2)
490  {
491  QString lang = QString::fromUtf8(it2->first.c_str());
492  QString text = QString::fromUtf8(it2->second.c_str());
493 
494  if (escapeCR)
496 
497  map.insert(lang, text);
498  }
499 
500  return map;
501  }
502  }
503  }
504  catch( Exiv2::Error& e )
505  {
506  d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Xmp key '%1' into image using Exiv2 ").arg(QString::fromLatin1(xmpTagName)), e);
507  }
508  catch(...)
509  {
510  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
511  }
512 
513 #else
514 
515  Q_UNUSED(xmpTagName);
516  Q_UNUSED(escapeCR);
517 
518 #endif // _XMP_SUPPORT_
519 
520  return AltLangMap();
521 }
522 
523 bool KExiv2::setXmpTagStringListLangAlt(const char* xmpTagName, const KExiv2::AltLangMap& values,
524  bool setProgramName) const
525 {
526 #ifdef _XMP_SUPPORT_
527 
528  if (!setProgramId(setProgramName))
529  return false;
530 
531  try
532  {
533  // Remove old XMP alternative Language tag.
534  removeXmpTag(xmpTagName);
535 
536  if (!values.isEmpty())
537  {
538  Exiv2::Value::AutoPtr xmpTxtVal = Exiv2::Value::create(Exiv2::langAlt);
539 
540  for (AltLangMap::const_iterator it = values.constBegin(); it != values.constEnd(); ++it)
541  {
542  QString lang = it.key();
543  QString text = it.value();
544  QString txtLangAlt = QString::fromLatin1("lang=%1 %2").arg(lang).arg(text);
545  const std::string &txt(txtLangAlt.toUtf8().constData());
546  xmpTxtVal->read(txt);
547  }
548 
549  // ...and add the new one instead.
550  d->xmpMetadata().add(Exiv2::XmpKey(xmpTagName), xmpTxtVal.get());
551  }
552  return true;
553  }
554  catch( Exiv2::Error& e )
555  {
556  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp tag string lang-alt into image using Exiv2 "), e);
557  }
558  catch(...)
559  {
560  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
561  }
562 
563 #else
564 
565  Q_UNUSED(xmpTagName);
566  Q_UNUSED(values);
567  Q_UNUSED(setProgramName);
568 
569 #endif // _XMP_SUPPORT_
570 
571  return false;
572 }
573 
574 QString KExiv2::getXmpTagStringLangAlt(const char* xmpTagName, const QString& langAlt, bool escapeCR) const
575 {
576 #ifdef _XMP_SUPPORT_
577 
578  try
579  {
580  Exiv2::XmpData xmpData(d->xmpMetadata());
581  Exiv2::XmpKey key(xmpTagName);
582 
583  for (Exiv2::XmpData::iterator it = xmpData.begin(); it != xmpData.end(); ++it)
584  {
585  if (it->key() == xmpTagName && it->typeId() == Exiv2::langAlt)
586  {
587  for (int i = 0; i < it->count(); i++)
588  {
589  std::ostringstream os;
590  os << it->toString(i);
591  QString lang;
592  QString tagValue = QString::fromUtf8(os.str().c_str());
593  tagValue = detectLanguageAlt(tagValue, lang);
594 
595  if (langAlt == lang)
596  {
597  if (escapeCR)
598  tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
599 
600  return tagValue;
601  }
602  }
603  }
604  }
605  }
606  catch( Exiv2::Error& e )
607  {
608  d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Xmp key '%1' into image using Exiv2 ").arg(QString::fromLatin1(xmpTagName)), e);
609  }
610  catch(...)
611  {
612  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
613  }
614 
615 #else
616 
617  Q_UNUSED(xmpTagName);
618  Q_UNUSED(langAlt);
619  Q_UNUSED(escapeCR);
620 
621 #endif // _XMP_SUPPORT_
622 
623  return QString();
624 }
625 
626 bool KExiv2::setXmpTagStringLangAlt(const char* xmpTagName, const QString& value,
627  const QString& langAlt, bool setProgramName) const
628 {
629 #ifdef _XMP_SUPPORT_
630 
631  if (!setProgramId(setProgramName))
632  return false;
633 
634  try
635  {
636  QString language(QString::fromLatin1("x-default")); // default alternative language.
637 
638  if (!langAlt.isEmpty())
639  language = langAlt;
640 
641  QString txtLangAlt = QString(QString::fromLatin1("lang=%1 %2")).arg(language).arg(value);
642 
643  const std::string &txt(txtLangAlt.toUtf8().constData());
644  Exiv2::Value::AutoPtr xmpTxtVal = Exiv2::Value::create(Exiv2::langAlt);
645 
646  // Search if an Xmp tag already exist.
647 
648  AltLangMap map = getXmpTagStringListLangAlt(xmpTagName, false);
649 
650  if (!map.isEmpty())
651  {
652  for (AltLangMap::iterator it = map.begin(); it != map.end(); ++it)
653  {
654  if (it.key() != langAlt)
655  {
656  const std::string &val((*it).toUtf8().constData());
657  xmpTxtVal->read(val);
658  qCDebug(LIBKEXIV2_LOG) << *it;
659  }
660  }
661  }
662 
663  xmpTxtVal->read(txt);
664  removeXmpTag(xmpTagName);
665  d->xmpMetadata().add(Exiv2::XmpKey(xmpTagName), xmpTxtVal.get());
666  return true;
667  }
668  catch( Exiv2::Error& e )
669  {
670  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp tag string lang-alt into image using Exiv2 "), e);
671  }
672  catch(...)
673  {
674  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
675  }
676 
677 #else
678 
679  Q_UNUSED(xmpTagName);
680  Q_UNUSED(value);
681  Q_UNUSED(langAlt);
682  Q_UNUSED(setProgramName);
683 
684 #endif // _XMP_SUPPORT_
685 
686  return false;
687 }
688 
689 QStringList KExiv2::getXmpTagStringSeq(const char* xmpTagName, bool escapeCR) const
690 {
691 #ifdef _XMP_SUPPORT_
692 
693  try
694  {
695  Exiv2::XmpData xmpData(d->xmpMetadata());
696  Exiv2::XmpKey key(xmpTagName);
697  Exiv2::XmpData::iterator it = xmpData.findKey(key);
698 
699  if (it != xmpData.end())
700  {
701  if (it->typeId() == Exiv2::xmpSeq)
702  {
703  QStringList seq;
704 
705  for (int i = 0; i < it->count(); i++)
706  {
707  std::ostringstream os;
708  os << it->toString(i);
709  QString seqValue = QString::fromUtf8(os.str().c_str());
710 
711  if (escapeCR)
712  seqValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
713 
714  seq.append(seqValue);
715  }
716  qCDebug(LIBKEXIV2_LOG) << "XMP String Seq (" << xmpTagName << "): " << seq;
717 
718  return seq;
719  }
720  }
721  }
722  catch( Exiv2::Error& e )
723  {
724  d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Xmp key '%1' into image using Exiv2 ").arg(QString::fromLatin1(xmpTagName)), e);
725  }
726  catch(...)
727  {
728  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
729  }
730 
731 #else
732 
733  Q_UNUSED(xmpTagName);
734  Q_UNUSED(escapeCR);
735 
736 #endif // _XMP_SUPPORT_
737 
738  return QStringList();
739 }
740 
741 bool KExiv2::setXmpTagStringSeq(const char* xmpTagName, const QStringList& seq,
742  bool setProgramName) const
743 {
744 #ifdef _XMP_SUPPORT_
745 
746  if (!setProgramId(setProgramName))
747  return false;
748 
749  try
750  {
751  if (seq.isEmpty())
752  {
753  removeXmpTag(xmpTagName);
754  }
755  else
756  {
757  const QStringList list = seq;
758  Exiv2::Value::AutoPtr xmpTxtSeq = Exiv2::Value::create(Exiv2::xmpSeq);
759 
760  for (QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
761  {
762  const std::string &txt((*it).toUtf8().constData());
763  xmpTxtSeq->read(txt);
764  }
765 
766  d->xmpMetadata()[xmpTagName].setValue(xmpTxtSeq.get());
767  }
768  return true;
769  }
770  catch( Exiv2::Error& e )
771  {
772  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp tag string Seq into image using Exiv2 "), e);
773  }
774  catch(...)
775  {
776  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
777  }
778 
779 #else
780 
781  Q_UNUSED(xmpTagName);
782  Q_UNUSED(seq);
783  Q_UNUSED(setProgramName);
784 
785 #endif // _XMP_SUPPORT_
786 
787  return false;
788 }
789 
790 QStringList KExiv2::getXmpTagStringBag(const char* xmpTagName, bool escapeCR) const
791 {
792 #ifdef _XMP_SUPPORT_
793 
794  try
795  {
796  Exiv2::XmpData xmpData(d->xmpMetadata());
797  Exiv2::XmpKey key(xmpTagName);
798  Exiv2::XmpData::iterator it = xmpData.findKey(key);
799 
800  if (it != xmpData.end())
801  {
802  if (it->typeId() == Exiv2::xmpBag)
803  {
804  QStringList bag;
805 
806  for (int i = 0; i < it->count(); i++)
807  {
808  std::ostringstream os;
809  os << it->toString(i);
810  QString bagValue = QString::fromUtf8(os.str().c_str());
811 
812  if (escapeCR)
813  bagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
814 
815  bag.append(bagValue);
816  }
817 
818  return bag;
819  }
820  }
821  }
822  catch( Exiv2::Error& e )
823  {
824  d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Xmp key '%1' into image using Exiv2 ").arg(QString::fromLatin1(xmpTagName)), e);
825  }
826  catch(...)
827  {
828  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
829  }
830 
831 #else
832 
833  Q_UNUSED(xmpTagName);
834  Q_UNUSED(escapeCR);
835 
836 #endif // _XMP_SUPPORT_
837 
838  return QStringList();
839 }
840 
841 bool KExiv2::setXmpTagStringBag(const char* xmpTagName, const QStringList& bag,
842  bool setProgramName) const
843 {
844 #ifdef _XMP_SUPPORT_
845 
846  if (!setProgramId(setProgramName))
847  return false;
848 
849  try
850  {
851  if (bag.isEmpty())
852  {
853  removeXmpTag(xmpTagName);
854  }
855  else
856  {
857  QStringList list = bag;
858  Exiv2::Value::AutoPtr xmpTxtBag = Exiv2::Value::create(Exiv2::xmpBag);
859 
860  for (QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
861  {
862  const std::string &txt((*it).toUtf8().constData());
863  xmpTxtBag->read(txt);
864  }
865 
866  d->xmpMetadata()[xmpTagName].setValue(xmpTxtBag.get());
867  }
868  return true;
869  }
870  catch( Exiv2::Error& e )
871  {
872  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Xmp tag string Bag into image using Exiv2 "), e);
873  }
874  catch(...)
875  {
876  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
877  }
878 
879 #else
880 
881  Q_UNUSED(xmpTagName);
882  Q_UNUSED(bag);
883  Q_UNUSED(setProgramName);
884 
885 #endif // _XMP_SUPPORT_
886 
887  return false;
888 }
889 
890 bool KExiv2::addToXmpTagStringBag(const char* xmpTagName, const QStringList& entriesToAdd,
891  bool setProgramName) const
892 {
893  if (!setProgramId(setProgramName))
894  return false;
895 
896  QStringList oldEntries = getXmpTagStringBag(xmpTagName, false);
897  QStringList newEntries = entriesToAdd;
898 
899  // Create a list of keywords including old one which already exists.
900  for (QStringList::const_iterator it = oldEntries.constBegin(); it != oldEntries.constEnd(); ++it )
901  {
902  if (!newEntries.contains(*it))
903  newEntries.append(*it);
904  }
905 
906  if (setXmpTagStringBag(xmpTagName, newEntries, false))
907  return true;
908 
909  return false;
910 }
911 
912 bool KExiv2::removeFromXmpTagStringBag(const char* xmpTagName, const QStringList& entriesToRemove,
913  bool setProgramName) const
914 {
915  if (!setProgramId(setProgramName))
916  return false;
917 
918  QStringList currentEntries = getXmpTagStringBag(xmpTagName, false);
919  QStringList newEntries;
920 
921  // Create a list of current keywords except those that shall be removed
922  for (QStringList::const_iterator it = currentEntries.constBegin(); it != currentEntries.constEnd(); ++it )
923  {
924  if (!entriesToRemove.contains(*it))
925  newEntries.append(*it);
926  }
927 
928  if (setXmpTagStringBag(xmpTagName, newEntries, false))
929  return true;
930 
931  return false;
932 }
933 
934 QVariant KExiv2::getXmpTagVariant(const char* xmpTagName, bool rationalAsListOfInts, bool stringEscapeCR) const
935 {
936 #ifdef _XMP_SUPPORT_
937  try
938  {
939  Exiv2::XmpData xmpData(d->xmpMetadata());
940  Exiv2::XmpKey key(xmpTagName);
941  Exiv2::XmpData::iterator it = xmpData.findKey(key);
942 
943  if (it != xmpData.end())
944  {
945  switch (it->typeId())
946  {
947  case Exiv2::unsignedByte:
948  case Exiv2::unsignedShort:
949  case Exiv2::unsignedLong:
950  case Exiv2::signedShort:
951  case Exiv2::signedLong:
952  return QVariant((int)it->toLong());
953  case Exiv2::unsignedRational:
954  case Exiv2::signedRational:
955  if (rationalAsListOfInts)
956  {
957  QList<QVariant> list;
958  list << (*it).toRational().first;
959  list << (*it).toRational().second;
960  return QVariant(list);
961  }
962  else
963  {
964  // prefer double precision
965  double num = (*it).toRational().first;
966  double den = (*it).toRational().second;
967 
968  if (den == 0.0)
969  return QVariant(QVariant::Double);
970 
971  return QVariant(num / den);
972  }
973  case Exiv2::date:
974  case Exiv2::time:
975  {
976  QDateTime dateTime = QDateTime::fromString(QString::fromLatin1(it->toString().c_str()), Qt::ISODate);
977  return QVariant(dateTime);
978  }
979  case Exiv2::asciiString:
980  case Exiv2::comment:
981  case Exiv2::string:
982  {
983  std::ostringstream os;
984  os << *it;
985  QString tagValue = QString::fromLocal8Bit(os.str().c_str());
986 
987  if (stringEscapeCR)
988  tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
989 
990  return QVariant(tagValue);
991  }
992  case Exiv2::xmpText:
993  {
994  std::ostringstream os;
995  os << *it;
996  QString tagValue = QString::fromUtf8(os.str().c_str());
997 
998  if (stringEscapeCR)
999  tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
1000 
1001  return tagValue;
1002  }
1003  case Exiv2::xmpBag:
1004  case Exiv2::xmpSeq:
1005  case Exiv2::xmpAlt:
1006  {
1007  QStringList list;
1008 
1009  for (int i=0; i < it->count(); i++)
1010  {
1011  list << QString::fromUtf8(it->toString(i).c_str());
1012  }
1013 
1014  return list;
1015  }
1016  case Exiv2::langAlt:
1017  {
1018  // access the value directly
1019  const Exiv2::LangAltValue &value = static_cast<const Exiv2::LangAltValue &>(it->value());
1021  // access the ValueType std::map< std::string, std::string>
1022  Exiv2::LangAltValue::ValueType::const_iterator i;
1023 
1024  for (i = value.value_.begin(); i != value.value_.end(); ++i)
1025  {
1026  map[QString::fromUtf8(i->first.c_str())] = QString::fromUtf8(i->second.c_str());
1027  }
1028 
1029  return map;
1030  }
1031  default:
1032  break;
1033  }
1034  }
1035  }
1036  catch( Exiv2::Error& e )
1037  {
1038  d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Xmp key '%1' into image using Exiv2 ").arg(QString::fromLatin1(xmpTagName)), e);
1039  }
1040  catch(...)
1041  {
1042  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
1043  }
1044 
1045 #else
1046 
1047  Q_UNUSED(xmpTagName);
1048  Q_UNUSED(rationalAsListOfInts);
1049  Q_UNUSED(stringEscapeCR);
1050 
1051 #endif // _XMP_SUPPORT_
1052 
1053  return QVariant();
1054 }
1055 
1056 bool KExiv2::registerXmpNameSpace(const QString& uri, const QString& prefix)
1057 {
1058 #ifdef _XMP_SUPPORT_
1059 
1060  try
1061  {
1062  QString ns = uri;
1063 
1064  if (!uri.endsWith(QString::fromLatin1("/")))
1065  ns.append(QString::fromLatin1("/"));
1066 
1067  Exiv2::XmpProperties::registerNs(ns.toLatin1().constData(), prefix.toLatin1().constData());
1068  return true;
1069  }
1070  catch( Exiv2::Error& e )
1071  {
1072  Private::printExiv2ExceptionError(QString::fromLatin1("Cannot register a new Xmp namespace using Exiv2 "), e);
1073  }
1074  catch(...)
1075  {
1076  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
1077  }
1078 
1079 #else
1080 
1081  Q_UNUSED(uri);
1082  Q_UNUSED(prefix);
1083 
1084 #endif // _XMP_SUPPORT_
1085 
1086  return false;
1087 }
1088 
1090 {
1091 #ifdef _XMP_SUPPORT_
1092 
1093  try
1094  {
1095  QString ns = uri;
1096 
1097  if (!uri.endsWith(QString::fromLatin1("/")))
1098  ns.append(QString::fromLatin1("/"));
1099 
1100  Exiv2::XmpProperties::unregisterNs(ns.toLatin1().constData());
1101  return true;
1102  }
1103  catch( Exiv2::Error& e )
1104  {
1105  Private::printExiv2ExceptionError(QString::fromLatin1("Cannot unregister a new Xmp namespace using Exiv2 "), e);
1106  }
1107  catch(...)
1108  {
1109  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
1110  }
1111 
1112 #else
1113 
1114  Q_UNUSED(uri);
1115 
1116 #endif // _XMP_SUPPORT_
1117 
1118  return false;
1119 }
1120 
1121 bool KExiv2::removeXmpTag(const char* xmpTagName, bool setProgramName) const
1122 {
1123 #ifdef _XMP_SUPPORT_
1124 
1125  if (!setProgramId(setProgramName))
1126  return false;
1127 
1128  try
1129  {
1130  Exiv2::XmpKey xmpKey(xmpTagName);
1131  Exiv2::XmpData::iterator it = d->xmpMetadata().findKey(xmpKey);
1132 
1133  if (it != d->xmpMetadata().end())
1134  {
1135  d->xmpMetadata().erase(it);
1136  return true;
1137  }
1138  }
1139  catch( Exiv2::Error& e )
1140  {
1141  d->printExiv2ExceptionError(QString::fromLatin1("Cannot remove Xmp tag using Exiv2 "), e);
1142  }
1143  catch(...)
1144  {
1145  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
1146  }
1147 
1148 #else
1149 
1150  Q_UNUSED(xmpTagName);
1151  Q_UNUSED(setProgramName);
1152 
1153 #endif // _XMP_SUPPORT_
1154 
1155  return false;
1156 }
1157 
1159 {
1160  return (getXmpTagStringBag("Xmp.dc.subject", false));
1161 }
1162 
1163 bool KExiv2::setXmpKeywords(const QStringList& newKeywords, bool setProgramName) const
1164 {
1165  return addToXmpTagStringBag("Xmp.dc.subject", newKeywords, setProgramName);
1166 }
1167 
1168 bool KExiv2::removeXmpKeywords(const QStringList& keywordsToRemove, bool setProgramName)
1169 {
1170  return removeFromXmpTagStringBag("Xmp.dc.subject", keywordsToRemove, setProgramName);
1171 }
1172 
1174 {
1175  return (getXmpTagStringBag("Xmp.photoshop.SupplementalCategories", false));
1176 }
1177 
1178 bool KExiv2::setXmpSubCategories(const QStringList& newSubCategories, bool setProgramName) const
1179 {
1180  return addToXmpTagStringBag("Xmp.photoshop.SupplementalCategories", newSubCategories, setProgramName);
1181 }
1182 
1183 bool KExiv2::removeXmpSubCategories(const QStringList& subCategoriesToRemove, bool setProgramName)
1184 {
1185  return removeFromXmpTagStringBag("Xmp.photoshop.SupplementalCategories", subCategoriesToRemove, setProgramName);
1186 }
1187 
1189 {
1190  return (getXmpTagStringBag("Xmp.iptc.SubjectCode", false));
1191 }
1192 
1193 bool KExiv2::setXmpSubjects(const QStringList& newSubjects, bool setProgramName) const
1194 {
1195  return addToXmpTagStringBag("Xmp.iptc.SubjectCode", newSubjects, setProgramName);
1196 }
1197 
1198 bool KExiv2::removeXmpSubjects(const QStringList& subjectsToRemove, bool setProgramName)
1199 {
1200  return removeFromXmpTagStringBag("Xmp.iptc.SubjectCode", subjectsToRemove, setProgramName);
1201 }
1202 
1204 {
1205  TagsMap tagsMap;
1206  d->getXMPTagsListFromPrefix(QString::fromLatin1("dc"), tagsMap);
1207  d->getXMPTagsListFromPrefix(QString::fromLatin1("digiKam"), tagsMap);
1208  d->getXMPTagsListFromPrefix(QString::fromLatin1("xmp"), tagsMap);
1209  d->getXMPTagsListFromPrefix(QString::fromLatin1("xmpRights"), tagsMap);
1210  d->getXMPTagsListFromPrefix(QString::fromLatin1("xmpMM"), tagsMap);
1211  d->getXMPTagsListFromPrefix(QString::fromLatin1("xmpBJ"), tagsMap);
1212  d->getXMPTagsListFromPrefix(QString::fromLatin1("xmpTPg"), tagsMap);
1213  d->getXMPTagsListFromPrefix(QString::fromLatin1("xmpDM"), tagsMap);
1214  d->getXMPTagsListFromPrefix(QString::fromLatin1("MicrosoftPhoto"), tagsMap);
1215  d->getXMPTagsListFromPrefix(QString::fromLatin1("pdf"), tagsMap);
1216  d->getXMPTagsListFromPrefix(QString::fromLatin1("photoshop"), tagsMap);
1217  d->getXMPTagsListFromPrefix(QString::fromLatin1("crs"), tagsMap);
1218  d->getXMPTagsListFromPrefix(QString::fromLatin1("tiff"), tagsMap);
1219  d->getXMPTagsListFromPrefix(QString::fromLatin1("exif"), tagsMap);
1220  d->getXMPTagsListFromPrefix(QString::fromLatin1("aux"), tagsMap);
1221  d->getXMPTagsListFromPrefix(QString::fromLatin1("iptc"), tagsMap);
1222  d->getXMPTagsListFromPrefix(QString::fromLatin1("iptcExt"), tagsMap);
1223  d->getXMPTagsListFromPrefix(QString::fromLatin1("plus"), tagsMap);
1224  d->getXMPTagsListFromPrefix(QString::fromLatin1("mwg-rs"), tagsMap);
1225  d->getXMPTagsListFromPrefix(QString::fromLatin1("dwc"), tagsMap);
1226  return tagsMap;
1227 }
1228 
1229 } // NameSpace KExiv2Iface
static bool canWriteXmp(const QString &filePath)
Return &#39;true&#39; if Xmp can be written in file.
Definition: kexiv2xmp.cpp:37
QStringList getXmpTagStringSeq(const char *xmpTagName, bool escapeCR=true) const
Get a Xmp tag content like a sequence of strings.
Definition: kexiv2xmp.cpp:689
QStringList getXmpSubjects() const
Return a strings list of Xmp subjects from image.
Definition: kexiv2xmp.cpp:1188
QStringList getXmpSubCategories() const
Return a strings list of Xmp sub-categories from image.
Definition: kexiv2xmp.cpp:1173
static bool registerXmpNameSpace(const QString &uri, const QString &prefix)
Register a namespace which Exiv2 doesn&#39;t know yet.
Definition: kexiv2xmp.cpp:1056
QByteArray getXmp() const
Return a Qt byte array copy of XMp container get from current image.
Definition: kexiv2xmp.cpp:104
QString & append(QChar ch)
KExiv2Iface.
Definition: kexiv2.cpp:36
QMap< QString, QString > AltLangMap
A map used to store a list of Alternative Language values.
Definition: kexiv2.h:134
KExiv2::AltLangMap getXmpTagStringListLangAlt(const char *xmpTagName, bool escapeCR=true) const
Get all redondant Alternative Language Xmp tags content like a map.
Definition: kexiv2xmp.cpp:473
QMap::const_iterator constBegin() const const
bool setXmpTagString(const char *xmpTagName, const QString &value, bool setProgramName=true) const
Set a Xmp tag content using a string.
Definition: kexiv2xmp.cpp:387
QStringList getXmpTagStringBag(const char *xmpTagName, bool escapeCR) const
Get a Xmp tag content like a bag of strings.
Definition: kexiv2xmp.cpp:790
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QStringList getXmpKeywords() const
Return a strings list of Xmp keywords from image.
Definition: kexiv2xmp.cpp:1158
bool setXmp(const QByteArray &data) const
Set the Xmp data using a Qt byte array.
Definition: kexiv2xmp.cpp:136
QString fromLocal8Bit(const char *str, int size)
void append(const T &value)
XmpTagType
Xmp tag types, used by setXmpTag, only first three types are used.
Definition: kexiv2.h:117
QString fromUtf8(const char *str, int size)
static QString detectLanguageAlt(const QString &value, QString &lang)
Language Alternative autodetection.
bool isEmpty() const const
bool isEmpty() const const
bool setXmpTagStringBag(const char *xmpTagName, const QStringList &bag, bool setProgramName=true) const
Set a Xmp tag content using the bag of strings &#39;bag&#39;.
Definition: kexiv2xmp.cpp:841
QMap< QString, QString > MetaDataMap
A map used to store Tags Key and Tags Value.
Definition: kexiv2.h:128
QMap::const_iterator constEnd() const const
const char * constData() const const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
T & first()
bool removeXmpSubjects(const QStringList &subjectsToRemove, bool setProgramName=true)
Remove those Xmp subjects that are listed in subjectsToRemove from the subjects in metadata...
Definition: kexiv2xmp.cpp:1198
bool removeXmpTag(const char *xmpTagName, bool setProgramName=true) const
Remove the Xmp tag &#39;xmpTagName&#39; from Xmp metadata.
Definition: kexiv2xmp.cpp:1121
bool addToXmpTagStringBag(const char *xmpTagName, const QStringList &entriesToAdd, bool setProgramName) const
Set an Xmp tag content using a list of strings defined by the &#39;entriesToAdd&#39; parameter.
Definition: kexiv2xmp.cpp:890
QMap::iterator end()
bool removeFromXmpTagStringBag(const char *xmpTagName, const QStringList &entriesToRemove, bool setProgramName) const
Remove those Xmp tag entries that are listed in entriesToRemove from the entries in metadata...
Definition: kexiv2xmp.cpp:912
QMap::iterator begin()
static bool unregisterXmpNameSpace(const QString &uri)
Unregister a previously registered custom namespace.
Definition: kexiv2xmp.cpp:1089
bool setXmpTagStringLangAlt(const char *xmpTagName, const QString &value, const QString &langAlt, bool setProgramName=true) const
Set a Xmp tag content using a string with an alternative language header.
Definition: kexiv2xmp.cpp:626
bool setXmpTagStringListLangAlt(const char *xmpTagName, const KExiv2::AltLangMap &values, bool setProgramName) const
Set an Alternative Language Xmp tag content using a map.
Definition: kexiv2xmp.cpp:523
QString getXmpTagStringLangAlt(const char *xmpTagName, const QString &langAlt, bool escapeCR) const
Get a Xmp tag content like a string set with an alternative language header &#39;langAlt&#39; (like "fr-FR" f...
Definition: kexiv2xmp.cpp:574
QDateTime fromString(const QString &string, Qt::DateFormat format)
virtual bool setProgramId(bool on=true) const
Re-implement this method to set automatically the Program Name and Program Version information in Exi...
Definition: kexiv2.cpp:529
bool setXmpSubjects(const QStringList &newSubjects, bool setProgramName=true) const
Set Xmp subjects using a list of strings defined by &#39;newSubjects&#39; parameter.
Definition: kexiv2xmp.cpp:1193
bool clearXmp() const
Clear the Xmp metadata container in memory.
Definition: kexiv2xmp.cpp:81
bool removeXmpSubCategories(const QStringList &categoriesToRemove, bool setProgramName=true)
Remove those Xmp sub-categories that are listed in categoriesToRemove from the sub-categories in meta...
Definition: kexiv2xmp.cpp:1183
QString & replace(int position, int n, QChar after)
QString getXmpTagTitle(const char *xmpTagName)
Return the Xmp Tag title or a null string.
Definition: kexiv2xmp.cpp:291
QString getXmpTagString(const char *xmpTagName, bool escapeCR=true) const
Get a Xmp tag content like a string.
Definition: kexiv2xmp.cpp:346
QByteArray toLatin1() const const
QVariant getXmpTagVariant(const char *xmpTagName, bool rationalAsListOfInts=true, bool stringEscapeCR=true) const
Get an Xmp tag content as a QVariant.
Definition: kexiv2xmp.cpp:934
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
bool removeXmpKeywords(const QStringList &keywordsToRemove, bool setProgramName=true)
Remove those Xmp keywords that are listed in keywordsToRemove from the keywords in metadata...
Definition: kexiv2xmp.cpp:1168
char * data()
QString section(QChar sep, int start, int end, QString::SectionFlags flags) const const
bool setXmpSubCategories(const QStringList &newSubCategories, bool setProgramName=true) const
Set Xmp sub-categories using a list of strings defined by &#39;newSubCategories&#39; parameter.
Definition: kexiv2xmp.cpp:1178
QString fromLatin1(const char *str, int size)
bool hasXmp() const
Return &#39;true&#39; if metadata container in memory as Xmp.
Definition: kexiv2xmp.cpp:68
QMap::iterator insert(const Key &key, const T &value)
QString getXmpTagDescription(const char *xmpTagName)
Return the Xmp Tag description or a null string.
Definition: kexiv2xmp.cpp:319
bool isEmpty() const const
KExiv2::MetaDataMap getXmpTagsDataList(const QStringList &xmpKeysFilter=QStringList(), bool invertSelection=false) const
Return a map of Xmp tags name/value found in metadata sorted by Xmp keys given by &#39;xmpKeysFilter&#39;...
Definition: kexiv2xmp.cpp:174
QList::const_iterator constEnd() const const
QList::const_iterator constBegin() const const
bool setXmpTagStringSeq(const char *xmpTagName, const QStringList &seq, bool setProgramName=true) const
Set a Xmp tag content using the sequence of strings &#39;seq&#39;.
Definition: kexiv2xmp.cpp:741
int size() const const
bool setXmpKeywords(const QStringList &newKeywords, bool setProgramName=true) const
Set Xmp keywords using a list of strings defined by &#39;newKeywords&#39; parameter.
Definition: kexiv2xmp.cpp:1163
QMap::iterator find(const Key &key)
===========================================================This file is a part of KDE project ...
QByteArray encodeName(const QString &fileName)
KExiv2::TagsMap getXmpTagsList() const
Return a map of all standard Xmp tags supported by Exiv2.
Definition: kexiv2xmp.cpp:1203
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Thu Nov 26 2020 22:35:13 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.