kutils: essentially KExiv2 rewrite

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-10-16 00:44:05 +03:00
parent abde7f3cb7
commit e29151a728
3 changed files with 144 additions and 91 deletions

View file

@ -102,207 +102,206 @@ QList<KFileMetaInfoItem> KFileMetaDataExiv2Plugin::metaData(const KUrl &url, con
Q_UNUSED(flags);
QList<KFileMetaInfoItem> result;
const KExiv2 kexiv2(url.toLocalFile());
const KExiv2::DataMap kexiv2metadata = kexiv2.data();
foreach (const QByteArray &kexiv2key, kexiv2metadata.keys()) {
const QString kexiv2value = kexiv2metadata.value(kexiv2key);
// qDebug() << Q_FUNC_INFO << kexiv2key << kexiv2value;
const KExiv2PropertyList kexiv2metadata = kexiv2.metadata();
foreach (const KExiv2Property &kexiv2property, kexiv2metadata) {
// qDebug() << Q_FUNC_INFO << kexiv2property.name << kexiv2property.value;
// for reference:
// https://exiv2.org/tags.html
if (kexiv2key == "Exif.Image.ImageWidth") {
if (kexiv2property.name == "Exif.Image.ImageWidth") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#width"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.ImageLength") {
} else if (kexiv2property.name == "Exif.Image.ImageLength") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#height"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.FrameRate") {
} else if (kexiv2property.name == "Exif.Image.FrameRate") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#frameRate"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.Copyright") {
} else if (kexiv2property.name == "Exif.Image.Copyright") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#copyright"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.UserComment" || kexiv2key == "Exif.Photo.XPComment") {
} else if (kexiv2property.name == "Exif.Image.UserComment" || kexiv2property.name == "Exif.Photo.XPComment") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#comment"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Photo.XPTitle") {
} else if (kexiv2property.name == "Exif.Photo.XPTitle") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#title"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.XPKeywords") {
} else if (kexiv2property.name == "Exif.Image.XPKeywords") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#keyword"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.XPSubject") {
} else if (kexiv2property.name == "Exif.Image.XPSubject") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#subject"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.ImageDescription") {
} else if (kexiv2property.name == "Exif.Image.ImageDescription") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#description"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.Software") {
} else if (kexiv2property.name == "Exif.Image.Software") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#generator"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.DateTimeOriginal" || kexiv2key == "Exif.Photo.DateTimeOriginal") {
} else if (kexiv2property.name == "Exif.Image.DateTimeOriginal" || kexiv2property.name == "Exif.Photo.DateTimeOriginal") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#contentCreated"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.Make") {
} else if (kexiv2property.name == "Exif.Image.Make") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#make"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.Model") {
} else if (kexiv2property.name == "Exif.Image.Model") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#model"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.Orientation") {
} else if (kexiv2property.name == "Exif.Image.Orientation") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#orientation"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.Artist") {
} else if (kexiv2property.name == "Exif.Image.Artist") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#artist"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.GPSInfo.GPSLatitudeRef") {
} else if (kexiv2property.name == "Exif.GPSInfo.GPSLatitudeRef") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#gpsLatitudeRef"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.GPSInfo.GPSLongitudeRef") {
} else if (kexiv2property.name == "Exif.GPSInfo.GPSLongitudeRef") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#gpsLongitudeRef"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.Flash") {
} else if (kexiv2property.name == "Exif.Image.Flash") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#flash"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Photo.ExposureTime") {
} else if (kexiv2property.name == "Exif.Photo.ExposureTime") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#exposureTime"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.ExposureBiasValue") {
} else if (kexiv2property.name == "Exif.Image.ExposureBiasValue") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#exposureBiasValue"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Photo.ExposureMode") {
} else if (kexiv2property.name == "Exif.Photo.ExposureMode") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#exposureMode"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Photo.ApertureValue") {
} else if (kexiv2property.name == "Exif.Photo.ApertureValue") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#apertureValue"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.FocalLength") {
} else if (kexiv2property.name == "Exif.Image.FocalLength") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#focalLength"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Photo.FocalLengthIn35mmFilm") {
} else if (kexiv2property.name == "Exif.Photo.FocalLengthIn35mmFilm") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#focalLengthIn35mmFilm"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Image.ISOSpeedRatings") {
} else if (kexiv2property.name == "Exif.Image.ISOSpeedRatings") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#isoSpeedRatings"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Photo.MeteringMode") {
} else if (kexiv2property.name == "Exif.Photo.MeteringMode") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#meteringMode"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Photo.WhiteBalance") {
} else if (kexiv2property.name == "Exif.Photo.WhiteBalance") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#whiteBalance"),
kexiv2value
kexiv2property.value
)
);
} else if (kexiv2key == "Exif.Photo.ImageUniqueID") {
} else if (kexiv2property.name == "Exif.Photo.ImageUniqueID") {
result.append(
KFileMetaInfoItem(
QString::fromLatin1("http://www.semanticdesktop.org/ontologies/2007/05/10/nid3#uniqueFileIdentifier"),
kexiv2value
kexiv2property.value
)
);
}

