56QVariant
decodeXmpData(
const QString &key, Exiv2::XmpData::const_iterator &it )
59 if ( key == QLatin1String(
"Xmp.xmp.MetadataDate" ) ||
60 key == QLatin1String(
"Xmp.xmp.CreateDate" ) ||
61 key == QLatin1String(
"Xmp.xmp.ModifyDate" ) )
63 val = QVariant::fromValue( QDateTime::fromString( QString::fromStdString( it->toString() ), Qt::ISODate ) );
67 switch ( it->typeId() )
69 case Exiv2::asciiString:
72 case Exiv2::directory:
74 val = QString::fromStdString( it->toString() );
77 case Exiv2::unsignedLong:
78 case Exiv2::signedLong:
79 case Exiv2::unsignedLongLong:
80 case Exiv2::signedLongLong:
81#if EXIV2_TEST_VERSION (0, 28, 0)
82 val = QVariant::fromValue( it->toUint32() );
84 val = QVariant::fromValue( it->toLong() );
88 case Exiv2::tiffDouble:
89 case Exiv2::tiffFloat:
90 val = QVariant::fromValue( it->toFloat() );
93 case Exiv2::unsignedShort:
94 case Exiv2::signedShort:
95 case Exiv2::unsignedByte:
96 case Exiv2::signedByte:
99#if EXIV2_TEST_VERSION (0, 28, 0)
100 val = QVariant::fromValue(
static_cast< int >( it->toUint32() ) );
102 val = QVariant::fromValue(
static_cast< int >( it->toLong() ) );
108 const Exiv2::DateValue::Date date =
static_cast< const Exiv2::DateValue *
>( &it->value() )->getDate();
109 val = QVariant::fromValue( QDate::fromString( QStringLiteral(
"%1-%2-%3" ).arg( date.year )
110 .arg( QString::number( date.month ).rightJustified( 2,
'0' ) )
111 .arg( QString::number( date.day ).rightJustified( 2,
'0' ) ), QLatin1String(
"yyyy-MM-dd" ) ) );
117 const Exiv2::TimeValue::Time time =
static_cast< const Exiv2::TimeValue *
>( &it->value() )->getTime();
118 val = QVariant::fromValue( QTime::fromString( QStringLiteral(
"%1:%2:%3" ).arg( QString::number( time.hour ).rightJustified( 2,
'0' ) )
119 .arg( QString::number( time.minute ).rightJustified( 2,
'0' ) )
120 .arg( QString::number( time.second ).rightJustified( 2,
'0' ) ), QLatin1String(
"hh:mm:ss" ) ) );
124 case Exiv2::unsignedRational:
125 case Exiv2::signedRational:
127 if ( it->count() == 1 )
129 val = QVariant::fromValue(
readRational( it->value() ) );
133 val = QString::fromStdString( it->toString() );
138 case Exiv2::undefined:
143 case Exiv2::invalidTypeId:
144 case Exiv2::lastTypeId:
145 val = QString::fromStdString( it->toString() );
153QVariant
decodeExifData(
const QString &key, Exiv2::ExifData::const_iterator &it )
157 if ( key == QLatin1String(
"Exif.GPSInfo.GPSLatitude" ) ||
158 key == QLatin1String(
"Exif.GPSInfo.GPSLongitude" ) ||
159 key == QLatin1String(
"Exif.GPSInfo.GPSDestLatitude" ) ||
160 key == QLatin1String(
"Exif.GPSInfo.GPSDestLongitude" ) )
164 else if ( key == QLatin1String(
"Exif.GPSInfo.GPSTimeStamp" ) )
166 const QStringList parts = QString::fromStdString( it->toString() ).split( QRegularExpression( QStringLiteral(
"\\s+" ) ) );
167 if ( parts.size() == 3 )
169 const int hour = std::max( 0, std::min( 23,
static_cast< int >(
readRational( it->value(), 0 ) ) ) );
170 const int minute = std::max( 0, std::min( 59,
static_cast< int >(
readRational( it->value(), 1 ) ) ) );
171 const int second = std::max( 0, std::min( 59,
static_cast< int >(
readRational( it->value(), 2 ) ) ) );
173 val = QVariant::fromValue( QTime::fromString( QStringLiteral(
"%1:%2:%3" )
174 .arg( QString::number( hour ).rightJustified( 2,
'0' ) )
175 .arg( QString::number( minute ).rightJustified( 2,
'0' ) )
176 .arg( QString::number( second ).rightJustified( 2,
'0' ) ), QLatin1String(
"hh:mm:ss" ) ) );
179 else if ( key == QLatin1String(
"Exif.GPSInfo.GPSDateStamp" ) )
181 val = QVariant::fromValue( QDate::fromString( QString::fromStdString( it->toString() ), QLatin1String(
"yyyy:MM:dd" ) ) );
183 else if ( key == QLatin1String(
"Exif.Image.DateTime" ) ||
184 key == QLatin1String(
"Exif.Image.DateTime" ) ||
185 key == QLatin1String(
"Exif.Photo.DateTimeDigitized" ) ||
186 key == QLatin1String(
"Exif.Photo.DateTimeOriginal" ) )
188 val = QVariant::fromValue( QDateTime::fromString( QString::fromStdString( it->toString() ), QLatin1String(
"yyyy:MM:dd hh:mm:ss" ) ) );
192 switch ( it->typeId() )
194 case Exiv2::asciiString:
197 case Exiv2::directory:
199 val = QString::fromStdString( it->toString() );
202 case Exiv2::unsignedLong:
203 case Exiv2::signedLong:
204 case Exiv2::unsignedLongLong:
205 case Exiv2::signedLongLong:
206#if EXIV2_TEST_VERSION (0, 28, 0)
207 val = QVariant::fromValue( it->toUint32() );
209 val = QVariant::fromValue( it->toLong() );
213 case Exiv2::tiffDouble:
214 case Exiv2::tiffFloat:
215 val = QVariant::fromValue( it->toFloat() );
218 case Exiv2::unsignedShort:
219 case Exiv2::signedShort:
220 case Exiv2::unsignedByte:
221 case Exiv2::signedByte:
223 case Exiv2::tiffIfd8:
224#if EXIV2_TEST_VERSION (0, 28, 0)
225 val = QVariant::fromValue(
static_cast< int >( it->toUint32() ) );
227 val = QVariant::fromValue(
static_cast< int >( it->toLong() ) );
233 const Exiv2::DateValue::Date date =
static_cast< const Exiv2::DateValue *
>( &it->value() )->getDate();
234 val = QVariant::fromValue( QDate::fromString( QStringLiteral(
"%1-%2-%3" ).arg( date.year )
235 .arg( QString::number( date.month ).rightJustified( 2,
'0' ) )
236 .arg( QString::number( date.day ).rightJustified( 2,
'0' ) ), QLatin1String(
"yyyy-MM-dd" ) ) );
242 const Exiv2::TimeValue::Time time =
static_cast< const Exiv2::TimeValue *
>( &it->value() )->getTime();
243 val = QVariant::fromValue( QTime::fromString( QStringLiteral(
"%1:%2:%3" ).arg( QString::number( time.hour ).rightJustified( 2,
'0' ) )
244 .arg( QString::number( time.minute ).rightJustified( 2,
'0' ) )
245 .arg( QString::number( time.second ).rightJustified( 2,
'0' ) ), QLatin1String(
"hh:mm:ss" ) ) );
249 case Exiv2::unsignedRational:
250 case Exiv2::signedRational:
252 if ( it->count() == 1 )
254 val = QVariant::fromValue(
readRational( it->value() ) );
258 val = QString::fromStdString( it->toString() );
263 case Exiv2::undefined:
268 case Exiv2::invalidTypeId:
269 case Exiv2::lastTypeId:
270 val = QString::fromStdString( it->toString() );
290 if ( !QFileInfo::exists( imagePath ) )
295 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
296 if ( !image || key.isEmpty() )
299 image->readMetadata();
301 if ( key.startsWith( QLatin1String(
"Xmp." ) ) )
303 Exiv2::XmpData &xmpData = image->xmpData();
304 if ( xmpData.empty() )
308 Exiv2::XmpData::const_iterator i = xmpData.findKey( Exiv2::XmpKey( key.toUtf8().constData() ) );
309 return i != xmpData.end() ?
decodeXmpData( key, i ) : QVariant();
313 Exiv2::ExifData &exifData = image->exifData();
314 if ( exifData.empty() )
318 Exiv2::ExifData::const_iterator i = exifData.findKey( Exiv2::ExifKey( key.toUtf8().constData() ) );
319 return i != exifData.end() ?
decodeExifData( key, i ) : QVariant();
330 if ( !QFileInfo::exists( imagePath ) )
331 return QVariantMap();
336 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
338 return QVariantMap();
339 image->readMetadata();
341 Exiv2::ExifData &exifData = image->exifData();
342 if ( !exifData.empty() )
344 const Exiv2::ExifData::const_iterator end = exifData.end();
345 for ( Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i )
347 const QString key = QString::fromStdString( i->key() );
352 Exiv2::XmpData &xmpData = image->xmpData();
353 if ( !xmpData.empty() )
355 const Exiv2::XmpData::const_iterator end = xmpData.end();
356 for ( Exiv2::XmpData::const_iterator i = xmpData.begin(); i != end; ++i )
358 const QString key = QString::fromStdString( i->key() );
367 return QVariantMap();
381 if ( !QFileInfo::exists( imagePath ) )
385 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
389 image->readMetadata();
390 Exiv2::ExifData &exifData = image->exifData();
392 if ( exifData.empty() )
395 const Exiv2::ExifData::iterator itLatRef = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLatitudeRef" ) );
396 const Exiv2::ExifData::iterator itLatVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLatitude" ) );
397 const Exiv2::ExifData::iterator itLonRef = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLongitudeRef" ) );
398 const Exiv2::ExifData::iterator itLonVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLongitude" ) );
400 if ( itLatRef == exifData.end() || itLatVal == exifData.end() ||
401 itLonRef == exifData.end() || itLonVal == exifData.end() )
407 const QString latRef = QString::fromStdString( itLatRef->value().toString() );
408 const QString lonRef = QString::fromStdString( itLonRef->value().toString() );
409 if ( latRef.compare( QLatin1String(
"S" ), Qt::CaseInsensitive ) == 0 )
413 if ( lonRef.compare( QLatin1String(
"W" ), Qt::CaseInsensitive ) == 0 )
420 const Exiv2::ExifData::iterator itElevVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitude" ) );
421 const Exiv2::ExifData::iterator itElevRefVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitudeRef" ) );
422 if ( itElevVal != exifData.end() )
425 if ( itElevRefVal != exifData.end() )
427 const QString elevRef = QString::fromStdString( itElevRefVal->value().toString() );
428 if ( elevRef.compare( QLatin1String(
"1" ), Qt::CaseInsensitive ) == 0 )
483 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
487 QVariant actualValue;
488 bool actualValueIsUShort =
false;
489 if ( tag == QLatin1String(
"Exif.GPSInfo.GPSLatitude" ) ||
490 tag == QLatin1String(
"Exif.GPSInfo.GPSLongitude" ) ||
491 tag == QLatin1String(
"Exif.GPSInfo.GPSDestLatitude" ) ||
492 tag == QLatin1String(
"Exif.GPSInfo.GPSDestLongitude" ) )
496 else if ( tag == QLatin1String(
"Exif.GPSInfo.GPSAltitude" ) )
498 actualValue = QStringLiteral(
"%1/1000" ).arg(
static_cast< int>( std::floor( std::abs( value.toDouble() ) * 1000 ) ) );
500 else if ( tag == QLatin1String(
"Exif.Image.Orientation" ) )
502 actualValueIsUShort =
true;
505 else if ( value.userType() == QMetaType::Type::QDateTime )
507 const QDateTime dateTime = value.toDateTime();
508 if ( tag == QLatin1String(
"Exif.Image.DateTime" ) ||
509 tag == QLatin1String(
"Exif.Image.DateTime" ) ||
510 tag == QLatin1String(
"Exif.Photo.DateTimeDigitized" ) ||
511 tag == QLatin1String(
"Exif.Photo.DateTimeOriginal" ) )
513 actualValue = dateTime.toString( QStringLiteral(
"yyyy:MM:dd hh:mm:ss" ) );
517 actualValue = dateTime.toString( Qt::ISODate );
520 else if ( value.userType() == QMetaType::Type::QDate )
522 const QDate date = value.toDate();
523 if ( tag == QLatin1String(
"Exif.GPSInfo.GPSDateStamp" ) )
525 actualValue = date.toString( QStringLiteral(
"yyyy:MM:dd" ) );
529 actualValue = date.toString( QStringLiteral(
"yyyy-MM-dd" ) );
532 else if ( value.userType() == QMetaType::Type::QTime )
534 const QTime time = value.toTime();
535 if ( tag == QLatin1String(
"Exif.GPSInfo.GPSTimeStamp" ) )
537 actualValue = QStringLiteral(
"%1/1 %2/1 %3/1" ).arg( time.hour() ).arg( time.minute() ).arg( time.second() );
541 actualValue = time.toString( QStringLiteral(
"HH:mm:ss" ) );
549 const bool isXmp = tag.startsWith( QLatin1String(
"Xmp." ) );
550 image->readMetadata();
551 if ( actualValueIsUShort )
555 Exiv2::XmpData &xmpData = image->xmpData();
556 xmpData[tag.toStdString()] =
static_cast<ushort
>( actualValue.toLongLong() );
560 Exiv2::ExifData &exifData = image->exifData();
561 exifData[tag.toStdString()] =
static_cast<ushort
>( actualValue.toLongLong() );
564 else if ( actualValue.userType() == QMetaType::Type::Int ||
565 actualValue.userType() == QMetaType::Type::LongLong )
569 Exiv2::XmpData &xmpData = image->xmpData();
570 xmpData[tag.toStdString()] =
static_cast<uint32_t
>( actualValue.toLongLong() );
574 Exiv2::ExifData &exifData = image->exifData();
575 exifData[tag.toStdString()] =
static_cast<uint32_t
>( actualValue.toLongLong() );
578 else if ( actualValue.userType() == QMetaType::Type::UInt ||
579 actualValue.userType() == QMetaType::Type::ULongLong )
583 Exiv2::XmpData &xmpData = image->xmpData();
584 xmpData[tag.toStdString()] =
static_cast<int32_t
>( actualValue.toULongLong() );
588 Exiv2::ExifData &exifData = image->exifData();
589 exifData[tag.toStdString()] =
static_cast<int32_t
>( actualValue.toULongLong() );
592 else if ( actualValue.userType() == QMetaType::Type::Double )
596 Exiv2::XmpData &xmpData = image->xmpData();
597 xmpData[tag.toStdString()] = Exiv2::floatToRationalCast( actualValue.toFloat() );
601 Exiv2::ExifData &exifData = image->exifData();
602 exifData[tag.toStdString()] = Exiv2::floatToRationalCast( actualValue.toFloat() );
609 Exiv2::XmpData &xmpData = image->xmpData();
610 xmpData[tag.toStdString()] = actualValue.toString().toStdString();
614 Exiv2::ExifData &exifData = image->exifData();
615 exifData[tag.toStdString()] = actualValue.toString().toStdString();
618 image->writeMetadata();