18 #include <exiv2/exiv2.hpp>    19 #include <QRegularExpression>    22 #if 0 // needs further work on the correct casting of tag values to QVariant values!    23 QVariantMap QgsExifTools::readTags( 
const QString &imagePath )
    25   std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
    29   image->readMetadata();
    30   Exiv2::ExifData &exifData = image->exifData();
    31   if ( exifData.empty() )
    37   Exiv2::ExifData::const_iterator end = exifData.end();
    38   for ( Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i )
    40     const QString key = QString::fromStdString( i->key() );
    42     switch ( i->typeId() )
    44       case Exiv2::asciiString:
    47       case Exiv2::directory:
    49         val = QString::fromStdString( i->toString() );
    52       case Exiv2::unsignedLong:
    53       case Exiv2::signedLong:
    54         val = QVariant::fromValue( i->toLong() );
    57       case Exiv2::tiffDouble:
    58       case Exiv2::tiffFloat:
    59         val = QVariant::fromValue( i->toFloat() );
    62       case Exiv2::unsignedShort:
    63       case Exiv2::signedShort:
    64         val = QVariant::fromValue( static_cast< int >( i->toLong() ) );
    67       case Exiv2::unsignedRational:
    68       case Exiv2::signedRational:
    69       case Exiv2::unsignedByte:
    70       case Exiv2::signedByte:
    71       case Exiv2::undefined:
    79       case Exiv2::invalidTypeId:
    80       case Exiv2::lastTypeId:
    81         val = QString::fromStdString( i->toString() );
    86     res.insert( key, val );
    94   double d = std::abs( val );
    95   int degrees = 
static_cast< int >( std::floor( d ) );
    96   double m = 60 * ( d - degrees );
    97   int minutes = 
static_cast< int >( std::floor( m ) );
    98   double s = 60 * ( m - minutes );
    99   int seconds = 
static_cast< int >( std::floor( s * 1000 ) );
   100   return QStringLiteral( 
"%1/1 %2/1 %3/1000" ).arg( degrees ).arg( minutes ).arg( seconds );
   106   if ( !QFileInfo::exists( imagePath ) )
   110     std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
   114     image->readMetadata();
   115     Exiv2::ExifData &exifData = image->exifData();
   117     if ( exifData.empty() )
   120     Exiv2::ExifData::iterator itLatRef = exifData.findKey( Exiv2::ExifKey( 
"Exif.GPSInfo.GPSLatitudeRef" ) );
   121     Exiv2::ExifData::iterator itLatVal = exifData.findKey( Exiv2::ExifKey( 
"Exif.GPSInfo.GPSLatitude" ) );
   122     Exiv2::ExifData::iterator itLonRef = exifData.findKey( Exiv2::ExifKey( 
"Exif.GPSInfo.GPSLongitudeRef" ) );
   123     Exiv2::ExifData::iterator itLonVal = exifData.findKey( Exiv2::ExifKey( 
"Exif.GPSInfo.GPSLongitude" ) );
   125     if ( itLatRef == exifData.end() || itLatVal == exifData.end() ||
   126          itLonRef == exifData.end() || itLonVal == exifData.end() )
   129     auto readCoord = []( 
const QString & coord )->
double   133       const QStringList parts = coord.split( QRegularExpression( QStringLiteral( 
"\\s+" ) ) );
   134       for ( 
const QString &rational : parts )
   136         const QStringList pair = rational.split( 
'/' );
   137         if ( pair.size() != 2 )
   139         res += ( pair[0].toDouble() / pair[1].toDouble() ) / div;
   145     auto readRationale = []( 
const QString & rational )->
double   147       const QStringList pair = rational.split( 
'/' );
   148       if ( pair.size() != 2 )
   149         return std::numeric_limits< double >::quiet_NaN();
   150       return pair[0].toDouble() / pair[1].toDouble();
   153     double lat = readCoord( QString::fromStdString( itLatVal->value().toString() ) );
   154     double lon = readCoord( QString::fromStdString( itLonVal->value().toString() ) );
   156     const QString latRef = QString::fromStdString( itLatRef->value().toString() );
   157     const QString lonRef = QString::fromStdString( itLonRef->value().toString() );
   158     if ( latRef.compare( QLatin1String( 
"S" ), Qt::CaseInsensitive ) == 0 )
   162     if ( lonRef.compare( QLatin1String( 
"W" ), Qt::CaseInsensitive ) == 0 )
   169     Exiv2::ExifData::iterator itElevVal = exifData.findKey( Exiv2::ExifKey( 
"Exif.GPSInfo.GPSAltitude" ) );
   170     Exiv2::ExifData::iterator itElevRefVal = exifData.findKey( Exiv2::ExifKey( 
"Exif.GPSInfo.GPSAltitudeRef" ) );
   171     if ( itElevVal != exifData.end() )
   173       double elev = readRationale( QString::fromStdString( itElevVal->value().toString() ) );
   174       if ( itElevRefVal != exifData.end() )
   176         const QString elevRef = QString::fromStdString( itElevRefVal->value().toString() );
   177         if ( elevRef.compare( QLatin1String( 
"1" ), Qt::CaseInsensitive ) == 0 )
   199     std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) );
   203     image->readMetadata();
   204     Exiv2::ExifData &exifData = image->exifData();
   206     exifData[
"Exif.GPSInfo.GPSVersionID"] = 
"2 0 0 0";
   207     exifData[
"Exif.GPSInfo.GPSMapDatum"] = 
"WGS-84";
   212       const QString elevationString = QStringLiteral( 
"%1/1000" ).arg( static_cast< int>( std::floor( std::abs( details.
elevation ) * 1000 ) ) );
   213       exifData[
"Exif.GPSInfo.GPSAltitude"] = elevationString.toStdString();
   214       exifData[
"Exif.GPSInfo.GPSAltitudeRef"] = details.
elevation < 0.0 ? 
"1" : 
"0";
   216     exifData[
"Exif.GPSInfo.GPSLatitudeRef"] = location.
y() > 0 ? 
"N" : 
"S";
   217     exifData[
"Exif.GPSInfo.GPSLongitudeRef"] = location.
x() > 0 ? 
"E" : 
"W";
   218     exifData[
"Exif.Image.GPSTag"] = 4908;
   219     image->writeMetadata();
 
A class to represent a 2D point. 
 
Point geometry type, with support for z-dimension and m-values.