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