19#include <exiv2/exiv2.hpp>
22#include <QRegularExpression>
29 const Exiv2::Rational rational = value.toRational( n );
30 return static_cast< double >( rational.first ) / rational.second;
37 for (
int i = 0; i < 3; i++ )
45QVariant
decodeExifData(
const QString &key, Exiv2::ExifData::const_iterator &it )
49 if ( key == QLatin1String(
"Exif.GPSInfo.GPSLatitude" ) ||
50 key == QLatin1String(
"Exif.GPSInfo.GPSLongitude" ) ||
51 key == QLatin1String(
"Exif.GPSInfo.GPSDestLatitude" ) ||
52 key == QLatin1String(
"Exif.GPSInfo.GPSDestLongitude" ) )
56 else if ( key == QLatin1String(
"Exif.GPSInfo.GPSTimeStamp" ) )
58 const QStringList parts = QString::fromStdString( it->toString() ).split( QRegularExpression( QStringLiteral(
"\\s+" ) ) );
59 if ( parts.size() == 3 )
64 val = QVariant::fromValue( QTime::fromString( QStringLiteral(
"%1:%2:%3" )
65 .arg( QString::number( hour ).rightJustified( 2,
'0' ) )
66 .arg( QString::number( minute ).rightJustified( 2,
'0' ) )
67 .arg( QString::number( second ).rightJustified( 2,
'0' ) ), QLatin1String(
"hh:mm:ss" ) ) );
70 else if ( key == QLatin1String(
"Exif.GPSInfo.GPSDateStamp" ) )
72 val = QVariant::fromValue( QDate::fromString( QString::fromStdString( it->toString() ), QLatin1String(
"yyyy:MM:dd" ) ) );
74 else if ( key == QLatin1String(
"Exif.Image.DateTime" ) ||
75 key == QLatin1String(
"Exif.Image.DateTime" ) ||
76 key == QLatin1String(
"Exif.Photo.DateTimeDigitized" ) ||
77 key == QLatin1String(
"Exif.Photo.DateTimeOriginal" ) )
79 val = QVariant::fromValue( QDateTime::fromString( QString::fromStdString( it->toString() ), QLatin1String(
"yyyy:MM:dd hh:mm:ss" ) ) );
83 switch ( it->typeId() )
85 case Exiv2::asciiString:
88 case Exiv2::directory:
90 val = QString::fromStdString( it->toString() );
93 case Exiv2::unsignedLong:
94 case Exiv2::signedLong:
95 case Exiv2::unsignedLongLong:
96 case Exiv2::signedLongLong:
97 val = QVariant::fromValue( it->toLong() );
100 case Exiv2::tiffDouble:
101 case Exiv2::tiffFloat:
102 val = QVariant::fromValue( it->toFloat() );
105 case Exiv2::unsignedShort:
106 case Exiv2::signedShort:
107 case Exiv2::unsignedByte:
108 case Exiv2::signedByte:
110 case Exiv2::tiffIfd8:
111 val = QVariant::fromValue(
static_cast< int >( it->toLong() ) );
116 const Exiv2::DateValue::Date date =
static_cast< const Exiv2::DateValue *
>( &it->value() )->getDate();
117 val = QVariant::fromValue( QDate::fromString( QStringLiteral(
"%1-%2-%3" ).arg( date.year )
118 .arg( QString::number( date.month ).rightJustified( 2,
'0' ) )
119 .arg( QString::number( date.day ).rightJustified( 2,
'0' ) ), QLatin1String(
"yyyy-MM-dd" ) ) );
125 const Exiv2::TimeValue::Time time =
static_cast< const Exiv2::TimeValue *
>( &it->value() )->getTime();
126 val = QVariant::fromValue( QTime::fromString( QStringLiteral(
"%1:%2:%3" ).arg( QString::number( time.hour ).rightJustified( 2,
'0' ) )
127 .arg( QString::number( time.minute ).rightJustified( 2,
'0' ) )
128 .arg( QString::number( time.second ).rightJustified( 2,
'0' ) ), QLatin1String(
"hh:mm:ss" ) ) );
132 case Exiv2::unsignedRational:
133 case Exiv2::signedRational:
135 if ( it->count() == 1 )
141 val = QString::fromStdString( it->toString() );
146 case Exiv2::undefined:
151 case Exiv2::invalidTypeId:
152 case Exiv2::lastTypeId:
153 val = QString::fromStdString( it->toString() );
163 const double d = std::abs( val );
164 const int degrees =
static_cast< int >( std::floor( d ) );
165 const double m = 60 * ( d - degrees );
166 const int minutes =
static_cast< int >( std::floor( m ) );
167 const double s = 60 * ( m - minutes );
168 const int seconds =
static_cast< int >( std::floor( s * 1000 ) );
169 return QStringLiteral(
"%1/1 %2/1 %3/1000" ).arg( degrees ).arg( minutes ).arg( seconds );
174 if ( !QFileInfo::exists( imagePath ) )
179 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
180 if ( !image || key.isEmpty() )
183 image->readMetadata();
184 Exiv2::ExifData &exifData = image->exifData();
185 if ( exifData.empty() )
190 Exiv2::ExifData::const_iterator i = exifData.findKey( Exiv2::ExifKey( key.toUtf8().constData() ) );
191 return i != exifData.end() ?
decodeExifData( key, i ) : QVariant();
201 if ( !QFileInfo::exists( imagePath ) )
202 return QVariantMap();
206 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
208 return QVariantMap();
210 image->readMetadata();
211 Exiv2::ExifData &exifData = image->exifData();
212 if ( exifData.empty() )
214 return QVariantMap();
218 const Exiv2::ExifData::const_iterator end = exifData.end();
219 for ( Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i )
221 const QString key = QString::fromStdString( i->key() );
228 return QVariantMap();
242 if ( !QFileInfo::exists( imagePath ) )
246 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
250 image->readMetadata();
251 Exiv2::ExifData &exifData = image->exifData();
253 if ( exifData.empty() )
256 const Exiv2::ExifData::iterator itLatRef = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLatitudeRef" ) );
257 const Exiv2::ExifData::iterator itLatVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLatitude" ) );
258 const Exiv2::ExifData::iterator itLonRef = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLongitudeRef" ) );
259 const Exiv2::ExifData::iterator itLonVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLongitude" ) );
261 if ( itLatRef == exifData.end() || itLatVal == exifData.end() ||
262 itLonRef == exifData.end() || itLonVal == exifData.end() )
268 const QString latRef = QString::fromStdString( itLatRef->value().toString() );
269 const QString lonRef = QString::fromStdString( itLonRef->value().toString() );
270 if ( latRef.compare( QLatin1String(
"S" ), Qt::CaseInsensitive ) == 0 )
274 if ( lonRef.compare( QLatin1String(
"W" ), Qt::CaseInsensitive ) == 0 )
281 const Exiv2::ExifData::iterator itElevVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitude" ) );
282 const Exiv2::ExifData::iterator itElevRefVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitudeRef" ) );
283 if ( itElevVal != exifData.end() )
286 if ( itElevRefVal != exifData.end() )
288 const QString elevRef = QString::fromStdString( itElevRefVal->value().toString() );
289 if ( elevRef.compare( QLatin1String(
"1" ), Qt::CaseInsensitive ) == 0 )
311 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
315 image->readMetadata();
316 Exiv2::ExifData &exifData = image->exifData();
318 exifData[
"Exif.GPSInfo.GPSVersionID"] =
"2 0 0 0";
319 exifData[
"Exif.GPSInfo.GPSMapDatum"] =
"WGS-84";
324 const QString elevationString = QStringLiteral(
"%1/1000" ).arg(
static_cast< int>( std::floor( std::abs( details.
elevation ) * 1000 ) ) );
325 exifData[
"Exif.GPSInfo.GPSAltitude"] = elevationString.toStdString();
326 exifData[
"Exif.GPSInfo.GPSAltitudeRef"] = details.
elevation < 0.0 ?
"1" :
"0";
328 exifData[
"Exif.GPSInfo.GPSLatitudeRef"] = location.
y() > 0 ?
"N" :
"S";
329 exifData[
"Exif.GPSInfo.GPSLongitudeRef"] = location.
x() > 0 ?
"E" :
"W";
330 exifData[
"Exif.Image.GPSTag"] = 4908;
331 image->writeMetadata();
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.