Index: libkexiv2/kexiv2comments.cpp =================================================================== --- libkexiv2/kexiv2comments.cpp (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ libkexiv2/kexiv2comments.cpp (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -10,10 +10,6 @@ * Copyright (C) 2006-2008 by Gilles Caulier * Copyright (C) 2006-2008 by Marcel Wiesweg * - * 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; @@ -47,7 +43,8 @@ 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()); + kDebug(51003) << "Cannot check Comment access mode using Exiv2 (Error #" + << e.code() << ": " << s.c_str() << ")" << endl; } return false; Index: libkexiv2/kexiv2gps.cpp =================================================================== --- libkexiv2/kexiv2gps.cpp (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ libkexiv2/kexiv2gps.cpp (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -10,20 +10,16 @@ * Copyright (C) 2006-2008 by Gilles Caulier * Copyright (C) 2006-2008 by Marcel Wiesweg * - * 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. @@ -185,7 +181,7 @@ Exiv2::ExifKey exifKey3("Exif.GPSInfo.GPSAltitude"); Exiv2::ExifData exifData(d->exifMetadata); Exiv2::ExifData::iterator it = exifData.findKey(exifKey3); - if (it != exifData.end()) + if (it != exifData.end() && (*it).count()) { num = (double)((*it).toRational(0).first); den = (double)((*it).toRational(0).second); @@ -226,7 +222,7 @@ Exiv2::ExifKey exifKey("Exif.GPSInfo.GPSLatitude"); Exiv2::ExifData exifData(d->exifMetadata); Exiv2::ExifData::iterator it = exifData.findKey(exifKey); - if (it != exifData.end()) + if (it != exifData.end() && (*it).count() == 3) { return convertToGPSCoordinateString((*it).toRational(0).first, (*it).toRational(0).second, (*it).toRational(1).first, (*it).toRational(1).second, @@ -258,7 +254,7 @@ Exiv2::ExifKey exifKey("Exif.GPSInfo.GPSLongitude"); Exiv2::ExifData exifData(d->exifMetadata); Exiv2::ExifData::iterator it = exifData.findKey(exifKey); - if (it != exifData.end()) + if (it != exifData.end() && (*it).count() == 3) { return convertToGPSCoordinateString((*it).toRational(0).first, (*it).toRational(0).second, (*it).toRational(1).first, (*it).toRational(1).second, @@ -276,7 +272,6 @@ return QString(); } - bool KExiv2::setGPSInfo(double altitude, double latitude, double longitude, bool setProgramName) const { if (!setProgramId(setProgramName)) @@ -425,7 +420,7 @@ // 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"); + else value->read("1"); d->exifMetadata.add(Exiv2::ExifKey("Exif.GPSInfo.GPSAltitudeRef"), value.get()); // And the actual altitude, as absolute value.. @@ -477,7 +472,7 @@ return false; try - { + { QStringList gpsTagsKeys; for (Exiv2::ExifData::iterator it = d->exifMetadata.begin(); @@ -489,7 +484,7 @@ gpsTagsKeys.append(key); } - for(QStringList::Iterator it2 = gpsTagsKeys.begin(); it2 != gpsTagsKeys.end(); ++it2) + for(QStringList::const_iterator it2 = gpsTagsKeys.begin(); it2 != gpsTagsKeys.end(); ++it2) { Exiv2::ExifKey gpsKey((*it2).toAscii().constData()); Exiv2::ExifData::iterator it3 = d->exifMetadata.findKey(gpsKey); @@ -630,7 +625,6 @@ } } - QString KExiv2::convertToGPSCoordinateString(long int numeratorDegrees, long int denominatorDegrees, long int numeratorMinutes, long int denominatorMinutes, long int numeratorSeconds, long int denominatorSeconds, @@ -878,6 +872,4 @@ *seconds = coordinate; } - - } // NameSpace KExiv2Iface Index: libkexiv2/kexiv2private.cpp =================================================================== --- libkexiv2/kexiv2private.cpp (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ libkexiv2/kexiv2private.cpp (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -9,10 +9,6 @@ * Copyright (C) 2006-2008 by Gilles Caulier * Copyright (C) 2006-2008 by Marcel Wiesweg * - * 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; @@ -35,24 +31,17 @@ KExiv2Priv::KExiv2Priv() { imageComments = std::string(); - -#ifdef _XMP_SUPPORT_ - Exiv2::XmpProperties::registerNs("http://www.microsoft.com/Photo/", "MicrosoftPhoto"); -#endif } KExiv2Priv::~KExiv2Priv() { - // Fix memory leak if Exiv2 support XMP. -#ifdef _XMP_SUPPORT_ - Exiv2::XmpParser::terminate(); -#endif // _XMP_SUPPORT_ } void KExiv2Priv::printExiv2ExceptionError(const QString& msg, Exiv2::Error& e) { std::string s(e.what()); - qDebug("%s (Error #%i: %s)", msg.toAscii().constData(), e.code(), s.c_str()); + kDebug(51003) << msg.toAscii().constData() << " (Error #" + << e.code() << ": " << s.c_str() << endl; } QString KExiv2Priv::convertCommentValue(const Exiv2::Exifdatum &exifDatum) Index: libkexiv2/kexiv2exif.cpp =================================================================== --- libkexiv2/kexiv2exif.cpp (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ libkexiv2/kexiv2exif.cpp (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -10,20 +10,16 @@ * Copyright (C) 2006-2008 by Gilles Caulier * Copyright (C) 2006-2008 by Marcel Wiesweg * - * 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. @@ -47,7 +43,8 @@ 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()); + kDebug(51003) << "Cannot check Exif access mode using Exiv2 (Error #" + << e.code() << ": " << s.c_str() << ")" << endl; } return false; @@ -106,7 +103,7 @@ catch( Exiv2::Error &e ) { if (!d->filePath.isEmpty()) - qDebug ("From file %s", d->filePath.toAscii().constData()); + kDebug(51003) << "From file " << d->filePath.toAscii().constData() << endl; d->printExiv2ExceptionError("Cannot get Exif data using Exiv2 ", e); } @@ -134,7 +131,7 @@ catch( Exiv2::Error &e ) { if (!d->filePath.isEmpty()) - qDebug ("From file %s", d->filePath.toAscii().constData()); + kDebug(51003) << "From file " << d->filePath.toAscii().constData() << endl; d->printExiv2ExceptionError("Cannot set Exif data using Exiv2 ", e); } @@ -618,11 +615,16 @@ case Exiv2::unsignedLong: case Exiv2::signedShort: case Exiv2::signedLong: - return QVariant((int)it->toLong(component)); + if (it->count() > component) + return QVariant((int)it->toLong(component)); + else + return QVariant(QVariant::Int); case Exiv2::unsignedRational: case Exiv2::signedRational: if (rationalAsListOfInts) { + if (it->count() <= component) + return QVariant(QVariant::List); QList list; list << (*it).toRational(component).first; list << (*it).toRational(component).second; @@ -630,6 +632,8 @@ } else { + if (it->count() <= component) + return QVariant(QVariant::Double); // prefer double precision double num = (*it).toRational(component).first; double den = (*it).toRational(component).second; @@ -743,7 +747,7 @@ if (it != exifData.end()) { long orientation = it->toLong(); - qDebug("Exif Thumbnail Orientation: %i", (int)orientation); + kDebug(51003) << "Exif Thumbnail Orientation: " << (int)orientation << endl; rotateExifQImage(thumbnail, (ImageOrientation)orientation); } @@ -820,7 +824,7 @@ thumbFile.setAutoRemove(true); thumbFile.open(); thumb.save(thumbFile.fileName(), "JPEG"); - qDebug("Thumbnail temp file: %s", thumbFile.fileName().toAscii().data()); + kDebug(51003) << "Thumbnail temp file: " << thumbFile.fileName().toAscii().data() << endl; const std::string &fileName((const char*)(QFile::encodeName(thumbFile.fileName()))); #if (EXIV2_TEST_VERSION(0,17,91)) Index: libkexiv2/kexiv2.cpp =================================================================== --- libkexiv2/kexiv2.cpp (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ libkexiv2/kexiv2.cpp (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -9,10 +9,6 @@ * Copyright (C) 2006-2008 by Gilles Caulier * Copyright (C) 2006-2008 by Marcel Wiesweg * - * 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; @@ -83,6 +79,25 @@ //-- Statics methods ---------------------------------------------- +bool KExiv2::initializeExiv2() +{ +#ifdef _XMP_SUPPORT_ + return (Exiv2::XmpParser::initialize()); +#endif // _XMP_SUPPORT_ + + return true; +} + +bool KExiv2::cleanupExiv2() +{ + // Fix memory leak if Exiv2 support XMP. +#ifdef _XMP_SUPPORT_ + Exiv2::XmpParser::terminate(); +#endif // _XMP_SUPPORT_ + + return true; +} + bool KExiv2::supportXmp() { #ifdef _XMP_SUPPORT_ @@ -92,13 +107,38 @@ #endif // _XMP_SUPPORT_ } -bool KExiv2::supportTiffWritting() +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; + 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; -#endif } QString KExiv2::Exiv2Version() @@ -141,18 +181,59 @@ //-- General methods ---------------------------------------------- +bool KExiv2::load(const QByteArray& imgData) const +{ + if (imgData.isEmpty()) + return false; + + try + { + Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open((Exiv2::byte*)imgData.data(), imgData.size()); + + d->filePath = QString(); + image->readMetadata(); + + // Image comments --------------------------------- + + d->imageComments = image->comment(); + + // Exif metadata ---------------------------------- + + d->exifMetadata = image->exifData(); + + // Iptc metadata ---------------------------------- + + d->iptcMetadata = image->iptcData(); + +#ifdef _XMP_SUPPORT_ + + // Xmp metadata ----------------------------------- + + d->xmpMetadata = image->xmpData(); + +#endif // _XMP_SUPPORT_ + + return true; + } + catch( Exiv2::Error &e ) + { + d->printExiv2ExceptionError("Cannot load metadata using Exiv2 ", e); + } + + return false; +} + bool KExiv2::load(const QString& filePath) const { QFileInfo finfo(filePath); if (filePath.isEmpty() || !finfo.isReadable()) { - qDebug("File '%s' is not readable.", finfo.fileName().toAscii().constData()); + kDebug(51003) << "File '" << finfo.fileName().toAscii().constData() << "' is not readable." << endl; return false; } try { - Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open((const char*) (QFile::encodeName(filePath))); @@ -199,15 +280,24 @@ QFileInfo dinfo(finfo.path()); if (!finfo.isWritable()) { - qDebug("File '%s' is read-only. Metadata not saved.", finfo.fileName().toAscii().constData()); + kDebug(51003) << "File '" << finfo.fileName().toAscii().constData() << "' is read-only. Metadata not saved." << endl; return false; } if (!dinfo.isWritable()) { - qDebug("Dir '%s' is read-only. Metadata not saved.", dinfo.filePath().toAscii().constData()); + kDebug(51003) << "Dir '" << dinfo.filePath().toAscii().constData() << "' is read-only. Metadata not saved." << endl; return false; } + // TIFF/EP Raw file based supported by Exiv2 0.18 are : DNG, NEF, PEF. + QString rawTiffBasedNotSupported("3fr arw cr2 dcr erf k25 kdc mos orf raw sr2 srf"); + if (rawTiffBasedNotSupported.contains(finfo.suffix().toUpper())) + { + kDebug(51003) << "'" << dinfo.filePath().toAscii().constData() + << "' is TIFF based RAW file not yet supported. Metadata not saved." << endl; + return false; + } + try { Exiv2::AccessMode mode; @@ -235,11 +325,12 @@ { if (image->mimeType() == "image/tiff") { + Exiv2::ExifData exif = image->exifData(); + QStringList untouchedTags; + // 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"; Index: libkexiv2/kexiv2iptc.cpp =================================================================== --- libkexiv2/kexiv2iptc.cpp (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ libkexiv2/kexiv2iptc.cpp (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -10,20 +10,16 @@ * Copyright (C) 2006-2008 by Gilles Caulier * Copyright (C) 2006-2008 by Marcel Wiesweg * - * 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. @@ -47,7 +43,8 @@ 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()); + kDebug(51003) << "Cannot check Iptc access mode using Exiv2 (Error #" + << e.code() << ": " << s.c_str() << ")" << endl; } return false; @@ -87,7 +84,7 @@ #if (EXIV2_TEST_VERSION(0,10,0)) c2 = Exiv2::Photoshop::setIptcIrb(0, 0, iptc); #else - qDebug("Exiv2 version is to old. Cannot add Irb header to Iptc metadata"); + kDebug(51003) << "Exiv2 version is to old. Cannot add Irb header to Iptc metadata" << endl; return QByteArray(); #endif } @@ -108,7 +105,7 @@ catch( Exiv2::Error &e ) { if (!d->filePath.isEmpty()) - qDebug ("From file %s", d->filePath.toAscii().constData()); + kDebug(51003) << "From file " << d->filePath.toAscii().constData() << endl; d->printExiv2ExceptionError("Cannot get Iptc data using Exiv2 ",e); } @@ -136,7 +133,7 @@ catch( Exiv2::Error &e ) { if (!d->filePath.isEmpty()) - qDebug ("From file %s", d->filePath.toAscii().constData()); + kDebug(51003) << "From file " << d->filePath.toAscii().constData() << endl; d->printExiv2ExceptionError("Cannot set Iptc data using Exiv2 ", e); } @@ -315,7 +312,7 @@ catch( Exiv2::Error &e ) { d->printExiv2ExceptionError(QString("Cannot find Iptc key '%1' into image using Exiv2 ") - .arg(iptcTagName), e); + .arg(iptcTagName), e); } return QByteArray(); @@ -343,7 +340,7 @@ catch( Exiv2::Error &e ) { d->printExiv2ExceptionError(QString("Cannot find Iptc key '%1' into image using Exiv2 ") - .arg(iptcTagName), e); + .arg(iptcTagName), e); } return QString(); @@ -397,7 +394,7 @@ catch( Exiv2::Error &e ) { d->printExiv2ExceptionError(QString("Cannot find Iptc key '%1' into image using Exiv2 ") - .arg(iptcTagName), e); + .arg(iptcTagName), e); } return QStringList(); @@ -415,8 +412,8 @@ QStringList oldvals = oldValues; QStringList newvals = newValues; - qDebug() << d->filePath.toAscii().constData() << " : " << iptcTagName - << " => " << newvals.join(",").toAscii().constData() << endl; + kDebug(51003) << d->filePath.toAscii().constData() << " : " << iptcTagName + << " => " << newvals.join(",").toAscii().constData() << endl; // Remove all old values. Exiv2::IptcData iptcData(d->iptcMetadata); @@ -457,7 +454,7 @@ catch( Exiv2::Error &e ) { d->printExiv2ExceptionError(QString("Cannot set Iptc key '%1' into image using Exiv2 ") - .arg(iptcTagName), e); + .arg(iptcTagName), e); } return false; @@ -505,7 +502,8 @@ QStringList oldkeys = oldKeywords; QStringList newkeys = newKeywords; - qDebug("%s ==> Iptc Keywords: %s", d->filePath.toAscii().constData(), newkeys.join(",").toAscii().constData()); + kDebug(51003) << d->filePath.toAscii().constData() + << " ==> Iptc Keywords: " << newkeys.join(",").toAscii().constData() << endl; // Remove all old keywords. Exiv2::IptcData iptcData(d->iptcMetadata); @@ -518,8 +516,7 @@ // Also remove new keywords to avoid duplicates. They will be added again below. if ( key == QString("Iptc.Application2.Keywords") && - (oldKeywords.contains(val) || newKeywords.contains(val)) - ) + (oldKeywords.contains(val) || newKeywords.contains(val)) ) it = iptcData.erase(it); else ++it; Index: libkexiv2/kexiv2private.h =================================================================== --- libkexiv2/kexiv2private.h (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ libkexiv2/kexiv2private.h (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -41,7 +41,6 @@ #include #include #include -#include // KDE includes. @@ -49,6 +48,7 @@ #include #include #include +#include // Exiv2 includes. Index: libkexiv2/kexiv2image.cpp =================================================================== --- libkexiv2/kexiv2image.cpp (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ libkexiv2/kexiv2image.cpp (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -10,20 +10,16 @@ * Copyright (C) 2006-2008 by Gilles Caulier * Copyright (C) 2006-2008 by Marcel Wiesweg * - * 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. @@ -236,7 +232,7 @@ if (it != exifData.end()) { orientation = it->toLong(); - qDebug() << "Orientation => Exif.MinoltaCs7D.Rotation => " << (int)orientation << endl; + kDebug(51003) << "Orientation => Exif.MinoltaCs7D.Rotation => " << (int)orientation << endl; switch(orientation) { case 76: @@ -255,7 +251,7 @@ if (it != exifData.end()) { orientation = it->toLong(); - qDebug() << "Orientation => Exif.MinoltaCs5D.Rotation => " << (int)orientation << endl; + kDebug(51003) << "Orientation => Exif.MinoltaCs5D.Rotation => " << (int)orientation << endl; switch(orientation) { case 76: @@ -276,7 +272,7 @@ if (it != exifData.end()) { orientation = it->toLong(); - qDebug() << "Orientation => Exif.Image.Orientation => " << (int)orientation << endl; + kDebug(51003) << "Orientation => Exif.Image.Orientation => " << (int)orientation << endl; return (ImageOrientation)orientation; } @@ -291,7 +287,7 @@ orientation = str.toLong(&ok); if (ok) { - qDebug() << "Orientation => Xmp.tiff.Orientation => " << (int)orientation << endl; + kDebug(51003) << "Orientation => Xmp.tiff.Orientation => " << (int)orientation << endl; return (ImageOrientation)orientation; } } @@ -316,14 +312,14 @@ { if (orientation < ORIENTATION_UNSPECIFIED || orientation > ORIENTATION_ROT_270) { - qDebug("Image orientation value is not correct!"); + kDebug(51003) << "Image orientation value is not correct!" << endl; return false; } // Set Exif values. d->exifMetadata["Exif.Image.Orientation"] = static_cast(orientation); - qDebug() << "Exif.Image.Orientation tag set to: " << (int)orientation; + kDebug(51003) << "Exif.Image.Orientation tag set to: " << (int)orientation << endl; // Set Xmp values. @@ -345,7 +341,7 @@ if (it != d->exifMetadata.end()) { d->exifMetadata.erase(it); - qDebug("Removing Exif.MinoltaCs7D.Rotation tag"); + kDebug(51003) << "Removing Exif.MinoltaCs7D.Rotation tag" << endl; } Exiv2::ExifKey minoltaKey2("Exif.MinoltaCs5D.Rotation"); @@ -353,7 +349,7 @@ if (it != d->exifMetadata.end()) { d->exifMetadata.erase(it); - qDebug("Removing Exif.MinoltaCs5D.Rotation tag"); + kDebug(51003) << "Removing Exif.MinoltaCs5D.Rotation tag" << endl; } return true; @@ -485,7 +481,7 @@ QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { - qDebug() << "DateTime => Exif.Photo.DateTimeOriginal => " << dateTime << endl; + kDebug(51003) << "DateTime => Exif.Photo.DateTimeOriginal => " << dateTime << endl; return dateTime; } } @@ -498,7 +494,7 @@ QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { - qDebug() << "DateTime => Exif.Photo.DateTimeDigitized => " << dateTime << endl; + kDebug(51003) << "DateTime => Exif.Photo.DateTimeDigitized => " << dateTime << endl; return dateTime; } } @@ -511,7 +507,7 @@ QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { - qDebug() << "DateTime => Exif.Image.DateTime => " << dateTime << endl; + kDebug(51003) << "DateTime => Exif.Image.DateTime => " << dateTime << endl; return dateTime; } } @@ -533,7 +529,7 @@ QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { - qDebug() << "DateTime => Xmp.exif.DateTimeOriginal => " << dateTime << endl; + kDebug(51003) << "DateTime => Xmp.exif.DateTimeOriginal => " << dateTime << endl; return dateTime; } } @@ -546,7 +542,7 @@ QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { - qDebug() << "DateTime => Xmp.exif.DateTimeDigitized => " << dateTime << endl; + kDebug(51003) << "DateTime => Xmp.exif.DateTimeDigitized => " << dateTime << endl; return dateTime; } } @@ -559,7 +555,7 @@ QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { - qDebug() << "DateTime => Xmp.photoshop.DateCreated => " << dateTime << endl; + kDebug(51003) << "DateTime => Xmp.photoshop.DateCreated => " << dateTime << endl; return dateTime; } } @@ -572,10 +568,10 @@ QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { - qDebug() << "DateTime => Xmp.xmp.CreateDate => " << dateTime << endl; + kDebug(51003) << "DateTime => Xmp.xmp.CreateDate => " << dateTime << endl; return dateTime; } - } + } } { Exiv2::XmpKey key("Xmp.tiff.DateTime"); @@ -585,10 +581,10 @@ QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { - qDebug() << "DateTime => Xmp.tiff.DateTime => " << dateTime << endl; + kDebug(51003) << "DateTime => Xmp.tiff.DateTime => " << dateTime << endl; return dateTime; } - } + } } { Exiv2::XmpKey key("Xmp.xmp.ModifyDate"); @@ -598,10 +594,10 @@ QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { - qDebug() << "DateTime => Xmp.xmp.ModifyDate => " << dateTime << endl; + kDebug(51003) << "DateTime => Xmp.xmp.ModifyDate => " << dateTime << endl; return dateTime; } - } + } } { Exiv2::XmpKey key("Xmp.xmp.MetadataDate"); @@ -611,10 +607,10 @@ QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { - qDebug() << "DateTime => Xmp.xmp.MetadataDate => " << dateTime << endl; + kDebug(51003) << "DateTime => Xmp.xmp.MetadataDate => " << dateTime << endl; return dateTime; } - } + } } } @@ -643,7 +639,7 @@ QDateTime dateTime = QDateTime(date, time); if (dateTime.isValid()) { - qDebug() << "DateTime => Iptc.Application2.DateCreated => " << dateTime << endl; + kDebug(51003) << "DateTime => Iptc.Application2.DateCreated => " << dateTime << endl; return dateTime; } } @@ -666,7 +662,7 @@ QDateTime dateTime = QDateTime(date, time); if (dateTime.isValid()) { - qDebug() << "DateTime => Iptc.Application2.DigitizationDate => " << dateTime << endl; + kDebug(51003) << "DateTime => Iptc.Application2.DigitizationDate => " << dateTime << endl; return dateTime; } } @@ -708,7 +704,7 @@ // In second we write date & time into Xmp. - const std::string &xmpdatetime(dateTime.toString(QString("yyyy:MM:dd hh:mm:ss")).toAscii().constData()); + const std::string &xmpdatetime(dateTime.toString(Qt::ISODate).toAscii().constData()); Exiv2::Value::AutoPtr xmpTxtVal = Exiv2::Value::create(Exiv2::xmpText); xmpTxtVal->read(xmpdatetime); @@ -769,7 +765,7 @@ if (dateTime.isValid()) { - // qDebug("DateTime (Exif digitalized): %s", dateTime.toString().toAscii().constData()); + kDebug(51003) << "DateTime (Exif digitalized): " << dateTime.toString().toAscii().constData() << endl; return dateTime; } } @@ -804,7 +800,7 @@ if (dateTime.isValid()) { - //qDebug("Date (IPTC digitalized): %s", dateTime.toString().toAscii().constData()); + kDebug(51003) << "Date (IPTC digitalized): " << dateTime.toString().toAscii().constData() << endl; return dateTime; } } @@ -857,9 +853,8 @@ // A little bit compressed preview jpeg image to limit IPTC size. preview.save(previewFile.fileName(), "JPEG"); - qDebug("JPEG image preview size: (%i x %i) pixels - %i bytes", - preview.width(), preview.height(), - (int)previewFile.size()); + kDebug(51003) << "JPEG image preview size: (" << preview.width() << " x " + << preview.height() << ") pixels - " << (int)previewFile.size() << " bytes" << endl; QByteArray data; data.resize(previewFile.size()); Index: libkexiv2/CMakeLists.txt =================================================================== --- libkexiv2/CMakeLists.txt (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ libkexiv2/CMakeLists.txt (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -1,7 +1,9 @@ -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}") INCLUDE_DIRECTORIES(${EXIV2_INCLUDE_DIR}) +ADD_DEFINITIONS(${EXIV2_DEFINITIONS}) +ADD_DEFINITIONS(${KDE4_ENABLE_EXCEPTIONS}) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/version.h) # This was used to enable catching of exceptions thrown by libexiv2. @@ -20,7 +22,7 @@ KDE4_ADD_LIBRARY(kexiv2 SHARED ${kexiv2_LIB_SRCS}) -TARGET_LINK_LIBRARIES(kexiv2 ${KDE4_KDECORE_LIBS} ${QT_QTGUI_LIBRARY} exiv2) +TARGET_LINK_LIBRARIES(kexiv2 ${KDE4_KDECORE_LIBS} ${QT_QTGUI_LIBRARY} ${EXIV2_LIBRARIES}) IF( WIN32 ) TARGET_LINK_LIBRARIES( kexiv2 ${EXPAT_LIBRARIES} ) Index: libkexiv2/kexiv2.h =================================================================== --- libkexiv2/kexiv2.h (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ libkexiv2/kexiv2.h (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -118,13 +118,27 @@ //-- STATICS methods ---------------------------------------------- //----------------------------------------------------------------- + /** Return true if Exiv2 library initialization is done properlly. + This method must be call before to use multithreading with libkexiv2. + It initialize several non re-entrancy code from Adobe XMP SDK + See B.K.O #166424 for details. + */ + static bool initializeExiv2(); + + /** Return true if Exiv2 library memory allocations are cleaned properlly. + This method must be call after to use multithreading with libkexiv2. + It cleanup memory used by Adobe XMP SDK + See B.K.O #166424 for details. + */ + static bool cleanupExiv2(); + /** Return true if library can handle Xmp metadata */ static bool supportXmp(); - /** Return true if library can writte metadata to TIFF/DNG files + /** Return true if library can writte metadata to typeMime file format. */ - static bool supportTiffWritting(); + static bool supportMetadataWritting(const QString& typeMime); /** Return a string version of Exiv2 release in format "major.minor.patch" */ @@ -142,6 +156,11 @@ //-- GENERAL methods ---------------------------------------------- //----------------------------------------------------------------- + /** Load all metadata (Exif, Iptc, Xmp, and JFIF Comments) from a byte array. + Return true if metadata have been loaded successfully from image data. + */ + bool load(const QByteArray& imgData) const; + /** Load all metadata (Exif, Iptc, Xmp, and JFIF Comments) from a picture (JPEG, RAW, TIFF, PNG, DNG, etc...). Return true if metadata have been loaded successfully from file. */ Index: libkexiv2/kexiv2xmp.cpp =================================================================== --- libkexiv2/kexiv2xmp.cpp (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ libkexiv2/kexiv2xmp.cpp (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -10,20 +10,16 @@ * Copyright (C) 2006-2008 by Gilles Caulier * Copyright (C) 2006-2008 by Marcel Wiesweg * - * 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. @@ -48,7 +44,8 @@ catch( Exiv2::Error &e ) { std::string s(e.what()); - qDebug("%s (Error #%i: %s)", "Cannot check Xmp access mode using Exiv2 ", e.code(), s.c_str()); + kDebug(51003) << "Cannot check Xmp access mode using Exiv2 (Error #" + << e.code() << ": " << s.c_str() << ")" << endl; } return false; @@ -110,8 +107,8 @@ catch( Exiv2::Error &e ) { if (!d->filePath.isEmpty()) - qDebug ("From file %s", d->filePath.toAscii().constData()); + d->printExiv2ExceptionError("Cannot get Xmp data using Exiv2 ", e); } @@ -140,7 +137,7 @@ catch( Exiv2::Error &e ) { if (!d->filePath.isEmpty()) - qDebug ("From file %s", d->filePath.toAscii().constData()); + kDebug(51003) << "From file " << d->filePath.toAscii().constData() << endl; d->printExiv2ExceptionError("Cannot set Xmp data using Exiv2 ", e); } @@ -299,7 +296,7 @@ catch( Exiv2::Error &e ) { d->printExiv2ExceptionError(QString("Cannot find Xmp key '%1' into image using Exiv2 ") - .arg(xmpTagName), e); + .arg(xmpTagName), e); } #endif // _XMP_SUPPORT_ @@ -355,7 +352,7 @@ QString text = QString::fromUtf8(it2->second.c_str()); if (escapeCR) text.replace("\n", " "); - + map.insert(lang, text); } @@ -366,7 +363,7 @@ catch( Exiv2::Error &e ) { d->printExiv2ExceptionError(QString("Cannot find Xmp key '%1' into image using Exiv2 ") - .arg(xmpTagName), e); + .arg(xmpTagName), e); } #endif // _XMP_SUPPORT_ @@ -388,7 +385,7 @@ removeXmpTag(xmpTagName); Exiv2::Value::AutoPtr xmpTxtVal = Exiv2::Value::create(Exiv2::langAlt); - + for (AltLangMap::const_iterator it = values.begin(); it != values.end(); ++it) { QString lang = it.key(); @@ -435,7 +432,7 @@ { if (escapeCR) tagValue.replace("\n", " "); - + return tagValue; } } @@ -445,7 +442,7 @@ catch( Exiv2::Error &e ) { d->printExiv2ExceptionError(QString("Cannot find Xmp key '%1' into image using Exiv2 ") - .arg(xmpTagName), e); + .arg(xmpTagName), e); } #endif // _XMP_SUPPORT_ @@ -484,7 +481,7 @@ { const std::string &val((*it).toUtf8().constData()); xmpTxtVal->read(val); - qDebug() << *it << endl; + kDebug(51003) << *it << endl; } } } @@ -524,13 +521,13 @@ std::ostringstream os; os << it->toString(i); QString seqValue = QString::fromUtf8(os.str().c_str()); - + if (escapeCR) seqValue.replace("\n", " "); seq.append(seqValue); } - qDebug() << "XMP String Seq (" << xmpTagName << "): " << seq << endl; + kDebug(51003) << "XMP String Seq (" << xmpTagName << "): " << seq << endl; return seq; } @@ -539,7 +536,7 @@ catch( Exiv2::Error &e ) { d->printExiv2ExceptionError(QString("Cannot find Xmp key '%1' into image using Exiv2 ") - .arg(xmpTagName), e); + .arg(xmpTagName), e); } #endif // _XMP_SUPPORT_ @@ -560,7 +557,7 @@ QStringList list = seq; Exiv2::Value::AutoPtr xmpTxtSeq = Exiv2::Value::create(Exiv2::xmpSeq); - for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) + for (QStringList::const_iterator it = list.begin(); it != list.end(); ++it ) { const std::string &txt((*it).toUtf8().constData()); xmpTxtSeq->read(txt); @@ -598,7 +595,7 @@ std::ostringstream os; os << it->toString(i); QString bagValue = QString::fromUtf8(os.str().c_str()); - + if (escapeCR) bagValue.replace("\n", " "); @@ -612,7 +609,7 @@ catch( Exiv2::Error &e ) { d->printExiv2ExceptionError(QString("Cannot find Xmp key '%1' into image using Exiv2 ") - .arg(xmpTagName), e); + .arg(xmpTagName), e); } #endif // _XMP_SUPPORT_ @@ -633,7 +630,7 @@ QStringList list = bag; Exiv2::Value::AutoPtr xmpTxtBag = Exiv2::Value::create(Exiv2::xmpBag); - for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) + for (QStringList::const_iterator it = list.begin(); it != list.end(); ++it ) { const std::string &txt((*it).toUtf8().constData()); xmpTxtBag->read(txt); @@ -748,7 +745,7 @@ catch( Exiv2::Error &e ) { d->printExiv2ExceptionError(QString("Cannot find Xmp key '%1' into image using Exiv2 ") - .arg(xmpTagName), e); + .arg(xmpTagName), e); } #endif // _XMP_SUPPORT_ @@ -797,7 +794,7 @@ catch( Exiv2::Error &e ) { d->printExiv2ExceptionError("Cannot remove Xmp tag using Exiv2 ", e); - } + } #endif // _XMP_SUPPORT_ @@ -818,9 +815,9 @@ QStringList oldkeys = getXmpKeywords(); QStringList newkeys = newKeywords; - + // Create a list of keywords including old one witch already exists. - for (QStringList::Iterator it = oldkeys.begin(); it != oldkeys.end(); ++it ) + for (QStringList::const_iterator it = oldkeys.begin(); it != oldkeys.end(); ++it ) { if (!newkeys.contains(*it)) newkeys.append(*it); @@ -848,9 +845,9 @@ QStringList oldSubCat = getXmpSubCategories(); QStringList newSubCat = newSubCategories; - + // Create a list of sub-categories including old one witch already exists. - for (QStringList::Iterator it = oldSubCat.begin(); it != oldSubCat.end(); ++it ) + for (QStringList::const_iterator it = oldSubCat.begin(); it != oldSubCat.end(); ++it ) { if (!newSubCat.contains(*it)) newSubCat.append(*it); @@ -878,9 +875,9 @@ QStringList oldSubjectCodes = getXmpSubjects(); QStringList newSubjectCodes = newSubjects; - + // Create a list of sub-categories including old one witch already exists. - for (QStringList::Iterator it = oldSubjectCodes.begin(); it != oldSubjectCodes.end(); ++it ) + for (QStringList::const_iterator it = oldSubjectCodes.begin(); it != oldSubjectCodes.end(); ++it ) { if (!newSubjectCodes.contains(*it)) newSubjectCodes.append(*it); Index: TODO =================================================================== --- TODO (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ TODO (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -1,3 +1,3 @@ - Extract GPS info from XMP tags. -- Exif/Iptc => Xmp synchrosization. +- Exif/Iptc => Xmp synchronization. - Xmp side-car file support. Index: NEWS =================================================================== --- NEWS (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ NEWS (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -1,9 +1,27 @@ -0.2.0 +0.4.0 - + +- Use kDebug(51003) instead qDebug() + +0.3.0 - Released with KDE 4.1.2 ------------------------------------------------------------------------ + +- API changed: Added 2 new static methods to init and clear non re-entrant Adobe XMP + SDK code from Exiv2 core. This code must be called before and after + all multithreaded operations with KExiv2. + * initializeExiv2(). + * cleanupExiv2(). + Added a new method to load image data from a byte array. + +Bugs fixed from B.K.O (http://bugs.kde.org): +001 ==> 166424: Crash when editing Caption with Digikam4 SVN. + +0.2.0 - Released with KDE 4.1.0 +------------------------------------------------------------------------ Port to CMake/KDE4/QT4 Support of XMP metadata (require Exiv2 0.16) Split methods to separate files to provide a more readable implementation. New method to fix orientation of a QImage accordingly with Exif orientation tag. +Moved from extragear/libs to kdegraphics/libs Bugs fixed from B.K.O (http://bugs.kde.org): 001 ==> 146864: Lesser XMP support in digiKam. Index: CMakeLists.txt =================================================================== --- CMakeLists.txt (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ CMakeLists.txt (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -15,11 +15,13 @@ # 0.1.7 => 4.0.1 # 0.1.8 => 5.0.0 # ... here we can have new releases from KDE3 branch -# 0.2.0 => 6.0.0 +# 0.2.0 => 6.0.0 (released with KDE 4.1.0) +# 0.3.0 => 7.0.0 (released with KDE 4.1.2) +# 0.4.0 => 7.1.0 # Library API version SET(KEXIV2_LIB_MAJOR_VERSION "0") -SET(KEXIV2_LIB_MINOR_VERSION "2") +SET(KEXIV2_LIB_MINOR_VERSION "4") SET(KEXIV2_LIB_PATCH_VERSION "0") # Suffix to add at end of version string. Usual values are: @@ -29,12 +31,12 @@ # "-beta3" : beta3 release. # "-rc" : release candidate. # "" : final relase. Can be used in production. -SET(KEXIV2_LIB_SUFFIX_VERSION "-svn") +SET(KEXIV2_LIB_SUFFIX_VERSION "") # Library ABI version used by linker. # For details : http://www.gnu.org/software/libtool/manual.html#Updating-version-info -SET(KEXIV2_LIB_SO_CUR_VERSION "6") -SET(KEXIV2_LIB_SO_REV_VERSION "0") +SET(KEXIV2_LIB_SO_CUR_VERSION "7") +SET(KEXIV2_LIB_SO_REV_VERSION "1") SET(KEXIV2_LIB_SO_AGE_VERSION "0") # ======================================================= Index: README =================================================================== --- README (.../tags/KDE/4.1.2/kdegraphics/libs/libkexiv2) (revision 877548) +++ README (.../trunk/KDE/kdegraphics/libs/libkexiv2) (revision 877548) @@ -9,18 +9,20 @@ -- ABOUT -------------------------------------------------------------- Libkexiv2 is a wrapper around Exiv2 library to manipulate pictures -metadata as EXIF/IPTC and XMP. +metadata as EXIF/IPTC and XMP. Metadata interface follow this paper: +http://www.metadataworkinggroup.com/pdf/mwg_guidance.pdf + This library is used by kipi-plugins, digiKam and others kipi host programs. The library documentation is available on header files. -- DEPENDENCIES ------------------------------------------------------- -CMake >= 2.4.x http://www.cmake.org -libqt >= 4.2.x http://www.trolltech.com -libkde >= 4.0.x http://www.kde.org -libexiv2 >= 0.12 (0.17 recommended) http://www.exiv2.org +CMake >= 2.4.x http://www.cmake.org +libqt >= 4.2.x http://www.trolltech.com +libkde >= 4.0.x http://www.kde.org +libexiv2 >= 0.13 (0.18 recommended) http://www.exiv2.org Note: Exiv2 >= 0.16 is require to handle XMP metadata. @@ -61,7 +63,7 @@ IMPORTANT : the bugreports and wishlist are hosted by the KDE bugs report system who can be contacted by the standard Kde help menu of plugins dialog. -A mail will be automaticly sent to the Kipi mailing list. +A mail will be automatically sent to the Kipi mailing list. There is no need to contact directly the Kipi mailing list for a bug report or a devel wish.