• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdegraphics API Reference
  • KDE Home
  • Contact Us
 

libs/libkexiv2/libkexiv2

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

KDE's Doxygen guidelines are available online.

libs/libkexiv2/libkexiv2

Skip menu "libs/libkexiv2/libkexiv2"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdegraphics API Reference

Skip menu "kdegraphics API Reference"
  •     libkdcraw
  •     libkexiv2
  •     libkipi
  •     libksane
  • okular

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal