diff --git a/src/exifreader.cpp b/src/exifreader.cpp index 48ab6d6..deaf876 100644 --- a/src/exifreader.cpp +++ b/src/exifreader.cpp @@ -34,6 +34,20 @@ static void addField(QList> &result, const char *label, result.append({QString::fromLatin1(label), value}); } +static double parseGpsCoordinate(const Exiv2::ExifData &exif, const std::string &key) +{ + try { + Exiv2::ExifData::const_iterator it = exif.findKey(Exiv2::ExifKey(key)); + if (it != exif.end() && it->count() >= 3) { + double d = it->toRational(0).first / static_cast(it->toRational(0).second); + double m = it->toRational(1).first / static_cast(it->toRational(1).second); + double s = it->toRational(2).first / static_cast(it->toRational(2).second); + return d + m / 60.0 + s / 3600.0; + } + } catch (...) {} + return 0.0; +} + // EXIF orientation values run 1-8 and may encode mirroring. A 90-degree // rotation maps each value to another; the tables below cover all eight so // mirrored images stay correct. Unknown values are treated as 1 (normal). @@ -73,7 +87,9 @@ bool ExifData::isEmpty() const && dateTime.isEmpty() && make.isEmpty() && model.isEmpty() && exposureTime.isEmpty() && fNumber.isEmpty() && iso.isEmpty() && focalLength.isEmpty() && flash.isEmpty() - && filename.isEmpty() && dimensions.isEmpty() && fileSize.isEmpty(); + && filename.isEmpty() && dimensions.isEmpty() && fileSize.isEmpty() + && orientation.isEmpty() && latitude.isEmpty() && longitude.isEmpty() + && osmLink.isEmpty(); } QList> ExifData::toList() const @@ -92,6 +108,10 @@ QList> ExifData::toList() const addField(result, "Filename", filename); addField(result, "Dimensions", dimensions); addField(result, "File Size", fileSize); + addField(result, "Orientation", orientation); + addField(result, "Latitude", latitude); + addField(result, "Longitude", longitude); + addField(result, "OpenStreetMap", osmLink); return result; } @@ -158,6 +178,29 @@ ExifData ExifReader::read(const QByteArray &path) data.focalLength = findTag(exif, "Exif.Photo.FocalLength"); data.flash = findTag(exif, "Exif.Photo.Flash"); data.description = findTag(exif, "Exif.Image.ImageDescription"); + data.orientation = findTag(exif, "Exif.Image.Orientation"); + + // GPS + QString latStr = findTag(exif, "Exif.GPSInfo.GPSLatitude"); + QString latRef = findTag(exif, "Exif.GPSInfo.GPSLatitudeRef"); + if (!latStr.isEmpty() && !latRef.isEmpty()) { + data.latitude = latStr + u" " + latRef; + } + + QString lonStr = findTag(exif, "Exif.GPSInfo.GPSLongitude"); + QString lonRef = findTag(exif, "Exif.GPSInfo.GPSLongitudeRef"); + if (!lonStr.isEmpty() && !lonRef.isEmpty()) { + data.longitude = lonStr + u" " + lonRef; + } + + if (!data.latitude.isEmpty() && !data.longitude.isEmpty()) { + double lat = parseGpsCoordinate(exif, "Exif.GPSInfo.GPSLatitude"); + if (latRef == u"S") lat = -lat; + double lon = parseGpsCoordinate(exif, "Exif.GPSInfo.GPSLongitude"); + if (lonRef == u"W") lon = -lon; + data.osmLink = QString::fromLatin1("https://www.openstreetmap.org/?mlat=%1&mlon=%2#map=16/%1/%2") + .arg(lat, 0, 'f', 6).arg(lon, 0, 'f', 6); + } // IPTC Caption-Abstract const Exiv2::IptcData &iptc = image->iptcData(); diff --git a/src/exifreader.h b/src/exifreader.h index bdd6632..51aad51 100644 --- a/src/exifreader.h +++ b/src/exifreader.h @@ -19,6 +19,10 @@ struct ExifData { QString filename; QString dimensions; QString fileSize; + QString orientation; + QString latitude; + QString longitude; + QString osmLink; bool isEmpty() const; QList> toList() const; diff --git a/test/test_exifreader.cpp b/test/test_exifreader.cpp index a135a68..74eae7b 100644 --- a/test/test_exifreader.cpp +++ b/test/test_exifreader.cpp @@ -19,15 +19,31 @@ int main(int argc, char *argv[]) { // Test ExifData::toList() data.fileSize = "1.2 MiB"; + data.orientation = "1 (top, left)"; + data.latitude = "55deg 40' 32.12\" N"; + data.longitude = "12deg 34' 11.23\" E"; + data.osmLink = "https://www.openstreetmap.org/?mlat=55.675589&mlon=12.569786#map=16/55.675589/12.569786"; auto list = data.toList(); bool foundFilename = false; bool foundSize = false; + bool foundOrientation = false; + bool foundLat = false; + bool foundLon = false; + bool foundOsm = false; for (const auto &pair : list) { if (pair.first == "Filename" && pair.second == "test.jpg") foundFilename = true; if (pair.first == "File Size" && pair.second == "1.2 MiB") foundSize = true; + if (pair.first == "Orientation" && pair.second == "1 (top, left)") foundOrientation = true; + if (pair.first == "Latitude" && pair.second == "55deg 40' 32.12\" N") foundLat = true; + if (pair.first == "Longitude" && pair.second == "12deg 34' 11.23\" E") foundLon = true; + if (pair.first == "OpenStreetMap" && pair.second == "https://www.openstreetmap.org/?mlat=55.675589&mlon=12.569786#map=16/55.675589/12.569786") foundOsm = true; } assert(foundFilename); assert(foundSize); + assert(foundOrientation); + assert(foundLat); + assert(foundLon); + assert(foundOsm); qDebug() << "ExifData::toList() passed."; qDebug() << "All ExifReader tests passed!";