summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-05-17 18:58:18 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-05-17 18:58:18 +0000
commit84d52ca1330afb56da0faa2d2c60f031f41b43e9 (patch)
tree58ce779cfaa23dbe8b1dd7bda7709633e2decd99
parentf83c303ef5a77029ba2169fcb405b7c72eb428e7 (diff)
downloadlibkexiv2-84d52ca1.tar.gz
libkexiv2-84d52ca1.zip
Update libkexiv2 to version 0.1.9
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/libraries/libkexiv2@1232460 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
-rw-r--r--libkexiv2/libkexiv2/Makefile.am6
-rw-r--r--libkexiv2/libkexiv2/kexiv2.cpp1178
-rw-r--r--libkexiv2/libkexiv2/kexiv2.h296
-rw-r--r--libkexiv2/libkexiv2/kexiv2private.cpp226
-rw-r--r--libkexiv2/libkexiv2/kexiv2private.h131
-rw-r--r--libkexiv2/libkexiv2/version.h6
6 files changed, 1122 insertions, 721 deletions
diff --git a/libkexiv2/libkexiv2/Makefile.am b/libkexiv2/libkexiv2/Makefile.am
index 0227442..eed13ee 100644
--- a/libkexiv2/libkexiv2/Makefile.am
+++ b/libkexiv2/libkexiv2/Makefile.am
@@ -1,13 +1,13 @@
METASOURCES = AUTO
KDE_CXXFLAGS = $(USE_EXCEPTIONS)
-INCLUDES= $(all_includes)
+INCLUDES= $(EXIV2_CFLAGS) $(all_includes)
lib_LTLIBRARIES = libkexiv2.la
-libkexiv2_la_SOURCES = kexiv2.cpp
+libkexiv2_la_SOURCES = kexiv2.cpp kexiv2private.cpp
-libkexiv2_version_info = 4:0:1
+libkexiv2_version_info = 5:0:0
libkexiv2_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -version-info $(libkexiv2_version_info) -no-undefined
libkexiv2_la_LIBADD = $(EXIV2_LIBS) $(LIB_KDECORE) $(LIB_QT)
diff --git a/libkexiv2/libkexiv2/kexiv2.cpp b/libkexiv2/libkexiv2/kexiv2.cpp
index dc48403..8116342 100644
--- a/libkexiv2/libkexiv2/kexiv2.cpp
+++ b/libkexiv2/libkexiv2/kexiv2.cpp
@@ -6,33 +6,32 @@
* Date : 2006-09-15
* Description : Exiv2 library interface for KDE
*
- * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
- * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
+ * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ * Copyright (C) 2006-2009 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
*
- * NOTE: Do not use kdDebug() in this implementation because
- * it will be multithreaded. Use qDebug() instead.
+ * NOTE: Do not use kdDebug() in this implementation because
+ * it will be multithreaded. Use qDebug() instead.
* See B.K.O #133026 for details.
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software Foundation;
* either version 2, or (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* ============================================================ */
- // C++ includes.
+// C ANSI includes.
-#include <cstdlib>
-#include <cstdio>
-#include <cassert>
-#include <cmath>
-#include <iostream>
-#include <iomanip>
+extern "C"
+{
+#include <sys/stat.h>
+#include <utime.h>
+}
// Qt includes.
@@ -42,63 +41,17 @@
#include <qtextcodec.h>
#include <qwmatrix.h>
#include <qfileinfo.h>
-
-// KDE includes.
-
-#include <ktempfile.h>
-#include <kstringhandler.h>
-#include <kdeversion.h>
-
-// Exiv2 includes.
-
-// The pragmas are required to be able to catch exceptions thrown by libexiv2:
-// See http://gcc.gnu.org/wiki/Visibility, the section about c++ exceptions.
-// They are needed for all libexiv2 versions that do not care about visibility.
-#pragma GCC visibility push(default)
-#include <exiv2/error.hpp>
-#include <exiv2/image.hpp>
-#include <exiv2/jpgimage.hpp>
-#include <exiv2/datasets.hpp>
-#include <exiv2/tags.hpp>
-#include <exiv2/types.hpp>
-#include <exiv2/exif.hpp>
-#pragma GCC visibility pop
-
-// Make sure an EXIV2_TEST_VERSION macro exists:
-
-#ifdef EXIV2_VERSION
-# ifndef EXIV2_TEST_VERSION
-# define EXIV2_TEST_VERSION(major,minor,patch) \
- ( EXIV2_VERSION >= EXIV2_MAKE_VERSION(major,minor,patch) )
-# endif
-#else
-# define EXIV2_TEST_VERSION(major,minor,patch) (false)
-#endif
+#include <qbuffer.h>
// Local includes.
#include "version.h"
+#include "kexiv2private.h"
#include "kexiv2.h"
namespace KExiv2Iface
{
-class KExiv2Priv
-{
-public:
-
- KExiv2Priv(){}
-
- QString filePath;
-
- std::string imageComments;
-
- Exiv2::ExifData exifMetadata;
-
- Exiv2::IptcData iptcMetadata;
-
-};
-
KExiv2::KExiv2()
{
d = new KExiv2Priv;
@@ -115,6 +68,40 @@ KExiv2::~KExiv2()
delete d;
}
+bool KExiv2::supportMetadataWritting(const QString& typeMime)
+{
+ if (typeMime == QString("image/jpeg"))
+ {
+ return true;
+ }
+ else if (typeMime == QString("image/tiff"))
+ {
+#if (EXIV2_TEST_VERSION(0,17,91))
+ return true;
+#else
+ return false;
+#endif
+ }
+ else if (typeMime == QString("image/png"))
+ {
+#if (EXIV2_TEST_VERSION(0,17,91))
+ return true;
+#else
+ return false;
+#endif
+ }
+ else if (typeMime == QString("image/jp2"))
+ {
+#if (EXIV2_TEST_VERSION(0,17,91))
+ return true;
+#else
+ return false;
+#endif
+ }
+
+ return false;
+}
+
QString KExiv2::version()
{
return QString( kexiv2_version );
@@ -134,27 +121,6 @@ QString KExiv2::Exiv2Version()
#endif
}
-void KExiv2::printExiv2ExceptionError(const QString& msg, Exiv2::Error& e)
-{
- std::string s(e.what());
- qDebug("%s (Error #%i: %s)", msg.ascii(), e.code(), s.c_str());
-}
-
-std::string& KExiv2::commentsMetaData()
-{
- return d->imageComments;
-}
-
-Exiv2::ExifData& KExiv2::exifMetaData()
-{
- return d->exifMetadata;
-}
-
-Exiv2::IptcData& KExiv2::iptcMetaData()
-{
- return d->iptcMetadata;
-}
-
bool KExiv2::clearComments()
{
return setComments(QByteArray());
@@ -169,25 +135,25 @@ bool KExiv2::clearExif()
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot clear Exif data using Exiv2 ", e);
- }
+ d->printExiv2ExceptionError("Cannot clear Exif data using Exiv2 ", e);
+ }
- return false;
+ return false;
}
bool KExiv2::clearIptc()
{
try
- {
+ {
d->iptcMetadata.clear();
return true;
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot clear Iptc data using Exiv2 ", e);
- }
+ d->printExiv2ExceptionError("Cannot clear Iptc data using Exiv2 ", e);
+ }
- return false;
+ return false;
}
QString KExiv2::getFilePath() const
@@ -202,27 +168,32 @@ QByteArray KExiv2::getComments() const
QString KExiv2::getCommentsDecoded() const
{
- return detectEncodingAndDecode(getCommentsString());
-}
-
-std::string KExiv2::getCommentsString() const
-{
- return d->imageComments;
+ return d->detectEncodingAndDecode(d->imageComments);
}
QByteArray KExiv2::getExif() const
{
try
- {
+ {
if (!d->exifMetadata.empty())
{
Exiv2::ExifData& exif = d->exifMetadata;
+
+#if (EXIV2_TEST_VERSION(0,17,91))
+ Exiv2::Blob blob;
+ Exiv2::ExifParser::encode(blob, Exiv2::bigEndian, exif);
+ QByteArray ba(blob.size());
+ if (ba.size())
+ memcpy(ba.data(), (const char*)&blob[0], blob.size());
+#else
Exiv2::DataBuf c2 = exif.copy();
- QByteArray data(c2.size_);
- if (data.size())
- memcpy(data.data(), c2.pData_, c2.size_);
- return data;
+ QByteArray ba(c2.size_);
+ if (ba.size())
+ memcpy(ba.data(), c2.pData_, c2.size_);
+#endif
+
+ return ba;
}
}
catch( Exiv2::Error &e )
@@ -230,22 +201,22 @@ QByteArray KExiv2::getExif() const
if (!d->filePath.isEmpty())
qDebug ("From file %s", d->filePath.ascii());
- printExiv2ExceptionError("Cannot get Exif data using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot get Exif data using Exiv2 ", e);
+ }
+
return QByteArray();
}
QByteArray KExiv2::getIptc(bool addIrbHeader) const
{
try
- {
+ {
if (!d->iptcMetadata.empty())
- {
+ {
Exiv2::IptcData& iptc = d->iptcMetadata;
Exiv2::DataBuf c2;
- if (addIrbHeader)
+ if (addIrbHeader)
{
#if (EXIV2_TEST_VERSION(0,10,0))
c2 = Exiv2::Photoshop::setIptcIrb(0, 0, iptc);
@@ -254,8 +225,14 @@ QByteArray KExiv2::getIptc(bool addIrbHeader) const
return QByteArray();
#endif
}
- else
+ else
+ {
+#if (EXIV2_TEST_VERSION(0,17,91))
+ c2 = Exiv2::IptcParser::encode(d->iptcMetadata);
+#else
c2 = iptc.copy();
+#endif
+ }
QByteArray data(c2.size_);
if (data.size())
@@ -268,9 +245,9 @@ QByteArray KExiv2::getIptc(bool addIrbHeader) const
if (!d->filePath.isEmpty())
qDebug ("From file %s", d->filePath.ascii());
- printExiv2ExceptionError("Cannot get Iptc data using Exiv2 ",e);
- }
-
+ d->printExiv2ExceptionError("Cannot get Iptc data using Exiv2 ",e);
+ }
+
return QByteArray();
}
@@ -283,13 +260,18 @@ bool KExiv2::setComments(const QByteArray& data)
bool KExiv2::setExif(const QByteArray& data)
{
try
- {
+ {
if (!data.isEmpty())
{
+#if (EXIV2_TEST_VERSION(0,17,91))
+ Exiv2::ExifParser::decode(d->exifMetadata, (const Exiv2::byte*)data.data(), data.size());
+ return (!d->exifMetadata.empty());
+#else
if (d->exifMetadata.load((const Exiv2::byte*)data.data(), data.size()) != 0)
- return false;
- else
+ return false;
+ else
return true;
+#endif
}
}
catch( Exiv2::Error &e )
@@ -297,8 +279,8 @@ bool KExiv2::setExif(const QByteArray& data)
if (!d->filePath.isEmpty())
qDebug ("From file %s", d->filePath.ascii());
- printExiv2ExceptionError("Cannot set Exif data using Exiv2 ", e);
- }
+ d->printExiv2ExceptionError("Cannot set Exif data using Exiv2 ", e);
+ }
return false;
}
@@ -306,13 +288,18 @@ bool KExiv2::setExif(const QByteArray& data)
bool KExiv2::setIptc(const QByteArray& data)
{
try
- {
+ {
if (!data.isEmpty())
{
+#if (EXIV2_TEST_VERSION(0,17,91))
+ Exiv2::IptcParser::decode(d->iptcMetadata, (const Exiv2::byte*)data.data(), data.size());
+ return (!d->iptcMetadata.empty());
+#else
if (d->iptcMetadata.load((const Exiv2::byte*)data.data(), data.size()) != 0)
- return false;
- else
+ return false;
+ else
return true;
+#endif
}
}
catch( Exiv2::Error &e )
@@ -320,54 +307,42 @@ bool KExiv2::setIptc(const QByteArray& data)
if (!d->filePath.isEmpty())
qDebug ("From file %s", d->filePath.ascii());
- printExiv2ExceptionError("Cannot set Iptc data using Exiv2 ", e);
- }
+ d->printExiv2ExceptionError("Cannot set Iptc data using Exiv2 ", e);
+ }
- return false;
+ return false;
}
-bool KExiv2::setExif(Exiv2::DataBuf const data)
+bool KExiv2::load(const QByteArray& imgData)
{
+ if (imgData.isEmpty())
+ return false;
+
try
- {
- if (data.size_ != 0)
- {
- if (d->exifMetadata.load(data.pData_, data.size_) != 0)
- return false;
- else
- return true;
- }
- }
- catch( Exiv2::Error &e )
{
- if (!d->filePath.isEmpty())
- qDebug ("From file %s", d->filePath.ascii());
- printExiv2ExceptionError("Cannot set Exif data using Exiv2 ", e);
- }
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open((Exiv2::byte*)imgData.data(), imgData.size());
+ d->filePath = QString();
+ image->readMetadata();
- return false;
-}
+ // Image comments ---------------------------------
-bool KExiv2::setIptc(Exiv2::DataBuf const data)
-{
- try
- {
- if (data.size_ != 0)
- {
- if (d->iptcMetadata.load(data.pData_, data.size_) != 0)
- return false;
- else
- return true;
- }
+ d->imageComments = image->comment();
+
+ // Exif metadata ----------------------------------
+
+ d->exifMetadata = image->exifData();
+
+ // Iptc metadata ----------------------------------
+
+ d->iptcMetadata = image->iptcData();
+
+ return true;
}
catch( Exiv2::Error &e )
{
- if (!d->filePath.isEmpty())
- qDebug ("From file %s", d->filePath.ascii());
-
- printExiv2ExceptionError("Cannot set Iptc data using Exiv2 ", e);
- }
+ d->printExiv2ExceptionError("Cannot load metadata using Exiv2 ", e);
+ }
return false;
}
@@ -383,8 +358,10 @@ bool KExiv2::load(const QString& filePath)
try
{
+
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open((const char*)
(QFile::encodeName(filePath)));
+ d->filePath = filePath;
image->readMetadata();
// Image comments ---------------------------------
@@ -392,22 +369,20 @@ bool KExiv2::load(const QString& filePath)
d->imageComments = image->comment();
// Exif metadata ----------------------------------
-
+
d->exifMetadata = image->exifData();
// Iptc metadata ----------------------------------
-
- d->iptcMetadata = image->iptcData();
- d->filePath = filePath;
+ d->iptcMetadata = image->iptcData();
return true;
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot load metadata using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot load metadata using Exiv2 ", e);
}
-
+
return false;
}
@@ -417,8 +392,8 @@ bool KExiv2::save(const QString& filePath)
return false;
// NOTE: see B.K.O #137770 & #138540 : never touch the file if is read only.
- QFileInfo finfo(filePath);
- QFileInfo dinfo(finfo.dirPath());
+ QFileInfo finfo(filePath);
+ QFileInfo dinfo(finfo.dirPath());
if (!finfo.isWritable())
{
qDebug("File '%s' is read-only. Metadata not saved.", finfo.fileName().ascii());
@@ -430,39 +405,102 @@ bool KExiv2::save(const QString& filePath)
return false;
}
+ // TIFF/EP Raw files based are supported by Exiv2 0.18 as experimental. We will do touch it for the moment.
+ // Metadata writing is supported in implementation from svn trunk.
+ QString rawTiffBased("dng nef pef 3fr arw cr2 dcr erf k25 kdc mos orf raw sr2 srf");
+ if (rawTiffBased.contains(finfo.extension(false).lower()))
+ {
+ qDebug("'%s' is TIFF based RAW file and writing mode is disable with this libkexiv2 version. Metadata not saved.",
+ finfo.fileName().ascii());
+ return false;
+ }
+
try
- {
+ {
+ Exiv2::AccessMode mode;
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open((const char*)
(QFile::encodeName(filePath)));
-
+
+ // We need to load target file metadata to merge with new one. It's mandatory with TIFF format:
+ // like all tiff file structure is based on Exif.
+ image->readMetadata();
+
// Image Comments ---------------------------------
-
- if (!d->imageComments.empty())
+
+ mode = image->checkMode(Exiv2::mdComment);
+ if (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite)
{
image->setComment(d->imageComments);
}
// Exif metadata ----------------------------------
-
- if (!d->exifMetadata.empty())
+
+ mode = image->checkMode(Exiv2::mdExif);
+ if (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite)
{
- image->setExifData(d->exifMetadata);
+ if (image->mimeType() == "image/tiff")
+ {
+ // With tiff image we cannot overwrite whole Exif data as well, because
+ // image data are stored in Exif container. We need to take a care about
+ // to not lost image data.
+ Exiv2::ExifData exif = image->exifData();
+ QStringList untouchedTags;
+ untouchedTags << "Exif.Image.ImageWidth";
+ untouchedTags << "Exif.Image.ImageLength";
+ untouchedTags << "Exif.Image.BitsPerSample";
+ untouchedTags << "Exif.Image.Compression";
+ untouchedTags << "Exif.Image.PhotometricInterpretation";
+ untouchedTags << "Exif.Image.FillOrder";
+ untouchedTags << "Exif.Image.SamplesPerPixel";
+ untouchedTags << "Exif.Image.StripOffsets";
+ untouchedTags << "Exif.Image.RowsPerStrip";
+ untouchedTags << "Exif.Image.StripByteCounts";
+ untouchedTags << "Exif.Image.XResolution";
+ untouchedTags << "Exif.Image.YResolution";
+ untouchedTags << "Exif.Image.PlanarConfiguration";
+ untouchedTags << "Exif.Image.ResolutionUnit";
+
+ for (Exiv2::ExifData::iterator it = d->exifMetadata.begin(); it != d->exifMetadata.end(); ++it)
+ {
+ if (!untouchedTags.contains(it->key().c_str()))
+ {
+ exif[it->key().c_str()] = d->exifMetadata[it->key().c_str()];
+ }
+ }
+
+ image->setExifData(exif);
+ }
+ else
+ {
+ image->setExifData(d->exifMetadata);
+ }
}
// Iptc metadata ----------------------------------
-
- if (!d->iptcMetadata.empty())
+
+ mode = image->checkMode(Exiv2::mdIptc);
+ if (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite)
{
image->setIptcData(d->iptcMetadata);
}
-
+
+ // NOTE: Don't touch access and modification timestamp of file.
+ struct stat st;
+ ::stat(QFile::encodeName(filePath), &st);
+
+ struct utimbuf ut;
+ ut.modtime = st.st_mtime;
+ ut.actime = st.st_atime;
+
image->writeMetadata();
+ ::utime(QFile::encodeName(filePath), &ut);
+
return true;
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot save metadata using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot save metadata using Exiv2 ", e);
}
return false;
@@ -470,17 +508,80 @@ bool KExiv2::save(const QString& filePath)
bool KExiv2::applyChanges()
{
+ if (d->filePath.isEmpty())
+ return false;
+
return save(d->filePath);
}
bool KExiv2::isReadOnly(const QString& filePath)
{
- QFileInfo fi(filePath);
- QString ext = fi.extension(false).upper();
-
- if (ext != QString("JPG") && ext != QString("JPEG") && ext != QString("JPE"))
+ if (!canWriteComment(filePath))
+ return true;
+
+ if (!canWriteExif(filePath))
return true;
+ if (!canWriteIptc(filePath))
+ return true;
+
+ return false;
+}
+
+bool KExiv2::canWriteComment(const QString& filePath)
+{
+ try
+ {
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open((const char*)
+ (QFile::encodeName(filePath)));
+
+ Exiv2::AccessMode mode = image->checkMode(Exiv2::mdComment);
+ return (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite);
+ }
+ catch( Exiv2::Error &e )
+ {
+ std::string s(e.what());
+ qDebug("%s (Error #%i: %s)", "Cannot check Comment access mode using Exiv2 ", e.code(), s.c_str());
+ }
+
+ return false;
+}
+
+bool KExiv2::canWriteExif(const QString& filePath)
+{
+ try
+ {
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open((const char*)
+ (QFile::encodeName(filePath)));
+
+ Exiv2::AccessMode mode = image->checkMode(Exiv2::mdExif);
+ return (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite);
+ }
+ catch( Exiv2::Error &e )
+ {
+ std::string s(e.what());
+ qDebug("%s (Error #%i: %s)", "Cannot check Exif access mode using Exiv2 ", e.code(), s.c_str());
+ }
+
+ return false;
+}
+
+bool KExiv2::canWriteIptc(const QString& filePath)
+{
+ try
+ {
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open((const char*)
+ (QFile::encodeName(filePath)));
+
+ Exiv2::AccessMode mode = image->checkMode(Exiv2::mdIptc);
+ return (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite);
+ }
+ catch( Exiv2::Error &e )
+ {
+ std::string s(e.what());
+ qDebug("%s (Error #%i: %s)", "Cannot check Iptc access mode using Exiv2 ", e.code(), s.c_str());
+ }
+
return false;
}
@@ -488,8 +589,8 @@ bool KExiv2::setImageProgramId(const QString& program, const QString& version)
{
try
{
- // Record program info in Exif.Image.ProcessingSoftware tag (only available with Exiv2 >= 0.14.0).
-
+ // Record program info in Exif.Image.ProcessingSoftware tag (only available with Exiv2 >= 0.14.0).
+
#if (EXIV2_TEST_VERSION(0,14,0))
QString software(program);
software.append("-");
@@ -498,23 +599,23 @@ bool KExiv2::setImageProgramId(const QString& program, const QString& version)
#endif
// See B.K.O #142564: Check if Exif.Image.Software already exist. If yes, do not touch this tag.
-
+
if (!d->exifMetadata.empty())
- {
+ {
Exiv2::ExifData exifData(d->exifMetadata);
Exiv2::ExifKey key("Exif.Image.Software");
Exiv2::ExifData::iterator it = exifData.findKey(key);
-
+
if (it == exifData.end())
- {
+ {
QString software(program);
software.append("-");
software.append(version);
d->exifMetadata["Exif.Image.Software"] = software.ascii();
- }
- }
+ }
+ }
- // Record program info in IPTC tags.
+ // Record program info in IPTC tags.
d->iptcMetadata["Iptc.Application2.Program"] = program.ascii();
d->iptcMetadata["Iptc.Application2.ProgramVersion"] = version.ascii();
@@ -522,7 +623,7 @@ bool KExiv2::setImageProgramId(const QString& program, const QString& version)
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set Program identity into image using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot set Program identity into image using Exiv2 ", e);
}
return false;
@@ -534,21 +635,21 @@ QSize KExiv2::getImageDimensions() const
return QSize();
try
- {
+ {
long width=-1, height=-1;
// Try to get Exif.Photo tags
-
+
Exiv2::ExifData exifData(d->exifMetadata);
Exiv2::ExifKey key("Exif.Photo.PixelXDimension");
Exiv2::ExifData::iterator it = exifData.findKey(key);
-
+
if (it != exifData.end())
width = it->toLong();
Exiv2::ExifKey key2("Exif.Photo.PixelYDimension");
Exiv2::ExifData::iterator it2 = exifData.findKey(key2);
-
+
if (it2 != exifData.end())
height = it2->toLong();
@@ -556,30 +657,30 @@ QSize KExiv2::getImageDimensions() const
return QSize(width, height);
// Try to get Exif.Image tags
-
- width=-1;
- height=-1;
+
+ width = -1;
+ height = -1;
Exiv2::ExifKey key3("Exif.Image.ImageWidth");
Exiv2::ExifData::iterator it3 = exifData.findKey(key3);
-
+
if (it3 != exifData.end())
width = it3->toLong();
Exiv2::ExifKey key4("Exif.Image.ImageLength");
Exiv2::ExifData::iterator it4 = exifData.findKey(key4);
-
+
if (it4 != exifData.end())
height = it4->toLong();
-
+
if (width != -1 && height != -1)
return QSize(width, height);
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot parse image dimensions tag using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot parse image dimensions tag using Exiv2 ", e);
+ }
+
return QSize();
}
@@ -589,7 +690,7 @@ bool KExiv2::setImageDimensions(const QSize& size, bool setProgramName)
return false;
try
- {
+ {
// NOTE: see B.K.O #144604: you a cast to record an unsigned integer value.
d->exifMetadata["Exif.Image.ImageWidth"] = static_cast<uint32_t>(size.width());
d->exifMetadata["Exif.Image.ImageLength"] = static_cast<uint32_t>(size.height());
@@ -599,24 +700,29 @@ bool KExiv2::setImageDimensions(const QSize& size, bool setProgramName)
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set image dimensions using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot set image dimensions using Exiv2 ", e);
+ }
+
return false;
}
QImage KExiv2::getExifThumbnail(bool fixOrientation) const
{
QImage thumbnail;
-
+
if (d->exifMetadata.empty())
return thumbnail;
-
+
try
- {
+ {
+#if (EXIV2_TEST_VERSION(0,17,91))
+ Exiv2::ExifThumbC thumb(d->exifMetadata);
+ Exiv2::DataBuf const c1 = thumb.copy();
+#else
Exiv2::DataBuf const c1(d->exifMetadata.copyThumbnail());
+#endif
thumbnail.loadFromData(c1.pData_, c1.size_);
-
+
if (!thumbnail.isNull())
{
if (fixOrientation)
@@ -629,56 +735,56 @@ QImage KExiv2::getExifThumbnail(bool fixOrientation) const
QWMatrix matrix;
long orientation = it->toLong();
qDebug("Exif Thumbnail Orientation: %i", (int)orientation);
-
- switch (orientation)
+
+ switch (orientation)
{
case ORIENTATION_HFLIP:
matrix.scale(-1, 1);
break;
-
+
case ORIENTATION_ROT_180:
matrix.rotate(180);
break;
-
+
case ORIENTATION_VFLIP:
matrix.scale(1, -1);
break;
-
+
case ORIENTATION_ROT_90_HFLIP:
matrix.scale(-1, 1);
matrix.rotate(90);
break;
-
+
case ORIENTATION_ROT_90:
matrix.rotate(90);
break;
-
+
case ORIENTATION_ROT_90_VFLIP:
matrix.scale(1, -1);
matrix.rotate(90);
break;
-
+
case ORIENTATION_ROT_270:
matrix.rotate(270);
break;
-
+
default:
break;
}
-
+
if ( orientation != ORIENTATION_NORMAL )
thumbnail = thumbnail.xForm( matrix );
}
-
+
return thumbnail;
}
}
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot get Exif Thumbnail using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot get Exif Thumbnail using Exiv2 ", e);
+ }
+
return thumbnail;
}
@@ -688,20 +794,29 @@ bool KExiv2::setExifThumbnail(const QImage& thumb, bool setProgramName)
return false;
try
- {
+ {
+#if (EXIV2_TEST_VERSION(0,17,91))
+ QByteArray data;
+ QBuffer buffer(data);
+ buffer.open(IO_WriteOnly);
+ thumb.save(&buffer, "JPEG");
+ Exiv2::ExifThumb thumb(d->exifMetadata);
+ thumb.setJpegThumbnail((Exiv2::byte *)data.data(), data.size());
+#else
KTempFile thumbFile(QString(), "KExiv2ExifThumbnail");
thumbFile.setAutoDelete(true);
thumb.save(thumbFile.name(), "JPEG");
const std::string &fileName( (const char*)(QFile::encodeName(thumbFile.name())) );
d->exifMetadata.setJpegThumbnail( fileName );
+#endif
return true;
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set Exif Thumbnail using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot set Exif Thumbnail using Exiv2 ", e);
+ }
+
return false;
}
@@ -730,7 +845,7 @@ KExiv2::ImageOrientation KExiv2::getImageOrientation() const
long orientation;
ImageOrientation imageOrient = ORIENTATION_NORMAL;
- // Because some camera set a wrong standard exif orientation tag,
+ // Because some camera set a wrong standard exif orientation tag,
// We need to check makernote tags in first!
// -- Minolta Cameras ----------------------------------
@@ -790,7 +905,7 @@ KExiv2::ImageOrientation KExiv2::getImageOrientation() const
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot parse Exif Orientation tag using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot parse Exif Orientation tag using Exiv2 ", e);
}
return ORIENTATION_UNSPECIFIED;
@@ -818,13 +933,13 @@ bool KExiv2::setImageOrientation(ImageOrientation orientation, bool setProgramNa
}
try
- {
+ {
if (orientation < ORIENTATION_UNSPECIFIED || orientation > ORIENTATION_ROT_270)
{
qDebug("Exif orientation tag value is not correct!");
return false;
}
-
+
d->exifMetadata["Exif.Image.Orientation"] = static_cast<uint16_t>(orientation);
qDebug("Exif orientation tag set to: %i", (int)orientation);
@@ -833,8 +948,8 @@ bool KExiv2::setImageOrientation(ImageOrientation orientation, bool setProgramNa
if (supportMinolta)
{
// Minolta camera store image rotation in Makernote.
- // We remove these information to prevent duplicate values.
-
+ // We remove these information to prevent duplicate values.
+
Exiv2::ExifData::iterator it;
Exiv2::ExifKey minoltaKey1("Exif.MinoltaCs7D.Rotation");
@@ -844,7 +959,7 @@ bool KExiv2::setImageOrientation(ImageOrientation orientation, bool setProgramNa
d->exifMetadata.erase(it);
qDebug("Removing Exif.MinoltaCs7D.Rotation tag");
}
-
+
Exiv2::ExifKey minoltaKey2("Exif.MinoltaCs5D.Rotation");
it = d->exifMetadata.findKey(minoltaKey2);
if (it != d->exifMetadata.end())
@@ -858,18 +973,18 @@ bool KExiv2::setImageOrientation(ImageOrientation orientation, bool setProgramNa
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set Exif Orientation tag using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot set Exif Orientation tag using Exiv2 ", e);
+ }
+
return false;
}
KExiv2::ImageColorWorkSpace KExiv2::getImageColorWorkSpace() const
{
if (!d->exifMetadata.empty())
- {
+ {
long colorSpace;
-
+
if (getExifTagLong("Exif.Photo.ColorSpace", colorSpace))
{
switch (colorSpace)
@@ -886,13 +1001,13 @@ KExiv2::ImageColorWorkSpace KExiv2::getImageColorWorkSpace() const
}
case 65535:
{
- // Nikon camera set Exif.Photo.ColorSpace to uncalibrated and
+ // Nikon camera set Exif.Photo.ColorSpace to uncalibrated and
// Exif.Nikon3.ColorMode to "MODE2" when users work in AdobRGB color space.
if (getExifTagString("Exif.Nikon3.ColorMode").contains("MODE2"))
return WORKSPACE_ADOBERGB;
-
+
// TODO : add more Makernote parsing here ...
-
+
return WORKSPACE_UNCALIBRATED;
break;
}
@@ -903,9 +1018,9 @@ KExiv2::ImageColorWorkSpace KExiv2::getImageColorWorkSpace() const
}
}
}
- }
+ }
- return WORKSPACE_UNSPECIFIED;
+ return WORKSPACE_UNSPECIFIED;
}
bool KExiv2::setImageColorWorkSpace(ImageColorWorkSpace workspace, bool setProgramName)
@@ -917,53 +1032,53 @@ bool KExiv2::setImageColorWorkSpace(ImageColorWorkSpace workspace, bool setProgr
return false;
try
- {
+ {
d->exifMetadata["Exif.Photo.ColorSpace"] = static_cast<uint16_t>(workspace);
qDebug("Exif color workspace tag set to: %i", (int)workspace);
return true;
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set Exif color workspace tag using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot set Exif color workspace tag using Exiv2 ", e);
+ }
+
return false;
}
QDateTime KExiv2::getImageDateTime() const
{
try
- {
+ {
// In first, trying to get Date & time from Exif tags.
-
+
if (!d->exifMetadata.empty())
- {
+ {
// Try Exif date time original.
-
+
Exiv2::ExifData exifData(d->exifMetadata);
Exiv2::ExifKey key2("Exif.Photo.DateTimeOriginal");
Exiv2::ExifData::iterator it2 = exifData.findKey(key2);
-
+
if (it2 != exifData.end())
{
QDateTime dateTime = QDateTime::fromString(it2->toString().c_str(), Qt::ISODate);
-
+
if (dateTime.isValid())
{
// qDebug("DateTime (Exif original): %s", dateTime.toString().ascii());
return dateTime;
}
}
-
+
// Bogus Exif date time original entry. Try Exif date time digitized.
-
+
Exiv2::ExifKey key3("Exif.Photo.DateTimeDigitized");
Exiv2::ExifData::iterator it3 = exifData.findKey(key3);
-
+
if (it3 != exifData.end())
{
QDateTime dateTime = QDateTime::fromString(it3->toString().c_str(), Qt::ISODate);
-
+
if (dateTime.isValid())
{
// qDebug("DateTime (Exif digitalized): %s", dateTime.toString().ascii());
@@ -972,90 +1087,89 @@ QDateTime KExiv2::getImageDateTime() const
}
// Bogus Exif date time digitized. Try standard Exif date time entry.
-
+
Exiv2::ExifKey key("Exif.Image.DateTime");
Exiv2::ExifData::iterator it = exifData.findKey(key);
-
+
if (it != exifData.end())
{
QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate);
-
+
if (dateTime.isValid())
{
// qDebug("DateTime (Exif standard): %s", dateTime.toString().ascii());
return dateTime;
}
}
-
}
-
+
// In second, trying to get Date & time from Iptc tags.
-
+
if (!d->iptcMetadata.empty())
- {
+ {
// Try creation Iptc date time entries.
Exiv2::IptcKey keyDateCreated("Iptc.Application2.DateCreated");
Exiv2::IptcData iptcData(d->iptcMetadata);
Exiv2::IptcData::iterator it = iptcData.findKey(keyDateCreated);
-
+
if (it != iptcData.end())
{
QString IptcDateCreated(it->toString().c_str());
-
+
Exiv2::IptcKey keyTimeCreated("Iptc.Application2.TimeCreated");
Exiv2::IptcData::iterator it2 = iptcData.findKey(keyTimeCreated);
-
+
if (it2 != iptcData.end())
{
QString IptcTimeCreated(it2->toString().c_str());
-
+
QDate date = QDate::fromString(IptcDateCreated, Qt::ISODate);
QTime time = QTime::fromString(IptcTimeCreated, Qt::ISODate);
QDateTime dateTime = QDateTime(date, time);
-
+
if (dateTime.isValid())
{
// qDebug("Date (IPTC created): %s", dateTime.toString().ascii());
return dateTime;
- }
+ }
}
- }
-
+ }
+
// Try digitization Iptc date time entries.
-
+
Exiv2::IptcKey keyDigitizationDate("Iptc.Application2.DigitizationDate");
Exiv2::IptcData::iterator it3 = iptcData.findKey(keyDigitizationDate);
-
+
if (it3 != iptcData.end())
{
QString IptcDateDigitization(it3->toString().c_str());
-
+
Exiv2::IptcKey keyDigitizationTime("Iptc.Application2.DigitizationTime");
Exiv2::IptcData::iterator it4 = iptcData.findKey(keyDigitizationTime);
-
+
if (it4 != iptcData.end())
{
QString IptcTimeDigitization(it4->toString().c_str());
-
+
QDate date = QDate::fromString(IptcDateDigitization, Qt::ISODate);
QTime time = QTime::fromString(IptcTimeDigitization, Qt::ISODate);
QDateTime dateTime = QDateTime(date, time);
-
+
if (dateTime.isValid())
{
//qDebug("Date (IPTC digitalized): %s", dateTime.toString().ascii());
return dateTime;
- }
+ }
}
- }
+ }
}
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot parse Exif date & time tag using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot parse Exif date & time tag using Exiv2 ", e);
+ }
+
return QDateTime();
}
@@ -1063,14 +1177,14 @@ bool KExiv2::setImageDateTime(const QDateTime& dateTime, bool setDateTimeDigitiz
{
if(!dateTime.isValid())
return false;
-
+
if (!setProgramId(setProgramName))
return false;
-
+
try
- {
+ {
// In first we write date & time into Exif.
-
+
// DateTimeDigitized is set by slide scanners etc. when a picture is digitized.
// DateTimeOriginal specifies the date/time when the picture was taken.
// For digital cameras, these dates should be both set, and identical.
@@ -1081,7 +1195,7 @@ bool KExiv2::setImageDateTime(const QDateTime& dateTime, bool setDateTimeDigitiz
d->exifMetadata["Exif.Photo.DateTimeOriginal"] = exifdatetime;
if(setDateTimeDigitized)
d->exifMetadata["Exif.Photo.DateTimeDigitized"] = exifdatetime;
-
+
// In Second we write date & time into Iptc.
const std::string &iptcdate(dateTime.date().toString(Qt::ISODate).ascii());
@@ -1093,14 +1207,14 @@ bool KExiv2::setImageDateTime(const QDateTime& dateTime, bool setDateTimeDigitiz
d->iptcMetadata["Iptc.Application2.DigitizationDate"] = iptcdate;
d->iptcMetadata["Iptc.Application2.DigitizationTime"] = iptctime;
}
-
+
return true;
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set Date & Time into image using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot set Date & Time into image using Exiv2 ", e);
+ }
+
return false;
}
@@ -1116,7 +1230,7 @@ bool KExiv2::getImagePreview(QImage& preview) const
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot get image preview using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot get image preview using Exiv2 ", e);
}
return false;
@@ -1129,36 +1243,28 @@ bool KExiv2::setImagePreview(const QImage& preview, bool setProgramName)
try
{
- KTempFile previewFile(QString(), "KExiv2ImagePreview");
- previewFile.setAutoDelete(true);
- // A little bit compressed preview jpeg image to limit IPTC size.
- preview.save(previewFile.name(), "JPEG");
+ QByteArray data;
+ QBuffer buffer(data);
+ buffer.open(IO_WriteOnly);
- QFile file(previewFile.name());
- if ( !file.open(IO_ReadOnly) )
- return false;
+ // A little bit compressed preview jpeg image to limit IPTC size.
+ preview.save(&buffer, "JPEG");
+ qDebug("JPEG image preview size: (%i x %i) pixels - %i bytes",
+ preview.width(), preview.height(), (int)data.size());
- qDebug("JPEG image preview size: (%i x %i) pixels - %i bytes",
- preview.width(), preview.height(), (int)file.size());
-
- QByteArray data(file.size());
- QDataStream stream( &file );
- stream.readRawBytes(data.data(), data.size());
- file.close();
-
Exiv2::DataValue val;
val.read((Exiv2::byte *)data.data(), data.size());
d->iptcMetadata["Iptc.Application2.Preview"] = val;
-
+
// See http://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf Appendix A for details.
- d->iptcMetadata["Iptc.Application2.PreviewFormat"] = 11; // JPEG
+ d->iptcMetadata["Iptc.Application2.PreviewFormat"] = 11; // JPEG
d->iptcMetadata["Iptc.Application2.PreviewVersion"] = 1;
-
+
return true;
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot get image preview using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot get image preview using Exiv2 ", e);
}
return false;
@@ -1173,10 +1279,15 @@ QString KExiv2::getExifTagString(const char* exifTagName, bool escapeCR) const
Exiv2::ExifData::iterator it = exifData.findKey(exifKey);
if (it != exifData.end())
{
+#if (EXIV2_TEST_VERSION(0,17,91))
+ // See B.K.O #184156 comment #13
+ std::string val = it->print(&exifData);
+ QString tagValue = QString::fromLocal8Bit(val.c_str());
+#else
std::ostringstream os;
os << *it;
QString tagValue = QString::fromLocal8Bit(os.str().c_str());
-
+#endif
if (escapeCR)
tagValue.replace("\n", " ");
@@ -1185,7 +1296,7 @@ QString KExiv2::getExifTagString(const char* exifTagName, bool escapeCR) const
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError(QString("Cannot find Exif key '%1' into image using Exiv2 ")
+ d->printExiv2ExceptionError(QString("Cannot find Exif key '%1' into image using Exiv2 ")
.arg(exifTagName), e);
}
@@ -1204,7 +1315,7 @@ bool KExiv2::setExifTagString(const char *exifTagName, const QString& value, boo
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set Exif tag string into image using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot set Exif tag string into image using Exiv2 ", e);
}
return false;
@@ -1231,7 +1342,7 @@ QString KExiv2::getIptcTagString(const char* iptcTagName, bool escapeCR) const
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError(QString("Cannot find Iptc key '%1' into image using Exiv2 ")
+ d->printExiv2ExceptionError(QString("Cannot find Iptc key '%1' into image using Exiv2 ")
.arg(iptcTagName), e);
}
@@ -1250,7 +1361,7 @@ bool KExiv2::setIptcTagString(const char *iptcTagName, const QString& value, boo
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set Iptc tag string into image using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot set Iptc tag string into image using Exiv2 ", e);
}
return false;
@@ -1259,7 +1370,7 @@ bool KExiv2::setIptcTagString(const char *iptcTagName, const QString& value, boo
bool KExiv2::getExifTagLong(const char* exifTagName, long &val) const
{
try
- {
+ {
Exiv2::ExifKey exifKey(exifTagName);
Exiv2::ExifData exifData(d->exifMetadata);
Exiv2::ExifData::iterator it = exifData.findKey(exifKey);
@@ -1271,11 +1382,11 @@ bool KExiv2::getExifTagLong(const char* exifTagName, long &val) const
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError(QString("Cannot find Exif key '%1' into image using Exiv2 ")
+ d->printExiv2ExceptionError(QString("Cannot find Exif key '%1' into image using Exiv2 ")
.arg(exifTagName), e);
- }
-
- return false;
+ }
+
+ return false;
}
QByteArray KExiv2::getExifTagData(const char* exifTagName) const
@@ -1289,13 +1400,19 @@ QByteArray KExiv2::getExifTagData(const char* exifTagName) const
{
QByteArray data((*it).size());
if (data.size())
+ {
+#if (EXIV2_TEST_VERSION(0,17,91))
+ (*it).copy((Exiv2::byte*)data.data(), Exiv2::bigEndian);
+#else
(*it).copy((Exiv2::byte*)data.data(), exifData.byteOrder());
+#endif
+ }
return data;
}
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError(QString("Cannot find Exif key '%1' into image using Exiv2 ")
+ d->printExiv2ExceptionError(QString("Cannot find Exif key '%1' into image using Exiv2 ")
.arg(exifTagName), e);
}
@@ -1319,7 +1436,7 @@ QByteArray KExiv2::getIptcTagData(const char *iptcTagName) const
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError(QString("Cannot find Iptc key '%1' into image using Exiv2 ")
+ d->printExiv2ExceptionError(QString("Cannot find Iptc key '%1' into image using Exiv2 ")
.arg(iptcTagName), e);
}
@@ -1342,7 +1459,7 @@ bool KExiv2::getExifTagRational(const char *exifTagName, long int &num, long int
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError(QString("Cannot find Exif Rational value from key '%1' "
+ d->printExiv2ExceptionError(QString("Cannot find Exif Rational value from key '%1' "
"into image using Exiv2 ").arg(exifTagName), e);
}
@@ -1361,7 +1478,7 @@ bool KExiv2::setExifTagLong(const char *exifTagName, long val, bool setProgramNa
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set Exif tag long value into image using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot set Exif tag long value into image using Exiv2 ", e);
}
return false;
@@ -1379,7 +1496,7 @@ bool KExiv2::setExifTagRational(const char *exifTagName, long int num, long int
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set Exif tag rational value into image using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot set Exif tag rational value into image using Exiv2 ", e);
}
return false;
@@ -1388,7 +1505,7 @@ bool KExiv2::setExifTagRational(const char *exifTagName, long int num, long int
bool KExiv2::setExifTagData(const char *exifTagName, const QByteArray& data, bool setProgramName)
{
if (data.isEmpty())
- return false;
+ return false;
if (!setProgramId(setProgramName))
return false;
@@ -1401,7 +1518,7 @@ bool KExiv2::setExifTagData(const char *exifTagName, const QByteArray& data, boo
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set Exif tag data into image using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot set Exif tag data into image using Exiv2 ", e);
}
return false;
@@ -1410,20 +1527,20 @@ bool KExiv2::setExifTagData(const char *exifTagName, const QByteArray& data, boo
bool KExiv2::setIptcTagData(const char *iptcTagName, const QByteArray& data, bool setProgramName)
{
if (data.isEmpty())
- return false;
-
+ return false;
+
if (!setProgramId(setProgramName))
return false;
try
- {
+ {
Exiv2::DataValue val((Exiv2::byte *)data.data(), data.size());
d->iptcMetadata[iptcTagName] = val;
return true;
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set Iptc tag data into image using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot set Iptc tag data into image using Exiv2 ", e);
}
return false;
@@ -1435,7 +1552,7 @@ bool KExiv2::removeExifTag(const char *exifTagName, bool setProgramName)
return false;
try
- {
+ {
Exiv2::ExifKey exifKey(exifTagName);
Exiv2::ExifData::iterator it = d->exifMetadata.findKey(exifKey);
if (it != d->exifMetadata.end())
@@ -1446,9 +1563,9 @@ bool KExiv2::removeExifTag(const char *exifTagName, bool setProgramName)
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot remove Exif tag using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot remove Exif tag using Exiv2 ", e);
+ }
+
return false;
}
@@ -1458,34 +1575,39 @@ bool KExiv2::removeIptcTag(const char *iptcTagName, bool setProgramName)
return false;
try
- {
- Exiv2::IptcKey iptcKey(iptcTagName);
- Exiv2::IptcData::iterator it = d->iptcMetadata.findKey(iptcKey);
- if (it != d->iptcMetadata.end())
+ {
+ Exiv2::IptcData::iterator it = d->iptcMetadata.begin();
+ while(it != d->iptcMetadata.end())
{
- d->iptcMetadata.erase(it);
- return true;
- }
+ QString key = QString::fromLocal8Bit(it->key().c_str());
+
+ if (key == QString(iptcTagName))
+ it = d->iptcMetadata.erase(it);
+ else
+ ++it;
+ };
+
+ return true;
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot remove Iptc tag using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot remove Iptc tag using Exiv2 ", e);
+ }
+
return false;
}
QString KExiv2::getExifTagTitle(const char *exifTagName)
{
- try
+ try
{
std::string exifkey(exifTagName);
- Exiv2::ExifKey ek(exifkey);
+ Exiv2::ExifKey ek(exifkey);
return QString::fromLocal8Bit( Exiv2::ExifTags::tagTitle(ek.tag(), ek.ifdId()) );
}
- catch (Exiv2::Error& e)
+ catch (Exiv2::Error& e)
{
- printExiv2ExceptionError("Cannot get metadata tag title using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot get metadata tag title using Exiv2 ", e);
}
return QString();
@@ -1493,15 +1615,15 @@ QString KExiv2::getExifTagTitle(const char *exifTagName)
QString KExiv2::getExifTagDescription(const char *exifTagName)
{
- try
+ try
{
std::string exifkey(exifTagName);
- Exiv2::ExifKey ek(exifkey);
+ Exiv2::ExifKey ek(exifkey);
return QString::fromLocal8Bit( Exiv2::ExifTags::tagDesc(ek.tag(), ek.ifdId()) );
}
- catch (Exiv2::Error& e)
+ catch (Exiv2::Error& e)
{
- printExiv2ExceptionError("Cannot get metadata tag description using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot get metadata tag description using Exiv2 ", e);
}
return QString();
@@ -1509,15 +1631,15 @@ QString KExiv2::getExifTagDescription(const char *exifTagName)
QString KExiv2::getIptcTagTitle(const char *iptcTagName)
{
- try
+ try
{
std::string iptckey(iptcTagName);
- Exiv2::IptcKey ik(iptckey);
+ Exiv2::IptcKey ik(iptckey);
return QString::fromLocal8Bit( Exiv2::IptcDataSets::dataSetTitle(ik.tag(), ik.record()) );
}
- catch (Exiv2::Error& e)
+ catch (Exiv2::Error& e)
{
- printExiv2ExceptionError("Cannot get metadata tag title using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot get metadata tag title using Exiv2 ", e);
}
return QString();
@@ -1525,15 +1647,15 @@ QString KExiv2::getIptcTagTitle(const char *iptcTagName)
QString KExiv2::getIptcTagDescription(const char *iptcTagName)
{
- try
+ try
{
std::string iptckey(iptcTagName);
- Exiv2::IptcKey ik(iptckey);
+ Exiv2::IptcKey ik(iptckey);
return QString::fromLocal8Bit( Exiv2::IptcDataSets::dataSetDesc(ik.tag(), ik.record()) );
}
- catch (Exiv2::Error& e)
+ catch (Exiv2::Error& e)
{
- printExiv2ExceptionError("Cannot get metadata tag description using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot get metadata tag description using Exiv2 ", e);
}
return QString();
@@ -1548,7 +1670,7 @@ KExiv2::MetaDataMap KExiv2::getExifTagsDataList(const QStringList &exifKeysFilte
{
Exiv2::ExifData exifData = d->exifMetadata;
exifData.sortByKey();
-
+
QString ifDItemName;
MetaDataMap metaDataMap;
@@ -1560,7 +1682,7 @@ KExiv2::MetaDataMap KExiv2::getExifTagsDataList(const QStringList &exifKeysFilte
QString tagValue;
if (key == "Exif.Photo.UserComment")
{
- tagValue = convertCommentValue(*md);
+ tagValue = d->convertCommentValue(*md);
}
else
{
@@ -1590,7 +1712,7 @@ KExiv2::MetaDataMap KExiv2::getExifTagsDataList(const QStringList &exifKeysFilte
}
catch (Exiv2::Error& e)
{
- printExiv2ExceptionError("Cannot parse EXIF metadata using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot parse EXIF metadata using Exiv2 ", e);
}
return MetaDataMap();
@@ -1605,14 +1727,14 @@ KExiv2::MetaDataMap KExiv2::getIptcTagsDataList(const QStringList &iptcKeysFilte
{
Exiv2::IptcData iptcData = d->iptcMetadata;
iptcData.sortByKey();
-
+
QString ifDItemName;
MetaDataMap metaDataMap;
for (Exiv2::IptcData::iterator md = iptcData.begin(); md != iptcData.end(); ++md)
{
QString key = QString::fromAscii(md->key().c_str());
-
+
// Decode the tag value with a user friendly output.
std::ostringstream os;
os << *md;
@@ -1637,7 +1759,7 @@ KExiv2::MetaDataMap KExiv2::getIptcTagsDataList(const QStringList &iptcKeysFilte
v.append(", ");
v.append(value);
metaDataMap.replace(key, v);
- }
+ }
}
}
else
@@ -1652,7 +1774,7 @@ KExiv2::MetaDataMap KExiv2::getIptcTagsDataList(const QStringList &iptcKeysFilte
v.append(", ");
v.append(value);
metaDataMap.replace(key, v);
- }
+ }
}
}
}
@@ -1661,7 +1783,7 @@ KExiv2::MetaDataMap KExiv2::getIptcTagsDataList(const QStringList &iptcKeysFilte
}
catch (Exiv2::Error& e)
{
- printExiv2ExceptionError("Cannot parse IPTC metadata using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot parse IPTC metadata using Exiv2 ", e);
}
return MetaDataMap();
@@ -1670,10 +1792,10 @@ KExiv2::MetaDataMap KExiv2::getIptcTagsDataList(const QStringList &iptcKeysFilte
bool KExiv2::getGPSInfo(double& altitude, double& latitude, double& longitude) const
{
try
- {
+ {
double num, den, min, sec;
latitude=0.0, longitude=0.0, altitude=0.0;
-
+
// Get the reference in first.
QByteArray latRef = getExifTagData("Exif.GPSInfo.GPSLatitudeRef");
@@ -1707,11 +1829,11 @@ bool KExiv2::getGPSInfo(double& altitude, double& latitude, double& longitude) c
if (sec != -1.0)
latitude = latitude + sec/3600.0;
}
- else
+ else
return false;
-
+
if (latRef[0] == 'S') latitude *= -1.0;
-
+
// Longitude decoding.
Exiv2::ExifKey exifKey2("Exif.GPSInfo.GPSLongitude");
@@ -1734,14 +1856,14 @@ bool KExiv2::getGPSInfo(double& altitude, double& latitude, double& longitude) c
if (sec != -1.0)
longitude = longitude + sec/3600.0;
}
- else
+ else
return false;
-
+
if (lngRef[0] == 'W') longitude *= -1.0;
// Altitude decoding.
- if (!altRef.isEmpty())
+ if (!altRef.isEmpty())
{
Exiv2::ExifKey exifKey3("Exif.GPSInfo.GPSAltitude");
it = exifData.findKey(exifKey3);
@@ -1751,7 +1873,7 @@ bool KExiv2::getGPSInfo(double& altitude, double& latitude, double& longitude) c
den = (double)((*it).toRational(0).second);
altitude = num/den;
}
-
+
if (altRef[0] == '1') altitude *= -1.0;
}
@@ -1759,9 +1881,9 @@ bool KExiv2::getGPSInfo(double& altitude, double& latitude, double& longitude) c
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot get Exif GPS tag using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot get Exif GPS tag using Exiv2 ", e);
+ }
+
return false;
}
@@ -1771,14 +1893,14 @@ bool KExiv2::setGPSInfo(double altitude, double latitude, double longitude, bool
return false;
try
- {
+ {
// In first, we need to clean up all existing GPS info.
removeGPSInfo();
char scratchBuf[100];
long int nom, denom;
long int deg, min;
-
+
// Do all the easy constant ones first.
// GPSVersionID tag: standard says is should be four bytes: 02 00 00 00
// (and, must be present).
@@ -1788,16 +1910,16 @@ bool KExiv2::setGPSInfo(double altitude, double latitude, double longitude, bool
// Datum: the datum of the measured data. If not given, we insert WGS-84.
d->exifMetadata["Exif.GPSInfo.GPSMapDatum"] = "WGS-84";
-
+
// Now start adding data.
// ALTITUDE.
// Altitude reference: byte "00" meaning "above sea level", "01" mening "behing sea level".
value = Exiv2::Value::create(Exiv2::unsignedByte);
- if (altitude >= 0) value->read("0");
- else value->read("1");
+ if (altitude >= 0) value->read("0");
+ else value->read("1");
d->exifMetadata.add(Exiv2::ExifKey("Exif.GPSInfo.GPSAltitudeRef"), value.get());
-
+
// And the actual altitude, as absolute value.
convertToRational(fabs(altitude), &nom, &denom, 4);
snprintf(scratchBuf, 100, "%ld/%ld", nom, denom);
@@ -1810,14 +1932,14 @@ bool KExiv2::setGPSInfo(double altitude, double latitude, double longitude, bool
// Less than Zero: ie, minus: means
// Southern hemisphere. Where I live.
d->exifMetadata["Exif.GPSInfo.GPSLatitudeRef"] = "S";
- }
- else
+ }
+ else
{
// More than Zero: ie, plus: means
// Northern hemisphere.
d->exifMetadata["Exif.GPSInfo.GPSLatitudeRef"] = "N";
}
-
+
// Now the actual lattitude itself.
// This is done as three rationals.
// I choose to do it as:
@@ -1837,7 +1959,7 @@ bool KExiv2::setGPSInfo(double altitude, double latitude, double longitude, bool
min = (int)floor((fabs(latitude) - floor(fabs(latitude))) * 60000000);
snprintf(scratchBuf, 100, "%ld/1 %ld/1000000 0/1", deg, min);
d->exifMetadata["Exif.GPSInfo.GPSLatitude"] = scratchBuf;
-
+
// LONGITUDE
// Longitude reference: "E" or "W".
if (longitude < 0)
@@ -1845,8 +1967,8 @@ bool KExiv2::setGPSInfo(double altitude, double latitude, double longitude, bool
// Less than Zero: ie, minus: means
// Western hemisphere.
d->exifMetadata["Exif.GPSInfo.GPSLongitudeRef"] = "W";
- }
- else
+ }
+ else
{
// More than Zero: ie, plus: means
// Eastern hemisphere. Where I live.
@@ -1871,15 +1993,15 @@ bool KExiv2::setGPSInfo(double altitude, double latitude, double longitude, bool
deg = (int)floor(fabs(longitude)); // Slice off after decimal.
min = (int)floor((fabs(longitude) - floor(fabs(longitude))) * 60000000);
snprintf(scratchBuf, 100, "%ld/1 %ld/1000000 0/1", deg, min);
- d->exifMetadata["Exif.GPSInfo.GPSLongitude"] = scratchBuf;
-
+ d->exifMetadata["Exif.GPSInfo.GPSLongitude"] = scratchBuf;
+
return true;
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set Exif GPS tag using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot set Exif GPS tag using Exiv2 ", e);
+ }
+
return false;
}
@@ -1889,9 +2011,9 @@ bool KExiv2::removeGPSInfo(bool setProgramName)
return false;
try
- {
+ {
QStringList gpsTagsKeys;
-
+
for (Exiv2::ExifData::iterator it = d->exifMetadata.begin();
it != d->exifMetadata.end(); ++it)
{
@@ -1901,46 +2023,46 @@ bool KExiv2::removeGPSInfo(bool setProgramName)
gpsTagsKeys.append(key);
}
- for(QStringList::Iterator it2 = gpsTagsKeys.begin(); it2 != gpsTagsKeys.end(); ++it2)
+ for(QStringList::Iterator it2 = gpsTagsKeys.begin(); it2 != gpsTagsKeys.end(); ++it2)
{
Exiv2::ExifKey gpsKey((*it2).ascii());
Exiv2::ExifData::iterator it3 = d->exifMetadata.findKey(gpsKey);
if (it3 != d->exifMetadata.end())
d->exifMetadata.erase(it3);
}
-
+
return true;
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot remove Exif GPS tag using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot remove Exif GPS tag using Exiv2 ", e);
+ }
+
return false;
}
-void KExiv2::convertToRational(double number, long int* numerator,
- long int* denominator, int rounding)
+void KExiv2::convertToRational(double number, long int* numerator,
+ long int* denominator, int rounding)
{
// This function converts the given decimal number
// to a rational (fractional) number.
//
// Examples in comments use Number as 25.12345, Rounding as 4.
-
+
// Split up the number.
double whole = trunc(number);
double fractional = number - whole;
// Calculate the "number" used for rounding.
// This is 10^Digits - ie, 4 places gives us 10000.
- double rounder = pow(10, rounding);
+ double rounder = pow(10.0, rounding);
// Round the fractional part, and leave the number
// as greater than 1.
// To do this we: (for example)
// 0.12345 * 10000 = 1234.5
// floor(1234.5) = 1234 - now bigger than 1 - ready...
- fractional = trunc(fractional * rounder);
+ fractional = round(fractional * rounder);
// Convert the whole thing to a fraction.
// Fraction is:
@@ -1951,7 +2073,7 @@ void KExiv2::convertToRational(double number, long int* numerator,
double denTemp = rounder;
// Now we should reduce until we can reduce no more.
-
+
// Try simple reduction...
// if Num
// ----- = integer out then....
@@ -1962,7 +2084,7 @@ void KExiv2::convertToRational(double number, long int* numerator,
numTemp /= denTemp;
denTemp /= denTemp;
}
-
+
// And, if that fails, brute force it.
while (1)
{
@@ -1982,47 +2104,47 @@ void KExiv2::convertToRational(double number, long int* numerator,
QStringList KExiv2::getImageKeywords() const
{
try
- {
+ {
if (!d->iptcMetadata.empty())
{
- QStringList keywords;
+ QStringList keywords;
Exiv2::IptcData iptcData(d->iptcMetadata);
for (Exiv2::IptcData::iterator it = iptcData.begin(); it != iptcData.end(); ++it)
{
QString key = QString::fromLocal8Bit(it->key().c_str());
-
+
if (key == QString("Iptc.Application2.Keywords"))
{
QString val(it->toString().c_str());
keywords.append(val);
}
}
-
+
return keywords;
}
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot get IPTC Keywords from image using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot get IPTC Keywords from image using Exiv2 ", e);
+ }
+
return QStringList();
}
-bool KExiv2::setImageKeywords(const QStringList& oldKeywords, const QStringList& newKeywords,
+bool KExiv2::setImageKeywords(const QStringList& oldKeywords, const QStringList& newKeywords,
bool setProgramName)
{
if (!setProgramId(setProgramName))
return false;
try
- {
+ {
QStringList oldkeys = oldKeywords;
QStringList newkeys = newKeywords;
-
+
qDebug("%s ==> Keywords: %s", d->filePath.ascii(), newkeys.join(",").ascii());
-
+
// Remove all old keywords.
Exiv2::IptcData iptcData(d->iptcMetadata);
Exiv2::IptcData::iterator it = iptcData.begin();
@@ -2037,7 +2159,7 @@ bool KExiv2::setImageKeywords(const QStringList& oldKeywords, const QStringList&
(oldKeywords.contains(val) || newKeywords.contains(val))
)
it = iptcData.erase(it);
- else
+ else
++it;
};
@@ -2049,10 +2171,10 @@ bool KExiv2::setImageKeywords(const QStringList& oldKeywords, const QStringList&
{
QString key = *it;
key.truncate(64);
-
+
Exiv2::Value::AutoPtr val = Exiv2::Value::create(Exiv2::string);
val->read(key.latin1());
- iptcData.add(iptcTag, val.get());
+ iptcData.add(iptcTag, val.get());
}
d->iptcMetadata = iptcData;
@@ -2061,54 +2183,54 @@ bool KExiv2::setImageKeywords(const QStringList& oldKeywords, const QStringList&
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set IPTC Keywords into image using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot set IPTC Keywords into image using Exiv2 ", e);
+ }
+
return false;
}
QStringList KExiv2::getImageSubjects() const
{
try
- {
+ {
if (!d->iptcMetadata.empty())
{
- QStringList subjects;
+ QStringList subjects;
Exiv2::IptcData iptcData(d->iptcMetadata);
for (Exiv2::IptcData::iterator it = iptcData.begin(); it != iptcData.end(); ++it)
{
QString key = QString::fromLocal8Bit(it->key().c_str());
-
+
if (key == QString("Iptc.Application2.Subject"))
{
QString val(it->toString().c_str());
subjects.append(val);
}
}
-
+
return subjects;
}
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot get IPTC Subjects from image using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot get IPTC Subjects from image using Exiv2 ", e);
+ }
+
return QStringList();
}
-bool KExiv2::setImageSubjects(const QStringList& oldSubjects, const QStringList& newSubjects,
+bool KExiv2::setImageSubjects(const QStringList& oldSubjects, const QStringList& newSubjects,
bool setProgramName)
{
if (!setProgramId(setProgramName))
return false;
try
- {
+ {
QStringList oldDef = oldSubjects;
QStringList newDef = newSubjects;
-
+
// Remove all old subjects.
Exiv2::IptcData iptcData(d->iptcMetadata);
Exiv2::IptcData::iterator it = iptcData.begin();
@@ -2117,10 +2239,10 @@ bool KExiv2::setImageSubjects(const QStringList& oldSubjects, const QStringList&
{
QString key = QString::fromLocal8Bit(it->key().c_str());
QString val(it->toString().c_str());
-
+
if (key == QString("Iptc.Application2.Subject") && oldDef.contains(val))
it = iptcData.erase(it);
- else
+ else
++it;
};
@@ -2132,10 +2254,10 @@ bool KExiv2::setImageSubjects(const QStringList& oldSubjects, const QStringList&
{
QString key = *it;
key.truncate(236);
-
+
Exiv2::Value::AutoPtr val = Exiv2::Value::create(Exiv2::string);
val->read(key.latin1());
- iptcData.add(iptcTag, val.get());
+ iptcData.add(iptcTag, val.get());
}
d->iptcMetadata = iptcData;
@@ -2144,54 +2266,54 @@ bool KExiv2::setImageSubjects(const QStringList& oldSubjects, const QStringList&
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set IPTC Subjects into image using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot set IPTC Subjects into image using Exiv2 ", e);
+ }
+
return false;
}
QStringList KExiv2::getImageSubCategories() const
{
try
- {
+ {
if (!d->iptcMetadata.empty())
{
- QStringList subCategories;
+ QStringList subCategories;
Exiv2::IptcData iptcData(d->iptcMetadata);
for (Exiv2::IptcData::iterator it = iptcData.begin(); it != iptcData.end(); ++it)
{
QString key = QString::fromLocal8Bit(it->key().c_str());
-
+
if (key == QString("Iptc.Application2.SuppCategory"))
{
QString val(it->toString().c_str());
subCategories.append(val);
}
}
-
+
return subCategories;
}
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot get IPTC Sub Categories from image using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot get IPTC Sub Categories from image using Exiv2 ", e);
+ }
+
return QStringList();
}
-bool KExiv2::setImageSubCategories(const QStringList& oldSubCategories, const QStringList& newSubCategories,
+bool KExiv2::setImageSubCategories(const QStringList& oldSubCategories, const QStringList& newSubCategories,
bool setProgramName)
{
if (!setProgramId(setProgramName))
return false;
try
- {
+ {
QStringList oldkeys = oldSubCategories;
QStringList newkeys = newSubCategories;
-
+
// Remove all old Sub Categories.
Exiv2::IptcData iptcData(d->iptcMetadata);
Exiv2::IptcData::iterator it = iptcData.begin();
@@ -2200,14 +2322,14 @@ bool KExiv2::setImageSubCategories(const QStringList& oldSubCategories, const QS
{
QString key = QString::fromLocal8Bit(it->key().c_str());
QString val(it->toString().c_str());
-
+
if (key == QString("Iptc.Application2.SuppCategory") && oldSubCategories.contains(val))
it = iptcData.erase(it);
- else
+ else
++it;
};
- // Add new Sub Categories. Note that SubCategories IPTC tag is limited to 32
+ // Add new Sub Categories. Note that SubCategories IPTC tag is limited to 32
// characters but can be redondant.
Exiv2::IptcKey iptcTag("Iptc.Application2.SuppCategory");
@@ -2216,10 +2338,10 @@ bool KExiv2::setImageSubCategories(const QStringList& oldSubCategories, const QS
{
QString key = *it;
key.truncate(32);
-
+
Exiv2::Value::AutoPtr val = Exiv2::Value::create(Exiv2::string);
val->read(key.latin1());
- iptcData.add(iptcTag, val.get());
+ iptcData.add(iptcTag, val.get());
}
d->iptcMetadata = iptcData;
@@ -2228,9 +2350,9 @@ bool KExiv2::setImageSubCategories(const QStringList& oldSubCategories, const QS
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set IPTC Sub Categories into image using Exiv2 ", e);
- }
-
+ d->printExiv2ExceptionError("Cannot set IPTC Sub Categories into image using Exiv2 ", e);
+ }
+
return false;
}
@@ -2246,7 +2368,7 @@ QString KExiv2::getExifComment() const
if (it != exifData.end())
{
- QString exifComment = convertCommentValue(*it);
+ QString exifComment = d->convertCommentValue(*it);
// some cameras fill the UserComment with whitespace
if (!exifComment.isEmpty() && !exifComment.stripWhiteSpace().isEmpty())
@@ -2256,7 +2378,7 @@ QString KExiv2::getExifComment() const
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot find Exif User Comment using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot find Exif User Comment using Exiv2 ", e);
}
return QString();
@@ -2299,131 +2421,15 @@ bool KExiv2::setExifComment(const QString& comment, bool setProgramName)
}
catch( Exiv2::Error &e )
{
- printExiv2ExceptionError("Cannot set Exif Comment using Exiv2 ", e);
+ d->printExiv2ExceptionError("Cannot set Exif Comment using Exiv2 ", e);
}
return false;
}
-QString KExiv2::convertCommentValue(const Exiv2::Exifdatum &exifDatum)
-{
- try
- {
- std::string comment;
- std::string charset;
-
-#if (EXIV2_TEST_VERSION(0,11,0))
- comment = exifDatum.toString();
-#else
- // workaround for bug in TIFF parser: CommentValue is loaded as DataValue
- const Exiv2::Value &value = exifDatum.value();
- Exiv2::byte *data = new Exiv2::byte[value.size()];
- value.copy(data, Exiv2::invalidByteOrder);
- Exiv2::CommentValue commentValue;
- // this read method is hidden in CommentValue
- static_cast<Exiv2::Value &>(commentValue).read(data, value.size(), Exiv2::invalidByteOrder);
- comment = commentValue.toString();
- delete [] data;
-#endif
-
- // libexiv2 will prepend "charset=\"SomeCharset\" " if charset is specified
- // Before conversion to QString, we must know the charset, so we stay with std::string for a while
- if (comment.length() > 8 && comment.substr(0, 8) == "charset=")
- {
- // the prepended charset specification is followed by a blank
- std::string::size_type pos = comment.find_first_of(' ');
- if (pos != std::string::npos)
- {
- // extract string between the = and the blank
- charset = comment.substr(8, pos-8);
- // get the rest of the string after the charset specification
- comment = comment.substr(pos+1);
- }
- }
-
- if (charset == "\"Unicode\"")
- {
- // QString expects a null-terminated UCS-2 string.
- // Is it already null terminated? In any case, add termination "\0\0" for safety.
- comment.resize(comment.length() + 2, '\0');
- return QString::fromUcs2((unsigned short *)comment.data());
- }
- else if (charset == "\"Jis\"")
- {
- QTextCodec *codec = QTextCodec::codecForName("JIS7");
- return codec->toUnicode(comment.c_str());
- }
- else if (charset == "\"Ascii\"")
- {
- return QString::fromLatin1(comment.c_str());
- }
- else
- {
- return detectEncodingAndDecode(comment);
- }
- }
- catch( Exiv2::Error &e )
- {
- printExiv2ExceptionError("Cannot convert Comment using Exiv2 ", e);
- }
-
- return QString();
-}
-
-QString KExiv2::detectEncodingAndDecode(const std::string &value)
-{
- // For charset autodetection, we could use sophisticated code
- // (Mozilla chardet, KHTML's autodetection, QTextCodec::codecForContent),
- // but that is probably too much.
- // We check for UTF8, Local encoding and ASCII.
-
- if (value.empty())
- return QString();
-
-#if KDE_IS_VERSION(3,2,0)
- if (KStringHandler::isUtf8(value.c_str()))
- {
- return QString::fromUtf8(value.c_str());
- }
-#else
- // anyone who is still running KDE 3.0 or 3.1 is missing so many features
- // that he will have to accept this missing feature.
- return QString::fromUtf8(value.c_str());
-#endif
-
- // Utf8 has a pretty unique byte pattern.
- // Thats not true for ASCII, it is not possible
- // to reliably autodetect different ISO-8859 charsets.
- // We try if QTextCodec can decide here, otherwise we use Latin1.
- // Or use local8Bit as default?
-
- // load QTextCodecs
- QTextCodec *latin1Codec = QTextCodec::codecForName("iso8859-1");
- //QTextCodec *utf8Codec = QTextCodec::codecForName("utf8");
- QTextCodec *localCodec = QTextCodec::codecForLocale();
-
- // make heuristic match
- int latin1Score = latin1Codec->heuristicContentMatch(value.c_str(), value.length());
- int localScore = localCodec->heuristicContentMatch(value.c_str(), value.length());
-
- // convert string:
- // Use whatever has the larger score, local or ASCII
- if (localScore >= 0 && localScore >= latin1Score)
- {
- // workaround for bug #134999:
- // The QLatin15Codec may crash if strlen < value.length()
- int length = value.length();
- if (localCodec->name() == QString::fromLatin1("ISO 8859-15"))
- length = strlen(value.c_str());
- return localCodec->toUnicode(value.c_str(), length);
- }
- else
- return QString::fromLatin1(value.c_str());
-}
-
bool KExiv2::setProgramId(bool /*on*/)
{
- return true;
+ return true;
}
} // NameSpace KExiv2Iface
diff --git a/libkexiv2/libkexiv2/kexiv2.h b/libkexiv2/libkexiv2/kexiv2.h
index 037b86f..4ddac43 100644
--- a/libkexiv2/libkexiv2/kexiv2.h
+++ b/libkexiv2/libkexiv2/kexiv2.h
@@ -6,8 +6,8 @@
* Date : 2006-09-15
* Description : Exiv2 library interface for KDE
*
- * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
- * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
+ * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ * Copyright (C) 2006-2009 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
*
* Exiv2: http://www.exiv2.org
* Exif : http://www.exif.org/Exif2-2.PDF
@@ -17,7 +17,7 @@
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software Foundation;
* either version 2, or (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -28,10 +28,6 @@
#ifndef KEXIV2_H
#define KEXIV2_H
-// C++ includes.
-
-#include <string>
-
// QT includes.
#include <qcstring.h>
@@ -44,15 +40,6 @@
#include "libkexiv2_export.h"
-namespace Exiv2
-{
- class DataBuf;
- class Exifdatum;
- class ExifData;
- class IptcData;
- class Error;
-}
-
namespace KExiv2Iface
{
@@ -63,7 +50,8 @@ class LIBKEXIV2_EXPORT KExiv2
public:
- /** The image color workspace values given by Exif metadata. */
+ /** The image color workspace values given by Exif metadata.
+ */
enum ImageColorWorkSpace
{
WORKSPACE_UNSPECIFIED = 0,
@@ -72,7 +60,8 @@ public:
WORKSPACE_UNCALIBRATED = 65535
};
- /** The image orientation values given by Exif metadata. */
+ /** The image orientation values given by Exif metadata.
+ */
enum ImageOrientation
{
ORIENTATION_UNSPECIFIED = 0,
@@ -87,143 +76,192 @@ public:
};
/** A map used by decodeExifMetadata() decodeIptcMetadata() methods
- to store Tags Key and Tags Value. */
+ to store Tags Key and Tags Value.
+ */
typedef QMap<QString, QString> MetaDataMap;
public:
- /** Standard constructor. */
+ /** Standard constructor.
+ */
KExiv2();
- /** Contructor to Load Metadata from image file. */
+ /** Contructor to Load Metadata from image file.
+ */
KExiv2(const QString& filePath);
- /** Standard destructor */
+ /** Standard destructor
+ */
virtual ~KExiv2();
- /** Return a string version of Exiv2 release in format "major.minor.patch" */
+ /** Return true if library can writte metadata to typeMime file format.
+ */
+ static bool supportMetadataWritting(const QString& typeMime);
+
+ /** Return a string version of Exiv2 release in format "major.minor.patch"
+ */
static QString Exiv2Version();
- /** Return a string version of libkexiv2 release */
+ /** Return a string version of libkexiv2 release
+ */
static QString version();
- /** Generic method to print the Exiv2 C++ Exception error message from 'e'.
- 'msg' string is printed just before like debug header.
- */
- static void printExiv2ExceptionError(const QString& msg, Exiv2::Error& e);
-
//-- Metadata manipulation methods ----------------------------------------------
- /** Clear the Comments metadata container in memory. */
+ /** Clear the Comments metadata container in memory.
+ */
bool clearComments();
- /** Clear the Exif metadata container in memory. */
+ /** Clear the Exif metadata container in memory.
+ */
bool clearExif();
- /** Clear the Iptc metadata container in memory. */
+ /** Clear the Iptc metadata container in memory.
+ */
bool clearIptc();
- /** Return the file path open with the current instance of interface. */
+ /** Return the file path open with the current instance of interface.
+ */
QString getFilePath() const;
/** Return a Qt byte array copy of Comments container get from current image.
Comments are JFIF section of JPEG images. Look Exiv2 API for more information.
- Return a null Qt byte array if there is no Comments metadata in memory. */
+ Return a null Qt byte array if there is no Comments metadata in memory.
+ */
QByteArray getComments() const;
/** Return a Qt string object of Comments from current image decoded using
the 'detectEncodingAndDecode()' method. Return a null string if there is no
- Comments metadata available. */
+ Comments metadata available.
+ */
QString getCommentsDecoded() const;
/** Return a Qt byte array copy of Exif container get from current image.
- Return a null Qt byte array if there is no Exif metadata in memory. */
+ Return a null Qt byte array if there is no Exif metadata in memory.
+ */
QByteArray getExif() const;
/** Return a Qt byte array copy of Iptc container get from current image.
Set true 'addIrbHeader' parameter to add an Irb header to IPTC metadata.
- Return a null Qt byte array if there is no Iptc metadata in memory. */
+ Return a null Qt byte array if there is no Iptc metadata in memory.
+ */
QByteArray getIptc(bool addIrbHeader=false) const;
/** Set the Comments data using a Qt byte array. Return true if Comments metadata
- have been changed in memory. */
+ have been changed in memory.
+ */
bool setComments(const QByteArray& data);
/** Set the Exif data using a Qt byte array. Return true if Exif metadata
- have been changed in memory. */
+ have been changed in memory.
+ */
bool setExif(const QByteArray& data);
/** Set the Iptc data using a Qt byte array. Return true if Iptc metadata
- have been changed in memory. */
+ have been changed in memory.
+ */
bool setIptc(const QByteArray& data);
//-- File access methods ----------------------------------------------
+ /** Load all metadata (EXIF, IPTC and JFIF Comments) from a byte array.
+ Return true if metadata have been loaded successfully from image data.
+ */
+ bool load(const QByteArray& imgData);
+
/** Load all metadata (EXIF, IPTC and JFIF Comments) from a picture (JPEG, RAW, TIFF, PNG,
- DNG, etc...). Return true if metadata have been loaded successfully from file. */
+ DNG, etc...). Return true if metadata have been loaded successfully from file.
+ */
virtual bool load(const QString& filePath);
/** Save all metadata to a file. This one can be different than original picture to perform
- transfert operation Return true if metadata have been saved into file. */
+ transfert operation Return true if metadata have been saved into file.
+ */
bool save(const QString& filePath);
/** The same than save() method, but it apply on current image. Return true if metadata
- have been saved into file. */
+ have been saved into file.
+ */
bool applyChanges();
- /** return true is the file metadata cannot be written by Exiv2. */
+ /** return true is the file metadata cannot be written by Exiv2.
+ */
static bool isReadOnly(const QString& filePath);
+ /** Return 'true' if Comments can be written in file.
+ */
+ static bool canWriteComment(const QString& filePath);
+
+ /** Return 'true' if Exif can be written in file.
+ */
+ static bool canWriteExif(const QString& filePath);
+
+ /** Return 'true' if Iptc can be written in file.
+ */
+ static bool canWriteIptc(const QString& filePath);
+
//-- Metadata Image Information manipulation methods ----------------
/** Set Program name and program version in Exif and Iptc Metadata. Return true if information
- have been changed in metadata. */
+ have been changed in metadata.
+ */
bool setImageProgramId(const QString& program, const QString& version);
/** Return the size of image in pixels using Exif tags. Return a null dimmension if size cannot
- be found. */
+ be found.
+ */
QSize getImageDimensions() const;
/** Set the size of image in pixels in Exif tags. Return true if size have been changed
- in metadata. */
+ in metadata.
+ */
bool setImageDimensions(const QSize& size, bool setProgramName=true);
/** Return a QImage copy of Exif thumbnail image. Return a null image if thumbnail cannot
be found. The 'fixOrientation' parameter will rotate automatically the thumbnail if Exif
- orientation tags information are attached with thumbnail. */
+ orientation tags information are attached with thumbnail.
+ */
QImage getExifThumbnail(bool fixOrientation) const;
/** Set the Exif Thumbnail image. The thumbnail image must have the right dimensions before.
- Look Exif specification for details. Return true if thumbnail have been changed in metadata. */
+ Look Exif specification for details. Return true if thumbnail have been changed in metadata.
+ */
bool setExifThumbnail(const QImage& thumb, bool setProgramName=true);
/** Return the image orientation set in Exif metadata. The makernotes of image are also parsed to
- get this information. See ImageOrientation values for details. */
+ get this information. See ImageOrientation values for details.
+ */
KExiv2::ImageOrientation getImageOrientation() const;
/** Set the Exif orientation tag of image. See ImageOrientation values for details
- Return true if orientation have been changed in metadata. */
+ Return true if orientation have been changed in metadata.
+ */
bool setImageOrientation(ImageOrientation orientation, bool setProgramName=true);
/** Return the image color-space set in Exif metadata. The makernotes of image are also parsed to
- get this information. See ImageColorWorkSpace values for details. */
+ get this information. See ImageColorWorkSpace values for details.
+ */
KExiv2::ImageColorWorkSpace getImageColorWorkSpace() const;
/** Set the Exif color-space tag of image. See ImageColorWorkSpace values for details
- Return true if work-space have been changed in metadata. */
+ Return true if work-space have been changed in metadata.
+ */
bool setImageColorWorkSpace(ImageColorWorkSpace workspace, bool setProgramName=true);
/** Return the time stamp of image. Exif information are check in first, IPTC in second
- if image don't have Exif information. If no time stamp is found, a null date is returned. */
+ if image don't have Exif information. If no time stamp is found, a null date is returned.
+ */
QDateTime getImageDateTime() const;
/** Set the Exif and Iptc time stamp. If 'setDateTimeDigitized' parameter is true, the 'Digitalized'
- time stamp is set, else only 'Created' time stamp is set. */
+ time stamp is set, else only 'Created' time stamp is set.
+ */
bool setImageDateTime(const QDateTime& dateTime, bool setDateTimeDigitized = false,
bool setProgramName=true);
/** Return a QImage copy of Iptc preview image. Return a null image if preview cannot
- be found. */
+ be found.
+ */
bool getImagePreview(QImage& preview) const;
/** Set the Iptc preview image. The thumbnail image must have the right size before (64Kb max
@@ -240,7 +278,8 @@ public:
/** Set Iptc keywords using a list of strings defined by 'newKeywords' parameter. Use 'getImageKeywords()'
method to set 'oldKeywords' parameter with existing keywords from image. The method will compare
all new keywords with all old keywords to prevent duplicate entries in image. Return true if keywords
- have been changed in metadata. */
+ have been changed in metadata.
+ */
bool setImageKeywords(const QStringList& oldKeywords, const QStringList& newKeywords,
bool setProgramName=true);
@@ -250,109 +289,135 @@ public:
/** Set Iptc subjects using a list of strings defined by 'newSubjects' parameter. Use 'getImageSubjects()'
method to set 'oldSubjects' parameter with existing subjects from image. The method will compare
all new subjects with all old subjects to prevent duplicate entries in image. Return true if subjects
- have been changed in metadata. */
+ have been changed in metadata.
+ */
bool setImageSubjects(const QStringList& oldSubjects, const QStringList& newSubjects,
bool setProgramName=true);
/** Return a strings list of Iptc sub-categories from image. Return an empty list if no sub-category
- are set. */
+ are set.
+ */
QStringList getImageSubCategories() const;
/** Set Iptc sub-categories using a list of strings defined by 'newSubCategories' parameter. Use
'getImageSubCategories()' method to set 'oldSubCategories' parameter with existing sub-categories
from image. The method will compare all new sub-categories with all old sub-categories to prevent
- duplicate entries in image. Return true if sub-categories have been changed in metadata. */
+ duplicate entries in image. Return true if sub-categories have been changed in metadata.
+ */
bool setImageSubCategories(const QStringList& oldSubCategories, const QStringList& newSubCategories,
bool setProgramName=true);
-
+
/** Return a QString copy of Exif user comments. Return a null string if user comments cannot
- be found. */
+ be found.
+ */
QString getExifComment() const;
/** Set the Exif user comments from image. Look Exif specification for more details about this tag.
- Return true if Exif user comments have been changed in metadata. */
+ Return true if Exif user comments have been changed in metadata.
+ */
bool setExifComment(const QString& comment, bool setProgramName=true);
- /** Get all GPS location information set in image. Return true if all information can be found. */
+ /** Get all GPS location information set in image. Return true if all information can be found.
+ */
bool getGPSInfo(double& altitude, double& latitude, double& longitude) const;
/** Set all GPS location information into image. Return true if all information have been
- changed in metadata. */
+ changed in metadata.
+ */
bool setGPSInfo(double altitude, double latitude, double longitude, bool setProgramName=true);
/** Remove all Exif tags relevant of GPS location information. Return true if all tags have been
- removed successfully in metadata. */
+ removed successfully in metadata.
+ */
bool removeGPSInfo(bool setProgramName=true);
//-- Metadata Tags manipulation methods ----------------------------------------
/** Get an Exif tags content like a string. If 'escapeCR' parameter is true, the CR characters
- will be removed. If Exif tag cannot be found a null string is returned. */
+ will be removed. If Exif tag cannot be found a null string is returned.
+ */
QString getExifTagString(const char *exifTagName, bool escapeCR=true) const;
- /** Set an Exif tag content using a string. Return true if tag is set successfully. */
+ /** Set an Exif tag content using a string. Return true if tag is set successfully.
+ */
bool setExifTagString(const char *exifTagName, const QString& value, bool setProgramName=true);
- /** Get an Exif tags content like a long value. Return true if Exif tag be found. */
+ /** Get an Exif tags content like a long value. Return true if Exif tag be found.
+ */
bool getExifTagLong(const char* exifTagName, long &val) const;
- /** Set an Exif tag content using a long value. Return true if tag is set successfully. */
+ /** Set an Exif tag content using a long value. Return true if tag is set successfully.
+ */
bool setExifTagLong(const char *exifTagName, long val, bool setProgramName=true);
/** Get the 'component' index of an Exif tags content like a rational value.
'num' and 'den' are the numerator and the denominator of the rational value.
- Return true if Exif tag be found. */
+ Return true if Exif tag be found.
+ */
bool getExifTagRational(const char *exifTagName, long int &num, long int &den, int component=0) const;
/** Set an Exif tags content using a rational value.
'num' and 'den' are the numerator and the denominator of the rational value.
- Return true if tag is set successfully. */
+ Return true if tag is set successfully.
+ */
bool setExifTagRational(const char *exifTagName, long int num, long int den, bool setProgramName=true);
/** Get an Exif tags content like a bytes array. Return an empty bytes array if Exif
- tag cannot be found. */
+ tag cannot be found.
+ */
QByteArray getExifTagData(const char *exifTagName) const;
- /** Set an Exif tag content using a bytes array. Return true if tag is set successfully. */
+ /** Set an Exif tag content using a bytes array. Return true if tag is set successfully.
+ */
bool setExifTagData(const char *exifTagName, const QByteArray& data, bool setProgramName=true);
-
+
/** Get an Iptc tags content like a string. If 'escapeCR' parameter is true, the CR characters
- will be removed. If Iptc tag cannot be found a null string is returned. */
+ will be removed. If Iptc tag cannot be found a null string is returned.
+ */
QString getIptcTagString(const char* iptcTagName, bool escapeCR=true) const;
- /** Set an Iptc tag content using a string. Return true if tag is set successfully. */
+ /** Set an Iptc tag content using a string. Return true if tag is set successfully.
+ */
bool setIptcTagString(const char *iptcTagName, const QString& value, bool setProgramName=true);
/** Get an Iptc tags content like a bytes array. Return an empty bytes array if Iptc
- tag cannot be found. */
+ tag cannot be found.
+ */
QByteArray getIptcTagData(const char *iptcTagName) const;
- /** Set an Iptc tag content using a bytes array. Return true if tag is set successfully. */
+ /** Set an Iptc tag content using a bytes array. Return true if tag is set successfully.
+ */
bool setIptcTagData(const char *iptcTagName, const QByteArray& data, bool setProgramName=true);
/** Remove the Exif tag 'exifTagName' from Exif metadata. Return true if tag is
- removed successfully. */
+ removed successfully.
+ */
bool removeExifTag(const char *exifTagName, bool setProgramName=true);
- /** Remove the Iptc tag 'iptcTagName' from Iptc metadata. Return true if tag is
- removed successfully. */
+ /** Remove the all instance of Iptc tags 'iptcTagName' from Iptc metadata. Return true if all
+ tags have been removed successfully.
+ */
bool removeIptcTag(const char *iptcTagName, bool setProgramName=true);
- /** Return the Exif Tag title or a null string. */
- static QString getExifTagTitle(const char *exifTagName);
+ /** Return the Exif Tag title or a null string.
+ */
+ QString getExifTagTitle(const char *exifTagName);
- /** Return the Exif Tag description or a null string. */
- static QString getExifTagDescription(const char *exifTagName);
+ /** Return the Exif Tag description or a null string.
+ */
+ QString getExifTagDescription(const char *exifTagName);
- /** Return the Iptc Tag title or a null string. */
- static QString getIptcTagTitle(const char *iptcTagName);
+ /** Return the Iptc Tag title or a null string.
+ */
+ QString getIptcTagTitle(const char *iptcTagName);
- /** Return the Iptc Tag description or a null string. */
- static QString getIptcTagDescription(const char *iptcTagName);
+ /** Return the Iptc Tag description or a null string.
+ */
+ QString getIptcTagDescription(const char *iptcTagName);
/** Return a map of Exif tags name/value found in metadata sorted by
Exif keys given by 'exifKeysFilter'.
-
+
'exifKeysFilter' is a QStringList of Exif keys.
For example, if you use the string list given below:
@@ -367,12 +432,12 @@ public:
if 'inverSelection' is false.
- not include "Iop", or "Thumbnail", or "Image", or "Photo" in the Exif tag keys
if 'inverSelection' is true.
- */
+ */
KExiv2::MetaDataMap getExifTagsDataList(const QStringList &exifKeysFilter, bool invertSelection=false);
/** Return a map of Iptc tags name/value found in metadata sorted by
Iptc keys given by 'iptcKeysFilter'.
-
+
'iptcKeysFilter' is a QStringList of Iptc keys.
For example, if you use the string list given below:
@@ -385,28 +450,23 @@ public:
if 'inverSelection' is false.
- not include "Envelope", or "Application2" in the Iptc tag keys
if 'inverSelection' is true.
- */
+ */
KExiv2::MetaDataMap getIptcTagsDataList(const QStringList &iptcKeysFilter, bool invertSelection=false);
//-- Advanced methods to convert and decode data -------------------------
/** This method convert 'number' like a rational value, returned in 'numerator' and
- 'denominator' parameters. Set the precision using 'rounding' parameter. */
+ 'denominator' parameters. Set the precision using 'rounding' parameter.
+ */
static void convertToRational(double number, long int* numerator,
long int* denominator, int rounding);
- /** Wrapper method to convert a Comments content to a QString. */
- static QString convertCommentValue(const Exiv2::Exifdatum &comment);
-
- /** Charset autodetection to convert a string to a QString. */
- static QString detectEncodingAndDecode(const std::string &value);
-
protected:
-
+
/** Re-implemente this method to set automatically the Program Name and Program Version
information in Exif and Iptc metadata if 'on' argument is true. This method is called by all methods witch
change tags in metadata. By default this method do nothing and return true.
-
+
In digiKam this method is re-implementated like this:
if (on)
@@ -415,37 +475,15 @@ protected:
QString software("digiKam");
return setImageProgramId(software, version);
}
-
+
return true;
- */
+ */
virtual bool setProgramId(bool on=true);
private:
- /** Return a reference to Exif metadata object in memory. */
- Exiv2::ExifData& exifMetaData();
-
- /** Return a reference to Iptc metadata object in memory. */
- Exiv2::IptcData& iptcMetaData();
-
- /** Set the Exif data using an Exiv2 byte array. Return true if Exif metadata
- have been changed in memory. */
- bool setExif(Exiv2::DataBuf const data);
-
- /** Set the Iptc data using an Exiv2 byte array. Return true if Iptc metadata
- have been changed in memory. */
- bool setIptc(Exiv2::DataBuf const data);
-
- /** Return a reference to comments string object in memory. */
- std::string& commentsMetaData();
-
- /** Return a standard C++ string copy of Comments container get from current image.
- Return a null standard string if there is no Comments metadata in memory. */
- std::string getCommentsString() const;
-
-private:
-
- /** Internal class to store private members. Used to improve binary compatibility */
+ /** Internal class to store private members. Used to improve binary compatibility
+ */
KExiv2Priv *d;
};
diff --git a/libkexiv2/libkexiv2/kexiv2private.cpp b/libkexiv2/libkexiv2/kexiv2private.cpp
new file mode 100644
index 0000000..a1b7a9f
--- /dev/null
+++ b/libkexiv2/libkexiv2/kexiv2private.cpp
@@ -0,0 +1,226 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2007-09-03
+ * Description : Exiv2 library interface for KDE
+ *
+ * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ * Copyright (C) 2006-2009 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
+ *
+ * NOTE: Do not use kdDebug() in this implementation because
+ * it will be multithreaded. Use qDebug() instead.
+ * See B.K.O #133026 for details.
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ============================================================ */
+
+// Local includes.
+
+#include "kexiv2private.h"
+
+namespace KExiv2Iface
+{
+
+KExiv2Priv::KExiv2Priv()
+{
+ imageComments = std::string();
+}
+
+KExiv2Priv::~KExiv2Priv()
+{
+#ifdef _XMP_SUPPORT_
+ // Fix memory leak if Exiv2 support XMP.
+ Exiv2::XmpParser::terminate();
+#endif // _XMP_SUPPORT_
+}
+
+bool KExiv2Priv::setExif(Exiv2::DataBuf const data)
+{
+ try
+ {
+ if (data.size_ != 0)
+ {
+#if (EXIV2_TEST_VERSION(0,17,91))
+ Exiv2::ExifParser::decode(exifMetadata, data.pData_, data.size_);
+ return (!exifMetadata.empty());
+#else
+ if (exifMetadata.load(data.pData_, data.size_) != 0)
+ return false;
+ else
+ return true;
+#endif
+ }
+ }
+ catch( Exiv2::Error &e )
+ {
+ if (!filePath.isEmpty())
+ qDebug ("From file %s", filePath.ascii());
+
+ printExiv2ExceptionError("Cannot set Exif data using Exiv2 ", e);
+ }
+
+ return false;
+}
+
+bool KExiv2Priv::setIptc(Exiv2::DataBuf const data)
+{
+ try
+ {
+ if (data.size_ != 0)
+ {
+#if (EXIV2_TEST_VERSION(0,17,91))
+ Exiv2::IptcParser::decode(iptcMetadata, data.pData_, data.size_);
+ return (!iptcMetadata.empty());
+#else
+ if (iptcMetadata.load(data.pData_, data.size_) != 0)
+ return false;
+ else
+ return true;
+#endif
+ }
+ }
+ catch( Exiv2::Error &e )
+ {
+ if (!filePath.isEmpty())
+ qDebug ("From file %s", filePath.ascii());
+
+ printExiv2ExceptionError("Cannot set Iptc data using Exiv2 ", e);
+ }
+
+ return false;
+}
+
+void KExiv2Priv::printExiv2ExceptionError(const QString& msg, Exiv2::Error& e)
+{
+ std::string s(e.what());
+ qDebug("%s (Error #%i: %s)", msg.ascii(), e.code(), s.c_str());
+}
+
+QString KExiv2Priv::convertCommentValue(const Exiv2::Exifdatum &exifDatum)
+{
+ try
+ {
+ std::string comment;
+ std::string charset;
+
+#if (EXIV2_TEST_VERSION(0,11,0))
+ comment = exifDatum.toString();
+#else
+ // workaround for bug in TIFF parser: CommentValue is loaded as DataValue
+ const Exiv2::Value &value = exifDatum.value();
+ Exiv2::byte *data = new Exiv2::byte[value.size()];
+ value.copy(data, Exiv2::invalidByteOrder);
+ Exiv2::CommentValue commentValue;
+ // this read method is hidden in CommentValue
+ static_cast<Exiv2::Value &>(commentValue).read(data, value.size(), Exiv2::invalidByteOrder);
+ comment = commentValue.toString();
+ delete [] data;
+#endif
+
+ // libexiv2 will prepend "charset=\"SomeCharset\" " if charset is specified
+ // Before conversion to QString, we must know the charset, so we stay with std::string for a while
+ if (comment.length() > 8 && comment.substr(0, 8) == "charset=")
+ {
+ // the prepended charset specification is followed by a blank
+ std::string::size_type pos = comment.find_first_of(' ');
+ if (pos != std::string::npos)
+ {
+ // extract string between the = and the blank
+ charset = comment.substr(8, pos-8);
+ // get the rest of the string after the charset specification
+ comment = comment.substr(pos+1);
+ }
+ }
+
+ if (charset == "\"Unicode\"")
+ {
+ // QString expects a null-terminated UCS-2 string.
+ // Is it already null terminated? In any case, add termination "\0\0" for safety.
+ comment.resize(comment.length() + 2, '\0');
+ return QString::fromUcs2((unsigned short *)comment.data());
+ }
+ else if (charset == "\"Jis\"")
+ {
+ QTextCodec *codec = QTextCodec::codecForName("JIS7");
+ return codec->toUnicode(comment.c_str());
+ }
+ else if (charset == "\"Ascii\"")
+ {
+ return QString::fromLatin1(comment.c_str());
+ }
+ else
+ {
+ return detectEncodingAndDecode(comment);
+ }
+ }
+ catch( Exiv2::Error &e )
+ {
+ printExiv2ExceptionError("Cannot convert Comment using Exiv2 ", e);
+ }
+
+ return QString();
+}
+
+QString KExiv2Priv::detectEncodingAndDecode(const std::string &value)
+{
+ // For charset autodetection, we could use sophisticated code
+ // (Mozilla chardet, KHTML's autodetection, QTextCodec::codecForContent),
+ // but that is probably too much.
+ // We check for UTF8, Local encoding and ASCII.
+
+ if (value.empty())
+ return QString();
+
+#if KDE_IS_VERSION(3,2,0)
+ if (KStringHandler::isUtf8(value.c_str()))
+ {
+ return QString::fromUtf8(value.c_str());
+ }
+#else
+ // anyone who is still running KDE 3.0 or 3.1 is missing so many features
+ // that he will have to accept this missing feature.
+ return QString::fromUtf8(value.c_str());
+#endif
+
+ // Utf8 has a pretty unique byte pattern.
+ // Thats not true for ASCII, it is not possible
+ // to reliably autodetect different ISO-8859 charsets.
+ // We try if QTextCodec can decide here, otherwise we use Latin1.
+ // Or use local8Bit as default?
+
+ // load QTextCodecs
+ QTextCodec *latin1Codec = QTextCodec::codecForName("iso8859-1");
+ //QTextCodec *utf8Codec = QTextCodec::codecForName("utf8");
+ QTextCodec *localCodec = QTextCodec::codecForLocale();
+
+ // make heuristic match
+ int latin1Score = latin1Codec->heuristicContentMatch(value.c_str(), value.length());
+ int localScore = localCodec->heuristicContentMatch(value.c_str(), value.length());
+
+ // convert string:
+ // Use whatever has the larger score, local or ASCII
+ if (localScore >= 0 && localScore >= latin1Score)
+ {
+ // workaround for bug #134999:
+ // The QLatin15Codec may crash if strlen < value.length()
+ int length = value.length();
+ if (localCodec->name() == QString::fromLatin1("ISO 8859-15"))
+ length = strlen(value.c_str());
+ return localCodec->toUnicode(value.c_str(), length);
+ }
+ else
+ return QString::fromLatin1(value.c_str());
+}
+
+} // NameSpace KExiv2Iface
diff --git a/libkexiv2/libkexiv2/kexiv2private.h b/libkexiv2/libkexiv2/kexiv2private.h
new file mode 100644
index 0000000..1df5f94
--- /dev/null
+++ b/libkexiv2/libkexiv2/kexiv2private.h
@@ -0,0 +1,131 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2007-09-03
+ * Description : Exiv2 library interface for KDE
+ *
+ * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ * Copyright (C) 2006-2009 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ============================================================ */
+
+#ifndef KEXIV2_PRIVATE_H
+#define KEXIV2_PRIVATE_H
+
+ // C++ includes.
+
+#include <cstdlib>
+#include <cstdio>
+#include <cassert>
+#include <cmath>
+#include <iostream>
+#include <iomanip>
+#include <string>
+
+// Qt includes.
+
+#include <qfile.h>
+#include <qsize.h>
+#include <qtextcodec.h>
+#include <qwmatrix.h>
+#include <qfileinfo.h>
+
+// KDE includes.
+
+#include <ktempfile.h>
+#include <kstringhandler.h>
+#include <kdeversion.h>
+
+// Exiv2 includes.
+
+// The pragmas are required to be able to catch exceptions thrown by libexiv2:
+// See http://gcc.gnu.org/wiki/Visibility, the section about c++ exceptions.
+// They are needed for all libexiv2 versions that do not care about visibility.
+#pragma GCC visibility push(default)
+#include <exiv2/error.hpp>
+#include <exiv2/image.hpp>
+#include <exiv2/jpgimage.hpp>
+#include <exiv2/datasets.hpp>
+#include <exiv2/tags.hpp>
+#include <exiv2/types.hpp>
+#include <exiv2/exif.hpp>
+#pragma GCC visibility pop
+
+// Check if Exiv2 support XMP
+
+#if (EXIV2_MAJOR_VERSION ==0 && EXIV2_MINOR_VERSION ==15 && EXIV2_PATCH_VERSION >=99) || \
+ (EXIV2_MAJOR_VERSION ==0 && EXIV2_MINOR_VERSION >15 ) || \
+ (EXIV2_MAJOR_VERSION >0)
+# define _XMP_SUPPORT_ 1
+#endif
+
+// Make sure an EXIV2_TEST_VERSION macro exists:
+
+#ifdef EXIV2_VERSION
+# ifndef EXIV2_TEST_VERSION
+# define EXIV2_TEST_VERSION(major,minor,patch) \
+ ( EXIV2_VERSION >= EXIV2_MAKE_VERSION(major,minor,patch) )
+# endif
+#else
+# define EXIV2_TEST_VERSION(major,minor,patch) (false)
+#endif
+
+namespace KExiv2Iface
+{
+
+class KExiv2Priv
+{
+public:
+
+ KExiv2Priv();
+ ~KExiv2Priv();
+
+ /** Set the Exif data using an Exiv2 byte array. Return true if Exif metadata
+ have been changed in memory.
+ */
+ bool setExif(Exiv2::DataBuf const data);
+
+ /** Set the Iptc data using an Exiv2 byte array. Return true if Iptc metadata
+ have been changed in memory.
+ */
+ bool setIptc(Exiv2::DataBuf const data);
+
+ /** Generic method to print the Exiv2 C++ Exception error message from 'e'.
+ 'msg' string is printed just before like debug header.
+ */
+ void printExiv2ExceptionError(const QString& msg, Exiv2::Error& e);
+
+ /** Wrapper method to convert a Comments content to a QString.
+ */
+ QString convertCommentValue(const Exiv2::Exifdatum &exifDatum);
+
+ /** Charset autodetection to convert a string to a QString.
+ */
+ QString detectEncodingAndDecode(const std::string &value);
+
+public:
+
+ QString filePath;
+
+ std::string imageComments;
+
+ Exiv2::ExifData exifMetadata;
+
+ Exiv2::IptcData iptcMetadata;
+};
+
+} // NameSpace KExiv2Iface
+
+#endif /* KEXIV2_PRIVATE_H */
diff --git a/libkexiv2/libkexiv2/version.h b/libkexiv2/libkexiv2/version.h
index fa071f9..10cf082 100644
--- a/libkexiv2/libkexiv2/version.h
+++ b/libkexiv2/libkexiv2/version.h
@@ -6,7 +6,7 @@
* Date : 2007-02-06
* Description : Exiv2 library interface for KDE
*
- * Copyright (C) 2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ * Copyright (C) 2007-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
@@ -23,9 +23,9 @@
#ifndef KEXIV2_VERSION_H
#define KEXIV2_VERSION_H
-static const char kexiv2_version[] = "0.1.7";
+static const char kexiv2_version[] = "0.1.9";
-#define KEXIV2_VERSION 0x000107
+#define KEXIV2_VERSION 0x000109
#endif // KEXIV2_VERSION_H