mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-28 05:34:47 +01:00
Added support for Geotagged JPEG files
This commit is contained in:
parent
78d07cc166
commit
bf845a4a65
10
gpxsee.pro
10
gpxsee.pro
@ -29,6 +29,7 @@ HEADERS += src/common/config.h \
|
|||||||
src/common/kv.h \
|
src/common/kv.h \
|
||||||
src/common/greatcircle.h \
|
src/common/greatcircle.h \
|
||||||
src/common/programpaths.h \
|
src/common/programpaths.h \
|
||||||
|
src/common/tifffile.h \
|
||||||
src/GUI/app.h \
|
src/GUI/app.h \
|
||||||
src/GUI/icons.h \
|
src/GUI/icons.h \
|
||||||
src/GUI/gui.h \
|
src/GUI/gui.h \
|
||||||
@ -108,7 +109,6 @@ HEADERS += src/common/config.h \
|
|||||||
src/map/pcs.h \
|
src/map/pcs.h \
|
||||||
src/map/transform.h \
|
src/map/transform.h \
|
||||||
src/map/mapfile.h \
|
src/map/mapfile.h \
|
||||||
src/map/tifffile.h \
|
|
||||||
src/map/gcs.h \
|
src/map/gcs.h \
|
||||||
src/map/angularunits.h \
|
src/map/angularunits.h \
|
||||||
src/map/primemeridian.h \
|
src/map/primemeridian.h \
|
||||||
@ -161,7 +161,8 @@ HEADERS += src/common/config.h \
|
|||||||
src/GUI/coordinatesitem.h \
|
src/GUI/coordinatesitem.h \
|
||||||
src/map/rmap.h \
|
src/map/rmap.h \
|
||||||
src/map/calibrationpoint.h \
|
src/map/calibrationpoint.h \
|
||||||
src/map/color.h
|
src/map/color.h \
|
||||||
|
src/data/exifparser.h
|
||||||
SOURCES += src/main.cpp \
|
SOURCES += src/main.cpp \
|
||||||
src/common/coordinates.cpp \
|
src/common/coordinates.cpp \
|
||||||
src/common/rectc.cpp \
|
src/common/rectc.cpp \
|
||||||
@ -169,6 +170,7 @@ SOURCES += src/main.cpp \
|
|||||||
src/common/util.cpp \
|
src/common/util.cpp \
|
||||||
src/common/greatcircle.cpp \
|
src/common/greatcircle.cpp \
|
||||||
src/common/programpaths.cpp \
|
src/common/programpaths.cpp \
|
||||||
|
src/common/tifffile.cpp \
|
||||||
src/GUI/app.cpp \
|
src/GUI/app.cpp \
|
||||||
src/GUI/gui.cpp \
|
src/GUI/gui.cpp \
|
||||||
src/GUI/axisitem.cpp \
|
src/GUI/axisitem.cpp \
|
||||||
@ -233,7 +235,6 @@ SOURCES += src/main.cpp \
|
|||||||
src/map/pcs.cpp \
|
src/map/pcs.cpp \
|
||||||
src/map/transform.cpp \
|
src/map/transform.cpp \
|
||||||
src/map/mapfile.cpp \
|
src/map/mapfile.cpp \
|
||||||
src/map/tifffile.cpp \
|
|
||||||
src/map/projection.cpp \
|
src/map/projection.cpp \
|
||||||
src/map/gcs.cpp \
|
src/map/gcs.cpp \
|
||||||
src/map/angularunits.cpp \
|
src/map/angularunits.cpp \
|
||||||
@ -277,7 +278,8 @@ SOURCES += src/main.cpp \
|
|||||||
src/data/polygon.cpp \
|
src/data/polygon.cpp \
|
||||||
src/map/obliquestereographic.cpp \
|
src/map/obliquestereographic.cpp \
|
||||||
src/GUI/coordinatesitem.cpp \
|
src/GUI/coordinatesitem.cpp \
|
||||||
src/map/rmap.cpp
|
src/map/rmap.cpp \
|
||||||
|
src/data/exifparser.cpp
|
||||||
|
|
||||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||||
HEADERS += src/data/geojsonparser.h
|
HEADERS += src/data/geojsonparser.h
|
||||||
|
@ -4,25 +4,23 @@
|
|||||||
#define TIFF_MM 0x4D4D
|
#define TIFF_MM 0x4D4D
|
||||||
#define TIFF_MAGIC 42
|
#define TIFF_MAGIC 42
|
||||||
|
|
||||||
bool TIFFFile::readHeader(quint32 &ifd)
|
TIFFFile::TIFFFile(QIODevice *device) : _device(device), _ifd(0)
|
||||||
{
|
{
|
||||||
quint16 endian, magic;
|
quint16 endian, magic;
|
||||||
|
|
||||||
if (QFile::read((char*)&endian, sizeof(endian)) < (qint64)sizeof(endian))
|
if (_device->read((char*)&endian, sizeof(endian)) < (qint64)sizeof(endian))
|
||||||
return false;
|
return;
|
||||||
if (endian == TIFF_II)
|
if (endian == TIFF_II)
|
||||||
_be = false;
|
_be = false;
|
||||||
else if (endian == TIFF_MM)
|
else if (endian == TIFF_MM)
|
||||||
_be = true;
|
_be = true;
|
||||||
else
|
else
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
if (!readValue(magic))
|
if (!readValue(magic))
|
||||||
return false;
|
return;
|
||||||
if (magic != TIFF_MAGIC)
|
if (magic != TIFF_MAGIC)
|
||||||
return false;
|
return;
|
||||||
if (!readValue(ifd))
|
if (!readValue(_ifd))
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
@ -1,21 +1,31 @@
|
|||||||
#ifndef TIFFFILE_H
|
#ifndef TIFFFILE_H
|
||||||
#define TIFFFILE_H
|
#define TIFFFILE_H
|
||||||
|
|
||||||
#include <QFile>
|
#include <QIODevice>
|
||||||
#include <QtEndian>
|
#include <QtEndian>
|
||||||
|
|
||||||
class TIFFFile : public QFile
|
#define TIFF_BYTE 1
|
||||||
|
#define TIFF_ASCII 2
|
||||||
|
#define TIFF_SHORT 3
|
||||||
|
#define TIFF_LONG 4
|
||||||
|
#define TIFF_RATIONAL 5
|
||||||
|
#define TIFF_DOUBLE 12
|
||||||
|
|
||||||
|
class TIFFFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TIFFFile() : _be(false) {}
|
TIFFFile(QIODevice *device);
|
||||||
TIFFFile(const QString &path) : QFile(path), _be(false) {}
|
|
||||||
|
|
||||||
bool readHeader(quint32 &ifd);
|
bool isValid() const {return _ifd != 0;}
|
||||||
|
quint32 ifd() const {return _ifd;}
|
||||||
|
|
||||||
|
bool seek(qint64 pos) {return _device->seek(pos);}
|
||||||
|
qint64 pos() const {return _device->pos();}
|
||||||
template<class T> bool readValue(T &val)
|
template<class T> bool readValue(T &val)
|
||||||
{
|
{
|
||||||
T data;
|
T data;
|
||||||
|
|
||||||
if (QFile::read((char*)&data, sizeof(T)) < (qint64)sizeof(T))
|
if (_device->read((char*)&data, sizeof(T)) < (qint64)sizeof(T))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||||
@ -37,7 +47,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QIODevice *_device;
|
||||||
bool _be;
|
bool _be;
|
||||||
|
quint32 _ifd;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TIFFFILE_H
|
#endif // TIFFFILE_H
|
@ -14,6 +14,7 @@
|
|||||||
#include "slfparser.h"
|
#include "slfparser.h"
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||||
#include "geojsonparser.h"
|
#include "geojsonparser.h"
|
||||||
|
#include "exifparser.h"
|
||||||
#endif // QT 5
|
#endif // QT 5
|
||||||
#include "dem.h"
|
#include "dem.h"
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
@ -34,6 +35,7 @@ static SLFParser slf;
|
|||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||||
static GeoJSONParser geojson;
|
static GeoJSONParser geojson;
|
||||||
#endif // QT 5
|
#endif // QT 5
|
||||||
|
static EXIFParser exif;
|
||||||
|
|
||||||
static QHash<QString, Parser*> parsers()
|
static QHash<QString, Parser*> parsers()
|
||||||
{
|
{
|
||||||
@ -55,6 +57,8 @@ static QHash<QString, Parser*> parsers()
|
|||||||
hash.insert("json", &geojson);
|
hash.insert("json", &geojson);
|
||||||
hash.insert("geojson", &geojson);
|
hash.insert("geojson", &geojson);
|
||||||
#endif // QT 5
|
#endif // QT 5
|
||||||
|
hash.insert("jpeg", &exif);
|
||||||
|
hash.insert("jpg", &exif);
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
@ -148,6 +152,7 @@ QString Data::formats()
|
|||||||
#endif // QT5
|
#endif // QT5
|
||||||
+ qApp->translate("Data", "GPX files") + " (*.gpx);;"
|
+ qApp->translate("Data", "GPX files") + " (*.gpx);;"
|
||||||
+ qApp->translate("Data", "IGC files") + " (*.igc);;"
|
+ qApp->translate("Data", "IGC files") + " (*.igc);;"
|
||||||
|
+ qApp->translate("Data", "JPEG images") + " (*.jpg *.jpeg);;"
|
||||||
+ qApp->translate("Data", "KML files") + " (*.kml);;"
|
+ qApp->translate("Data", "KML files") + " (*.kml);;"
|
||||||
+ qApp->translate("Data", "LOC files") + " (*.loc);;"
|
+ qApp->translate("Data", "LOC files") + " (*.loc);;"
|
||||||
+ qApp->translate("Data", "NMEA files") + " (*.nmea);;"
|
+ qApp->translate("Data", "NMEA files") + " (*.nmea);;"
|
||||||
|
196
src/data/exifparser.cpp
Normal file
196
src/data/exifparser.cpp
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
#include <QDataStream>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include "common/tifffile.h"
|
||||||
|
#include "exifparser.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define GPSIFDTag 34853
|
||||||
|
#define GPSLatitudeRef 1
|
||||||
|
#define GPSLatitude 2
|
||||||
|
#define GPSLongitudeRef 3
|
||||||
|
#define GPSLongitude 4
|
||||||
|
#define GPSAltitudeRef 5
|
||||||
|
#define GPSAltitude 6
|
||||||
|
|
||||||
|
static double altitude(TIFFFile &file, quint32 offset)
|
||||||
|
{
|
||||||
|
if (!file.seek(offset))
|
||||||
|
return NAN;
|
||||||
|
|
||||||
|
quint32 num, den;
|
||||||
|
if (!file.readValue(num))
|
||||||
|
return false;
|
||||||
|
if (!file.readValue(den))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return num/den;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double coordinate(TIFFFile &file, quint32 offset)
|
||||||
|
{
|
||||||
|
if (!file.seek(offset))
|
||||||
|
return NAN;
|
||||||
|
|
||||||
|
double dms[3];
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
quint32 num, den;
|
||||||
|
if (!file.readValue(num))
|
||||||
|
return false;
|
||||||
|
if (!file.readValue(den))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
dms[i] = num/den;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dms[0] + dms[1]/60 + dms[2]/3600;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EXIFParser::readEntry(TIFFFile &file, const QSet<quint16> &tags,
|
||||||
|
QMap<quint16, IFDEntry> &entries) const
|
||||||
|
{
|
||||||
|
IFDEntry entry;
|
||||||
|
quint16 tag;
|
||||||
|
|
||||||
|
if (!file.readValue(tag))
|
||||||
|
return false;
|
||||||
|
if (!file.readValue(entry.type))
|
||||||
|
return false;
|
||||||
|
if (!file.readValue(entry.count))
|
||||||
|
return false;
|
||||||
|
if (!file.readValue(entry.offset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tags.contains(tag))
|
||||||
|
entries.insert(tag, entry);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EXIFParser::readIFD(TIFFFile &file, quint32 offset,
|
||||||
|
const QSet<quint16> &tags, QMap<quint16, IFDEntry> &entries) const
|
||||||
|
{
|
||||||
|
quint16 count;
|
||||||
|
|
||||||
|
if (!file.seek(offset))
|
||||||
|
return false;
|
||||||
|
if (!file.readValue(count))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (quint16 i = 0; i < count; i++)
|
||||||
|
if (!readEntry(file, tags, entries))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EXIFParser::parseTIFF(QDataStream &stream, QVector<Waypoint> &waypoints)
|
||||||
|
{
|
||||||
|
quint16 size;
|
||||||
|
char magic[6];
|
||||||
|
|
||||||
|
stream >> size;
|
||||||
|
if (stream.readRawData(magic, sizeof(magic)) != sizeof(magic) ||
|
||||||
|
memcmp(magic, "Exif\0\0", sizeof(magic))) {
|
||||||
|
_errorString = "No EXIF data found";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 offset = stream.device()->pos();
|
||||||
|
|
||||||
|
TIFFFile tiff(stream.device());
|
||||||
|
if (!tiff.isValid()) {
|
||||||
|
_errorString = "Invalid EXIF data";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<quint16> exifTags;
|
||||||
|
exifTags.insert(GPSIFDTag);
|
||||||
|
QMap<quint16, IFDEntry> exifEntries;
|
||||||
|
for (quint32 ifd = tiff.ifd(); ifd; ) {
|
||||||
|
if (!readIFD(tiff, offset + ifd, exifTags, exifEntries)
|
||||||
|
|| !tiff.readValue(ifd)) {
|
||||||
|
_errorString = "Invalid EXIF IFD";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!exifEntries.contains(GPSIFDTag)) {
|
||||||
|
_errorString = "GPS IFD not found";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<quint16> gpsTags;
|
||||||
|
gpsTags.insert(GPSLatitude);
|
||||||
|
gpsTags.insert(GPSLongitude);
|
||||||
|
gpsTags.insert(GPSLatitudeRef);
|
||||||
|
gpsTags.insert(GPSLongitudeRef);
|
||||||
|
gpsTags.insert(GPSAltitude);
|
||||||
|
gpsTags.insert(GPSAltitudeRef);
|
||||||
|
QMap<quint16, IFDEntry> gpsEntries;
|
||||||
|
for (quint32 ifd = exifEntries.first().offset; ifd; ) {
|
||||||
|
if (!readIFD(tiff, offset + ifd, gpsTags, gpsEntries)
|
||||||
|
|| !tiff.readValue(ifd)) {
|
||||||
|
_errorString = "Invalid GPS IFD";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IFDEntry lat(gpsEntries.value(GPSLatitude));
|
||||||
|
IFDEntry lon(gpsEntries.value(GPSLongitude));
|
||||||
|
IFDEntry latRef(gpsEntries.value(GPSLatitudeRef));
|
||||||
|
IFDEntry lonRef(gpsEntries.value(GPSLongitudeRef));
|
||||||
|
if (!(lat.type == TIFF_RATIONAL && lat.count == 3
|
||||||
|
&& lon.type == TIFF_RATIONAL && lon.count == 3
|
||||||
|
&& latRef.type == TIFF_ASCII && latRef.count == 2
|
||||||
|
&& lonRef.type == TIFF_ASCII && lonRef.count == 2)) {
|
||||||
|
_errorString = "Invalid/missing GPS IFD Lat/Lon entry";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordinates c(coordinate(tiff, offset + lon.offset),
|
||||||
|
coordinate(tiff, offset + lat.offset));
|
||||||
|
if (lonRef.offset == 'W')
|
||||||
|
c.rlon() = -c.lon();
|
||||||
|
if (latRef.offset == 'S')
|
||||||
|
c.rlat() = -c.lat();
|
||||||
|
if (!c.isValid()) {
|
||||||
|
_errorString = "Invalid coordinates";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Waypoint wp(c);
|
||||||
|
QFile *file = static_cast<QFile*>(stream.device());
|
||||||
|
wp.setName(QFileInfo(file->fileName()).fileName());
|
||||||
|
IFDEntry alt(gpsEntries.value(GPSAltitude));
|
||||||
|
IFDEntry altRef(gpsEntries.value(GPSAltitudeRef));
|
||||||
|
if (alt.type == TIFF_RATIONAL && alt.count == 1 && altRef.type == TIFF_BYTE
|
||||||
|
&& altRef.count == 1)
|
||||||
|
wp.setElevation(altRef.offset ? -altitude(tiff, alt.offset)
|
||||||
|
: altitude(tiff, alt.offset));
|
||||||
|
|
||||||
|
waypoints.append(wp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EXIFParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||||
|
QList<RouteData> &routes, QList<Area> &polygons,
|
||||||
|
QVector<Waypoint> &waypoints)
|
||||||
|
{
|
||||||
|
Q_UNUSED(tracks);
|
||||||
|
Q_UNUSED(routes);
|
||||||
|
Q_UNUSED(polygons);
|
||||||
|
|
||||||
|
QDataStream stream(file);
|
||||||
|
stream.setByteOrder(QDataStream::BigEndian);
|
||||||
|
|
||||||
|
quint16 marker;
|
||||||
|
while (!stream.atEnd()) {
|
||||||
|
stream >> marker;
|
||||||
|
if (marker == 0xFFE1)
|
||||||
|
return parseTIFF(stream, waypoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
_errorString = "No EXIF data found";
|
||||||
|
return false;
|
||||||
|
}
|
35
src/data/exifparser.h
Normal file
35
src/data/exifparser.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef EXIFPARSER_H
|
||||||
|
#define EXIFPARSER_H
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
class QDataStream;
|
||||||
|
class TIFFFile;
|
||||||
|
|
||||||
|
class EXIFParser : public Parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
|
||||||
|
QList<Area> &polygons, QVector<Waypoint> &waypoints);
|
||||||
|
QString errorString() const {return _errorString;}
|
||||||
|
int errorLine() const {return 0;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct IFDEntry {
|
||||||
|
IFDEntry() : type(0), count(0), offset(0) {}
|
||||||
|
|
||||||
|
quint16 type;
|
||||||
|
quint32 count;
|
||||||
|
quint32 offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool parseTIFF(QDataStream &stream, QVector<Waypoint> &waypoints);
|
||||||
|
bool readIFD(TIFFFile &file, quint32 offset, const QSet<quint16> &tags,
|
||||||
|
QMap<quint16, IFDEntry> &entries) const;
|
||||||
|
bool readEntry(TIFFFile &file, const QSet<quint16> &tags,
|
||||||
|
QMap<quint16, IFDEntry> &entries) const;
|
||||||
|
|
||||||
|
QString _errorString;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EXIFPARSER_H
|
@ -1,12 +1,8 @@
|
|||||||
|
#include "common/tifffile.h"
|
||||||
#include "pcs.h"
|
#include "pcs.h"
|
||||||
#include "tifffile.h"
|
|
||||||
#include "geotiff.h"
|
#include "geotiff.h"
|
||||||
|
|
||||||
|
|
||||||
#define TIFF_DOUBLE 12
|
|
||||||
#define TIFF_SHORT 3
|
|
||||||
#define TIFF_LONG 4
|
|
||||||
|
|
||||||
#define ModelPixelScaleTag 33550
|
#define ModelPixelScaleTag 33550
|
||||||
#define ModelTiepointTag 33922
|
#define ModelTiepointTag 33922
|
||||||
#define ModelTransformationTag 34264
|
#define ModelTransformationTag 34264
|
||||||
@ -126,7 +122,7 @@ bool GeoTIFF::readEntry(TIFFFile &file, Ctx &ctx) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeoTIFF::readIFD(TIFFFile &file, quint32 &offset, Ctx &ctx) const
|
bool GeoTIFF::readIFD(TIFFFile &file, quint32 offset, Ctx &ctx) const
|
||||||
{
|
{
|
||||||
quint16 count;
|
quint16 count;
|
||||||
|
|
||||||
@ -139,9 +135,6 @@ bool GeoTIFF::readIFD(TIFFFile &file, quint32 &offset, Ctx &ctx) const
|
|||||||
if (!readEntry(file, ctx))
|
if (!readEntry(file, ctx))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!file.readValue(offset))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,27 +468,26 @@ bool GeoTIFF::geographicModel(QMap<quint16, Value> &kv)
|
|||||||
|
|
||||||
GeoTIFF::GeoTIFF(const QString &path)
|
GeoTIFF::GeoTIFF(const QString &path)
|
||||||
{
|
{
|
||||||
quint32 ifd;
|
|
||||||
QList<ReferencePoint> points;
|
QList<ReferencePoint> points;
|
||||||
PointD scale;
|
PointD scale;
|
||||||
QMap<quint16, Value> kv;
|
QMap<quint16, Value> kv;
|
||||||
Ctx ctx;
|
Ctx ctx;
|
||||||
TIFFFile file;
|
|
||||||
|
|
||||||
|
|
||||||
file.setFileName(path);
|
QFile file(path);
|
||||||
if (!file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
_errorString = QString("Error opening TIFF file: %1")
|
_errorString = file.errorString();
|
||||||
.arg(file.errorString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!file.readHeader(ifd)) {
|
|
||||||
_errorString = "Invalid TIFF header";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ifd) {
|
TIFFFile tiff(&file);
|
||||||
if (!readIFD(file, ifd, ctx)) {
|
if (!tiff.isValid()) {
|
||||||
|
_errorString = "Not a TIFF file";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (quint32 ifd = tiff.ifd(); ifd; ) {
|
||||||
|
if (!readIFD(tiff, ifd, ctx) || !tiff.readValue(ifd)) {
|
||||||
_errorString = "Invalid IFD";
|
_errorString = "Invalid IFD";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -507,19 +499,19 @@ GeoTIFF::GeoTIFF(const QString &path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.scale) {
|
if (ctx.scale) {
|
||||||
if (!readScale(file, ctx.scale, scale)) {
|
if (!readScale(tiff, ctx.scale, scale)) {
|
||||||
_errorString = "Error reading model pixel scale";
|
_errorString = "Error reading model pixel scale";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ctx.tiepoints) {
|
if (ctx.tiepoints) {
|
||||||
if (!readTiepoints(file, ctx.tiepoints, ctx.tiepointCount, points)) {
|
if (!readTiepoints(tiff, ctx.tiepoints, ctx.tiepointCount, points)) {
|
||||||
_errorString = "Error reading raster->model tiepoint pairs";
|
_errorString = "Error reading raster->model tiepoint pairs";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!readKeys(file, ctx, kv)) {
|
if (!readKeys(tiff, ctx, kv)) {
|
||||||
_errorString = "Error reading Geo key/value";
|
_errorString = "Error reading Geo key/value";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -547,7 +539,7 @@ GeoTIFF::GeoTIFF(const QString &path)
|
|||||||
_transform = Transform(points);
|
_transform = Transform(points);
|
||||||
else if (ctx.matrix) {
|
else if (ctx.matrix) {
|
||||||
double matrix[16];
|
double matrix[16];
|
||||||
if (!readMatrix(file, ctx.matrix, matrix)) {
|
if (!readMatrix(tiff, ctx.matrix, matrix)) {
|
||||||
_errorString = "Error reading transformation matrix";
|
_errorString = "Error reading transformation matrix";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool readEntry(TIFFFile &file, Ctx &ctx) const;
|
bool readEntry(TIFFFile &file, Ctx &ctx) const;
|
||||||
bool readIFD(TIFFFile &file, quint32 &offset, Ctx &ctx) const;
|
bool readIFD(TIFFFile &file, quint32 offset, Ctx &ctx) const;
|
||||||
bool readScale(TIFFFile &file, quint32 offset, PointD &scale) const;
|
bool readScale(TIFFFile &file, quint32 offset, PointD &scale) const;
|
||||||
bool readTiepoints(TIFFFile &file, quint32 offset, quint32 count,
|
bool readTiepoints(TIFFFile &file, quint32 offset, quint32 count,
|
||||||
QList<ReferencePoint> &points) const;
|
QList<ReferencePoint> &points) const;
|
||||||
|
Loading…
Reference in New Issue
Block a user