mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 18:32:49 +00:00
kutils: essentially KExiv2 rewrite
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
abde7f3cb7
commit
e29151a728
3 changed files with 144 additions and 91 deletions
|
@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue