File indexing completed on 2024-05-12 04:46:37

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 
0003 /*
0004  *    Copyright (C) 2012-15  Vishesh Handa <vhanda@kde.org>
0005  * 
0006  *    This library is free software; you can redistribute it and/or
0007  *    modify it under the terms of the GNU Lesser General Public
0008  *    License as published by the Free Software Foundation; either
0009  *    version 2.1 of the License, or (at your option) any later version.
0010  * 
0011  *    This library is distributed in the hope that it will be useful,
0012  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  *    Lesser General Public License for more details.
0015  * 
0016  *    You should have received a copy of the GNU Lesser General Public
0017  *    License along with this library; if not, write to the Free Software
0018  *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0019  */
0020 
0021 #include "exiv2extractor.h"
0022 
0023 #include <QGeoAddress>
0024 #include <QFileInfo>
0025 #include <QDateTime>
0026 #include <QDebug>
0027 #include <QFile>
0028 
0029 #include <QTextCodec>
0030 
0031 #include "geolocation/cities.h"
0032 #include "geolocation/city.h"
0033 
0034 Exiv2Extractor::Exiv2Extractor(const QUrl &url, QObject *parent) : QObject(parent)
0035 , m_error(true)
0036 
0037 {
0038     this->setUrl(url);
0039 }
0040 
0041 Exiv2Extractor::Exiv2Extractor(QObject *parent) : QObject(parent)
0042 , m_error(true)
0043 
0044 {
0045 }
0046 
0047 void Exiv2Extractor::setUrl(const QUrl &url)
0048 {
0049     qDebug() << "Start parsing image file url for metadata";
0050     m_url = url;
0051     if (!QFileInfo::exists(m_url.toLocalFile()) || m_url.isEmpty() || !m_url.isValid()) {
0052         qDebug() << "Image file is not valid or does not exists.";
0053        return;
0054     }    
0055     
0056     try {
0057         m_image =  Exiv2::ImageFactory::open(m_url.toLocalFile().toStdString());
0058     } catch (const std::exception &) {
0059         qDebug() << "Failed to open image to extract metadata information.";
0060         return;
0061     }
0062     
0063     if (!m_image.get()) {
0064         qDebug() << "Image can not be accessed.";
0065         return;
0066     }
0067     
0068     if (!m_image->good()) {
0069         qDebug() << "Image is not good.";
0070         return;
0071     }
0072     
0073     try {
0074         m_image->readMetadata();
0075     } catch (const std::exception &) {
0076        qDebug() << "Can not read metadta from the image.";
0077         return;
0078     }
0079     
0080     m_error = false;
0081 }
0082 
0083 
0084 Exiv2::ExifData & Exiv2Extractor::exifData() const
0085 {   
0086     Exiv2::ExifData &exifData = m_image->exifData();
0087 //     if (exifData.empty()) {
0088 //         qWarning() <<  "No EXIF data in : " << m_url.toString();
0089 //     }    
0090     
0091     return exifData;
0092 }
0093 
0094 Coordinates Exiv2Extractor::extractGPS() const
0095 {
0096     double latitude = fetchGpsDouble("Exif.GPSInfo.GPSLatitude");
0097     double longitude = fetchGpsDouble("Exif.GPSInfo.GPSLongitude");
0098     
0099     QByteArray latRef = getExifTagData("Exif.GPSInfo.GPSLatitudeRef");
0100     if (!latRef.isEmpty() && latRef[0] == 'S')
0101         latitude *= -1;
0102     
0103     QByteArray longRef = getExifTagData("Exif.GPSInfo.GPSLongitudeRef");
0104     if (!longRef.isEmpty() && longRef[0] == 'W')
0105         longitude *= -1;
0106     
0107     return {latitude, longitude};
0108 }
0109 
0110 double Exiv2Extractor::fetchGpsDouble(const char *name) const
0111 {
0112     Exiv2::ExifData &data = (exifData());
0113     Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey(name));
0114     if (it != data.end() && it->count() == 3) {
0115         double n = 0.0;
0116         double d = 0.0;
0117         
0118         n = (*it).toRational(0).first;
0119         d = (*it).toRational(0).second;
0120         
0121         if (d == 0) {
0122             return 0.0;
0123         }
0124         
0125         double deg = n / d;
0126         
0127         n = (*it).toRational(1).first;
0128         d = (*it).toRational(1).second;
0129         
0130         if (d == 0) {
0131             return deg;
0132         }
0133         
0134         double min = n / d;
0135         if (min != -1.0) {
0136             deg += min / 60.0;
0137         }
0138         
0139         n = (*it).toRational(2).first;
0140         d = (*it).toRational(2).second;
0141         
0142         if (d == 0) {
0143             return deg;
0144         }
0145         
0146         double sec = n / d;
0147         if (sec != -1.0) {
0148             deg += sec / 3600.0;
0149         }
0150         
0151         return deg;
0152     }
0153     
0154     return 0.0;
0155 }
0156 
0157 bool Exiv2Extractor::error() const
0158 {
0159     return m_error;
0160 }
0161 
0162 QString Exiv2Extractor::getExifTagString(const char* exifTagName, bool escapeCR) const
0163 {    
0164     try
0165     {
0166         Exiv2::ExifKey exifKey(exifTagName);
0167         Exiv2::ExifData &data = (exifData());
0168         Exiv2::ExifData::iterator it = data.findKey(exifKey);
0169         
0170         
0171         if (it != data.end())
0172         {
0173             // See B.K.O #184156 comment #13
0174             std::string val  = it->print(&data);
0175             QString tagValue = QString::fromLocal8Bit(val.c_str());
0176             
0177             if (escapeCR)
0178                 tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
0179             
0180             return tagValue;
0181         }
0182     }
0183     catch( Exiv2::Error& e )
0184     {
0185         qWarning() << QString("Cannot find Exif key '%1' into image using Exiv2 ").arg(QString::fromLatin1(exifTagName)) << e.what();
0186     }
0187     catch(...)
0188     {
0189         qWarning() << "Default exception from Exiv2";
0190     }
0191     
0192     return QString();
0193 }
0194 
0195 QByteArray Exiv2Extractor::getExifTagData(const char* exifTagName) const
0196 {
0197     try
0198     {
0199         Exiv2::ExifKey exifKey(exifTagName);
0200         Exiv2::ExifData &data = (exifData());        
0201         Exiv2::ExifData::iterator it = data.findKey(exifKey);
0202         
0203         if (it != data.end())
0204         {
0205             char* const s = new char[(*it).size()];
0206             (*it).copy((Exiv2::byte*)s, Exiv2::bigEndian);
0207             QByteArray data(s, (*it).size());
0208             delete[] s;
0209             
0210             return data;
0211         }
0212     }
0213     catch( Exiv2::Error& e )
0214     {
0215         qWarning() << QString("Cannot find Exif key '%1' into image using Exiv2 ").arg(QString::fromLatin1(exifTagName)) << e.what();
0216     }
0217     catch(...)
0218     {
0219         qWarning() << "Default exception from Exiv2";
0220     }
0221     
0222     return QByteArray();
0223 }
0224 
0225 QVariant Exiv2Extractor::getExifTagVariant(const char* exifTagName, bool rationalAsListOfInts, bool stringEscapeCR, int component) const
0226 {
0227     try
0228     {
0229         Exiv2::ExifKey exifKey(exifTagName);
0230         Exiv2::ExifData &data = (exifData());
0231         Exiv2::ExifData::iterator it = data.findKey(exifKey);
0232         
0233         if (it != data.end())
0234         {
0235             switch (it->typeId())
0236             {
0237                 case Exiv2::unsignedByte:
0238                 case Exiv2::unsignedShort:
0239                 case Exiv2::unsignedLong:
0240                 case Exiv2::signedShort:
0241                 case Exiv2::signedLong:
0242                     if (it->count() > component)
0243                         return QVariant((int)it->toFloat(component));
0244                 else
0245                     return QVariant(QVariant::Int);
0246                 case Exiv2::unsignedRational:
0247                 case Exiv2::signedRational:
0248                     
0249                     if (rationalAsListOfInts)
0250                     {
0251                         if (it->count() <= component)
0252                             return QVariant(QVariant::List);
0253                         
0254                         QList<QVariant> list;
0255                         list << (*it).toRational(component).first;
0256                         list << (*it).toRational(component).second;
0257                         
0258                         return QVariant(list);
0259                     }
0260                     else
0261                     {
0262                         if (it->count() <= component)
0263                             return QVariant(QVariant::Double);
0264                         
0265                         // prefer double precision
0266                         double num = (*it).toRational(component).first;
0267                         double den = (*it).toRational(component).second;
0268                         
0269                         if (den == 0.0)
0270                             return QVariant(QVariant::Double);
0271                         
0272                         return QVariant(num / den);
0273                     }
0274                 case Exiv2::date:
0275                 case Exiv2::time:
0276                 {
0277                     QDateTime dateTime = QDateTime::fromString(QString::fromLatin1(it->toString().c_str()), Qt::ISODate);
0278                     return QVariant(dateTime);
0279                 }
0280                 case Exiv2::asciiString:
0281                 case Exiv2::comment:
0282                 case Exiv2::string:
0283                 {
0284                     std::ostringstream os;
0285                     os << *it;
0286                     QString tagValue = QString::fromLocal8Bit(os.str().c_str());
0287                     
0288                     if (stringEscapeCR)
0289                         tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
0290                     
0291                     return QVariant(tagValue);
0292                 }
0293                 default:
0294                     break;
0295             }
0296         }
0297     }
0298     catch( Exiv2::Error& e )
0299     {
0300         qWarning () << QString("Cannot find Exif key '%1' in the image using Exiv2 ").arg(QString::fromLatin1(exifTagName)) << e.what();
0301     }
0302     catch(...)
0303     {
0304         qWarning() << "Default exception from Exiv2";
0305     }
0306     
0307     return QVariant();
0308 }
0309 
0310 static bool isUtf8(const char* const buffer)
0311 {
0312     int i, n;
0313     unsigned char c;
0314     bool gotone = false;
0315     
0316     if (!buffer)
0317         return true;
0318     
0319     // character never appears in text
0320     #define F 0
0321     // character appears in plain ASCII text
0322     #define T 1
0323     // character appears in ISO-8859 text
0324     #define I 2
0325     // character appears in non-ISO extended ASCII (Mac, IBM PC)
0326     #define X 3
0327     
0328     static const unsigned char text_chars[256] =
0329     {
0330         //                  BEL BS HT LF    FF CR    
0331         F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F,  // 0x0X
0332         //                              ESC          
0333         F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F,  // 0x1X
0334         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  // 0x2X
0335         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  // 0x3X
0336         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  // 0x4X
0337         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  // 0x5X
0338         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  // 0x6X
0339         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F,  // 0x7X
0340         //            NEL                            
0341         X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X,  // 0x8X
0342         X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,  // 0x9X
0343         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  // 0xaX
0344         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  // 0xbX
0345         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  // 0xcX
0346         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  // 0xdX
0347         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  // 0xeX
0348         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I   // 0xfX
0349     };
0350     
0351     for (i = 0; (c = buffer[i]); ++i)
0352     {
0353         if ((c & 0x80) == 0)
0354         {
0355             // 0xxxxxxx is plain ASCII
0356             
0357             // Even if the whole file is valid UTF-8 sequences,
0358             // still reject it if it uses weird control characters.
0359             
0360             if (text_chars[c] != T)
0361                 return false;
0362             
0363         }
0364         else if ((c & 0x40) == 0)
0365         {
0366             // 10xxxxxx never 1st byte
0367             return false;
0368         }
0369         else
0370         {
0371             // 11xxxxxx begins UTF-8
0372             int following = 0;
0373             
0374             if ((c & 0x20) == 0)
0375             {
0376                 // 110xxxxx
0377                 following = 1;
0378             }
0379             else if ((c & 0x10) == 0)
0380             {
0381                 // 1110xxxx
0382                 following = 2;
0383             }
0384             else if ((c & 0x08) == 0)
0385             {
0386                 // 11110xxx
0387                 following = 3;
0388             }
0389             else if ((c & 0x04) == 0)
0390             {
0391                 // 111110xx
0392                 following = 4;
0393             }
0394             else if ((c & 0x02) == 0)
0395             {
0396                 // 1111110x
0397                 following = 5;
0398             }
0399             else
0400             {
0401                 return false;
0402             }
0403             
0404             for (n = 0; n < following; ++n)
0405             {
0406                 i++;
0407                 
0408                 if (!(c = buffer[i]))
0409                     goto done;
0410                 
0411                 if ((c & 0x80) == 0 || (c & 0x40))
0412                     return false;
0413             }
0414             
0415             gotone = true;
0416         }
0417     }
0418     
0419     done:
0420     
0421     return gotone;   // don't claim it's UTF-8 if it's all 7-bit.
0422 }
0423 
0424 static QString detectEncodingAndDecode(const std::string& value) 
0425 {
0426     // For charset autodetection, we could use sophisticated code
0427     // (Mozilla chardet, KHTML's autodetection, QTextCodec::codecForContent),
0428     // but that is probably too much.
0429     // We check for UTF8, Local encoding and ASCII.
0430     // Look like KEncodingDetector class can provide a full implementation for encoding detection.
0431     
0432     if (value.empty())
0433     {
0434         return QString();
0435     }
0436     
0437     if (isUtf8(value.c_str()))
0438     {
0439         return QString::fromUtf8(value.c_str());
0440     }
0441     
0442     // Utf8 has a pretty unique byte pattern.
0443     // Thats not true for ASCII, it is not possible
0444     // to reliably autodetect different ISO-8859 charsets.
0445     // So we can use either local encoding, or latin1.
0446     
0447     return QString::fromLocal8Bit(value.c_str());
0448 }
0449 
0450 static QString convertCommentValue(const Exiv2::Exifdatum& exifDatum)
0451 {
0452     try
0453     {
0454         std::string comment;
0455         std::string charset;
0456         
0457         comment = exifDatum.toString();
0458         
0459         // libexiv2 will prepend "charset=\"SomeCharset\" " if charset is specified
0460         // Before conversion to QString, we must know the charset, so we stay with std::string for a while
0461         if (comment.length() > 8 && comment.substr(0, 8) == "charset=")
0462         {
0463             // the prepended charset specification is followed by a blank
0464             std::string::size_type pos = comment.find_first_of(' ');
0465             
0466             if (pos != std::string::npos)
0467             {
0468                 // extract string between the = and the blank
0469                 charset = comment.substr(8, pos-8);
0470                 // get the rest of the string after the charset specification
0471                 comment = comment.substr(pos+1);
0472             }
0473         }
0474         
0475         if (charset == "\"Unicode\"")
0476         {
0477             return QString::fromUtf8(comment.data());
0478         }
0479         else if (charset == "\"Jis\"")
0480         {
0481             QTextCodec* const codec = QTextCodec::codecForName("JIS7");
0482             return codec->toUnicode(comment.c_str());
0483         }
0484         else if (charset == "\"Ascii\"")
0485         {
0486             return QString::fromLatin1(comment.c_str());
0487         }
0488         else
0489         {
0490             return detectEncodingAndDecode(comment);
0491         }
0492     }
0493     catch( Exiv2::Error& e )
0494     {
0495         qWarning() << (QString::fromLatin1("Cannot convert Comment using Exiv2 "), e.what());
0496     }
0497     catch(...)
0498     {
0499         qWarning()<< "Default exception from Exiv2";
0500     }
0501     
0502     return QString();
0503 }
0504 
0505 MetaDataMap Exiv2Extractor::getExifTagsDataList(const QStringList& exifKeysFilter, bool invertSelection) const
0506 {
0507     if (exifData().empty())
0508         return MetaDataMap();
0509     
0510     try
0511     {
0512         Exiv2::ExifData &data = exifData();
0513         data.sortByKey();
0514         
0515         MetaDataMap metaDataMap;
0516         
0517         for (Exiv2::ExifData::iterator md = data.begin(); md != data.end(); ++md)
0518         {
0519             QString key = QString::fromLatin1(md->key().c_str());
0520             
0521             // Decode the tag value with a user friendly output.
0522             QString tagValue;
0523             
0524             if (key == QString::fromLatin1("Exif.Photo.UserComment"))
0525             {
0526                 tagValue = convertCommentValue(*md);
0527             }
0528             else if (key == QString::fromLatin1("Exif.Image.0x935c"))
0529             {
0530                 tagValue = QString::number(md->value().size());
0531             }
0532             else
0533             {
0534                 std::ostringstream os;
0535                 os << *md;
0536                 
0537                 // Exif tag contents can be an translated strings, no only simple ascii.
0538                 tagValue = QString::fromLocal8Bit(os.str().c_str());
0539             }
0540             
0541             tagValue.replace(QString::fromLatin1("\n"), QString::fromLatin1(" "));
0542             
0543             // We apply a filter to get only the Exif tags that we need.
0544             
0545             if (!exifKeysFilter.isEmpty())
0546             {
0547                 if (!invertSelection)
0548                 {
0549                     if (exifKeysFilter.contains(key.section(QString::fromLatin1("."), 1, 1)))
0550                         metaDataMap.insert(key, tagValue);
0551                 }
0552                 else
0553                 {
0554                     if (!exifKeysFilter.contains(key.section(QString::fromLatin1("."), 1, 1)))
0555                         metaDataMap.insert(key, tagValue);
0556                 }
0557             }
0558             else // else no filter at all.
0559             {
0560                 metaDataMap.insert(key, tagValue);
0561             }
0562         }
0563         
0564         return metaDataMap;
0565     }
0566     catch (Exiv2::Error& e)
0567     {
0568         qWarning() << (QString::fromLatin1("Cannot parse EXIF metadata using Exiv2 "), e.what());
0569     }
0570     catch(...)
0571     {
0572         qWarning() << "Default exception from Exiv2";
0573     }
0574     
0575     return MetaDataMap();
0576 }
0577 
0578 QString Exiv2Extractor::getExifComment() const
0579 {
0580     try
0581     {
0582         if (!exifData().empty())
0583         {
0584             Exiv2::ExifData &data(exifData());
0585             Exiv2::ExifKey key("Exif.Photo.UserComment");
0586             Exiv2::ExifData::iterator it = data.findKey(key);
0587             
0588             if (it != data.end())
0589             {
0590                 QString exifComment = convertCommentValue(*it);
0591                 
0592                 // some cameras fill the UserComment with whitespace
0593                 if (!exifComment.isEmpty() && !exifComment.trimmed().isEmpty())
0594                     return exifComment;
0595             }
0596             
0597             Exiv2::ExifKey key2("Exif.Image.ImageDescription");
0598             Exiv2::ExifData::iterator it2 = data.findKey(key2);
0599             
0600             if (it2 != data.end())
0601             {
0602                 QString exifComment = convertCommentValue(*it2);
0603                 
0604                 // Some cameras fill in nonsense default values
0605                 QStringList blackList;
0606                 blackList << QString::fromLatin1("SONY DSC"); // + whitespace
0607                 blackList << QString::fromLatin1("OLYMPUS DIGITAL CAMERA");
0608                 blackList << QString::fromLatin1("MINOLTA DIGITAL CAMERA");
0609                 
0610                 QString trimmedComment = exifComment.trimmed();
0611                 
0612                 // some cameras fill the UserComment with whitespace
0613                 if (!exifComment.isEmpty() && !trimmedComment.isEmpty() && !blackList.contains(trimmedComment))
0614                     return exifComment;
0615             }
0616         }
0617     }
0618     catch( Exiv2::Error& e )
0619     {
0620         qWarning() << (QString::fromLatin1("Cannot find Exif User Comment using Exiv2 "), e.what());
0621     }
0622     catch(...)
0623     {
0624         qWarning() << "Default exception from Exiv2";
0625     }
0626     
0627     return QString();
0628 }
0629 
0630 QString Exiv2Extractor::GPSString() const
0631 {
0632     if(error())
0633     {
0634         return QString();
0635     }
0636     
0637     City m_city(city());
0638        
0639     if(!m_city.isValid())
0640     {
0641         return QString();
0642     }
0643     
0644     return m_city.name();
0645 }
0646 
0647 QString Exiv2Extractor::cityId() const
0648 {
0649     if(error())
0650     {
0651         return QString();
0652     }   
0653  
0654     return city().id();
0655 }
0656 
0657 City Exiv2Extractor::city() const
0658 {
0659     if(error())
0660     {
0661         return City();
0662     }
0663     
0664     auto c = extractGPS();
0665     
0666     if(c.first == 0.0 || c.second == 0.0)
0667     {
0668         return City();
0669     }
0670     
0671     return Cities::getInstance()->findCity(c.first, c.second);
0672 }
0673 
0674 bool Exiv2Extractor::writeTag(const char *tagName, const QVariant &value)
0675 {
0676     try
0677     {
0678         qDebug() << "trying to write tag4";
0679         
0680         Exiv2::ExifKey exifKey(tagName);
0681         Exiv2::ExifData &data = (exifData());
0682         Exiv2::ExifData::iterator it = data.findKey(exifKey);
0683         qDebug() << "trying to write tag5";
0684         
0685         if (it != data.end())
0686         {
0687             qDebug() << "trying to write tag2";
0688             
0689             switch (it->typeId())
0690             {
0691                 case Exiv2::unsignedByte:
0692                 case Exiv2::unsignedShort:
0693                 case Exiv2::unsignedLong:
0694                 case Exiv2::signedShort:
0695                 case Exiv2::signedLong:
0696                 case Exiv2::unsignedLongLong:
0697                 case Exiv2::signedLongLong:
0698                 {
0699                     if(!value.canConvert<QString>())
0700                         return false;
0701                     
0702                     qDebug() << "Writting number metadata" << tagName;
0703                     
0704 #if EXIV2_TEST_VERSION(0,28,0)
0705             Exiv2::Value::UniquePtr v = Exiv2::Value::create(Exiv2::signedLongLong);
0706 
0707 #else
0708             Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::signedLongLong);
0709 #endif
0710                     v->read(value.toString().toStdString());
0711                     it->setValue(v.get());
0712                     break;
0713                 }
0714                 
0715                 case Exiv2::unsignedRational:
0716                 case Exiv2::signedRational:
0717                 {
0718                     if(!value.canConvert<QString>())
0719                         return false;                
0720                                                             qDebug() << "Writting rational metadata" << tagName;
0721 
0722 #if EXIV2_TEST_VERSION(0,28,0)
0723             Exiv2::RationalValue::UniquePtr rv(new Exiv2::RationalValue);
0724 
0725 #else
0726             Exiv2::RationalValue::AutoPtr rv(new Exiv2::RationalValue);
0727 #endif
0728                     rv->read(value.toString().toStdString());
0729                     it->setValue(rv.get());
0730                     break;               
0731                     
0732                 }
0733                 case Exiv2::date:
0734                 case Exiv2::time:
0735                 {
0736                     if(!value.canConvert<QString>())
0737                         return false;
0738                     
0739                     auto date = value.toString();
0740 
0741 #if EXIV2_TEST_VERSION(0,28,0)
0742             Exiv2::Value::UniquePtr v = Exiv2::Value::create(Exiv2::asciiString);
0743 
0744 #else
0745             Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::asciiString);
0746 #endif
0747                     v->read(date.toStdString());
0748                     it->setValue(v.get());
0749                     break;
0750                     
0751                 }
0752                 case Exiv2::asciiString:
0753                 case Exiv2::comment:
0754                 case Exiv2::string:
0755                 {
0756                     if(!value.canConvert<QString>())
0757                         return false;
0758                     qDebug() << "Writting ascii metadata" << tagName;
0759                     
0760                     auto string = value.toString();
0761 
0762 #if EXIV2_TEST_VERSION(0,28,0)
0763             Exiv2::Value::UniquePtr v = Exiv2::Value::create(Exiv2::asciiString);
0764 
0765 #else
0766             Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::asciiString);
0767 #endif
0768                     v->read(string.toStdString());
0769                     it->setValue(v.get());
0770                     break;
0771                     
0772                     
0773                 }
0774                 default:
0775                                         qDebug() << "Writting unkown metadata" << tagName;
0776 
0777                     return false;
0778             }
0779             
0780             qDebug() << "Writting metadata EXIF tag to file" << tagName;
0781             //             m_image->setExifData(data);
0782             m_image->writeMetadata();
0783             return true;
0784         }else
0785         {
0786             Exiv2::Exifdatum& tag = data[tagName];
0787             std::string str = value.toString().toStdString();
0788             tag.setValue(str);
0789             m_image->writeMetadata();
0790             return true;
0791         }
0792     }
0793     catch( Exiv2::Error& e )
0794     {
0795         qWarning () << QString("Cannot find Exif key '%1' in the image using Exiv2 ").arg(QString::fromLatin1(tagName)) << e.what();
0796         return false;
0797         
0798     }
0799     catch(...)
0800     {
0801         qWarning() << "Default exception from Exiv2";
0802         return false;
0803         
0804     }
0805     return false;
0806 }
0807 
0808 bool Exiv2Extractor::removeTag(const char *tagName)
0809 {
0810     
0811     try
0812     {
0813         Exiv2::ExifKey key = Exiv2::ExifKey(tagName);
0814         Exiv2::ExifData &data = (exifData());
0815         
0816         Exiv2::ExifData::iterator it = data.findKey(key);
0817         
0818         if (it != data.end())
0819         {
0820             data.erase(it);
0821             m_image->writeMetadata();
0822             return true;
0823         }
0824     }
0825     catch( Exiv2::Error& e )
0826     {
0827         qWarning () << QString("Cannot find Exif key '%1' in the image using Exiv2 ").arg(QString::fromLatin1(tagName)) << e.what();
0828         return false;
0829         
0830     }
0831     catch(...)
0832     {
0833         qWarning() << "Default exception from Exiv2";
0834         return false;
0835         
0836     }
0837     
0838     return false;
0839 }
0840