KExiv2

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

KDE's Doxygen guidelines are available online.