21#include "exiv2extractor.h" 
   30#include "geolocation/cities.h" 
   31#include "geolocation/city.h" 
   47void Exiv2Extractor::setUrl(
const QUrl &url)
 
   50    if (!
QFileInfo::exists(m_url.toLocalFile()) || m_url.isEmpty() || !m_url.isValid()) {
 
   55        m_image =  Exiv2::ImageFactory::open(m_url.toLocalFile().toStdString());
 
   56    } 
catch (
const std::exception &) {
 
   63    if (!m_image->good()) {
 
   68        m_image->readMetadata();
 
   69    } 
catch (
const std::exception &) {
 
   77Exiv2::ExifData & Exiv2Extractor::exifData()
 const 
   79    Exiv2::ExifData &exifData = m_image->exifData();
 
   87Coordinates Exiv2Extractor::extractGPS()
 const 
   89    double latitude = fetchGpsDouble(
"Exif.GPSInfo.GPSLatitude");
 
   90    double longitude = fetchGpsDouble(
"Exif.GPSInfo.GPSLongitude");
 
   92    QByteArray latRef = getExifTagData(
"Exif.GPSInfo.GPSLatitudeRef");
 
   93    if (!latRef.
isEmpty() && latRef[0] == 
'S')
 
   96    QByteArray longRef = getExifTagData(
"Exif.GPSInfo.GPSLongitudeRef");
 
   97    if (!longRef.
isEmpty() && longRef[0] == 
'W')
 
  100    return {latitude, longitude};
 
  103double Exiv2Extractor::fetchGpsDouble(
const char *name)
 const 
  105    Exiv2::ExifData &data = (exifData());
 
  106    Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey(name));
 
  107    if (it != data.end() && it->count() == 3) {
 
  111        n = (*it).toRational(0).first;
 
  112        d = (*it).toRational(0).second;
 
  120        n = (*it).toRational(1).first;
 
  121        d = (*it).toRational(1).second;
 
  132        n = (*it).toRational(2).first;
 
  133        d = (*it).toRational(2).second;
 
  150bool Exiv2Extractor::error()
 const 
  155QString Exiv2Extractor::getExifTagString(
const char* exifTagName, 
bool escapeCR)
 const 
  159        Exiv2::ExifKey exifKey(exifTagName);
 
  160        Exiv2::ExifData &data = (exifData());
 
  161        Exiv2::ExifData::iterator it = data.findKey(exifKey);
 
  164        if (it != data.end())
 
  167            std::string val  = it->print(&data);
 
  176    catch( Exiv2::Error& e )
 
  178        qWarning() << QString(
"Cannot find Exif key '%1' into image using Exiv2 ").arg(
QString::fromLatin1(exifTagName)) << e.what();
 
  182        qWarning() << 
"Default exception from Exiv2";
 
  188QByteArray Exiv2Extractor::getExifTagData(
const char* exifTagName)
 const 
  192        Exiv2::ExifKey exifKey(exifTagName);
 
  193        Exiv2::ExifData &data = (exifData());        
 
  194        Exiv2::ExifData::iterator it = data.findKey(exifKey);
 
  196        if (it != data.end())
 
  198            char* 
const s = 
new char[(*it).size()];
 
  199            (*it).copy((Exiv2::byte*)s, Exiv2::bigEndian);
 
  200            QByteArray data(s, (*it).size());
 
  206    catch( Exiv2::Error& e )
 
  208        qWarning() << QString(
"Cannot find Exif key '%1' into image using Exiv2 ").arg(
QString::fromLatin1(exifTagName)) << e.what();
 
  212        qWarning() << 
"Default exception from Exiv2";
 
  218QVariant Exiv2Extractor::getExifTagVariant(
const char* exifTagName, 
bool rationalAsListOfInts, 
bool stringEscapeCR, 
int component)
 const 
  222        Exiv2::ExifKey exifKey(exifTagName);
 
  223        Exiv2::ExifData &data = (exifData());
 
  224        Exiv2::ExifData::iterator it = data.findKey(exifKey);
 
  226        if (it != data.end())
 
  228            switch (it->typeId())
 
  230                case Exiv2::unsignedByte:
 
  231                case Exiv2::unsignedShort:
 
  232                case Exiv2::unsignedLong:
 
  233                case Exiv2::signedShort:
 
  234                case Exiv2::signedLong:
 
  235                    if (it->count() > component)
 
  236                        return QVariant((
int)it->toLong(component));
 
  239                case Exiv2::unsignedRational:
 
  240                case Exiv2::signedRational:
 
  242                    if (rationalAsListOfInts)
 
  244                        if (it->count() <= component)
 
  247                        QList<QVariant> 
list;
 
  248                        list << (*it).toRational(component).
first;
 
  249                        list << (*it).toRational(component).second;
 
  251                        return QVariant(list);
 
  255                        if (it->count() <= component)
 
  259                        double num = (*it).toRational(component).first;
 
  260                        double den = (*it).toRational(component).second;
 
  265                        return QVariant(num / den);
 
  271                    return QVariant(dateTime);
 
  273                case Exiv2::asciiString:
 
  277                    std::ostringstream os;
 
  284                    return QVariant(tagValue);
 
  291    catch( Exiv2::Error& e )
 
  293        qWarning () << QString(
"Cannot find Exif key '%1' in the image using Exiv2 ").arg(
QString::fromLatin1(exifTagName)) << e.what();
 
  297        qWarning() << 
"Default exception from Exiv2";
 
  303static bool isUtf8(
const char* 
const buffer)
 
  321    static const unsigned char text_chars[256] =
 
  324        F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F,  
 
  326        F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F,  
 
  327        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  
 
  328        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  
 
  329        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  
 
  330        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  
 
  331        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  
 
  332        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F,  
 
  334        X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X,  
 
  335        X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,  
 
  336        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  
 
  337        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  
 
  338        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  
 
  339        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  
 
  340        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  
 
  341        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I   
 
  344    for (i = 0; (c = buffer[i]); ++i)
 
  353            if (text_chars[c] != T)
 
  357        else if ((c & 0x40) == 0)
 
  372            else if ((c & 0x10) == 0)
 
  377            else if ((c & 0x08) == 0)
 
  382            else if ((c & 0x04) == 0)
 
  387            else if ((c & 0x02) == 0)
 
  397            for (n = 0; n < following; ++n)
 
  401                if (!(c = buffer[i]))
 
  404                if ((c & 0x80) == 0 || (c & 0x40))
 
  417static QString detectEncodingAndDecode(
const std::string& value) 
 
  430    if (isUtf8(value.c_str()))
 
  443static QString convertCommentValue(
const Exiv2::Exifdatum& exifDatum)
 
  450        comment = exifDatum.toString();
 
  454        if (comment.length() > 8 && comment.substr(0, 8) == 
"charset=")
 
  457            std::string::size_type pos = comment.find_first_of(
' ');
 
  459            if (pos != std::string::npos)
 
  462                charset = comment.substr(8, pos-8);
 
  464                comment = comment.substr(pos+1);
 
  468        if (charset == 
"\"Unicode\"")
 
  472        else if (charset == 
"\"Jis\"")
 
  474            QTextCodec* 
const codec = QTextCodec::codecForName(
"JIS7");
 
  475            return codec->toUnicode(comment.c_str());
 
  477        else if (charset == 
"\"Ascii\"")
 
  483            return detectEncodingAndDecode(comment);
 
  486    catch( Exiv2::Error& e )
 
  492        qWarning()<< 
"Default exception from Exiv2";
 
  498MetaDataMap Exiv2Extractor::getExifTagsDataList(
const QStringList& exifKeysFilter, 
bool invertSelection)
 const 
  500    if (exifData().empty())
 
  501        return MetaDataMap();
 
  505        Exiv2::ExifData &data = exifData();
 
  508        MetaDataMap metaDataMap;
 
  510        for (Exiv2::ExifData::iterator md = data.begin(); md != data.end(); ++md)
 
  519                tagValue = convertCommentValue(*md);
 
  527                std::ostringstream os;
 
  540                if (!invertSelection)
 
  543                        metaDataMap.
insert(key, tagValue);
 
  548                        metaDataMap.
insert(key, tagValue);
 
  553                metaDataMap.
insert(key, tagValue);
 
  559    catch (Exiv2::Error& e)
 
  565        qWarning() << 
"Default exception from Exiv2";
 
  568    return MetaDataMap();
 
  571QString Exiv2Extractor::getExifComment()
 const 
  575        if (!exifData().empty())
 
  577            Exiv2::ExifData &data(exifData());
 
  578            Exiv2::ExifKey key(
"Exif.Photo.UserComment");
 
  579            Exiv2::ExifData::iterator it = data.findKey(key);
 
  581            if (it != data.end())
 
  583                QString exifComment = convertCommentValue(*it);
 
  590            Exiv2::ExifKey key2(
"Exif.Image.ImageDescription");
 
  591            Exiv2::ExifData::iterator it2 = data.findKey(key2);
 
  593            if (it2 != data.end())
 
  595                QString exifComment = convertCommentValue(*it2);
 
  598                QStringList blackList;
 
  603                QString trimmedComment = exifComment.
trimmed();
 
  611    catch( Exiv2::Error& e )
 
  613        qWarning() << (
QString::fromLatin1(
"Cannot find Exif User Comment using Exiv2 "), e.what());
 
  617        qWarning() << 
"Default exception from Exiv2";
 
  623QString Exiv2Extractor::GPSString()
 const 
  630    std::unique_ptr<City>m_city(city());
 
  637    if(!m_city->isValid())
 
  642    return m_city->name();
 
  645QString Exiv2Extractor::cityId()
 const 
  652    std::unique_ptr<City>m_city(city());
 
  659    if(!m_city->isValid())
 
  667City* Exiv2Extractor::city()
 const 
  674    auto c = extractGPS();
 
  676    if(c.first == 0.0 || c.second == 0.0)
 
  681    return Cities::getInstance()->findCity(c.first, c.second);
 
  684bool Exiv2Extractor::writeTag(
const char *tagName, 
const QVariant &value)
 
  688        qDebug() << 
"trying to write tag4";
 
  690        Exiv2::ExifKey exifKey(tagName);
 
  691        Exiv2::ExifData &data = (exifData());
 
  692        Exiv2::ExifData::iterator it = data.findKey(exifKey);
 
  693        qDebug() << 
"trying to write tag5";
 
  695        if (it != data.end())
 
  697            qDebug() << 
"trying to write tag2";
 
  699            switch (it->typeId())
 
  701                case Exiv2::unsignedByte:
 
  702                case Exiv2::unsignedShort:
 
  703                case Exiv2::unsignedLong:
 
  704                case Exiv2::signedShort:
 
  705                case Exiv2::signedLong:
 
  706                case Exiv2::unsignedLongLong:
 
  707                case Exiv2::signedLongLong:
 
  712                    qDebug() << 
"Writting number metadata" << tagName;
 
  714                    Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::signedLongLong);
 
  716                    it->setValue(v.get());
 
  720                case Exiv2::unsignedRational:
 
  721                case Exiv2::signedRational:
 
  725                                                            qDebug() << 
"Writting rational metadata" << tagName;
 
  727                    Exiv2::RationalValue::AutoPtr rv(
new Exiv2::RationalValue);
 
  729                    it->setValue(rv.get());
 
  740                    Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::asciiString);
 
  741                    v->read(date.toStdString());
 
  742                    it->setValue(v.get());
 
  746                case Exiv2::asciiString:
 
  752                    qDebug() << 
