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