• 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
kexiv2image.cpp
Go to the documentation of this file.
1 
28 #include "kexiv2.h"
29 #include "kexiv2_p.h"
30 
31 // Local includes
32 
33 #include "rotationmatrix.h"
34 
35 namespace KExiv2Iface
36 {
37 
38 bool KExiv2::setImageProgramId(const QString& program, const QString& version) const
39 {
40  try
41  {
42  QString software(program);
43  software.append("-");
44  software.append(version);
45 
46  // Set program info into Exif.Image.ProcessingSoftware tag (only available with Exiv2 >= 0.14.0).
47 
48  d->exifMetadata()["Exif.Image.ProcessingSoftware"] = std::string(software.toAscii().constData());
49 
50  // See B.K.O #142564: Check if Exif.Image.Software already exist. If yes, do not touch this tag.
51 
52  if (!d->exifMetadata().empty())
53  {
54  Exiv2::ExifData exifData(d->exifMetadata());
55  Exiv2::ExifKey key("Exif.Image.Software");
56  Exiv2::ExifData::iterator it = exifData.findKey(key);
57  if (it == exifData.end())
58  d->exifMetadata()["Exif.Image.Software"] = std::string(software.toAscii().constData());
59  }
60 
61  // set program info into XMP tags.
62 
63 #ifdef _XMP_SUPPORT_
64 
65  if (!d->xmpMetadata().empty())
66  {
67  // Only create Xmp.xmp.CreatorTool if it do not exist.
68  Exiv2::XmpData xmpData(d->xmpMetadata());
69  Exiv2::XmpKey key("Xmp.xmp.CreatorTool");
70  Exiv2::XmpData::iterator it = xmpData.findKey(key);
71  if (it == xmpData.end())
72  setXmpTagString("Xmp.xmp.CreatorTool", software, false);
73  }
74 
75  setXmpTagString("Xmp.tiff.Software", software, false);
76 
77 #endif // _XMP_SUPPORT_
78 
79  // Set program info into IPTC tags.
80 
81  d->iptcMetadata()["Iptc.Application2.Program"] = std::string(program.toAscii().constData());
82  d->iptcMetadata()["Iptc.Application2.ProgramVersion"] = std::string(version.toAscii().constData());
83  return true;
84  }
85  catch( Exiv2::Error& e )
86  {
87  d->printExiv2ExceptionError("Cannot set Program identity into image using Exiv2 ", e);
88  }
89  catch(...)
90  {
91  kError() << "Default exception from Exiv2";
92  }
93 
94  return false;
95 }
96 
97 QSize KExiv2::getImageDimensions() const
98 {
99  try
100  {
101  long width=-1, height=-1;
102 
103  // Try to get Exif.Photo tags
104 
105  Exiv2::ExifData exifData(d->exifMetadata());
106  Exiv2::ExifKey key("Exif.Photo.PixelXDimension");
107  Exiv2::ExifData::iterator it = exifData.findKey(key);
108  if (it != exifData.end() && it->count())
109  width = it->toLong();
110 
111  Exiv2::ExifKey key2("Exif.Photo.PixelYDimension");
112  Exiv2::ExifData::iterator it2 = exifData.findKey(key2);
113  if (it2 != exifData.end() && it2->count())
114  height = it2->toLong();
115 
116  if (width != -1 && height != -1)
117  return QSize(width, height);
118 
119  // Try to get Exif.Image tags
120 
121  width = -1;
122  height = -1;
123 
124  Exiv2::ExifKey key3("Exif.Image.ImageWidth");
125  Exiv2::ExifData::iterator it3 = exifData.findKey(key3);
126  if (it3 != exifData.end() && it3->count())
127  width = it3->toLong();
128 
129  Exiv2::ExifKey key4("Exif.Image.ImageLength");
130  Exiv2::ExifData::iterator it4 = exifData.findKey(key4);
131  if (it4 != exifData.end() && it4->count())
132  height = it4->toLong();
133 
134  if (width != -1 && height != -1)
135  return QSize(width, height);
136 
137 #ifdef _XMP_SUPPORT_
138 
139  // Try to get Xmp.tiff tags
140 
141  width = -1;
142  height = -1;
143  bool wOk = false;
144  bool hOk = false;
145 
146  QString str = getXmpTagString("Xmp.tiff.ImageWidth");
147  if (!str.isEmpty())
148  width = str.toInt(&wOk);
149 
150  str = getXmpTagString("Xmp.tiff.ImageLength");
151  if (!str.isEmpty())
152  height = str.toInt(&hOk);
153 
154  if (wOk && hOk)
155  return QSize(width, height);
156 
157  // Try to get Xmp.exif tags
158 
159  width = -1;
160  height = -1;
161  wOk = false;
162  hOk = false;
163 
164  str = getXmpTagString("Xmp.exif.PixelXDimension");
165  if (!str.isEmpty())
166  width = str.toInt(&wOk);
167 
168  str = getXmpTagString("Xmp.exif.PixelYDimension");
169  if (!str.isEmpty())
170  height = str.toInt(&hOk);
171 
172  if (wOk && hOk)
173  return QSize(width, height);
174 
175 #endif // _XMP_SUPPORT_
176 
177  }
178  catch( Exiv2::Error& e )
179  {
180  d->printExiv2ExceptionError("Cannot parse image dimensions tag using Exiv2 ", e);
181  }
182  catch(...)
183  {
184  kError() << "Default exception from Exiv2";
185  }
186 
187  return QSize();
188 }
189 
190 bool KExiv2::setImageDimensions(const QSize& size, bool setProgramName) const
191 {
192  if (!setProgramId(setProgramName))
193  return false;
194 
195  try
196  {
197  // Set Exif values.
198 
199  // NOTE: see B.K.O #144604: need to cast to record an unsigned integer value.
200  d->exifMetadata()["Exif.Image.ImageWidth"] = static_cast<uint32_t>(size.width());
201  d->exifMetadata()["Exif.Image.ImageLength"] = static_cast<uint32_t>(size.height());
202  d->exifMetadata()["Exif.Photo.PixelXDimension"] = static_cast<uint32_t>(size.width());
203  d->exifMetadata()["Exif.Photo.PixelYDimension"] = static_cast<uint32_t>(size.height());
204 
205  // Set Xmp values.
206 
207 #ifdef _XMP_SUPPORT_
208 
209  setXmpTagString("Xmp.tiff.ImageWidth", QString::number(size.width()), false);
210  setXmpTagString("Xmp.tiff.ImageLength", QString::number(size.height()), false);
211  setXmpTagString("Xmp.exif.PixelXDimension", QString::number(size.width()), false);
212  setXmpTagString("Xmp.exif.PixelYDimension", QString::number(size.height()), false);
213 
214 #endif // _XMP_SUPPORT_
215 
216  return true;
217  }
218  catch( Exiv2::Error& e )
219  {
220  d->printExiv2ExceptionError("Cannot set image dimensions using Exiv2 ", e);
221  }
222  catch(...)
223  {
224  kError() << "Default exception from Exiv2";
225  }
226 
227  return false;
228 }
229 
230 KExiv2::ImageOrientation KExiv2::getImageOrientation() const
231 {
232  try
233  {
234  Exiv2::ExifData exifData(d->exifMetadata());
235  Exiv2::ExifData::iterator it;
236  long orientation;
237  ImageOrientation imageOrient = ORIENTATION_NORMAL;
238 
239  // -- Standard Xmp tag --------------------------------
240 
241 #ifdef _XMP_SUPPORT_
242 
243  bool ok = false;
244  QString str = getXmpTagString("Xmp.tiff.Orientation");
245  if (!str.isEmpty())
246  {
247  orientation = str.toLong(&ok);
248  if (ok)
249  {
250  kDebug() << "Orientation => Xmp.tiff.Orientation => " << (int)orientation;
251  return (ImageOrientation)orientation;
252  }
253  }
254 
255 #endif // _XMP_SUPPORT_
256 
257  // Because some camera set a wrong standard exif orientation tag,
258  // We need to check makernote tags in first!
259 
260  // -- Minolta Cameras ----------------------------------
261 
262  Exiv2::ExifKey minoltaKey1("Exif.MinoltaCs7D.Rotation");
263  it = exifData.findKey(minoltaKey1);
264 
265  if (it != exifData.end() && it->count())
266  {
267  orientation = it->toLong();
268  kDebug() << "Orientation => Exif.MinoltaCs7D.Rotation => " << (int)orientation;
269  switch(orientation)
270  {
271  case 76:
272  imageOrient = ORIENTATION_ROT_90;
273  break;
274  case 82:
275  imageOrient = ORIENTATION_ROT_270;
276  break;
277  }
278  return imageOrient;
279  }
280 
281  Exiv2::ExifKey minoltaKey2("Exif.MinoltaCs5D.Rotation");
282  it = exifData.findKey(minoltaKey2);
283 
284  if (it != exifData.end() && it->count())
285  {
286  orientation = it->toLong();
287  kDebug() << "Orientation => Exif.MinoltaCs5D.Rotation => " << (int)orientation;
288  switch(orientation)
289  {
290  case 76:
291  imageOrient = ORIENTATION_ROT_90;
292  break;
293  case 82:
294  imageOrient = ORIENTATION_ROT_270;
295  break;
296  }
297  return imageOrient;
298  }
299 
300  // -- Standard Exif tag --------------------------------
301 
302  Exiv2::ExifKey keyStd("Exif.Image.Orientation");
303  it = exifData.findKey(keyStd);
304 
305  if (it != exifData.end() && it->count())
306  {
307  orientation = it->toLong();
308  kDebug() << "Orientation => Exif.Image.Orientation => " << (int)orientation;
309  return (ImageOrientation)orientation;
310  }
311 
312  }
313  catch( Exiv2::Error& e )
314  {
315  d->printExiv2ExceptionError("Cannot parse Exif Orientation tag using Exiv2 ", e);
316  }
317  catch(...)
318  {
319  kError() << "Default exception from Exiv2";
320  }
321 
322  return ORIENTATION_UNSPECIFIED;
323 }
324 
325 bool KExiv2::setImageOrientation(ImageOrientation orientation, bool setProgramName) const
326 {
327  if (!setProgramId(setProgramName))
328  return false;
329 
330  try
331  {
332  if (orientation < ORIENTATION_UNSPECIFIED || orientation > ORIENTATION_ROT_270)
333  {
334  kDebug() << "Image orientation value is not correct!";
335  return false;
336  }
337 
338  // Set Exif values.
339 
340  d->exifMetadata()["Exif.Image.Orientation"] = static_cast<uint16_t>(orientation);
341  kDebug() << "Exif.Image.Orientation tag set to: " << (int)orientation;
342 
343  // Set Xmp values.
344 
345 #ifdef _XMP_SUPPORT_
346 
347  setXmpTagString("Xmp.tiff.Orientation", QString::number((int)orientation), false);
348 
349 #endif // _XMP_SUPPORT_
350 
351  // -- Minolta/Sony Cameras ----------------------------------
352 
353  // Minolta and Sony camera store image rotation in Makernote.
354  // We remove these information to prevent duplicate values.
355 
356  Exiv2::ExifData::iterator it;
357 
358  Exiv2::ExifKey minoltaKey1("Exif.MinoltaCs7D.Rotation");
359  it = d->exifMetadata().findKey(minoltaKey1);
360  if (it != d->exifMetadata().end())
361  {
362  d->exifMetadata().erase(it);
363  kDebug() << "Removing Exif.MinoltaCs7D.Rotation tag";
364  }
365 
366  Exiv2::ExifKey minoltaKey2("Exif.MinoltaCs5D.Rotation");
367  it = d->exifMetadata().findKey(minoltaKey2);
368  if (it != d->exifMetadata().end())
369  {
370  d->exifMetadata().erase(it);
371  kDebug() << "Removing Exif.MinoltaCs5D.Rotation tag";
372  }
373 
374  // -- Exif embedded thumbnail ----------------------------------
375 
376  Exiv2::ExifKey thumbKey("Exif.Thumbnail.Orientation");
377  it = d->exifMetadata().findKey(thumbKey);
378  if (it != d->exifMetadata().end() && it->count())
379  {
380  RotationMatrix operation((KExiv2Iface::KExiv2::ImageOrientation)it->toLong());
381  operation *= orientation;
382  (*it) = static_cast<uint16_t>(operation.exifOrientation());
383  }
384 
385  return true;
386  }
387  catch( Exiv2::Error& e )
388  {
389  d->printExiv2ExceptionError("Cannot set Exif Orientation tag using Exiv2 ", e);
390  }
391  catch(...)
392  {
393  kError() << "Default exception from Exiv2";
394  }
395 
396  return false;
397 }
398 
399 KExiv2::ImageColorWorkSpace KExiv2::getImageColorWorkSpace() const
400 {
401  // Check Exif values.
402 
403  long exifColorSpace = -1;
404  if (!getExifTagLong("Exif.Photo.ColorSpace", exifColorSpace))
405  {
406 #ifdef _XMP_SUPPORT_
407  QVariant var = getXmpTagVariant("Xmp.exif.ColorSpace");
408  if (!var.isNull())
409  exifColorSpace = var.toInt();
410 #endif // _XMP_SUPPORT_
411  }
412 
413  if (exifColorSpace == 1)
414  {
415  return WORKSPACE_SRGB; // as specified by standard
416  }
417  else if (exifColorSpace == 2)
418  {
419  return WORKSPACE_ADOBERGB; // not in the standard!
420  }
421  else
422  {
423  if (exifColorSpace == 65535)
424  {
425  // A lot of cameras set the Exif.Iop.InteroperabilityIndex,
426  // as documented for ExifTool
427  QString interopIndex = getExifTagString("Exif.Iop.InteroperabilityIndex");
428  if (!interopIndex.isNull())
429  {
430  if (interopIndex == "R03")
431  return WORKSPACE_ADOBERGB;
432  else if (interopIndex == "R98")
433  return WORKSPACE_SRGB;
434  }
435  }
436 
437  // Note: Text EXIF ColorSpace tag may just not be present (NEF files)
438 
439  // Nikon camera set Exif.Photo.ColorSpace to uncalibrated or just skip this field,
440  // then add additional information into the makernotes.
441  // Exif.Nikon3.ColorSpace: 1 => sRGB, 2 => AdobeRGB
442  long nikonColorSpace;
443  if (getExifTagLong("Exif.Nikon3.ColorSpace", nikonColorSpace))
444  {
445  if (nikonColorSpace == 1)
446  return WORKSPACE_SRGB;
447  else if (nikonColorSpace == 2)
448  return WORKSPACE_ADOBERGB;
449  }
450  // Exif.Nikon3.ColorMode is set to "MODE2" for AdobeRGB, but there are sometimes two ColorMode fields
451  // in a NEF, with the first one "COLOR" and the second one "MODE2"; but in this case, ColorSpace (above) was set.
452  if (getExifTagString("Exif.Nikon3.ColorMode").contains("MODE2"))
453  return WORKSPACE_ADOBERGB;
454 
455  //TODO: This makernote tag (0x00b4) must be added to libexiv2
456  /*
457  long canonColorSpace;
458  if (getExifTagLong("Exif.Canon.ColorSpace", canonColorSpace))
459  {
460  if (canonColorSpace == 1)
461  return WORKSPACE_SRGB;
462  else if (canonColorSpace == 2)
463  return WORKSPACE_ADOBERGB;
464  }
465  */
466 
467  // TODO : add more Makernote parsing here ...
468 
469  if (exifColorSpace == 65535)
470  return WORKSPACE_UNCALIBRATED;
471  }
472 
473  return WORKSPACE_UNSPECIFIED;
474 }
475 
476 bool KExiv2::setImageColorWorkSpace(ImageColorWorkSpace workspace, bool setProgramName) const
477 {
478  if (!setProgramId(setProgramName))
479  return false;
480 
481  try
482  {
483  // Set Exif value.
484 
485  d->exifMetadata()["Exif.Photo.ColorSpace"] = static_cast<uint16_t>(workspace);
486 
487  // Set Xmp value.
488 
489 #ifdef _XMP_SUPPORT_
490 
491  setXmpTagString("Xmp.exif.ColorSpace", QString::number((int)workspace), false);
492 
493 #endif // _XMP_SUPPORT_
494 
495  return true;
496  }
497  catch( Exiv2::Error& e )
498  {
499  d->printExiv2ExceptionError("Cannot set Exif color workspace tag using Exiv2 ", e);
500  }
501  catch(...)
502  {
503  kError() << "Default exception from Exiv2";
504  }
505 
506  return false;
507 }
508 
509 QDateTime KExiv2::getImageDateTime() const
510 {
511  try
512  {
513  // In first, trying to get Date & time from Exif tags.
514 
515  if (!d->exifMetadata().empty())
516  {
517  Exiv2::ExifData exifData(d->exifMetadata());
518  {
519  Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal");
520  Exiv2::ExifData::iterator it = exifData.findKey(key);
521 
522  if (it != exifData.end())
523  {
524  QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate);
525 
526  if (dateTime.isValid())
527  {
528  kDebug() << "DateTime => Exif.Photo.DateTimeOriginal => " << dateTime;
529  return dateTime;
530  }
531  }
532  }
533  {
534  Exiv2::ExifKey key("Exif.Photo.DateTimeDigitized");
535  Exiv2::ExifData::iterator it = exifData.findKey(key);
536 
537  if (it != exifData.end())
538  {
539  QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate);
540 
541  if (dateTime.isValid())
542  {
543  kDebug() << "DateTime => Exif.Photo.DateTimeDigitized => " << dateTime;
544  return dateTime;
545  }
546  }
547  }
548  {
549  Exiv2::ExifKey key("Exif.Image.DateTime");
550  Exiv2::ExifData::iterator it = exifData.findKey(key);
551 
552  if (it != exifData.end())
553  {
554  QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate);
555 
556  if (dateTime.isValid())
557  {
558  kDebug() << "DateTime => Exif.Image.DateTime => " << dateTime;
559  return dateTime;
560  }
561  }
562  }
563  }
564 
565  // In second, trying to get Date & time from Xmp tags.
566 
567 #ifdef _XMP_SUPPORT_
568 
569  if (!d->xmpMetadata().empty())
570  {
571  Exiv2::XmpData xmpData(d->xmpMetadata());
572  {
573  Exiv2::XmpKey key("Xmp.exif.DateTimeOriginal");
574  Exiv2::XmpData::iterator it = xmpData.findKey(key);
575 
576  if (it != xmpData.end())
577  {
578  QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate);
579 
580  if (dateTime.isValid())
581  {
582  kDebug() << "DateTime => Xmp.exif.DateTimeOriginal => " << dateTime;
583  return dateTime;
584  }
585  }
586  }
587  {
588  Exiv2::XmpKey key("Xmp.exif.DateTimeDigitized");
589  Exiv2::XmpData::iterator it = xmpData.findKey(key);
590 
591  if (it != xmpData.end())
592  {
593  QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate);
594 
595  if (dateTime.isValid())
596  {
597  kDebug() << "DateTime => Xmp.exif.DateTimeDigitized => " << dateTime;
598  return dateTime;
599  }
600  }
601  }
602  {
603  Exiv2::XmpKey key("Xmp.photoshop.DateCreated");
604  Exiv2::XmpData::iterator it = xmpData.findKey(key);
605 
606  if (it != xmpData.end())
607  {
608  QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate);
609 
610  if (dateTime.isValid())
611  {
612  kDebug() << "DateTime => Xmp.photoshop.DateCreated => " << dateTime;
613  return dateTime;
614  }
615  }
616  }
617  {
618  Exiv2::XmpKey key("Xmp.xmp.CreateDate");
619  Exiv2::XmpData::iterator it = xmpData.findKey(key);
620 
621  if (it != xmpData.end())
622  {
623  QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate);
624 
625  if (dateTime.isValid())
626  {
627  kDebug() << "DateTime => Xmp.xmp.CreateDate => " << dateTime;
628  return dateTime;
629  }
630  }
631  }
632  {
633  Exiv2::XmpKey key("Xmp.tiff.DateTime");
634  Exiv2::XmpData::iterator it = xmpData.findKey(key);
635 
636  if (it != xmpData.end())
637  {
638  QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate);
639 
640  if (dateTime.isValid())
641  {
642  kDebug() << "DateTime => Xmp.tiff.DateTime => " << dateTime;
643  return dateTime;
644  }
645  }
646  }
647  {
648  Exiv2::XmpKey key("Xmp.xmp.ModifyDate");
649  Exiv2::XmpData::iterator it = xmpData.findKey(key);
650 
651  if (it != xmpData.end())
652  {
653  QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate);
654 
655  if (dateTime.isValid())
656  {
657  kDebug() << "DateTime => Xmp.xmp.ModifyDate => " << dateTime;
658  return dateTime;
659  }
660  }
661  }
662  {
663  Exiv2::XmpKey key("Xmp.xmp.MetadataDate");
664  Exiv2::XmpData::iterator it = xmpData.findKey(key);
665 
666  if (it != xmpData.end())
667  {
668  QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate);
669 
670  if (dateTime.isValid())
671  {
672  kDebug() << "DateTime => Xmp.xmp.MetadataDate => " << dateTime;
673  return dateTime;
674  }
675  }
676  }
677  }
678 
679 #endif // _XMP_SUPPORT_
680 
681  // In third, trying to get Date & time from Iptc tags.
682 
683  if (!d->iptcMetadata().empty())
684  {
685  Exiv2::IptcData iptcData(d->iptcMetadata());
686 
687  // Try creation Iptc date & time entries.
688 
689  Exiv2::IptcKey keyDateCreated("Iptc.Application2.DateCreated");
690  Exiv2::IptcData::iterator it = iptcData.findKey(keyDateCreated);
691 
692  if (it != iptcData.end())
693  {
694  QString IptcDateCreated(it->toString().c_str());
695  Exiv2::IptcKey keyTimeCreated("Iptc.Application2.TimeCreated");
696  Exiv2::IptcData::iterator it2 = iptcData.findKey(keyTimeCreated);
697 
698  if (it2 != iptcData.end())
699  {
700  QString IptcTimeCreated(it2->toString().c_str());
701  QDate date = QDate::fromString(IptcDateCreated, Qt::ISODate);
702  QTime time = QTime::fromString(IptcTimeCreated, Qt::ISODate);
703  QDateTime dateTime = QDateTime(date, time);
704 
705  if (dateTime.isValid())
706  {
707  kDebug() << "DateTime => Iptc.Application2.DateCreated => " << dateTime;
708  return dateTime;
709  }
710  }
711  }
712 
713  // Try digitization Iptc date & time entries.
714 
715  Exiv2::IptcKey keyDigitizationDate("Iptc.Application2.DigitizationDate");
716  Exiv2::IptcData::iterator it3 = iptcData.findKey(keyDigitizationDate);
717 
718  if (it3 != iptcData.end())
719  {
720  QString IptcDateDigitization(it3->toString().c_str());
721  Exiv2::IptcKey keyDigitizationTime("Iptc.Application2.DigitizationTime");
722  Exiv2::IptcData::iterator it4 = iptcData.findKey(keyDigitizationTime);
723 
724  if (it4 != iptcData.end())
725  {
726  QString IptcTimeDigitization(it4->toString().c_str());
727  QDate date = QDate::fromString(IptcDateDigitization, Qt::ISODate);
728  QTime time = QTime::fromString(IptcTimeDigitization, Qt::ISODate);
729  QDateTime dateTime = QDateTime(date, time);
730 
731  if (dateTime.isValid())
732  {
733  kDebug() << "DateTime => Iptc.Application2.DigitizationDate => " << dateTime;
734  return dateTime;
735  }
736  }
737  }
738  }
739  }
740  catch( Exiv2::Error& e )
741  {
742  d->printExiv2ExceptionError("Cannot parse Exif date & time tag using Exiv2 ", e);
743  }
744  catch(...)
745  {
746  kError() << "Default exception from Exiv2";
747  }
748 
749  return QDateTime();
750 }
751 
752 bool KExiv2::setImageDateTime(const QDateTime& dateTime, bool setDateTimeDigitized, bool setProgramName) const
753 {
754  if(!dateTime.isValid())
755  return false;
756 
757  if (!setProgramId(setProgramName))
758  return false;
759 
760  try
761  {
762  // In first we write date & time into Exif.
763 
764  // DateTimeDigitized is set by slide scanners etc. when a picture is digitized.
765  // DateTimeOriginal specifies the date/time when the picture was taken.
766  // For digital cameras, these dates should be both set, and identical.
767  // Reference: http://www.exif.org/Exif2-2.PDF, chapter 4.6.5, table 4, section F.
768 
769  const std::string &exifdatetime(dateTime.toString(QString("yyyy:MM:dd hh:mm:ss")).toAscii().constData());
770  d->exifMetadata()["Exif.Image.DateTime"] = exifdatetime;
771  d->exifMetadata()["Exif.Photo.DateTimeOriginal"] = exifdatetime;
772  if(setDateTimeDigitized)
773  d->exifMetadata()["Exif.Photo.DateTimeDigitized"] = exifdatetime;
774 
775 #ifdef _XMP_SUPPORT_
776 
777  // In second we write date & time into Xmp.
778 
779  const std::string &xmpdatetime(dateTime.toString(Qt::ISODate).toAscii().constData());
780 
781  Exiv2::Value::AutoPtr xmpTxtVal = Exiv2::Value::create(Exiv2::xmpText);
782  xmpTxtVal->read(xmpdatetime);
783  d->xmpMetadata().add(Exiv2::XmpKey("Xmp.exif.DateTimeOriginal"), xmpTxtVal.get());
784  d->xmpMetadata().add(Exiv2::XmpKey("Xmp.photoshop.DateCreated"), xmpTxtVal.get());
785  d->xmpMetadata().add(Exiv2::XmpKey("Xmp.tiff.DateTime"), xmpTxtVal.get());
786  d->xmpMetadata().add(Exiv2::XmpKey("Xmp.xmp.CreateDate"), xmpTxtVal.get());
787  d->xmpMetadata().add(Exiv2::XmpKey("Xmp.xmp.MetadataDate"), xmpTxtVal.get());
788  d->xmpMetadata().add(Exiv2::XmpKey("Xmp.xmp.ModifyDate"), xmpTxtVal.get());
789  if(setDateTimeDigitized)
790  d->xmpMetadata().add(Exiv2::XmpKey("Xmp.exif.DateTimeDigitized"), xmpTxtVal.get());
791 
792  // Tag not updated:
793  // "Xmp.dc.DateTime" is a sequence of date relevant of dublin core change.
794  // This is not the picture date as well
795 
796 #endif // _XMP_SUPPORT_
797 
798  // In third we write date & time into Iptc.
799 
800  const std::string &iptcdate(dateTime.date().toString(Qt::ISODate).toAscii().constData());
801  const std::string &iptctime(dateTime.time().toString(Qt::ISODate).toAscii().constData());
802  d->iptcMetadata()["Iptc.Application2.DateCreated"] = iptcdate;
803  d->iptcMetadata()["Iptc.Application2.TimeCreated"] = iptctime;
804  if(setDateTimeDigitized)
805  {
806  d->iptcMetadata()["Iptc.Application2.DigitizationDate"] = iptcdate;
807  d->iptcMetadata()["Iptc.Application2.DigitizationTime"] = iptctime;
808  }
809 
810  return true;
811  }
812  catch( Exiv2::Error& e )
813  {
814  d->printExiv2ExceptionError("Cannot set Date & Time into image using Exiv2 ", e);
815  }
816  catch(...)
817  {
818  kError() << "Default exception from Exiv2";
819  }
820 
821  return false;
822 }
823 
824 QDateTime KExiv2::getDigitizationDateTime(bool fallbackToCreationTime) const
825 {
826  try
827  {
828  // In first, trying to get Date & time from Exif tags.
829 
830  if (!d->exifMetadata().empty())
831  {
832  // Try Exif date time digitized.
833 
834  Exiv2::ExifData exifData(d->exifMetadata());
835  Exiv2::ExifKey key("Exif.Photo.DateTimeDigitized");
836  Exiv2::ExifData::iterator it = exifData.findKey(key);
837 
838  if (it != exifData.end())
839  {
840  QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate);
841 
842  if (dateTime.isValid())
843  {
844  kDebug() << "DateTime (Exif digitalized): " << dateTime.toString().toAscii().constData();
845  return dateTime;
846  }
847  }
848  }
849 
850  // In second, trying to get Date & time from Iptc tags.
851 
852  if (!d->iptcMetadata().empty())
853  {
854  // Try digitization Iptc date time entries.
855 
856  Exiv2::IptcData iptcData(d->iptcMetadata());
857  Exiv2::IptcKey keyDigitizationDate("Iptc.Application2.DigitizationDate");
858  Exiv2::IptcData::iterator it = iptcData.findKey(keyDigitizationDate);
859 
860  if (it != iptcData.end())
861  {
862  QString IptcDateDigitization(it->toString().c_str());
863 
864  Exiv2::IptcKey keyDigitizationTime("Iptc.Application2.DigitizationTime");
865  Exiv2::IptcData::iterator it2 = iptcData.findKey(keyDigitizationTime);
866 
867  if (it2 != iptcData.end())
868  {
869  QString IptcTimeDigitization(it2->toString().c_str());
870 
871  QDate date = QDate::fromString(IptcDateDigitization, Qt::ISODate);
872  QTime time = QTime::fromString(IptcTimeDigitization, Qt::ISODate);
873  QDateTime dateTime = QDateTime(date, time);
874 
875  if (dateTime.isValid())
876  {
877  kDebug() << "Date (IPTC digitalized): " << dateTime.toString().toAscii().constData();
878  return dateTime;
879  }
880  }
881  }
882  }
883  }
884  catch( Exiv2::Error& e )
885  {
886  d->printExiv2ExceptionError("Cannot parse Exif digitization date & time tag using Exiv2 ", e);
887  }
888  catch(...)
889  {
890  kError() << "Default exception from Exiv2";
891  }
892 
893  if (fallbackToCreationTime)
894  return getImageDateTime();
895  else
896  return QDateTime();
897 }
898 
899 bool KExiv2::getImagePreview(QImage& preview) const
900 {
901  try
902  {
903  // In first we trying to get from Iptc preview tag.
904  if (preview.loadFromData(getIptcTagData("Iptc.Application2.Preview")) )
905  return true;
906 
907  // TODO : Added here Makernotes preview extraction when Exiv2 will be fixed for that.
908  }
909  catch( Exiv2::Error& e )
910  {
911  d->printExiv2ExceptionError("Cannot get image preview using Exiv2 ", e);
912  }
913  catch(...)
914  {
915  kError() << "Default exception from Exiv2";
916  }
917 
918  return false;
919 }
920 
921 bool KExiv2::setImagePreview(const QImage& preview, bool setProgramName) const
922 {
923  if (!setProgramId(setProgramName))
924  return false;
925 
926  if (preview.isNull())
927  {
928  removeIptcTag("Iptc.Application2.Preview");
929  removeIptcTag("Iptc.Application2.PreviewFormat");
930  removeIptcTag("Iptc.Application2.PreviewVersion");
931  return true;
932  }
933 
934  try
935  {
936  QByteArray data;
937  QBuffer buffer(&data);
938  buffer.open(QIODevice::WriteOnly);
939 
940  // A little bit compressed preview jpeg image to limit IPTC size.
941  preview.save(&buffer, "JPEG");
942  kDebug() << "JPEG image preview size: (" << preview.width() << " x "
943  << preview.height() << ") pixels - " << data.size() << " bytes";
944 
945  Exiv2::DataValue val;
946  val.read((Exiv2::byte *)data.data(), data.size());
947  d->iptcMetadata()["Iptc.Application2.Preview"] = val;
948 
949  // See http://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf Appendix A for details.
950  d->iptcMetadata()["Iptc.Application2.PreviewFormat"] = 11; // JPEG
951  d->iptcMetadata()["Iptc.Application2.PreviewVersion"] = 1;
952 
953  return true;
954  }
955  catch( Exiv2::Error& e )
956  {
957  d->printExiv2ExceptionError("Cannot get image preview using Exiv2 ", e);
958  }
959  catch(...)
960  {
961  kError() << "Default exception from Exiv2";
962  }
963 
964  return false;
965 }
966 
967 } // NameSpace KExiv2Iface
QDateTime::toString
QString toString(Qt::DateFormat format) 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
QString::append
QString & append(QChar ch)
KExiv2Iface::KExiv2::WORKSPACE_SRGB
Definition: kexiv2.h:89
QSize::width
int width() const
KExiv2Iface::KExiv2::ImageColorWorkSpace
ImageColorWorkSpace
The image color workspace values given by Exif metadata.
Definition: kexiv2.h:86
KExiv2Iface::KExiv2::Private::iptcMetadata
const Exiv2::IptcData & iptcMetadata() const
Definition: kexiv2_p.h:164
QTime::toString
QString toString(Qt::DateFormat format) const
QDate::toString
QString toString(Qt::DateFormat format) const
QByteArray
QImage::save
bool save(const QString &fileName, const char *format, int quality) const
KExiv2Iface::KExiv2::setXmpTagString
bool setXmpTagString(const char *xmpTagName, const QString &value, bool setProgramName=true) const
Set a Xmp tag content using a string.
Definition: kexiv2xmp.cpp:384
QDateTime::time
QTime time() const
QBuffer
QTime::fromString
QTime fromString(const QString &string, Qt::DateFormat format)
KExiv2Iface::KExiv2::setImageProgramId
bool setImageProgramId(const QString &program, const QString &version) const
Set Program name and program version in Exif and Iptc Metadata.
Definition: kexiv2image.cpp:38
QImage::isNull
bool isNull() const
KExiv2Iface::KExiv2::ImageOrientation
ImageOrientation
The image orientation values given by Exif metadata.
Definition: kexiv2.h:96
QTime
QString::isNull
bool isNull() const
KExiv2Iface::KExiv2::getExifTagLong
bool getExifTagLong(const char *exifTagName, long &val) const
Get an Exif tag content like a long value.
Definition: kexiv2exif.cpp:678
KExiv2Iface::KExiv2::getIptcTagData
QByteArray getIptcTagData(const char *iptcTagName) const
Get an Iptc tag content as a bytes array.
Definition: kexiv2iptc.cpp:363
QDate::fromString
QDate fromString(const QString &string, Qt::DateFormat format)
QString::number
QString number(int n, int base)
KExiv2Iface::KExiv2::ORIENTATION_ROT_270
Definition: kexiv2.h:106
QVariant::toInt
int toInt(bool *ok) const
QVariant::isNull
bool isNull() const
KExiv2Iface::RotationMatrix
Definition: rotationmatrix.h:43
QImage::width
int width() const
KExiv2Iface::KExiv2::WORKSPACE_UNCALIBRATED
Definition: kexiv2.h:91
QString::toInt
int toInt(bool *ok, int base) const
QString::isEmpty
bool isEmpty() const
QByteArray::constData
const char * constData() const
QBuffer::open
virtual bool open(QFlags< QIODevice::OpenModeFlag > flags)
QDate
KExiv2Iface::KExiv2::getImagePreview
bool getImagePreview(QImage &preview) const
Return a QImage copy of Iptc preview image.
Definition: kexiv2image.cpp:899
KExiv2Iface::KExiv2::getDigitizationDateTime
QDateTime getDigitizationDateTime(bool fallbackToCreationTime=false) const
Return the digitization time stamp of the image.
Definition: kexiv2image.cpp:824
QString
KExiv2Iface::KExiv2::getImageDimensions
QSize getImageDimensions() const
Return the size of image in pixels using Exif tags.
Definition: kexiv2image.cpp:97
KExiv2Iface::KExiv2::getExifTagString
QString getExifTagString(const char *exifTagName, bool escapeCR=true) const
Get an Exif tags content like a string.
Definition: kexiv2exif.cpp:827
QString::contains
bool contains(QChar ch, Qt::CaseSensitivity cs) const
QSize
KExiv2Iface::KExiv2::removeIptcTag
bool removeIptcTag(const char *iptcTagName, bool setProgramName=true) const
Remove the all instance of Iptc tags 'iptcTagName' from Iptc metadata.
Definition: kexiv2iptc.cpp:297
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
KExiv2Iface::KExiv2::setImageOrientation
bool setImageOrientation(ImageOrientation orientation, bool setProgramName=true) const
Set the Exif orientation tag of image.
Definition: kexiv2image.cpp:325
KExiv2Iface::KExiv2::setImageDimensions
bool setImageDimensions(const QSize &size, bool setProgramName=true) const
Set the size of image in pixels in Exif tags.
Definition: kexiv2image.cpp:190
QImage
QDateTime::isValid
bool isValid() const
KExiv2Iface::KExiv2::getImageOrientation
KExiv2::ImageOrientation getImageOrientation() const
Return the image orientation set in Exif metadata.
Definition: kexiv2image.cpp:230
QString::toLong
long toLong(bool *ok, int base) const
KExiv2Iface::KExiv2::setImageColorWorkSpace
bool setImageColorWorkSpace(ImageColorWorkSpace workspace, bool setProgramName=true) const
Set the Exif color-space tag of image.
Definition: kexiv2image.cpp:476
KExiv2Iface::KExiv2::getXmpTagString
QString getXmpTagString(const char *xmpTagName, bool escapeCR=true) const
Get a Xmp tag content like a string.
Definition: kexiv2xmp.cpp:343
rotationmatrix.h
===========================================================This file is a part of digiKam project htt...
KExiv2Iface::KExiv2::getXmpTagVariant
QVariant getXmpTagVariant(const char *xmpTagName, bool rationalAsListOfInts=true, bool stringEscapeCR=true) const
Get an Xmp tag content as a QVariant.
Definition: kexiv2xmp.cpp:925
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'.
QDateTime::date
QDate date() const
KExiv2Iface::KExiv2::ORIENTATION_UNSPECIFIED
Definition: kexiv2.h:98
KExiv2Iface::KExiv2::setImagePreview
virtual bool setImagePreview(const QImage &preview, bool setProgramName=true) const
Set the Iptc preview image.
Definition: kexiv2image.cpp:921
KExiv2Iface::KExiv2::ORIENTATION_ROT_90
Definition: kexiv2.h:104
KExiv2Iface::KExiv2::setImageDateTime
bool setImageDateTime(const QDateTime &dateTime, bool setDateTimeDigitized=false, bool setProgramName=true) const
Set the Exif and Iptc time stamp.
Definition: kexiv2image.cpp:752
kexiv2_p.h
===========================================================This file is a part of digiKam project htt...
KExiv2Iface::KExiv2::ORIENTATION_NORMAL
Definition: kexiv2.h:99
QSize::height
int height() const
KExiv2Iface::KExiv2::getImageColorWorkSpace
KExiv2::ImageColorWorkSpace getImageColorWorkSpace() const
Return the image color-space set in Exif metadata.
Definition: kexiv2image.cpp:399
QByteArray::data
char * data()
QImage::height
int height() const
KExiv2Iface::KExiv2::WORKSPACE_UNSPECIFIED
Definition: kexiv2.h:88
QByteArray::size
int size() const
KExiv2Iface::KExiv2::data
KExiv2Data data() const
Definition: kexiv2.cpp:218
KExiv2Iface::KExiv2::getImageDateTime
QDateTime getImageDateTime() const
Return the time stamp of image.
Definition: kexiv2image.cpp:509
kexiv2.h
===========================================================This file is a part of digiKam project htt...
QString::toAscii
QByteArray toAscii() const
QDateTime
QVariant
KExiv2Iface::KExiv2::WORKSPACE_ADOBERGB
Definition: kexiv2.h:90
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