55QVariant
decodeXmpData(
const QString &key, Exiv2::XmpData::const_iterator &it )
58 if ( key == QLatin1String(
"Xmp.xmp.MetadataDate" ) ||
59 key == QLatin1String(
"Xmp.xmp.CreateDate" ) ||
60 key == QLatin1String(
"Xmp.xmp.ModifyDate" ) )
62 val = QVariant::fromValue( QDateTime::fromString( QString::fromStdString( it->toString() ), Qt::ISODate ) );
66 switch ( it->typeId() )
68 case Exiv2::asciiString:
71 case Exiv2::directory:
73 val = QString::fromStdString( it->toString() );
76 case Exiv2::unsignedLong:
77 case Exiv2::signedLong:
78 case Exiv2::unsignedLongLong:
79 case Exiv2::signedLongLong:
80#if EXIV2_TEST_VERSION (0, 28, 0)
81 val = QVariant::fromValue( it->toUint32() );
83 val = QVariant::fromValue( it->toLong() );
87 case Exiv2::tiffDouble:
88 case Exiv2::tiffFloat:
89 val = QVariant::fromValue( it->toFloat() );
92 case Exiv2::unsignedShort:
93 case Exiv2::signedShort:
94 case Exiv2::unsignedByte:
95 case Exiv2::signedByte:
98#if EXIV2_TEST_VERSION (0, 28, 0)
99 val = QVariant::fromValue(
static_cast< int >( it->toUint32() ) );
101 val = QVariant::fromValue(
static_cast< int >( it->toLong() ) );
107 const Exiv2::DateValue::Date date =
static_cast< const Exiv2::DateValue *
>( &it->value() )->getDate();
108 val = QVariant::fromValue( QDate::fromString( QStringLiteral(
"%1-%2-%3" ).arg( date.year )
109 .arg( QString::number( date.month ).rightJustified( 2,
'0' ) )
110 .arg( QString::number( date.day ).rightJustified( 2,
'0' ) ), QLatin1String(
"yyyy-MM-dd" ) ) );
116 const Exiv2::TimeValue::Time time =
static_cast< const Exiv2::TimeValue *
>( &it->value() )->getTime();
117 val = QVariant::fromValue( QTime::fromString( QStringLiteral(
"%1:%2:%3" ).arg( QString::number( time.hour ).rightJustified( 2,
'0' ) )
118 .arg( QString::number( time.minute ).rightJustified( 2,
'0' ) )
119 .arg( QString::number( time.second ).rightJustified( 2,
'0' ) ), QLatin1String(
"hh:mm:ss" ) ) );
123 case Exiv2::unsignedRational:
124 case Exiv2::signedRational:
126 if ( it->count() == 1 )
128 val = QVariant::fromValue(
readRational( it->value() ) );
132 val = QString::fromStdString( it->toString() );
137 case Exiv2::undefined:
142 case Exiv2::invalidTypeId:
143 case Exiv2::lastTypeId:
144 val = QString::fromStdString( it->toString() );
152QVariant
decodeExifData(
const QString &key, Exiv2::ExifData::const_iterator &it )
156 if ( key == QLatin1String(
"Exif.GPSInfo.GPSLatitude" ) ||
157 key == QLatin1String(
"Exif.GPSInfo.GPSLongitude" ) ||
158 key == QLatin1String(
"Exif.GPSInfo.GPSDestLatitude" ) ||
159 key == QLatin1String(
"Exif.GPSInfo.GPSDestLongitude" ) )
163 else if ( key == QLatin1String(
"Exif.GPSInfo.GPSTimeStamp" ) )
165 const QStringList parts = QString::fromStdString( it->toString() ).split( QRegularExpression( QStringLiteral(
"\\s+" ) ) );
166 if ( parts.size() == 3 )
168 const int hour = std::max( 0, std::min( 23,
static_cast< int >(
readRational( it->value(), 0 ) ) ) );
169 const int minute = std::max( 0, std::min( 59,
static_cast< int >(
readRational( it->value(), 1 ) ) ) );
170 const int second = std::max( 0, std::min( 59,
static_cast< int >(
readRational( it->value(), 2 ) ) ) );
172 val = QVariant::fromValue( QTime::fromString( QStringLiteral(
"%1:%2:%3" )
173 .arg( QString::number( hour ).rightJustified( 2,
'0' ) )
174 .arg( QString::number( minute ).rightJustified( 2,
'0' ) )
175 .arg( QString::number( second ).rightJustified( 2,
'0' ) ), QLatin1String(
"hh:mm:ss" ) ) );
178 else if ( key == QLatin1String(
"Exif.GPSInfo.GPSDateStamp" ) )
180 val = QVariant::fromValue( QDate::fromString( QString::fromStdString( it->toString() ), QLatin1String(
"yyyy:MM:dd" ) ) );
182 else if ( key == QLatin1String(
"Exif.Image.DateTime" ) ||
183 key == QLatin1String(
"Exif.Image.DateTime" ) ||
184 key == QLatin1String(
"Exif.Photo.DateTimeDigitized" ) ||
185 key == QLatin1String(
"Exif.Photo.DateTimeOriginal" ) )
187 val = QVariant::fromValue( QDateTime::fromString( QString::fromStdString( it->toString() ), QLatin1String(
"yyyy:MM:dd hh:mm:ss" ) ) );
191 switch ( it->typeId() )
193 case Exiv2::asciiString:
196 case Exiv2::directory:
198 val = QString::fromStdString( it->toString() );
201 case Exiv2::unsignedLong:
202 case Exiv2::signedLong:
203 case Exiv2::unsignedLongLong:
204 case Exiv2::signedLongLong:
205#if EXIV2_TEST_VERSION (0, 28, 0)
206 val = QVariant::fromValue( it->toUint32() );
208 val = QVariant::fromValue( it->toLong() );
212 case Exiv2::tiffDouble:
213 case Exiv2::tiffFloat:
214 val = QVariant::fromValue( it->toFloat() );
217 case Exiv2::unsignedShort:
218 case Exiv2::signedShort:
219 case Exiv2::unsignedByte:
220 case Exiv2::signedByte:
222 case Exiv2::tiffIfd8:
223#if EXIV2_TEST_VERSION (0, 28, 0)
224 val = QVariant::fromValue(
static_cast< int >( it->toUint32() ) );
226 val = QVariant::fromValue(
static_cast< int >( it->toLong() ) );
232 const Exiv2::DateValue::Date date =
static_cast< const Exiv2::DateValue *
>( &it->value() )->getDate();
233 val = QVariant::fromValue( QDate::fromString( QStringLiteral(
"%1-%2-%3" ).arg( date.year )
234 .arg( QString::number( date.month ).rightJustified( 2,
'0' ) )
235 .arg( QString::number( date.day ).rightJustified( 2,
'0' ) ), QLatin1String(
"yyyy-MM-dd" ) ) );
241 const Exiv2::TimeValue::Time time =
static_cast< const Exiv2::TimeValue *
>( &it->value() )->getTime();
242 val = QVariant::fromValue( QTime::fromString( QStringLiteral(
"%1:%2:%3" ).arg( QString::number( time.hour ).rightJustified( 2,
'0' ) )
243 .arg( QString::number( time.minute ).rightJustified( 2,
'0' ) )
244 .arg( QString::number( time.second ).rightJustified( 2,
'0' ) ), QLatin1String(
"hh:mm:ss" ) ) );
248 case Exiv2::unsignedRational:
249 case Exiv2::signedRational:
251 if ( it->count() == 1 )
253 val = QVariant::fromValue(
readRational( it->value() ) );
257 val = QString::fromStdString( it->toString() );
262 case Exiv2::undefined:
267 case Exiv2::invalidTypeId:
268 case Exiv2::lastTypeId:
269 val = QString::fromStdString( it->toString() );
289 if ( !QFileInfo::exists( imagePath ) )
294 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
295 if ( !image || key.isEmpty() )
298 image->readMetadata();
300 if ( key.startsWith( QLatin1String(
"Xmp." ) ) )
302 Exiv2::XmpData &xmpData = image->xmpData();
303 if ( xmpData.empty() )
307 Exiv2::XmpData::const_iterator i = xmpData.findKey( Exiv2::XmpKey( key.toUtf8().constData() ) );
308 return i != xmpData.end() ?
decodeXmpData( key, i ) : QVariant();
312 Exiv2::ExifData &exifData = image->exifData();
313 if ( exifData.empty() )
317 Exiv2::ExifData::const_iterator i = exifData.findKey( Exiv2::ExifKey( key.toUtf8().constData() ) );
318 return i != exifData.end() ?
decodeExifData( key, i ) : QVariant();
329 if ( !QFileInfo::exists( imagePath ) )
330 return QVariantMap();
335 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
337 return QVariantMap();
338 image->readMetadata();
340 Exiv2::ExifData &exifData = image->exifData();
341 if ( !exifData.empty() )
343 const Exiv2::ExifData::const_iterator end = exifData.end();
344 for ( Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i )
346 const QString key = QString::fromStdString( i->key() );
351 Exiv2::XmpData &xmpData = image->xmpData();
352 if ( !xmpData.empty() )
354 const Exiv2::XmpData::const_iterator end = xmpData.end();
355 for ( Exiv2::XmpData::const_iterator i = xmpData.begin(); i != end; ++i )
357 const QString key = QString::fromStdString( i->key() );
366 return QVariantMap();
380 if ( !QFileInfo::exists( imagePath ) )
384 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
388 image->readMetadata();
389 Exiv2::ExifData &exifData = image->exifData();
391 if ( exifData.empty() )
394 const Exiv2::ExifData::iterator itLatRef = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLatitudeRef" ) );
395 const Exiv2::ExifData::iterator itLatVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLatitude" ) );
396 const Exiv2::ExifData::iterator itLonRef = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLongitudeRef" ) );
397 const Exiv2::ExifData::iterator itLonVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSLongitude" ) );
399 if ( itLatRef == exifData.end() || itLatVal == exifData.end() ||
400 itLonRef == exifData.end() || itLonVal == exifData.end() )
406 const QString latRef = QString::fromStdString( itLatRef->value().toString() );
407 const QString lonRef = QString::fromStdString( itLonRef->value().toString() );
408 if ( latRef.compare( QLatin1String(
"S" ), Qt::CaseInsensitive ) == 0 )
412 if ( lonRef.compare( QLatin1String(
"W" ), Qt::CaseInsensitive ) == 0 )
419 const Exiv2::ExifData::iterator itElevVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitude" ) );
420 const Exiv2::ExifData::iterator itElevRefVal = exifData.findKey( Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitudeRef" ) );
421 if ( itElevVal != exifData.end() )
424 if ( itElevRefVal != exifData.end() )
426 const QString elevRef = QString::fromStdString( itElevRefVal->value().toString() );
427 if ( elevRef.compare( QLatin1String(
"1" ), Qt::CaseInsensitive ) == 0 )
482 std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
486 QVariant actualValue;
487 bool actualValueIsUShort =
false;
488 if ( tag == QLatin1String(
"Exif.GPSInfo.GPSLatitude" ) ||
489 tag == QLatin1String(
"Exif.GPSInfo.GPSLongitude" ) ||
490 tag == QLatin1String(
"Exif.GPSInfo.GPSDestLatitude" ) ||
491 tag == QLatin1String(
"Exif.GPSInfo.GPSDestLongitude" ) )
495 else if ( tag == QLatin1String(
"Exif.GPSInfo.GPSAltitude" ) )
497 actualValue = QStringLiteral(
"%1/1000" ).arg(
static_cast< int>( std::floor( std::abs( value.toDouble() ) * 1000 ) ) );
499 else if ( tag == QLatin1String(
"Exif.Image.Orientation" ) )
501 actualValueIsUShort =
true;
504 else if ( value.userType() == QMetaType::Type::QDateTime )
506 const QDateTime dateTime = value.toDateTime();
507 if ( tag == QLatin1String(
"Exif.Image.DateTime" ) ||
508 tag == QLatin1String(
"Exif.Image.DateTime" ) ||
509 tag == QLatin1String(
"Exif.Photo.DateTimeDigitized" ) ||
510 tag == QLatin1String(
"Exif.Photo.DateTimeOriginal" ) )
512 actualValue = dateTime.toString( QStringLiteral(
"yyyy:MM:dd hh:mm:ss" ) );
516 actualValue = dateTime.toString( Qt::ISODate );
519 else if ( value.userType() == QMetaType::Type::QDate )
521 const QDate date = value.toDate();
522 if ( tag == QLatin1String(
"Exif.GPSInfo.GPSDateStamp" ) )
524 actualValue = date.toString( QStringLiteral(
"yyyy:MM:dd" ) );
528 actualValue = date.toString( QStringLiteral(
"yyyy-MM-dd" ) );
531 else if ( value.userType() == QMetaType::Type::QTime )
533 const QTime time = value.toTime();
534 if ( tag == QLatin1String(
"Exif.GPSInfo.GPSTimeStamp" ) )
536 actualValue = QStringLiteral(
"%1/1 %2/1 %3/1" ).arg( time.hour() ).arg( time.minute() ).arg( time.second() );
540 actualValue = time.toString( QStringLiteral(
"HH:mm:ss" ) );
548 const bool isXmp = tag.startsWith( QLatin1String(
"Xmp." ) );
549 image->readMetadata();
550 if ( actualValueIsUShort )
554 Exiv2::XmpData &xmpData = image->xmpData();
555 xmpData[tag.toStdString()] =
static_cast<ushort
>( actualValue.toLongLong() );
559 Exiv2::ExifData &exifData = image->exifData();
560 exifData[tag.toStdString()] =
static_cast<ushort
>( actualValue.toLongLong() );
563 else if ( actualValue.userType() == QMetaType::Type::Int ||
564 actualValue.userType() == QMetaType::Type::LongLong )
568 Exiv2::XmpData &xmpData = image->xmpData();
569 xmpData[tag.toStdString()] =
static_cast<uint32_t
>( actualValue.toLongLong() );
573 Exiv2::ExifData &exifData = image->exifData();
574 exifData[tag.toStdString()] =
static_cast<uint32_t
>( actualValue.toLongLong() );
577 else if ( actualValue.userType() == QMetaType::Type::UInt ||
578 actualValue.userType() == QMetaType::Type::ULongLong )
582 Exiv2::XmpData &xmpData = image->xmpData();
583 xmpData[tag.toStdString()] =
static_cast<int32_t
>( actualValue.toULongLong() );
587 Exiv2::ExifData &exifData = image->exifData();
588 exifData[tag.toStdString()] =
static_cast<int32_t
>( actualValue.toULongLong() );
591 else if ( actualValue.userType() == QMetaType::Type::Double )
595 Exiv2::XmpData &xmpData = image->xmpData();
596 xmpData[tag.toStdString()] = Exiv2::floatToRationalCast( actualValue.toFloat() );
600 Exiv2::ExifData &exifData = image->exifData();
601 exifData[tag.toStdString()] = Exiv2::floatToRationalCast( actualValue.toFloat() );
608 Exiv2::XmpData &xmpData = image->xmpData();
609 xmpData[tag.toStdString()] = actualValue.toString().toStdString();
613 Exiv2::ExifData &exifData = image->exifData();
614 exifData[tag.toStdString()] = actualValue.toString().toStdString();
617 image->writeMetadata();