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.