21#include "exiv2extractor.h"
30#include "geolocation/cities.h"
31#include "geolocation/city.h"
47void Exiv2Extractor::setUrl(
const QUrl &url)
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 )
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);
206 catch( Exiv2::Error& e )
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)
248 list << (*it).toRational(component).
first;
249 list << (*it).toRational(component).second;
255 if (it->count() <= component)
259 double num = (*it).toRational(component).first;
260 double den = (*it).toRational(component).second;
273 case Exiv2::asciiString:
277 std::ostringstream os;
291 catch( Exiv2::Error& e )
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())
505 Exiv2::ExifData &data = exifData();
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";
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);
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 )
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 )
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 arg(Args &&... args) const const
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 isEmpty() const const
bool isValid() const const
QString toLocalFile() const const
bool canConvert() const const
QString toString() const const