From 8a990d1b947c7a6ffd3bd508a5a9ebb4354ded5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Thu, 14 Mar 2019 18:52:15 +0100 Subject: [PATCH] Some more exif parser improvements --- src/GUI/waypointitem.cpp | 6 +-- src/data/exifparser.cpp | 107 +++++++++++++++++++++++---------------- src/data/exifparser.h | 2 +- 3 files changed, 66 insertions(+), 49 deletions(-) diff --git a/src/GUI/waypointitem.cpp b/src/GUI/waypointitem.cpp index 64f9f9a7..83c5b781 100644 --- a/src/GUI/waypointitem.cpp +++ b/src/GUI/waypointitem.cpp @@ -18,13 +18,13 @@ QString WaypointItem::toolTip(Units units, CoordinatesFormat format) tt.insert(qApp->translate("WaypointItem", "Name"), _waypoint.name()); tt.insert(qApp->translate("WaypointItem", "Coordinates"), Format::coordinates(_waypoint.coordinates(), format)); - if (!std::isnan(_waypoint.elevation())) + if (_waypoint.hasElevation()) tt.insert(qApp->translate("WaypointItem", "Elevation"), Format::elevation(_waypoint.elevation(), units)); - if (!_waypoint.timestamp().isNull()) + if (_waypoint.timestamp().isValid()) tt.insert(qApp->translate("WaypointItem", "Date"), _waypoint.timestamp().toString(Qt::SystemLocaleShortDate)); - if (!_waypoint.description().isNull()) + if (!_waypoint.description().isEmpty()) tt.insert(qApp->translate("WaypointItem", "Description"), _waypoint.description()); tt.setImage(_waypoint.image()); diff --git a/src/data/exifparser.cpp b/src/data/exifparser.cpp index 617a1ad2..0f8a4da5 100644 --- a/src/data/exifparser.cpp +++ b/src/data/exifparser.cpp @@ -4,15 +4,39 @@ #include "exifparser.h" -#define GPSIFDTag 34853 -#define GPSLatitudeRef 1 -#define GPSLatitude 2 -#define GPSLongitudeRef 3 -#define GPSLongitude 4 -#define GPSAltitudeRef 5 -#define GPSAltitude 6 -#define GPSTimeStamp 7 -#define GPSDateStamp 29 +#define SOI_MARKER 0xFFD8 +#define APP1_MARKER 0xFFE1 + +#define GPSIFDTag 34853 +#define ImageDescription 270 + +#define GPSLatitudeRef 1 +#define GPSLatitude 2 +#define GPSLongitudeRef 3 +#define GPSLongitude 4 +#define GPSAltitudeRef 5 +#define GPSAltitude 6 +#define GPSTimeStamp 7 +#define GPSDateStamp 29 + + +QString EXIFParser::text(TIFFFile &file, const IFDEntry &e) const +{ + if (e.type != TIFF_ASCII || !e.count) + return QString(); + + if (e.count <= sizeof(e.offset)) + return QString(QByteArray((const char *)&e.offset, sizeof(e.offset))); + + if (!file.seek(e.offset)) + return QString(); + + QByteArray str(file.read(e.count)); + if (str.size() < (int)e.count) + return QString(); + + return QString(str); +} QTime EXIFParser::time(TIFFFile &file, const IFDEntry &ts) const { @@ -36,21 +60,6 @@ QTime EXIFParser::time(TIFFFile &file, const IFDEntry &ts) const return QTime((int)hms[0], (int)hms[1], (int)hms[2]); } -QDate EXIFParser::date(TIFFFile &file, const IFDEntry &ds) const -{ - if (!(ds.type == TIFF_ASCII && ds.count == 11)) - return QDate(); - - if (!file.seek(ds.offset)) - return QDate(); - - QByteArray text(file.read(11)); - if (text.size() < 11) - return QDate(); - - return QDate::fromString(text, "yyyy:MM:dd"); -} - double EXIFParser::altitude(TIFFFile &file, const IFDEntry &alt, const IFDEntry &altRef) const { @@ -157,34 +166,35 @@ bool EXIFParser::parseTIFF(QFile *file, QVector &waypoints) return false; } - QSet exifTags; - exifTags << GPSIFDTag; - QMap exif; + QSet IFD0Tags; + IFD0Tags << GPSIFDTag << ImageDescription; + QMap IFD0; for (quint32 ifd = tiff.ifd(); ifd; ) { - if (!readIFD(tiff, ifd, exifTags, exif) || !tiff.readValue(ifd)) { - _errorString = "Invalid EXIF IFD"; + if (!readIFD(tiff, ifd, IFD0Tags, IFD0) || !tiff.readValue(ifd)) { + _errorString = "Invalid IFD0"; return false; } } - if (!exif.contains(GPSIFDTag)) { + if (!IFD0.contains(GPSIFDTag)) { _errorString = "GPS IFD not found"; return false; } - QSet gpsTags; - gpsTags << GPSLatitude << GPSLongitude << GPSLatitudeRef << GPSLongitudeRef - << GPSAltitude << GPSAltitudeRef << GPSDateStamp << GPSTimeStamp; - QMap gps; - for (quint32 ifd = exif.value(GPSIFDTag).offset; ifd; ) { - if (!readIFD(tiff, ifd, gpsTags, gps) || !tiff.readValue(ifd)) { + QSet GPSIFDTags; + GPSIFDTags << GPSLatitude << GPSLongitude << GPSLatitudeRef + << GPSLongitudeRef << GPSAltitude << GPSAltitudeRef << GPSDateStamp + << GPSTimeStamp; + QMap GPSIFD; + for (quint32 ifd = IFD0.value(GPSIFDTag).offset; ifd; ) { + if (!readIFD(tiff, ifd, GPSIFDTags, GPSIFD) || !tiff.readValue(ifd)) { _errorString = "Invalid GPS IFD"; return false; } } - Coordinates c(coordinates(tiff, gps.value(GPSLongitude), - gps.value(GPSLongitudeRef), gps.value(GPSLatitude), - gps.value(GPSLatitudeRef))); + Coordinates c(coordinates(tiff, GPSIFD.value(GPSLongitude), + GPSIFD.value(GPSLongitudeRef), GPSIFD.value(GPSLatitude), + GPSIFD.value(GPSLatitudeRef))); if (!c.isValid()) { _errorString = "Invalid/missing GPS coordinates"; return false; @@ -193,10 +203,12 @@ bool EXIFParser::parseTIFF(QFile *file, QVector &waypoints) Waypoint wp(c); wp.setName(QFileInfo(file->fileName()).baseName()); wp.setImage(file->fileName()); - wp.setElevation(altitude(tiff, gps.value(GPSAltitude), - gps.value(GPSAltitudeRef))); - wp.setTimestamp(QDateTime(date(tiff, gps.value(GPSDateStamp)), - time(tiff, gps.value(GPSTimeStamp)), Qt::UTC)); + wp.setElevation(altitude(tiff, GPSIFD.value(GPSAltitude), + GPSIFD.value(GPSAltitudeRef))); + wp.setTimestamp(QDateTime(QDate::fromString(text(tiff, + GPSIFD.value(GPSDateStamp)), "yyyy:MM:dd"), time(tiff, + GPSIFD.value(GPSTimeStamp)), Qt::UTC)); + wp.setDescription(text(tiff, IFD0.value(ImageDescription)).trimmed()); waypoints.append(wp); @@ -210,14 +222,19 @@ bool EXIFParser::parse(QFile *file, QList &tracks, Q_UNUSED(tracks); Q_UNUSED(routes); Q_UNUSED(polygons); + quint16 marker; QDataStream stream(file); stream.setByteOrder(QDataStream::BigEndian); + stream >> marker; + if (marker != SOI_MARKER) { + _errorString = "Not a JPEG file"; + return false; + } - quint16 marker; while (!stream.atEnd()) { stream >> marker; - if (marker == 0xFFE1) { + if (marker == APP1_MARKER) { quint16 size; char magic[6]; stream >> size; diff --git a/src/data/exifparser.h b/src/data/exifparser.h index 36a0e6e1..dcb1ad31 100644 --- a/src/data/exifparser.h +++ b/src/data/exifparser.h @@ -34,8 +34,8 @@ private: const IFDEntry &lonRef, const IFDEntry &lat, const IFDEntry &latRef) const; double altitude(TIFFFile &file, const IFDEntry &alt, const IFDEntry &altRef) const; - QDate date(TIFFFile &file, const IFDEntry &ds) const; QTime time(TIFFFile &file, const IFDEntry &ts) const; + QString text(TIFFFile &file, const IFDEntry &e) const; QString _errorString; };