KExiv2

kexiv2.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 "libkexiv2_version.h"
34 #include "libkexiv2_debug.h"
35 
36 namespace KExiv2Iface
37 {
38 
40  : d(new Private)
41 {
42 }
43 
44 KExiv2::KExiv2(const KExiv2& metadata)
45  : d(new Private)
46 {
47  d->copyPrivateData(metadata.d);
48 }
49 
50 KExiv2::KExiv2(const KExiv2Data& data)
51  : d(new Private)
52 {
53  setData(data);
54 }
55 
56 KExiv2::KExiv2(const QString& filePath)
57  : d(new Private)
58 {
59  load(filePath);
60 }
61 
63 {
64  delete d;
65 }
66 
67 KExiv2& KExiv2::operator=(const KExiv2& metadata)
68 {
69  d->copyPrivateData(metadata.d);
70 
71  return *this;
72 }
73 
74 //-- Statics methods ----------------------------------------------
75 
77 {
78 #ifdef _XMP_SUPPORT_
79 
80  if (!Exiv2::XmpParser::initialize())
81  return false;
82 
83  registerXmpNameSpace(QString::fromLatin1("http://ns.adobe.com/lightroom/1.0/"), QString::fromLatin1("lr"));
84  registerXmpNameSpace(QString::fromLatin1("http://www.digikam.org/ns/kipi/1.0/"), QString::fromLatin1("kipi"));
85  registerXmpNameSpace(QString::fromLatin1("http://ns.microsoft.com/photo/1.2/"), QString::fromLatin1("MP"));
86  registerXmpNameSpace(QString::fromLatin1("http://ns.acdsee.com/iptc/1.0/"), QString::fromLatin1("acdsee"));
87  registerXmpNameSpace(QString::fromLatin1("http://www.video"), QString::fromLatin1("video"));
88 
89 #endif // _XMP_SUPPORT_
90 
91  return true;
92 }
93 
95 {
96  // Fix memory leak if Exiv2 support XMP.
97 #ifdef _XMP_SUPPORT_
98 
99  unregisterXmpNameSpace(QString::fromLatin1("http://ns.adobe.com/lightroom/1.0/"));
100  unregisterXmpNameSpace(QString::fromLatin1("http://www.digikam.org/ns/kipi/1.0/"));
101  unregisterXmpNameSpace(QString::fromLatin1("http://ns.microsoft.com/photo/1.2/"));
102  unregisterXmpNameSpace(QString::fromLatin1("http://ns.acdsee.com/iptc/1.0/"));
103  unregisterXmpNameSpace(QString::fromLatin1("http://www.video"));
104 
105  Exiv2::XmpParser::terminate();
106 
107 #endif // _XMP_SUPPORT_
108 
109  return true;
110 }
111 
113 {
114 #ifdef _XMP_SUPPORT_
115  return true;
116 #else
117  return false;
118 #endif // _XMP_SUPPORT_
119 }
120 
122 {
123  if (typeMime == QString::fromLatin1("image/jpeg"))
124  {
125  return true;
126  }
127  else if (typeMime == QString::fromLatin1("image/tiff"))
128  {
129  return true;
130  }
131  else if (typeMime == QString::fromLatin1("image/png"))
132  {
133  return true;
134  }
135  else if (typeMime == QString::fromLatin1("image/jp2"))
136  {
137  return true;
138  }
139  else if (typeMime == QString::fromLatin1("image/x-raw"))
140  {
141  return true;
142  }
143  else if (typeMime == QString::fromLatin1("image/pgf"))
144  {
145  return true;
146  }
147 
148  return false;
149 }
150 
152 {
153  // Since 0.14.0 release, we can extract run-time version of Exiv2.
154  // else we return make version.
155 
156  return QString::fromStdString(Exiv2::versionString());
157 }
158 
160 {
161  return QString::fromLatin1(KEXIV2_VERSION_STRING);
162 }
163 
165 {
166  QString ret;
167 
168  if (!path.isEmpty())
169  {
170  ret = path + QString::fromLatin1(".xmp");
171  }
172 
173  return ret;
174 }
175 
177 {
179  QUrl sidecarUrl(url);
180  sidecarUrl.setPath(sidecarPath);
181  return sidecarUrl;
182 }
183 
185 {
187 }
188 
190 {
191  return sidecarFilePathForFile(path);
192 }
193 
194 bool KExiv2::hasSidecar(const QString& path)
195 {
196  return QFileInfo(sidecarFilePathForFile(path)).exists();
197 }
198 
199 //-- General methods ----------------------------------------------
200 
201 KExiv2Data KExiv2::data() const
202 {
203  KExiv2Data data;
204  data.d = d->data;
205  return data;
206 }
207 
208 void KExiv2::setData(const KExiv2Data& data)
209 {
210  if (data.d)
211  {
212  d->data = data.d;
213  }
214  else
215  {
216  // KExiv2Data can have a null pointer,
217  // but we never want a null pointer in Private.
218  d->data->clear();
219  }
220 }
221 
222 bool KExiv2::loadFromData(const QByteArray& imgData) const
223 {
224  if (imgData.isEmpty())
225  return false;
226 
227  try
228  {
229  Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open((Exiv2::byte*)imgData.data(), imgData.size());
230 
231  d->filePath.clear();
232  image->readMetadata();
233 
234  // Size and mimetype ---------------------------------
235 
236  d->pixelSize = QSize(image->pixelWidth(), image->pixelHeight());
237  d->mimeType = QString::fromLatin1(image->mimeType().c_str());
238 
239  // Image comments ---------------------------------
240 
241  d->imageComments() = image->comment();
242 
243  // Exif metadata ----------------------------------
244 
245  d->exifMetadata() = image->exifData();
246 
247  // Iptc metadata ----------------------------------
248 
249  d->iptcMetadata() = image->iptcData();
250 
251 #ifdef _XMP_SUPPORT_
252 
253  // Xmp metadata -----------------------------------
254 
255  d->xmpMetadata() = image->xmpData();
256 
257 #endif // _XMP_SUPPORT_
258 
259  return true;
260  }
261  catch( Exiv2::Error& e )
262  {
263  d->printExiv2ExceptionError(QString::fromLatin1("Cannot load metadata using Exiv2 "), e);
264  }
265  catch(...)
266  {
267  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
268  }
269 
270  return false;
271 }
272 
273 bool KExiv2::load(const QString& filePath) const
274 {
275  if (filePath.isEmpty())
276  {
277  return false;
278  }
279 
280  d->filePath = filePath;
281  bool hasLoaded = false;
282 
283  try
284  {
285  Exiv2::Image::AutoPtr image;
286 
287  image = Exiv2::ImageFactory::open((const char*)(QFile::encodeName(filePath)).constData());
288 
289  image->readMetadata();
290 
291  // Size and mimetype ---------------------------------
292 
293  d->pixelSize = QSize(image->pixelWidth(), image->pixelHeight());
294  d->mimeType = QString::fromLatin1(image->mimeType().c_str());
295 
296  // Image comments ---------------------------------
297 
298  d->imageComments() = image->comment();
299 
300  // Exif metadata ----------------------------------
301 
302  d->exifMetadata() = image->exifData();
303 
304  // Iptc metadata ----------------------------------
305 
306  d->iptcMetadata() = image->iptcData();
307 
308 #ifdef _XMP_SUPPORT_
309 
310  // Xmp metadata -----------------------------------
311  d->xmpMetadata() = image->xmpData();
312 
313 #endif // _XMP_SUPPORT_
314 
315  hasLoaded = true;
316  }
317  catch( Exiv2::Error& e )
318  {
319  d->printExiv2ExceptionError(QString::fromLatin1("Cannot load metadata from file "), e);
320  }
321  catch(...)
322  {
323  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
324  }
325 
326 #ifdef _XMP_SUPPORT_
327  try
328  {
329  if (d->useXMPSidecar4Reading)
330  {
331  QString xmpSidecarPath = sidecarFilePathForFile(filePath);
332  QFileInfo xmpSidecarFileInfo(xmpSidecarPath);
333 
334  Exiv2::Image::AutoPtr xmpsidecar;
335 
336  if (xmpSidecarFileInfo.exists() && xmpSidecarFileInfo.isReadable())
337  {
338  // Read sidecar data
339  xmpsidecar = Exiv2::ImageFactory::open(QFile::encodeName(xmpSidecarPath).constData());
340  xmpsidecar->readMetadata();
341 
342  // Merge
343  d->loadSidecarData(xmpsidecar);
344  hasLoaded = true;
345  }
346  }
347  }
348  catch( Exiv2::Error& e )
349  {
350  d->printExiv2ExceptionError(QString::fromLatin1("Cannot load XMP sidecar"), e);
351  }
352  catch(...)
353  {
354  qCCritical(LIBKEXIV2_LOG) << "Default exception from Exiv2";
355  }
356 
357 #endif // _XMP_SUPPORT_
358 
359  return hasLoaded;
360 }
361 
362 bool KExiv2::save(const QString& imageFilePath) const
363 {
364  // If our image is really a symlink, we should follow the symlink so that
365  // when we delete the file and rewrite it, we are honoring the symlink
366  // (rather than just deleting it and putting a file there).
367 
368  // However, this may be surprising to the user when they are writing sidecar
369  // files. They might expect them to show up where the symlink is. So, we
370  // shouldn't follow the link when figuring out what the filename for the
371  // sidecar should be.
372 
373  // Note, we are not yet handling the case where the sidecar itself is a
374  // symlink.
375  QString regularFilePath = imageFilePath; // imageFilePath might be a
376  // symlink. Below we will change
377  // regularFile to the pointed to
378  // file if so.
379  QFileInfo givenFileInfo(imageFilePath);
380 
381  if (givenFileInfo.isSymLink())
382  {
383  qCDebug(LIBKEXIV2_LOG) << "filePath" << imageFilePath << "is a symlink."
384  << "Using target" << givenFileInfo.canonicalPath();
385 
386  regularFilePath = givenFileInfo.canonicalPath();// Walk all the symlinks
387  }
388 
389  // NOTE: see B.K.O #137770 & #138540 : never touch the file if is read only.
390  QFileInfo finfo(regularFilePath);
391  QFileInfo dinfo(finfo.path());
392 
393  if (!dinfo.isWritable())
394  {
395  qCDebug(LIBKEXIV2_LOG) << "Dir '" << dinfo.filePath() << "' is read-only. Metadata not saved.";
396  return false;
397  }
398 
399  bool writeToFile = false;
400  bool writeToSidecar = false;
401  bool writeToSidecarIfFileNotPossible = false;
402  bool writtenToFile = false;
403  bool writtenToSidecar = false;
404 
405  qCDebug(LIBKEXIV2_LOG) << "KExiv2::metadataWritingMode" << d->metadataWritingMode;
406 
407  switch(d->metadataWritingMode)
408  {
409  case WRITETOSIDECARONLY:
410  writeToSidecar = true;
411  break;
412  case WRITETOIMAGEONLY:
413  writeToFile = true;
414  break;
416  writeToFile = true;
417  writeToSidecar = true;
418  break;
420  writeToFile = true;
421  writeToSidecarIfFileNotPossible = true;
422  break;
423  }
424 
425  if (writeToFile)
426  {
427  qCDebug(LIBKEXIV2_LOG) << "Will write Metadata to file" << finfo.absoluteFilePath();
428  writtenToFile = d->saveToFile(finfo);
429 
430  if (writeToFile)
431  {
432  qCDebug(LIBKEXIV2_LOG) << "Metadata for file" << finfo.fileName() << "written to file.";
433  }
434  }
435 
436  if (writeToSidecar || (writeToSidecarIfFileNotPossible && !writtenToFile))
437  {
438  qCDebug(LIBKEXIV2_LOG) << "Will write XMP sidecar for file" << givenFileInfo.fileName();
439  writtenToSidecar = d->saveToXMPSidecar(imageFilePath);
440 
441  if (writtenToSidecar)
442  {
443  qCDebug(LIBKEXIV2_LOG) << "Metadata for file '" << givenFileInfo.fileName() << "' written to XMP sidecar.";
444  }
445  }
446 
447  return writtenToFile || writtenToSidecar;
448 }
449 
451 {
452  if (d->filePath.isEmpty())
453  {
454  qCDebug(LIBKEXIV2_LOG) << "Failed to apply changes: file path is empty!";
455  return false;
456  }
457 
458  return save(d->filePath);
459 }
460 
461 bool KExiv2::isEmpty() const
462 {
463  if (!hasComments() && !hasExif() && !hasIptc() && !hasXmp())
464  return true;
465 
466  return false;
467 }
468 
469 void KExiv2::setFilePath(const QString& path)
470 {
471  d->filePath = path;
472 }
473 
475 {
476  return d->filePath;
477 }
478 
480 {
481  return d->pixelSize;
482 }
483 
485 {
486  return d->mimeType;
487 }
488 
489 void KExiv2::setWriteRawFiles(const bool on)
490 {
491  d->writeRawFiles = on;
492 }
493 
495 {
496  return d->writeRawFiles;
497 }
498 
500 {
501  d->useXMPSidecar4Reading = on;
502 }
503 
505 {
506  return d->useXMPSidecar4Reading;
507 }
508 
509 void KExiv2::setMetadataWritingMode(const int mode)
510 {
511  d->metadataWritingMode = mode;
512 }
513 
515 {
516  return d->metadataWritingMode;
517 }
518 
520 {
521  d->updateFileTimeStamp = on;
522 }
523 
525 {
526  return d->updateFileTimeStamp;
527 }
528 
529 bool KExiv2::setProgramId(bool /*on*/) const
530 {
531  return true;
532 }
533 
534 } // NameSpace KExiv2Iface
void setFilePath(const QString &path)
Set the file path of current image.
Definition: kexiv2.cpp:469
bool isReadable() const const
bool loadFromData(const QByteArray &imgData) const
Load all metadata (Exif, Iptc, Xmp, and JFIF Comments) from a byte array.
Definition: kexiv2.cpp:222
static bool registerXmpNameSpace(const QString &uri, const QString &prefix)
Register a namespace which Exiv2 doesn&#39;t know yet.
Definition: kexiv2xmp.cpp:1056
bool updateFileTimeStamp() const
Return true if file timestamp is updated when metadata are saved.
Definition: kexiv2.cpp:524
KExiv2Iface.
Definition: kexiv2.cpp:36
QString path() const const
static QString Exiv2Version()
Return a string version of Exiv2 release in format "major.minor.patch".
Definition: kexiv2.cpp:151
static QUrl sidecarUrl(const QUrl &url)
Like sidecarFilePathForFile(), but works for remote URLs.
Definition: kexiv2.cpp:176
static QString sidecarPath(const QString &path)
Like sidecarFilePathForFile(), but works for local file path.
Definition: kexiv2.cpp:189
bool hasComments() const
Return &#39;true&#39; if metadata container in memory as Comments.
bool isEmpty() const const
void setMetadataWritingMode(const int mode)
Set metadata writing mode.
Definition: kexiv2.cpp:509
bool save(const QString &filePath) const
Save all metadata to a file.
Definition: kexiv2.cpp:362
bool hasExif() const
Return &#39;true&#39; if metadata container in memory as Exif.
Definition: kexiv2exif.cpp:73
KExiv2 & operator=(const KExiv2 &metadata)
Create a copy of container.
Definition: kexiv2.cpp:67
virtual ~KExiv2()
Standard destructor.
Definition: kexiv2.cpp:62
Write metadata to image and sidecar files.
Definition: kexiv2.h:83
QString filePath() const const
bool hasIptc() const
Return &#39;true&#39; if metadata container in memory as Iptc.
Definition: kexiv2iptc.cpp:61
bool applyChanges() const
The same than save() method, but it apply on current image.
Definition: kexiv2.cpp:450
Write metadata to image file only.
Definition: kexiv2.h:77
QString getMimeType() const
Returns the mime type of this image.
Definition: kexiv2.cpp:484
QString fromStdString(const std::string &str)
Write metadata to sidecar file only for read only images such as RAW files for example.
Definition: kexiv2.h:86
QString canonicalPath() const const
static QString version()
Return a string version of libkexiv2 release.
Definition: kexiv2.cpp:159
QString fileName() const const
KExiv2.
Definition: kexiv2.h:66
QString absoluteFilePath() const const
bool isEmpty() const const
void setWriteRawFiles(const bool on)
Enable or disable writing metadata operations to RAW tiff based files.
Definition: kexiv2.cpp:489
QString path(QUrl::ComponentFormattingOptions options) const const
static bool supportXmp()
Return true if library can handle Xmp metadata.
Definition: kexiv2.cpp:112
static bool unregisterXmpNameSpace(const QString &uri)
Unregister a previously registered custom namespace.
Definition: kexiv2xmp.cpp:1089
int metadataWritingMode() const
Return the metadata writing mode.
Definition: kexiv2.cpp:514
virtual bool load(const QString &filePath) const
Load all metadata (Exif, Iptc, Xmp, and JFIF Comments) from a picture (JPEG, RAW, TIFF...
Definition: kexiv2.cpp:273
bool exists() const const
virtual bool setProgramId(bool on=true) const
Re-implement this method to set automatically the Program Name and Program Version information in Exi...
Definition: kexiv2.cpp:529
bool useXMPSidecar4Reading() const
Return true if using XMP sidecar for reading metadata is enabled.
Definition: kexiv2.cpp:504
static bool initializeExiv2()
Return true if Exiv2 library initialization is done properly.
Definition: kexiv2.cpp:76
void setUpdateFileTimeStamp(bool on)
Enable or disable file timestamp updating when metadata are saved.
Definition: kexiv2.cpp:519
bool isEmpty() const
Return &#39;true&#39; if metadata container in memory as no Comments, Exif, Iptc, and Xmp.
Definition: kexiv2.cpp:461
QString getFilePath() const
Return the file path of current image.
Definition: kexiv2.cpp:474
char * data()
QString fromLatin1(const char *str, int size)
bool hasXmp() const
Return &#39;true&#39; if metadata container in memory as Xmp.
Definition: kexiv2xmp.cpp:68
void setUseXMPSidecar4Reading(const bool on)
Enable or disable using XMP sidecar for reading metadata.
Definition: kexiv2.cpp:499
static bool hasSidecar(const QString &path)
Performs a QFileInfo based check if the given local file has a sidecar.
Definition: kexiv2.cpp:194
bool writeRawFiles() const
Return true if writing metadata operations on RAW tiff based files is enabled.
Definition: kexiv2.cpp:494
static bool supportMetadataWritting(const QString &typeMime)
Return true if library can write metadata to typeMime file format.
Definition: kexiv2.cpp:121
static bool cleanupExiv2()
Return true if Exiv2 library memory allocations are cleaned properly.
Definition: kexiv2.cpp:94
int size() const const
QSize getPixelSize() const
Returns the pixel size of the current image.
Definition: kexiv2.cpp:479
static QString sidecarFilePathForFile(const QString &path)
Return the XMP Sidecar file path for a image file path.
Definition: kexiv2.cpp:164
===========================================================This file is a part of KDE project ...
QByteArray encodeName(const QString &fileName)
Write metadata to sidecar file only.
Definition: kexiv2.h:80
QUrl fromLocalFile(const QString &localFile)
KExiv2()
Standard constructor.
Definition: kexiv2.cpp:39
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Thu Nov 26 2020 22:35:13 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.