"Writting ascii metadata" << tagName;
 
  755                    Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::asciiString);
 
  756                    v->read(
string.toStdString());
 
  757                    it->setValue(v.get());
 
  763                                        qDebug() << 
"Writting unkown metadata" << tagName;
 
  768            qDebug() << 
"Writting metadata EXIF tag to file" << tagName;
 
  770            m_image->writeMetadata();
 
  774            Exiv2::Exifdatum& tag = data[tagName];
 
  777            m_image->writeMetadata();
 
  781    catch( Exiv2::Error& e )
 
  783        qWarning () << QString(
"Cannot find Exif key '%1' in the image using Exiv2 ").arg(
QString::fromLatin1(tagName)) << e.what();
 
  789        qWarning() << 
"Default exception from Exiv2";
 
  796bool Exiv2Extractor::removeTag(
const char *tagName)
 
  801        Exiv2::ExifKey key = Exiv2::ExifKey(tagName);
 
  802        Exiv2::ExifData &data = (exifData());
 
  804        Exiv2::ExifData::iterator it = data.findKey(key);
 
  806        if (it != data.end())
 
  809            m_image->writeMetadata();
 
  813    catch( Exiv2::Error& e )
 
  815        qWarning () << QString(
"Cannot find Exif key '%1' in the image using Exiv2 ").arg(
QString::fromLatin1(tagName)) << e.what();
 
  821        qWarning() << 
"Default exception from Exiv2";
 
A class for representing the GPS coordinates and information of a city.
 
KIOCORE_EXPORT QStringList list(const QString &fileClass)
 
QByteArray tagValue(const Elem &elem, const char *keyName)
 
bool isEmpty() const const
 
QByteArray & replace(QByteArrayView before, QByteArrayView after)
 
QDateTime fromString(QStringView string, QStringView format, QCalendar cal)
 
bool exists() const const
 
bool isEmpty() const const
 
iterator insert(const Key &key, const T &value)
 
QString fromLatin1(QByteArrayView str)
 
QString fromLocal8Bit(QByteArrayView str)
 
QString fromUtf8(QByteArrayView str)
 
bool isEmpty() const const
 
QString number(double n, char format, int precision)
 
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
 
std::string toStdString() const const
 
QString trimmed() const const
 
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
 
bool canConvert() const const
 
QString toString() const const