19 #include <exiv2/exiv2.hpp>
21 #include <QRegularExpression>
25 QVariantMap QgsExifTools::readTags(
const QString &imagePath )
27 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
31 image->readMetadata();
32 Exiv2::ExifData &exifData = image->exifData();
33 if ( exifData.empty() )
39 Exiv2::ExifData::const_iterator end = exifData.end();
40 for ( Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i )
42 const QString key = QString::fromStdString( i->key() );
44 switch ( i->typeId() )
46 case Exiv2::asciiString:
49 case Exiv2::directory:
51 val = QString::fromStdString( i->toString() );
54 case Exiv2::unsignedLong:
55 case Exiv2::signedLong:
56 val = QVariant::fromValue( i->toLong() );
59 case Exiv2::tiffDouble:
60 case Exiv2::tiffFloat:
61 val = QVariant::fromValue( i->toFloat() );
64 case Exiv2::unsignedShort:
65 case Exiv2::signedShort:
66 val = QVariant::fromValue(
static_cast< int >( i->toLong() ) );
69 case Exiv2::unsignedRational:
70 case Exiv2::signedRational:
71 case Exiv2::unsignedByte:
72 case Exiv2::signedByte:
73 case Exiv2::undefined:
81 case Exiv2::invalidTypeId:
82 case Exiv2::lastTypeId:
83 val = QString::fromStdString( i->toString() );
88 res.insert( key, val );
96 double d = std::abs( val );
97 int degrees =
static_cast< int >( std::floor( d ) );
98 double m = 60 * ( d - degrees );
99 int minutes =
static_cast< int >( std::floor( m ) );
100 double s = 60 * ( m - minutes );
101 int seconds =
static_cast< int >( std::floor( s * 1000 ) );
102 return QStringLiteral(
"%1/1 %2/1 %3/1000" ).arg( degrees ).arg( minutes ).arg( seconds );
115 if ( !QFileInfo::exists( imagePath ) )
119 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
123 image->readMetadata();
124 Exiv2::ExifData &exifData = image->exifData();
126 if ( exifData.empty() )
129 Exiv2::ExifData::iterator itLatRef = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLatitudeRef" ) );
130 Exiv2::ExifData::iterator itLatVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLatitude" ) );
131 Exiv2::ExifData::iterator itLonRef = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLongitudeRef" ) );
132 Exiv2::ExifData::iterator itLonVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLongitude" ) );
134 if ( itLatRef == exifData.end() || itLatVal == exifData.end() ||
135 itLonRef == exifData.end() || itLonVal == exifData.end() )
138 auto readCoord = [](
const QString & coord )->
double
142 const QStringList parts = coord.split( QRegularExpression( QStringLiteral(
"\\s+" ) ) );
143 for (
const QString &rational : parts )
145 const QStringList pair = rational.split(
'/' );
146 if ( pair.size() != 2 )
148 res += ( pair[0].toDouble() / pair[1].toDouble() ) / div;
154 auto readRationale = [](
const QString & rational )->
double
156 const QStringList pair = rational.split(
'/' );
157 if ( pair.size() != 2 )
158 return std::numeric_limits< double >::quiet_NaN();
159 return pair[0].toDouble() / pair[1].toDouble();
162 double lat = readCoord( QString::fromStdString( itLatVal->value().toString() ) );
163 double lon = readCoord( QString::fromStdString( itLonVal->value().toString() ) );
165 const QString latRef = QString::fromStdString( itLatRef->value().toString() );
166 const QString lonRef = QString::fromStdString( itLonRef->value().toString() );
167 if ( latRef.compare( QLatin1String(
"S" ), Qt::CaseInsensitive ) == 0 )
171 if ( lonRef.compare( QLatin1String(
"W" ), Qt::CaseInsensitive ) == 0 )
178 Exiv2::ExifData::iterator itElevVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitude" ) );
179 Exiv2::ExifData::iterator itElevRefVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitudeRef" ) );
180 if ( itElevVal != exifData.end() )
182 double elev = readRationale( QString::fromStdString( itElevVal->value().toString() ) );
183 if ( itElevRefVal != exifData.end() )
185 const QString elevRef = QString::fromStdString( itElevRefVal->value().toString() );
186 if ( elevRef.compare( QLatin1String(
"1" ), Qt::CaseInsensitive ) == 0 )
208 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
212 image->readMetadata();
213 Exiv2::ExifData &exifData = image->exifData();
215 exifData[
"Exif.GPSInfo.GPSVersionID"] =
"2 0 0 0";
216 exifData[
"Exif.GPSInfo.GPSMapDatum"] =
"WGS-84";
221 const QString elevationString = QStringLiteral(
"%1/1000" ).arg(
static_cast< int>( std::floor( std::abs( details.
elevation ) * 1000 ) ) );
222 exifData[
"Exif.GPSInfo.GPSAltitude"] = elevationString.toStdString();
223 exifData[
"Exif.GPSInfo.GPSAltitudeRef"] = details.
elevation < 0.0 ?
"1" :
"0";
225 exifData[
"Exif.GPSInfo.GPSLatitudeRef"] = location.
y() > 0 ?
"N" :
"S";
226 exifData[
"Exif.GPSInfo.GPSLongitudeRef"] = location.
x() > 0 ?
"E" :
"W";
227 exifData[
"Exif.Image.GPSTag"] = 4908;
228 image->writeMetadata();
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.