File indexing completed on 2024-05-12 15:55:36

0001 // SPDX-FileCopyrightText: 2003-2010 Jesper K. Pedersen <blackie@kde.org>
0002 // SPDX-FileCopyrightText: 2023 Tobias Leupold <tl at stonemx dot de>
0003 //
0004 // SPDX-License-Identifier: GPL-2.0-or-later
0005 
0006 #include "DatabaseElement.h"
0007 
0008 #include <kpabase/Logging.h>
0009 
0010 #include <QVariant>
0011 #include <exiv2/exif.hpp>
0012 #include <exiv2/version.hpp>
0013 
0014 static QString replaceDotWithUnderscore(const char *cstr)
0015 {
0016     QString str(QString::fromLatin1(cstr));
0017     return str.replace(QString::fromLatin1("."), QString::fromLatin1("_"));
0018 }
0019 
0020 Exif::DatabaseElement::DatabaseElement()
0021     : m_value()
0022 {
0023 }
0024 
0025 QVariant Exif::DatabaseElement::value() const
0026 {
0027     return m_value;
0028 }
0029 void Exif::DatabaseElement::setValue(QVariant val)
0030 {
0031     m_value = val;
0032 }
0033 
0034 Exif::StringExifElement::StringExifElement(const char *tag)
0035     : m_tag(tag)
0036 {
0037 }
0038 
0039 QString Exif::StringExifElement::columnName() const
0040 {
0041     return replaceDotWithUnderscore(m_tag);
0042 }
0043 
0044 QString Exif::StringExifElement::createString() const
0045 {
0046     return QString::fromLatin1("%1 string").arg(replaceDotWithUnderscore(m_tag));
0047 }
0048 
0049 QString Exif::StringExifElement::queryString() const
0050 {
0051     return QString::fromLatin1("?");
0052 }
0053 
0054 QVariant Exif::StringExifElement::valueFromExif(Exiv2::ExifData &data) const
0055 {
0056     return QVariant { QLatin1String(data[m_tag].toString().c_str()) };
0057 }
0058 
0059 Exif::IntExifElement::IntExifElement(const char *tag)
0060     : m_tag(tag)
0061 {
0062 }
0063 
0064 QString Exif::IntExifElement::columnName() const
0065 {
0066     return replaceDotWithUnderscore(m_tag);
0067 }
0068 
0069 QString Exif::IntExifElement::createString() const
0070 {
0071     return QString::fromLatin1("%1 int").arg(replaceDotWithUnderscore(m_tag));
0072 }
0073 
0074 QString Exif::IntExifElement::queryString() const
0075 {
0076     return QString::fromLatin1("?");
0077 }
0078 
0079 QVariant Exif::IntExifElement::valueFromExif(Exiv2::ExifData &data) const
0080 {
0081     if (data[m_tag].count() > 0) {
0082 #if EXIV2_TEST_VERSION(0, 28, 0)
0083         return QVariant((int) data[m_tag].toInt64());
0084 #else
0085         return QVariant((int) data[m_tag].toLong());
0086 #endif
0087     } else {
0088         return QVariant(0);
0089     }
0090 }
0091 
0092 Exif::RationalExifElement::RationalExifElement(const char *tag)
0093     : m_tag(tag)
0094 {
0095 }
0096 
0097 QString Exif::RationalExifElement::columnName() const
0098 {
0099     return replaceDotWithUnderscore(m_tag);
0100 }
0101 
0102 QString Exif::RationalExifElement::createString() const
0103 {
0104     return QString::fromLatin1("%1 float").arg(replaceDotWithUnderscore(m_tag));
0105 }
0106 
0107 QString Exif::RationalExifElement::queryString() const
0108 {
0109     return QString::fromLatin1("?");
0110 }
0111 
0112 QVariant Exif::RationalExifElement::valueFromExif(Exiv2::ExifData &data) const
0113 {
0114     double value;
0115     Exiv2::Exifdatum &tagDatum = data[m_tag];
0116     switch (tagDatum.count()) {
0117     case 0: // empty
0118         value = -1.0;
0119         break;
0120     case 1: // "normal" rational
0121         value = 1.0 * tagDatum.toRational().first / tagDatum.toRational().second;
0122         break;
0123     case 3: // GPS lat/lon data:
0124     {
0125         value = 0.0;
0126         double divisor = 1.0;
0127         // degree / minute / second:
0128         for (int i = 0; i < 3; i++) {
0129             double nom = tagDatum.toRational(i).first;
0130             double denom = tagDatum.toRational(i).second;
0131             if (denom != 0)
0132                 value += (nom / denom) / divisor;
0133             divisor *= 60.0;
0134         }
0135     } break;
0136     default:
0137         // FIXME: there are at least the following other rational types:
0138         // whitepoints -> 2 components
0139         // YCbCrCoefficients -> 3 components (Coefficients for transformation from RGB to YCbCr image data. )
0140         // chromaticities -> 6 components
0141         qCWarning(ExifLog) << "Exif rational data with " << tagDatum.count() << " components is not handled, yet!";
0142         return QVariant {};
0143     }
0144     return QVariant { value };
0145 }
0146 
0147 Exif::LensExifElement::LensExifElement()
0148     : m_tag("Exif.Photo.LensModel")
0149 {
0150 }
0151 
0152 QString Exif::LensExifElement::columnName() const
0153 {
0154     return replaceDotWithUnderscore(m_tag);
0155 }
0156 
0157 QString Exif::LensExifElement::createString() const
0158 {
0159     return QString::fromLatin1("%1 string").arg(replaceDotWithUnderscore(m_tag));
0160 }
0161 
0162 QString Exif::LensExifElement::queryString() const
0163 {
0164     return QString::fromLatin1("?");
0165 }
0166 
0167 QVariant Exif::LensExifElement::valueFromExif(Exiv2::ExifData &data) const
0168 {
0169     QString value;
0170     bool canonHack = false;
0171     for (Exiv2::ExifData::const_iterator it = data.begin(); it != data.end(); ++it) {
0172         const QString datum = QString::fromLatin1(it->key().c_str());
0173 
0174         // Exif.Photo.LensModel [Ascii]
0175         // Exif.Canon.LensModel [Ascii]
0176         // Exif.OlympusEq.LensModel [Ascii]
0177         if (datum.endsWith(QString::fromLatin1(".LensModel"))) {
0178             qCDebug(ExifLog) << datum << ": " << it->toString().c_str();
0179             canonHack = false;
0180             value = QString::fromUtf8(it->toString().c_str());
0181             // we can break here since Exif.Photo.LensModel should be bound first
0182             break;
0183         }
0184 
0185         // Exif.NikonLd3.LensIDNumber [Byte]
0186         // on Nikon cameras, this seems to provide better results than .Lens and .LensType
0187         // (i.e. it includes the lens manufacturer).
0188         if (datum.endsWith(QString::fromLatin1(".LensIDNumber"))) {
0189             // ExifDatum::print() returns the interpreted value
0190             qCDebug(ExifLog) << datum << ": " << it->print(&data).c_str();
0191             canonHack = false;
0192             value = QString::fromUtf8(it->print(&data).c_str());
0193             continue;
0194         }
0195 
0196         // Exif.Nikon3.LensType [Byte]
0197         // Exif.OlympusEq.LensType [Byte]
0198         // Exif.Panasonic.LensType [Ascii]
0199         // Exif.Pentax.LensType [Byte]
0200         // Exif.Samsung2.LensType [Short]
0201         if (datum.endsWith(QString::fromLatin1(".LensType"))) {
0202             // ExifDatum::print() returns the interpreted value
0203             qCDebug(ExifLog) << datum << ": " << it->print(&data).c_str();
0204             // make sure this cannot overwrite LensIDNumber
0205             if (value.isEmpty()) {
0206                 canonHack = (datum == QString::fromLatin1("Exif.CanonCs.LensType"));
0207                 value = QString::fromUtf8(it->print(&data).c_str());
0208             }
0209         }
0210     }
0211 
0212     // some canon lenses have a dummy value as LensType:
0213     if (canonHack && value == QString::fromLatin1("(65535)")) {
0214         value = QString::fromLatin1("Canon generic");
0215         const auto datum = data.findKey(Exiv2::ExifKey("Exif.CanonCs.Lens"));
0216         if (datum != data.end()) {
0217             value += QString::fromLatin1(" ");
0218             value += QString::fromUtf8(datum->print(&data).c_str());
0219         }
0220     }
0221     qCDebug(ExifLog) << "final lens value " << value;
0222     return QVariant { value };
0223 }
0224 
0225 // vi:expandtab:tabstop=4 shiftwidth=4: