KExiv2

kexiv2exif.cpp
Go to the documentation of this file.
1 
28 #include "kexiv2.h"
29 #include "kexiv2_p.h"
30 
31 // C++ includes
32 
33 #include <cctype>
34 
35 // Qt includes
36 
37 #include <QTextCodec>
38 #include <QBuffer>
39 
40 // Local includes
41 
42 #include "rotationmatrix.h"
43 #include "libkexiv2_debug.h"
44 
45 namespace KExiv2Iface
46 {
47 
48 bool KExiv2::canWriteExif(const QString& filePath)
49 {
50  try
51  {
52  Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open((const char*)
53  (QFile::encodeName(filePath).constData()));
54 
55  Exiv2::AccessMode mode = image->checkMode(Exiv2::mdExif);
56 
57  return (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite);
58  }
59  catch( Exiv2::Error& e )
60  {
61  std::string s(e.what());
62  qCCritical(LIBKEXIV2_LOG) << "Cannot check Exif access mode using Exiv2 (Error #"
63  << e.code() << ": " << s.c_str() << ")";
64  }
65  catch(...)
66  {
67  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
68  }
69 
70  return false;
71 }
72 
73 bool KExiv2::hasExif() const
74 {
75  return !d->exifMetadata().empty();
76 }
77 
78 bool KExiv2::clearExif() const
79 {
80  try
81  {
82  d->exifMetadata().clear();
83  return true;
84  }
85  catch( Exiv2::Error& e )
86  {
87  d->printExiv2ExceptionError(QString::fromLatin1("Cannot clear Exif data using Exiv2 "), e);
88  }
89  catch(...)
90  {
91  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
92  }
93 
94  return false;
95 }
96 
97 QByteArray KExiv2::getExifEncoded(bool addExifHeader) const
98 {
99  try
100  {
101  if (!d->exifMetadata().empty())
102  {
103  QByteArray data;
104  Exiv2::ExifData& exif = d->exifMetadata();
105  Exiv2::Blob blob;
106  Exiv2::ExifParser::encode(blob, Exiv2::bigEndian, exif);
107  QByteArray ba((const char*)&blob[0], blob.size());
108 
109  if (addExifHeader)
110  {
111  const uchar ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
112  data.resize(ba.size() + sizeof(ExifHeader));
113  memcpy(data.data(), ExifHeader, sizeof(ExifHeader));
114  memcpy(data.data() + sizeof(ExifHeader), ba.data(), ba.size());
115  }
116  else
117  {
118  data = ba;
119  }
120  return data;
121  }
122  }
123  catch( Exiv2::Error& e )
124  {
125  if (!d->filePath.isEmpty())
126  qCDebug(LIBKEXIV2_LOG) << "From file " << d->filePath.toLatin1().constData();
127 
128  d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Exif data using Exiv2 "), e);
129  }
130  catch(...)
131  {
132  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
133  }
134 
135  return QByteArray();
136 }
137 
138 bool KExiv2::setExif(const QByteArray& data) const
139 {
140  try
141  {
142  if (!data.isEmpty())
143  {
144  Exiv2::ExifParser::decode(d->exifMetadata(), (const Exiv2::byte*)data.data(), data.size());
145  return (!d->exifMetadata().empty());
146  }
147  }
148  catch( Exiv2::Error& e )
149  {
150  if (!d->filePath.isEmpty())
151  qCCritical(LIBKEXIV2_LOG) << "From file " << d->filePath.toLatin1().constData();
152 
153  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Exif data using Exiv2 "), e);
154  }
155  catch(...)
156  {
157  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
158  }
159 
160  return false;
161 }
162 
163 KExiv2::MetaDataMap KExiv2::getExifTagsDataList(const QStringList& exifKeysFilter, bool invertSelection) const
164 {
165  if (d->exifMetadata().empty())
166  return MetaDataMap();
167 
168  try
169  {
170  Exiv2::ExifData exifData = d->exifMetadata();
171  exifData.sortByKey();
172 
173  QString ifDItemName;
174  MetaDataMap metaDataMap;
175 
176  for (Exiv2::ExifData::iterator md = exifData.begin(); md != exifData.end(); ++md)
177  {
178  QString key = QString::fromLatin1(md->key().c_str());
179 
180  // Decode the tag value with a user friendly output.
181  QString tagValue;
182 
183  if (key == QString::fromLatin1("Exif.Photo.UserComment"))
184  {
185  tagValue = d->convertCommentValue(*md);
186  }
187  else if (key == QString::fromLatin1("Exif.Image.0x935c"))
188  {
189  tagValue = QString::number(md->value().size());
190  }
191  else
192  {
193  std::ostringstream os;
194  os << *md;
195 
196  // Exif tag contents can be an translated strings, no only simple ascii.
197  tagValue = QString::fromLocal8Bit(os.str().c_str());
198  }
199 
200  tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
201 
202  // We apply a filter to get only the Exif tags that we need.
203 
204  if (!exifKeysFilter.isEmpty())
205  {
206  if (!invertSelection)
207  {
208  if (exifKeysFilter.contains(key.section(QString::fromLatin1("."), 1, 1)))
209  metaDataMap.insert(key, tagValue);
210  }
211  else
212  {
213  if (!exifKeysFilter.contains(key.section(QString::fromLatin1("."), 1, 1)))
214  metaDataMap.insert(key, tagValue);
215  }
216  }
217  else // else no filter at all.
218  {
219  metaDataMap.insert(key, tagValue);
220  }
221  }
222 
223  return metaDataMap;
224  }
225  catch (Exiv2::Error& e)
226  {
227  d->printExiv2ExceptionError(QString::fromLatin1("Cannot parse EXIF metadata using Exiv2 "), e);
228  }
229  catch(...)
230  {
231  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
232  }
233 
234  return MetaDataMap();
235 }
236 
238 {
239  try
240  {
241  if (!d->exifMetadata().empty())
242  {
243  Exiv2::ExifData exifData(d->exifMetadata());
244  Exiv2::ExifKey key("Exif.Photo.UserComment");
245  Exiv2::ExifData::iterator it = exifData.findKey(key);
246 
247  if (it != exifData.end())
248  {
249  QString exifComment = d->convertCommentValue(*it);
250 
251  // some cameras fill the UserComment with whitespace
252  if (!exifComment.isEmpty() && !exifComment.trimmed().isEmpty())
253  return exifComment;
254  }
255 
256  Exiv2::ExifKey key2("Exif.Image.ImageDescription");
257  Exiv2::ExifData::iterator it2 = exifData.findKey(key2);
258 
259  if (it2 != exifData.end())
260  {
261  QString exifComment = d->convertCommentValue(*it2);
262 
263  // Some cameras fill in nonsense default values
264  QStringList blackList;
265  blackList << QString::fromLatin1("SONY DSC"); // + whitespace
266  blackList << QString::fromLatin1("OLYMPUS DIGITAL CAMERA");
267  blackList << QString::fromLatin1("MINOLTA DIGITAL CAMERA");
268 
269  QString trimmedComment = exifComment.trimmed();
270 
271  // some cameras fill the UserComment with whitespace
272  if (!exifComment.isEmpty() && !trimmedComment.isEmpty() && !blackList.contains(trimmedComment))
273  return exifComment;
274  }
275  }
276  }
277  catch( Exiv2::Error& e )
278  {
279  d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Exif User Comment using Exiv2 "), e);
280  }
281  catch(...)
282  {
283  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
284  }
285 
286  return QString();
287 }
288 
289 static bool is7BitAscii(const QByteArray& s)
290 {
291  const int size = s.size();
292 
293  for (int i=0; i<size; i++)
294  {
295  if (!isascii(s[i]))
296  {
297  return false;
298  }
299  }
300 
301  return true;
302 }
303 
304 bool KExiv2::setExifComment(const QString& comment, bool setProgramName) const
305 {
306  if (!setProgramId(setProgramName))
307  return false;
308 
309  try
310  {
311  removeExifTag("Exif.Image.ImageDescription");
312  removeExifTag("Exif.Photo.UserComment");
313 
314  if (!comment.isNull())
315  {
316  setExifTagString("Exif.Image.ImageDescription", comment, setProgramName);
317 
318  // Write as Unicode only when necessary.
319  QTextCodec* latin1Codec = QTextCodec::codecForName("iso8859-1");
320  if (latin1Codec->canEncode(comment))
321  {
322  // We know it's in the ISO-8859-1 8bit range.
323  // Check if it's in the ASCII 7bit range
324  if (is7BitAscii(comment.toLatin1()))
325  {
326  // write as ASCII
327  std::string exifComment("charset=\"Ascii\" ");
328  exifComment += comment.toLatin1().constData();
329  d->exifMetadata()["Exif.Photo.UserComment"] = exifComment;
330  return true;
331  }
332  }
333  // write as Unicode (UCS-2)
334  std::string exifComment("charset=\"Unicode\" ");
335  exifComment += comment.toUtf8().constData();
336  d->exifMetadata()["Exif.Photo.UserComment"] = exifComment;
337  }
338 
339  return true;
340  }
341  catch( Exiv2::Error& e )
342  {
343  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Exif Comment using Exiv2 "), e);
344  }
345  catch(...)
346  {
347  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
348  }
349 
350  return false;
351 }
352 
353 QString KExiv2::getExifTagTitle(const char* exifTagName)
354 {
355  try
356  {
357  std::string exifkey(exifTagName);
358  Exiv2::ExifKey ek(exifkey);
359 
360  return QString::fromLocal8Bit( ek.tagLabel().c_str() );
361  }
362  catch (Exiv2::Error& e)
363  {
364  d->printExiv2ExceptionError(QString::fromLatin1("Cannot get metadata tag title using Exiv2 "), e);
365  }
366  catch(...)
367  {
368  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
369  }
370 
371  return QString();
372 }
373 
374 QString KExiv2::getExifTagDescription(const char* exifTagName)
375 {
376  try
377  {
378  std::string exifkey(exifTagName);
379  Exiv2::ExifKey ek(exifkey);
380 
381  return QString::fromLocal8Bit( ek.tagDesc().c_str() );
382  }
383  catch (Exiv2::Error& e)
384  {
385  d->printExiv2ExceptionError(QString::fromLatin1("Cannot get metadata tag description using Exiv2 "), e);
386  }
387  catch(...)
388  {
389  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
390  }
391 
392  return QString();
393 }
394 
395 bool KExiv2::removeExifTag(const char* exifTagName, bool setProgramName) const
396 {
397  if (!setProgramId(setProgramName))
398  return false;
399 
400  try
401  {
402  Exiv2::ExifKey exifKey(exifTagName);
403  Exiv2::ExifData::iterator it = d->exifMetadata().findKey(exifKey);
404 
405  if (it != d->exifMetadata().end())
406  {
407  d->exifMetadata().erase(it);
408  return true;
409  }
410  }
411  catch( Exiv2::Error& e )
412  {
413  d->printExiv2ExceptionError(QString::fromLatin1("Cannot remove Exif tag using Exiv2 "), e);
414  }
415  catch(...)
416  {
417  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
418  }
419 
420  return false;
421 }
422 
423 bool KExiv2::getExifTagRational(const char* exifTagName, long int& num, long int& den, int component) const
424 {
425  try
426  {
427  Exiv2::ExifKey exifKey(exifTagName);
428  Exiv2::ExifData exifData(d->exifMetadata());
429  Exiv2::ExifData::iterator it = exifData.findKey(exifKey);
430 
431  if (it != exifData.end())
432  {
433  num = (*it).toRational(component).first;
434  den = (*it).toRational(component).second;
435 
436  return true;
437  }
438  }
439  catch( Exiv2::Error& e )
440  {
441  d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Exif Rational value from key '%1' into image using Exiv2 ").arg(QString::fromLatin1(exifTagName)), e);
442  }
443  catch(...)
444  {
445  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
446  }
447 
448  return false;
449 }
450 
451 bool KExiv2::setExifTagLong(const char* exifTagName, long val, bool setProgramName) const
452 {
453  if (!setProgramId(setProgramName))
454  return false;
455 
456  try
457  {
458  d->exifMetadata()[exifTagName] = static_cast<int32_t>(val);
459  return true;
460  }
461  catch( Exiv2::Error& e )
462  {
463  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Exif tag long value into image using Exiv2 "), e);
464  }
465  catch(...)
466  {
467  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
468  }
469 
470  return false;
471 }
472 
473 bool KExiv2::setExifTagRational(const char* exifTagName, long int num, long int den, bool setProgramName) const
474 {
475  if (!setProgramId(setProgramName))
476  return false;
477 
478  try
479  {
480  d->exifMetadata()[exifTagName] = Exiv2::Rational(num, den);
481  return true;
482  }
483  catch( Exiv2::Error& e )
484  {
485  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Exif tag rational value into image using Exiv2 "), e);
486  }
487  catch(...)
488  {
489  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
490  }
491 
492  return false;
493 }
494 
495 bool KExiv2::setExifTagData(const char* exifTagName, const QByteArray& data, bool setProgramName) const
496 {
497  if (data.isEmpty())
498  return false;
499 
500  if (!setProgramId(setProgramName))
501  return false;
502 
503  try
504  {
505  Exiv2::DataValue val((Exiv2::byte*)data.data(), data.size());
506  d->exifMetadata()[exifTagName] = val;
507  return true;
508  }
509  catch( Exiv2::Error& e )
510  {
511  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Exif tag data into image using Exiv2 "), e);
512  }
513  catch(...)
514  {
515  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
516  }
517 
518  return false;
519 }
520 
521 bool KExiv2::setExifTagVariant(const char* exifTagName, const QVariant& val,
522  bool rationalWantSmallDenominator, bool setProgramName) const
523 {
524  switch (val.type())
525  {
526  case QVariant::Int:
527  case QVariant::UInt:
528  case QVariant::Bool:
529  case QVariant::LongLong:
530  case QVariant::ULongLong:
531  return setExifTagLong(exifTagName, val.toInt(), setProgramName);
532 
533  case QVariant::Double:
534  {
535  long num, den;
536 
537  if (rationalWantSmallDenominator)
538  convertToRationalSmallDenominator(val.toDouble(), &num, &den);
539  else
540  convertToRational(val.toDouble(), &num, &den, 4);
541 
542  return setExifTagRational(exifTagName, num, den, setProgramName);
543  }
544  case QVariant::List:
545  {
546  long num = 0, den = 1;
547  QList<QVariant> list = val.toList();
548 
549  if (list.size() >= 1)
550  num = list[0].toInt();
551 
552  if (list.size() >= 2)
553  den = list[1].toInt();
554 
555  return setExifTagRational(exifTagName, num, den, setProgramName);
556  }
557 
558  case QVariant::Date:
559  case QVariant::DateTime:
560  {
561  QDateTime dateTime = val.toDateTime();
562 
563  if(!dateTime.isValid())
564  return false;
565 
566  if (!setProgramId(setProgramName))
567  return false;
568 
569  try
570  {
571  const std::string &exifdatetime(dateTime.toString(QString::fromLatin1("yyyy:MM:dd hh:mm:ss")).toLatin1().constData());
572  d->exifMetadata()[exifTagName] = exifdatetime;
573  }
574  catch( Exiv2::Error &e )
575  {
576  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Date & Time in image using Exiv2 "), e);
577  }
578  catch(...)
579  {
580  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
581  }
582 
583  return false;
584  }
585 
586  case QVariant::String:
587  case QVariant::Char:
588  return setExifTagString(exifTagName, val.toString(), setProgramName);
589 
590  case QVariant::ByteArray:
591  return setExifTagData(exifTagName, val.toByteArray(), setProgramName);
592  default:
593  break;
594  }
595  return false;
596 }
597 
598 QString KExiv2::createExifUserStringFromValue(const char* exifTagName, const QVariant& val, bool escapeCR)
599 {
600  try
601  {
602  Exiv2::ExifKey key(exifTagName);
603  Exiv2::Exifdatum datum(key);
604 
605  switch (val.type())
606  {
607  case QVariant::Int:
608  case QVariant::Bool:
609  case QVariant::LongLong:
610  case QVariant::ULongLong:
611  datum = (int32_t)val.toInt();
612  break;
613  case QVariant::UInt:
614  datum = (uint32_t)val.toUInt();
615  break;
616 
617  case QVariant::Double:
618  {
619  long num, den;
620  convertToRationalSmallDenominator(val.toDouble(), &num, &den);
621  Exiv2::Rational rational;
622  rational.first = num;
623  rational.second = den;
624  datum = rational;
625  break;
626  }
627  case QVariant::List:
628  {
629  long num = 0, den = 1;
630  QList<QVariant> list = val.toList();
631  if (list.size() >= 1)
632  num = list[0].toInt();
633  if (list.size() >= 2)
634  den = list[1].toInt();
635  Exiv2::Rational rational;
636  rational.first = num;
637  rational.second = den;
638  datum = rational;
639  break;
640  }
641 
642  case QVariant::Date:
643  case QVariant::DateTime:
644  {
645  QDateTime dateTime = val.toDateTime();
646  if(!dateTime.isValid())
647  break;
648 
649  const std::string &exifdatetime(dateTime.toString(QString::fromLatin1("yyyy:MM:dd hh:mm:ss")).toLatin1().constData());
650  datum = exifdatetime;
651  break;
652  }
653 
654  case QVariant::String:
655  case QVariant::Char:
656  datum = (std::string)val.toString().toLatin1().constData();
657  break;
658  default:
659  break;
660  }
661 
662  std::ostringstream os;
663  os << datum;
664  QString tagValue = QString::fromLocal8Bit(os.str().c_str());
665 
666  if (escapeCR)
667  tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
668 
669  return tagValue;
670  }
671  catch( Exiv2::Error& e )
672  {
673  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Iptc tag string into image using Exiv2 "), e);
674  }
675  catch(...)
676  {
677  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
678  }
679 
680  return QString();
681 }
682 
683 bool KExiv2::getExifTagLong(const char* exifTagName, long& val) const
684 {
685  return getExifTagLong(exifTagName, val, 0);
686 }
687 
688 bool KExiv2::getExifTagLong(const char* exifTagName, long& val, int component) const
689 {
690  try
691  {
692  Exiv2::ExifKey exifKey(exifTagName);
693  Exiv2::ExifData exifData(d->exifMetadata());
694  Exiv2::ExifData::iterator it = exifData.findKey(exifKey);
695 
696  if (it != exifData.end() && it->count() > 0)
697  {
698  val = it->toLong(component);
699  return true;
700  }
701  }
702  catch( Exiv2::Error& e )
703  {
704  d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Exif key '%1' into image using Exiv2 ").arg(QString::fromLatin1(exifTagName)), e);
705  }
706  catch(...)
707  {
708  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
709  }
710 
711  return false;
712 }
713 
714 QByteArray KExiv2::getExifTagData(const char* exifTagName) const
715 {
716  try
717  {
718  Exiv2::ExifKey exifKey(exifTagName);
719  Exiv2::ExifData exifData(d->exifMetadata());
720  Exiv2::ExifData::iterator it = exifData.findKey(exifKey);
721 
722  if (it != exifData.end())
723  {
724  char* const s = new char[(*it).size()];
725  (*it).copy((Exiv2::byte*)s, Exiv2::bigEndian);
726  QByteArray data(s, (*it).size());
727  delete[] s;
728 
729  return data;
730  }
731  }
732  catch( Exiv2::Error& e )
733  {
734  d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Exif key '%1' into image using Exiv2 ").arg(QString::fromLatin1(exifTagName)), e);
735  }
736  catch(...)
737  {
738  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
739  }
740 
741  return QByteArray();
742 }
743 
744 QVariant KExiv2::getExifTagVariant(const char* exifTagName, bool rationalAsListOfInts, bool stringEscapeCR, int component) const
745 {
746  try
747  {
748  Exiv2::ExifKey exifKey(exifTagName);
749  Exiv2::ExifData exifData(d->exifMetadata());
750  Exiv2::ExifData::iterator it = exifData.findKey(exifKey);
751 
752  if (it != exifData.end())
753  {
754  switch (it->typeId())
755  {
756  case Exiv2::unsignedByte:
757  case Exiv2::unsignedShort:
758  case Exiv2::unsignedLong:
759  case Exiv2::signedShort:
760  case Exiv2::signedLong:
761  if (it->count() > component)
762  return QVariant((int)it->toLong(component));
763  else
764  return QVariant(QVariant::Int);
765  case Exiv2::unsignedRational:
766  case Exiv2::signedRational:
767 
768  if (rationalAsListOfInts)
769  {
770  if (it->count() <= component)
771  return QVariant(QVariant::List);
772 
773  QList<QVariant> list;
774  list << (*it).toRational(component).first;
775  list << (*it).toRational(component).second;
776 
777  return QVariant(list);
778  }
779  else
780  {
781  if (it->count() <= component)
782  return QVariant(QVariant::Double);
783 
784  // prefer double precision
785  double num = (*it).toRational(component).first;
786  double den = (*it).toRational(component).second;
787 
788  if (den == 0.0)
789  return QVariant(QVariant::Double);
790 
791  return QVariant(num / den);
792  }
793  case Exiv2::date:
794  case Exiv2::time:
795  {
796  QDateTime dateTime = QDateTime::fromString(QString::fromLatin1(it->toString().c_str()), Qt::ISODate);
797  return QVariant(dateTime);
798  }
799  case Exiv2::asciiString:
800  case Exiv2::comment:
801  case Exiv2::string:
802  {
803  std::ostringstream os;
804  os << *it;
805  QString tagValue = QString::fromLocal8Bit(os.str().c_str());
806 
807  if (stringEscapeCR)
808  tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
809 
810  return QVariant(tagValue);
811  }
812  default:
813  break;
814  }
815  }
816  }
817  catch( Exiv2::Error& e )
818  {
819  d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Exif key '%1' in the image using Exiv2 ").arg(QString::fromLatin1(exifTagName)), e);
820  }
821  catch(...)
822  {
823  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
824  }
825 
826  return QVariant();
827 }
828 
829 QString KExiv2::getExifTagString(const char* exifTagName, bool escapeCR) const
830 {
831  try
832  {
833  Exiv2::ExifKey exifKey(exifTagName);
834  Exiv2::ExifData exifData(d->exifMetadata());
835  Exiv2::ExifData::iterator it = exifData.findKey(exifKey);
836 
837  if (it != exifData.end())
838  {
839  // See B.K.O #184156 comment #13
840  std::string val = it->print(&exifData);
841  QString tagValue = QString::fromLocal8Bit(val.c_str());
842 
843  if (escapeCR)
844  tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
845 
846  return tagValue;
847  }
848  }
849  catch( Exiv2::Error& e )
850  {
851  d->printExiv2ExceptionError(QString::fromLatin1("Cannot find Exif key '%1' into image using Exiv2 ").arg(QString::fromLatin1(exifTagName)), e);
852  }
853  catch(...)
854  {
855  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
856  }
857 
858  return QString();
859 }
860 
861 bool KExiv2::setExifTagString(const char* exifTagName, const QString& value, bool setProgramName) const
862 {
863  if (!setProgramId(setProgramName))
864  return false;
865 
866  try
867  {
868  d->exifMetadata()[exifTagName] = std::string(value.toLatin1().constData());
869  return true;
870  }
871  catch( Exiv2::Error& e )
872  {
873  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Exif tag string into image using Exiv2 "), e);
874  }
875  catch(...)
876  {
877  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
878  }
879 
880  return false;
881 }
882 
883 QImage KExiv2::getExifThumbnail(bool fixOrientation) const
884 {
885  QImage thumbnail;
886 
887  if (d->exifMetadata().empty())
888  return thumbnail;
889 
890  try
891  {
892  Exiv2::ExifThumbC thumb(d->exifMetadata());
893  Exiv2::DataBuf const c1 = thumb.copy();
894  thumbnail.loadFromData(c1.pData_, c1.size_);
895 
896  if (!thumbnail.isNull())
897  {
898  if (fixOrientation)
899  {
900  Exiv2::ExifKey key1("Exif.Thumbnail.Orientation");
901  Exiv2::ExifKey key2("Exif.Image.Orientation");
902  Exiv2::ExifData exifData(d->exifMetadata());
903  Exiv2::ExifData::iterator it = exifData.findKey(key1);
904 
905  if (it == exifData.end())
906  it = exifData.findKey(key2);
907 
908  if (it != exifData.end() && it->count())
909  {
910  long orientation = it->toLong();
911  qCDebug(LIBKEXIV2_LOG) << "Exif Thumbnail Orientation: " << (int)orientation;
912  rotateExifQImage(thumbnail, (ImageOrientation)orientation);
913  }
914 
915  return thumbnail;
916  }
917  }
918  }
919  catch( Exiv2::Error& e )
920  {
921  d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Exif Thumbnail using Exiv2 "), e);
922  }
923  catch(...)
924  {
925  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
926  }
927 
928  return thumbnail;
929 }
930 
931 bool KExiv2::rotateExifQImage(QImage& image, ImageOrientation orientation) const
932 {
933  QMatrix matrix = RotationMatrix::toMatrix(orientation);
934 
935  if ((orientation != ORIENTATION_NORMAL) && (orientation != ORIENTATION_UNSPECIFIED))
936  {
937  image = image.transformed(matrix);
938  return true;
939  }
940 
941  return false;
942 }
943 
944 bool KExiv2::setExifThumbnail(const QImage& thumbImage, bool setProgramName) const
945 {
946  if (!setProgramId(setProgramName))
947  return false;
948 
949  if (thumbImage.isNull())
950  {
951  return removeExifThumbnail();
952  }
953 
954  try
955  {
956  QByteArray data;
957  QBuffer buffer(&data);
958  buffer.open(QIODevice::WriteOnly);
959  thumbImage.save(&buffer, "JPEG");
960  Exiv2::ExifThumb thumb(d->exifMetadata());
961  thumb.setJpegThumbnail((Exiv2::byte *)data.data(), data.size());
962  return true;
963  }
964  catch( Exiv2::Error& e )
965  {
966  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set Exif Thumbnail using Exiv2 "), e);
967  }
968  catch(...)
969  {
970  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
971  }
972 
973  return false;
974 }
975 
976 bool KExiv2::setTiffThumbnail(const QImage& thumbImage, bool setProgramName) const
977 {
978  if (!setProgramId(setProgramName))
979  return false;
980 
982 
983  try
984  {
985  // Make sure IFD0 is explicitly marked as a main image
986  Exiv2::ExifData::const_iterator pos = d->exifMetadata().findKey(Exiv2::ExifKey("Exif.Image.NewSubfileType"));
987 
988  if (pos == d->exifMetadata().end() || pos->count() != 1 || pos->toLong() != 0)
989  {
990 #if EXIV2_TEST_VERSION(0,27,0)
991  throw Exiv2::Error(Exiv2::kerErrorMessage, "Exif.Image.NewSubfileType missing or not set as main image");
992 #else
993  throw Exiv2::Error(1, "Exif.Image.NewSubfileType missing or not set as main image");
994 #endif
995  }
996 
997  // Remove sub-IFD tags
998  std::string subImage1("SubImage1");
999 
1000  for (Exiv2::ExifData::iterator md = d->exifMetadata().begin(); md != d->exifMetadata().end();)
1001  {
1002  if (md->groupName() == subImage1)
1003  md = d->exifMetadata().erase(md);
1004  else
1005  ++md;
1006  }
1007 
1008  if (!thumbImage.isNull())
1009  {
1010  // Set thumbnail tags
1011  QByteArray data;
1012  QBuffer buffer(&data);
1013  buffer.open(QIODevice::WriteOnly);
1014  thumbImage.save(&buffer, "JPEG");
1015 
1016  Exiv2::DataBuf buf((Exiv2::byte *)data.data(), data.size());
1017  Exiv2::ULongValue val;
1018  val.read("0");
1019  val.setDataArea(buf.pData_, buf.size_);
1020  d->exifMetadata()["Exif.SubImage1.JPEGInterchangeFormat"] = val;
1021  d->exifMetadata()["Exif.SubImage1.JPEGInterchangeFormatLength"] = uint32_t(buf.size_);
1022  d->exifMetadata()["Exif.SubImage1.Compression"] = uint16_t(6); // JPEG (old-style)
1023  d->exifMetadata()["Exif.SubImage1.NewSubfileType"] = uint32_t(1); // Thumbnail image
1024  return true;
1025  }
1026  }
1027  catch( Exiv2::Error& e )
1028  {
1029  d->printExiv2ExceptionError(QString::fromLatin1("Cannot set TIFF Thumbnail using Exiv2 "), e);
1030  }
1031  catch(...)
1032  {
1033  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
1034  }
1035 
1036  return false;
1037 }
1038 
1040 {
1041  try
1042  {
1043  // Remove all IFD0 subimages.
1044  Exiv2::ExifThumb thumb(d->exifMetadata());
1045  thumb.erase();
1046  return true;
1047  }
1048  catch( Exiv2::Error& e )
1049  {
1050  d->printExiv2ExceptionError(QString::fromLatin1("Cannot remove Exif Thumbnail using Exiv2 "), e);
1051  }
1052  catch(...)
1053  {
1054  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
1055  }
1056 
1057  return false;
1058 }
1059 
1061 {
1062  try
1063  {
1065  TagsMap tagsMap;
1066 
1067  const Exiv2::GroupInfo* gi = Exiv2::ExifTags::groupList();
1068 
1069  while (gi->tagList_ != nullptr)
1070  {
1071  if (QString::fromLatin1(gi->ifdName_) != QString::fromLatin1("Makernote"))
1072  {
1073  Exiv2::TagListFct tl = gi->tagList_;
1074  const Exiv2::TagInfo* ti = tl();
1075 
1076  while (ti->tag_ != 0xFFFF)
1077  {
1078  tags << ti;
1079  ++ti;
1080  }
1081  }
1082  ++gi;
1083  }
1084 
1085  for (QList<const Exiv2::TagInfo*>::iterator it = tags.begin(); it != tags.end(); ++it)
1086  {
1087  do
1088  {
1089  const Exiv2::TagInfo* const ti = *it;
1090  QString key = QLatin1String(Exiv2::ExifKey(*ti).key().c_str());
1092  values << QString::fromLatin1(ti->name_) << QString::fromLatin1(ti->title_) << QString::fromLatin1(ti->desc_);
1093  tagsMap.insert(key, values);
1094  ++(*it);
1095  }
1096  while((*it)->tag_ != 0xffff);
1097  }
1098  return tagsMap;
1099  }
1100  catch( Exiv2::Error& e )
1101  {
1102  d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Exif Tags list using Exiv2 "), e);
1103  }
1104  catch(...)
1105  {
1106  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
1107  }
1108 
1109  return TagsMap();
1110 }
1111 
1113 {
1114  try
1115  {
1117  TagsMap tagsMap;
1118 
1119  const Exiv2::GroupInfo* gi = Exiv2::ExifTags::groupList();
1120 
1121  while (gi->tagList_ != nullptr)
1122  {
1123  if (QString::fromLatin1(gi->ifdName_) == QString::fromLatin1("Makernote"))
1124  {
1125  Exiv2::TagListFct tl = gi->tagList_;
1126  const Exiv2::TagInfo* ti = tl();
1127 
1128  while (ti->tag_ != 0xFFFF)
1129  {
1130  tags << ti;
1131  ++ti;
1132  }
1133  }
1134  ++gi;
1135  }
1136 
1137  for (QList<const Exiv2::TagInfo*>::iterator it = tags.begin(); it != tags.end(); ++it)
1138  {
1139  do
1140  {
1141  const Exiv2::TagInfo* const ti = *it;
1142  QString key = QLatin1String(Exiv2::ExifKey(*ti).key().c_str());
1144  values << QString::fromLatin1(ti->name_) << QString::fromLatin1(ti->title_) << QString::fromLatin1(ti->desc_);
1145  tagsMap.insert(key, values);
1146  ++(*it);
1147  }
1148  while((*it)->tag_ != 0xffff);
1149  }
1150 
1151  return tagsMap;
1152  }
1153  catch( Exiv2::Error& e )
1154  {
1155  d->printExiv2ExceptionError(QString::fromLatin1("Cannot get Makernote Tags list using Exiv2 "), e);
1156  }
1157  catch(...)
1158  {
1159  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
1160  }
1161 
1162  return TagsMap();
1163 }
1164 
1165 } // NameSpace KExiv2Iface
QImage getExifThumbnail(bool fixOrientation) const
Return a QImage copy of Exif thumbnail image.
Definition: kexiv2exif.cpp:883
QString toString(Qt::DateFormat format) const const
QByteArray toByteArray() const const
bool loadFromData(const uchar *data, int len, const char *format)
KExiv2Iface.
Definition: kexiv2.cpp:36
bool save(const QString &fileName, const char *format, int quality) const const
QList< QVariant > toList() const const
QDateTime toDateTime() const const
TagsMap getStdExifTagsList() const
Return a map of all standard Exif tags supported by Exiv2.
static void convertToRationalSmallDenominator(const double number, long int *const numerator, long int *const denominator)
This method convert a &#39;number&#39; to a rational value, returned in &#39;numerator&#39; and &#39;denominator&#39; paramet...
Definition: kexiv2gps.cpp:656
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
bool setExifComment(const QString &comment, bool setProgramName=true) const
Set the Exif user comments from image.
Definition: kexiv2exif.cpp:304
KExiv2::MetaDataMap getExifTagsDataList(const QStringList &exifKeysFilter=QStringList(), bool invertSelection=false) const
Return a map of Exif tags name/value found in metadata sorted by Exif keys given by &#39;exifKeysFilter&#39;...
Definition: kexiv2exif.cpp:163
bool clearExif() const
Clear the Exif metadata container in memory.
Definition: kexiv2exif.cpp:78
static bool canWriteExif(const QString &filePath)
Return &#39;true&#39; if Exif can be written in file.
Definition: kexiv2exif.cpp:48
QByteArray getExifEncoded(bool addExifHeader=false) const
Returns the exif data encoded to a QByteArray in a form suitable for storage in a JPEG image...
Definition: kexiv2exif.cpp:97
bool isNull() const const
bool hasExif() const
Return &#39;true&#39; if metadata container in memory as Exif.
Definition: kexiv2exif.cpp:73
ImageOrientation
The image orientation values given by Exif metadata.
Definition: kexiv2.h:101
QImage copy(const QRect &rectangle) const const
bool rotateExifQImage(QImage &image, ImageOrientation orientation) const
Fix orientation of a QImage image accordingly with Exif orientation tag.
Definition: kexiv2exif.cpp:931
bool setExifTagData(const char *exifTagName, const QByteArray &data, bool setProgramName=true) const
Set an Exif tag content using a bytes array.
Definition: kexiv2exif.cpp:495
bool removeExifThumbnail() const
Remove the Exif Thumbnail from the image.
int size() const const
bool isNull() const const
bool getExifTagRational(const char *exifTagName, long int &num, long int &den, int component=0) const
Get the &#39;component&#39; index of an Exif tags content like a rational value.
Definition: kexiv2exif.cpp:423
bool getExifTagLong(const char *exifTagName, long &val) const
Get an Exif tag content like a long value.
Definition: kexiv2exif.cpp:683
QVector< V > values(const QMultiHash< K, V > &c)
void resize(int size)
bool setExifTagVariant(const char *exifTagName, const QVariant &data, bool rationalWantSmallDenominator=true, bool setProgramName=true) const
Set an Exif tag content using a QVariant.
Definition: kexiv2exif.cpp:521
QString number(int n, int base)
QString fromLocal8Bit(const char *str, int size)
bool setExif(const QByteArray &data) const
Set the Exif data using a Qt byte array.
Definition: kexiv2exif.cpp:138
uint toUInt(bool *ok) const const
int toInt(bool *ok) const const
QString getExifComment() const
Return a QString copy of Exif user comments.
Definition: kexiv2exif.cpp:237
QString getExifTagDescription(const char *exifTagName)
Return the Exif Tag description or a null string.
Definition: kexiv2exif.cpp:374
bool isEmpty() const const
bool isEmpty() const const
QMap< QString, QString > MetaDataMap
A map used to store Tags Key and Tags Value.
Definition: kexiv2.h:128
QString trimmed() const const
const char * constData() const const
static void convertToRational(const double number, long int *const numerator, long int *const denominator, const int rounding)
This method converts &#39;number&#39; to a rational value, returned in the &#39;numerator&#39; and &#39;denominator&#39; para...
Definition: kexiv2gps.cpp:596
QVariant getExifTagVariant(const char *exifTagName, bool rationalAsListOfInts=true, bool escapeCR=true, int component=0) const
Get an Exif tags content as a QVariant.
Definition: kexiv2exif.cpp:744
virtual bool open(QIODevice::OpenMode flags) override
T & first()
QString getExifTagString(const char *exifTagName, bool escapeCR=true) const
Get an Exif tags content like a string.
Definition: kexiv2exif.cpp:829
QList::iterator end()
TagsMap getMakernoteTagsList() const
Return a map of all non-standard Exif tags (makernotes) supported by Exiv2.
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 isValid() const const
QString & replace(int position, int n, QChar after)
QString getExifTagTitle(const char *exifTagName)
Return the Exif Tag title or a null string.
Definition: kexiv2exif.cpp:353
bool setExifTagLong(const char *exifTagName, long val, bool setProgramName=true) const
Set an Exif tag content using a long value.
Definition: kexiv2exif.cpp:451
===========================================================This file is a part of KDE project ...
QMap< QString, QStringList > TagsMap
A map used to store Tags Key and a list of Tags properties :
Definition: kexiv2.h:141
QByteArray toLatin1() const const
bool removeExifTag(const char *exifTagName, bool setProgramName=true) const
Remove the Exif tag &#39;exifTagName&#39; from Exif metadata.
Definition: kexiv2exif.cpp:395
QByteArray getExifTagData(const char *exifTagName) const
Get an Exif tag content like a bytes array.
Definition: kexiv2exif.cpp:714
QString createExifUserStringFromValue(const char *exifTagName, const QVariant &val, bool escapeCR=true)
Takes a QVariant value as it could have been retrieved by getExifTagVariant with the given exifTagNam...
Definition: kexiv2exif.cpp:598
QImage transformed(const QMatrix &matrix, Qt::TransformationMode mode) const const
QTextCodec * codecForName(const QByteArray &name)
bool canEncode(QChar ch) const const
char * data()
QString section(QChar sep, int start, int end, QString::SectionFlags flags) const const
bool setTiffThumbnail(const QImage &thumb, bool setProgramName=true) const
Adds a JPEG thumbnail to a TIFF images.
Definition: kexiv2exif.cpp:976
QString fromLatin1(const char *str, int size)
double toDouble(bool *ok) const const
QMap::iterator insert(const Key &key, const T &value)
bool setExifThumbnail(const QImage &thumb, bool setProgramName=true) const
Set the Exif Thumbnail image.
Definition: kexiv2exif.cpp:944
bool setExifTagRational(const char *exifTagName, long int num, long int den, bool setProgramName=true) const
Set an Exif tag content using a rational value.
Definition: kexiv2exif.cpp:473
bool setExifTagString(const char *exifTagName, const QString &value, bool setProgramName=true) const
Set an Exif tag content using a string.
Definition: kexiv2exif.cpp:861
QVariant::Type type() const const
int size() const const
QString toString() const const
QList::iterator begin()
QMatrix toMatrix() const
Returns a QMatrix representing this matrix.
===========================================================This file is a part of KDE project ...
QByteArray encodeName(const QString &fileName)
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.