View file

@ -101,6 +101,15 @@ KExiv2::KExiv2(const QString &path)
{
}
bool KExiv2::isSupported()
{
#if defined(HAVE_EXIV2)
return true;
#else
return false;
#endif
}
QImage KExiv2::preview() const
{
QImage result;
@ -134,9 +143,32 @@ QImage KExiv2::preview() const
bool KExiv2::rotateImage(QImage &image) const
{
#if defined(HAVE_EXIV2)
// for reference:
// https://exiv2.org/tags-xmp-tiff.html
const int orientation = data().value("Exif.Image.Orientation").toInt();
int orientation = 0;
if (d->m_exiv2image.get()) {
static const std::string s_orientationkey = std::string("Exif.Image.Orientation");
try {
kDebug() << "Checking for orientation Exif data for" << d->m_path;
const Exiv2::ExifData exiv2data = d->m_exiv2image->exifData();
for (Exiv2::ExifData::const_iterator it = exiv2data.begin(); it != exiv2data.end(); it++) {
const std::string key = (*it).key();
if (key != s_orientationkey) {
continue;
}
orientation = (*it).value().toLong();
kDebug() << "Found orientation Exif data" << orientation;
break;
}
} catch(Exiv2::Error &err) {
kWarning() << err.what() << err.code();
} catch(std::exception &err) {
kWarning() << err.what();
} catch (...) {
kWarning() << "Exception raised";
}
}
switch (orientation) {
case 0: // not documented, nothing to do I guess
case 1: { // normal orientation
@ -186,21 +218,30 @@ bool KExiv2::rotateImage(QImage &image) const
}
}
Q_UNREACHABLE();
#else
kWarning() << "KExiv2 is a stub";
return false;
#endif // HAVE_EXIV2
}
KExiv2::DataMap KExiv2::data() const
KExiv2PropertyList KExiv2::metadata() const
{
KExiv2::DataMap result;
KExiv2PropertyList result;
#if defined(HAVE_EXIV2)
if (d->m_exiv2image.get()) {
try {
KExiv2Property kexiv2property;
kDebug() << "Mapping Exif data for" << d->m_path;
const Exiv2::ExifData exiv2data = d->m_exiv2image->exifData();
for (Exiv2::ExifData::const_iterator it = exiv2data.begin(); it != exiv2data.end(); it++) {
const std::string key = (*it).key();
const std::string value = (*it).value().toString();
kDebug() << "Key" << key.c_str() << "value" << value.c_str();
result.insert(QByteArray(key.c_str(), key.size()), QString::fromStdString(value));
const std::string taglabel = (*it).tagLabel();
kDebug() << "Key" << key.c_str() << "value" << value.c_str() << "tag label" << taglabel.c_str();
kexiv2property.name = QByteArray(key.c_str(), key.size());
kexiv2property.value = QString::fromStdString(value);
kexiv2property.label = QString::fromStdString(taglabel);
result.append(kexiv2property);
}
kDebug() << "Mapping Iptc data for" << d->m_path;
@ -208,8 +249,12 @@ KExiv2::DataMap KExiv2::data() const
for (Exiv2::IptcData::const_iterator it = iptcdata.begin(); it != iptcdata.end(); it++) {
const std::string key = (*it).key();
const std::string value = (*it).value().toString();
kDebug() << "Key" << key.c_str() << "value" << value.c_str();
result.insert(QByteArray(key.c_str(), key.size()), QString::fromStdString(value));
const std::string taglabel = (*it).tagLabel();
kDebug() << "Key" << key.c_str() << "value" << value.c_str() << "tag label" << taglabel.c_str();
kexiv2property.name = QByteArray(key.c_str(), key.size());
kexiv2property.value = QString::fromStdString(value);
kexiv2property.label = QString::fromStdString(taglabel);
result.append(kexiv2property);
}
kDebug() << "Mapping Xmp data for" << d->m_path;
@ -217,8 +262,12 @@ KExiv2::DataMap KExiv2::data() const
for (Exiv2::XmpData::const_iterator it = xmpdata.begin(); it != xmpdata.end(); it++) {
const std::string key = (*it).key();
const std::string value = (*it).value().toString();
kDebug() << "Key" << key.c_str() << "value" << value.c_str();
result.insert(QByteArray(key.c_str(), key.size()), QString::fromStdString(value));
const std::string taglabel = (*it).tagLabel();
kDebug() << "Key" << key.c_str() << "value" << value.c_str() << "tag label" << taglabel.c_str();
kexiv2property.name = QByteArray(key.c_str(), key.size());
kexiv2property.value = QString::fromStdString(value);
kexiv2property.label = QString::fromStdString(taglabel);
result.append(kexiv2property);
}
} catch(Exiv2::Error &err) {
kWarning() << err.what() << err.code();
@ -232,11 +281,3 @@ KExiv2::DataMap KExiv2::data() const
return result;
}
QString KExiv2::label(const QByteArray &key) const
{
const int lastdotindex = key.lastIndexOf('.');
if (lastdotindex >= 0) {
return QString::fromLatin1(key.constData() + lastdotindex + 1, key.size() - lastdotindex - 1);
}
return QString::fromLatin1(key.constData(), key.size());
}

View file

@ -21,48 +21,61 @@
#include "kexiv2_export.h"
#include <QMap>
#include <QList>
#include <QString>
#include <QImage>
class KExiv2Private;
/*!
Class to obtain EXIF metadata, preview and rotate images based on the metadata.
Structure that holds information about Exif, IPTC or XMP property.
@since 4.22
@see KExiv2
@link https://exiv2.org/metadata.html
*/
struct KExiv2Property
{
QByteArray name;
QString value;
QString label;
};
typedef QList<KExiv2Property> KExiv2PropertyList;
/*!
Class to obtain Exif, IPTC and XMP metadata, preview and rotate images based on the metadata.
@note Initialization and cleanup of the Exiv2 library resources is automatic
@since 4.20
@see KExiv2Property
*/
class KEXIV2_EXPORT KExiv2
{
public:
typedef QMap<QByteArray,QString> DataMap;
/*!
@brief Contructs object from @p path and obtains EXIF data if possible
@brief Contructs object from @p path
*/
KExiv2(const QString &path);
static bool isSupported();
/*!
@return Largest preview image if provided in the EXIF data, the image is not rotated
@return Largest preview image if provided in the metadata, the image is not rotated
automatically and may be null
*/
QImage preview() const;
/*!
@return Rotates @p image according to the EXIF orientation data
@return Rotates @p image according to the orientation metadata
*/
bool rotateImage(QImage &image) const;
/*!
@return Map of all EXIF properties
@return List of all Exif, IPTC and XMP metadata properties
*/
DataMap data() const;
/*!
@return Tag label for EXIF property
*/
QString label(const QByteArray &key) const;
KExiv2PropertyList metadata() const;
private:
Q_DISABLE_COPY(KExiv2);