// vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2008 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ // Self #include "timeutils.h" // STL #include // Qt #include // KF #include // Exiv2 #include // Local #include "gwenview_lib_debug.h" #include #include namespace Gwenview { namespace TimeUtils { static Exiv2::ExifData::const_iterator findDateTimeKey(const Exiv2::ExifData &exifData) { // Ordered list of keys to try static QList lst = QList() << Exiv2::ExifKey("Exif.Photo.DateTimeOriginal") << Exiv2::ExifKey("Exif.Image.DateTimeOriginal") << Exiv2::ExifKey("Exif.Photo.DateTimeDigitized") << Exiv2::ExifKey("Exif.Image.DateTime"); Exiv2::ExifData::const_iterator it, end = exifData.end(); for (const Exiv2::ExifKey &key : qAsConst(lst)) { it = exifData.findKey(key); if (it != end) { return it; } } return end; } struct CacheItem { QDateTime fileMTime; QDateTime realTime; void update(const KFileItem &fileItem) { QDateTime time = fileItem.time(KFileItem::ModificationTime); if (fileMTime == time) { return; } fileMTime = time; if (!updateFromExif(fileItem.url())) { realTime = time; } } bool updateFromExif(const QUrl &url) { if (!UrlUtils::urlIsFastLocalFile(url)) { return false; } const QString path = url.path(); Exiv2ImageLoader loader; if (!loader.load(path)) { return false; } std::unique_ptr img(loader.popImage().release()); try { Exiv2::ExifData exifData = img->exifData(); if (exifData.empty()) { return false; } auto it = findDateTimeKey(exifData); if (it == exifData.end()) { qCWarning(GWENVIEW_LIB_LOG) << "No date in exif header of" << path; return false; } std::ostringstream stream; stream << *it; const QString value = QString::fromLocal8Bit(stream.str().c_str()); const QDateTime dt = QDateTime::fromString(value, QStringLiteral("yyyy:MM:dd hh:mm:ss")); if (!dt.isValid()) { qCWarning(GWENVIEW_LIB_LOG) << "Invalid date in exif header of" << path; return false; } realTime = dt; return true; } catch (const Exiv2::Error &error) { qCWarning(GWENVIEW_LIB_LOG) << "Failed to read date from exif header of" << path << ". Error:" << error.what(); return false; } } }; using Cache = QHash; QDateTime dateTimeForFileItem(const KFileItem &fileItem, CachePolicy cachePolicy) { if (cachePolicy == SkipCache) { CacheItem item; item.update(fileItem); return item.realTime; } static Cache cache; const QUrl url = fileItem.targetUrl(); Cache::iterator it = cache.find(url); if (it == cache.end()) { it = cache.insert(url, CacheItem()); } it.value().update(fileItem); return it.value().realTime; } } // namespace } // namespace