23#include "libkexiv2_debug.h"
58 Exiv2::ExifKey exifKey(
"Exif.GPSInfo.GPSLatitude");
59 Exiv2::ExifData exifData(d->exifMetadata());
60 Exiv2::ExifData::iterator it = exifData.findKey(exifKey);
62 if (it != exifData.end() && (*it).count() == 3)
65 double num, den, min, sec;
67 num = (double)((*it).toRational(0).first);
68 den = (double)((*it).toRational(0).second);
75 num = (double)((*it).toRational(1).first);
76 den = (double)((*it).toRational(1).second);
84 *latitude = *latitude + min/60.0;
86 num = (double)((*it).toRational(2).first);
87 den = (double)((*it).toRational(2).second);
101 *latitude = *latitude + sec/3600.0;
108 if (latRef[0] ==
'S')
114 catch( Exiv2::Error& e )
120 qCCritical(LIBKEXIV2_LOG) <<
"Default exception from Exiv2";
143 Exiv2::ExifKey exifKey2(
"Exif.GPSInfo.GPSLongitude");
144 Exiv2::ExifData exifData(d->exifMetadata());
145 Exiv2::ExifData::iterator it = exifData.findKey(exifKey2);
147 if (it != exifData.end() && (*it).count() == 3)
153 num = (double)((*it).toRational(0).first);
154 den = (double)((*it).toRational(0).second);
161 *longitude = num/den;
163 num = (double)((*it).toRational(1).first);
164 den = (double)((*it).toRational(1).second);
171 const double min = num/den;
175 *longitude = *longitude + min/60.0;
178 num = (double)((*it).toRational(2).first);
179 den = (double)((*it).toRational(2).second);
190 const double sec = num/den;
194 *longitude = *longitude + sec/3600.0;
202 if (lngRef[0] ==
'W')
210 catch( Exiv2::Error& e )
216 qCCritical(LIBKEXIV2_LOG) <<
"Default exception from Exiv2";
260 Exiv2::ExifKey exifKey3(
"Exif.GPSInfo.GPSAltitude");
261 Exiv2::ExifData exifData(d->exifMetadata());
262 Exiv2::ExifData::iterator it = exifData.findKey(exifKey3);
263 if (it != exifData.end() && (*it).count())
265 num = (double)((*it).toRational(0).first);
266 den = (double)((*it).toRational(0).second);
278 if (altRef[0] ==
'1')
284 catch( Exiv2::Error& e )
290 qCCritical(LIBKEXIV2_LOG) <<
"Default exception from Exiv2";
306QString KExiv2::getGPSLongitudeString()
const
328#if EXIV2_TEST_VERSION(0,28,0)
329 Exiv2::Value::UniquePtr value = Exiv2::Value::create(Exiv2::unsignedByte);
331 Exiv2::Value::AutoPtr value = Exiv2::Value::create(Exiv2::unsignedByte);
333 value->read(
"2 0 0 0");
334 d->exifMetadata().add(Exiv2::ExifKey(
"Exif.GPSInfo.GPSVersionID"), value.get());
337 d->exifMetadata()[
"Exif.GPSInfo.GPSMapDatum"] =
"WGS-84";
346 catch( Exiv2::Error& e )
348 d->printExiv2ExceptionError(
QString::fromLatin1(
"Cannot initialize GPS data using Exiv2 "), e);
352 qCCritical(LIBKEXIV2_LOG) <<
"Default exception from Exiv2";
358bool KExiv2::setGPSInfo(
const double altitude,
const double latitude,
const double longitude,
const bool setProgramName)
360 return setGPSInfo(&altitude, latitude, longitude, setProgramName);
363bool KExiv2::setGPSInfo(
const double*
const altitude,
const double latitude,
const double longitude,
const bool setProgramName)
377 char scratchBuf[100];
387#if EXIV2_TEST_VERSION(0,28,0)
388 Exiv2::Value::UniquePtr value = Exiv2::Value::create(Exiv2::unsignedByte);
390 Exiv2::Value::AutoPtr value = Exiv2::Value::create(Exiv2::unsignedByte);
393 if ((*altitude) >= 0) value->read(
"0");
394 else value->read(
"1");
396 d->exifMetadata().add(Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitudeRef"), value.get());
400 snprintf(scratchBuf, 100,
"%ld/%ld", nom, denom);
401 d->exifMetadata()[
"Exif.GPSInfo.GPSAltitude"] = scratchBuf;
414 d->exifMetadata()[
"Exif.GPSInfo.GPSLatitudeRef"] = (latitude < 0 ) ?
"S" :
"N";
431 deg = (int)floor(fabs(latitude));
432 min = (int)floor((fabs(latitude) - floor(fabs(latitude))) * 60000000);
433 snprintf(scratchBuf, 100,
"%ld/1 %ld/1000000 0/1", deg, min);
434 d->exifMetadata()[
"Exif.GPSInfo.GPSLatitude"] = scratchBuf;
449 d->exifMetadata()[
"Exif.GPSInfo.GPSLongitudeRef"] = (longitude < 0 ) ?
"W" :
"E";
466 deg = (int)floor(fabs(longitude));
467 min = (int)floor((fabs(longitude) - floor(fabs(longitude))) * 60000000);
468 snprintf(scratchBuf, 100,
"%ld/1 %ld/1000000 0/1", deg, min);
469 d->exifMetadata()[
"Exif.GPSInfo.GPSLongitude"] = scratchBuf;
482 catch( Exiv2::Error& e )
484 d->printExiv2ExceptionError(
QString::fromLatin1(
"Cannot set Exif GPS tag using Exiv2 "), e);
488 qCCritical(LIBKEXIV2_LOG) <<
"Default exception from Exiv2";
496 double longitudeValue, latitudeValue;
504 return setGPSInfo(&altitude, latitudeValue, longitudeValue, setProgramName);
516 for (Exiv2::ExifData::iterator it = d->exifMetadata().begin();
517 it != d->exifMetadata().end(); ++it)
527 Exiv2::ExifKey gpsKey((*it2).toLatin1().constData());
528 Exiv2::ExifData::iterator it3 = d->exifMetadata().findKey(gpsKey);
530 if (it3 != d->exifMetadata().end())
531 d->exifMetadata().erase(it3);
571 catch( Exiv2::Error& e )
573 d->printExiv2ExceptionError(
QString::fromLatin1(
"Cannot remove Exif GPS tag using Exiv2 "), e);
577 qCCritical(LIBKEXIV2_LOG) <<
"Default exception from Exiv2";
584 long int*
const denominator,
const int rounding)
592 double whole = trunc(number);
593 double fractional = number - whole;
597 double rounder = pow(10.0, rounding);
604 fractional = round(fractional * rounder);
611 double numTemp = (whole * rounder) + fractional;
612 double denTemp = rounder;
620 if (trunc(numTemp / denTemp) == (numTemp / denTemp))
631 if ((numTemp / 2) != trunc(numTemp / 2))
break;
632 if ((denTemp / 2) != trunc(denTemp / 2))
break;
639 *numerator = (int)numTemp;
640 *denominator = (int)denTemp;
653 double whole = trunc(number);
654 double fractional = number - whole;
666 long int num, approx, bestnum=0, bestdenom=1;
667 double value, error, leasterr, criterion;
673 *numerator = (
long int)whole;
678 criterion = 2 * value * DBL_EPSILON;
680 for (leasterr = value, num = 1; num < lastnum; ++num)
682 approx = (int)(num / value + 0.5);
683 error = fabs((
double)num / approx - value);
685 if (error < leasterr)
691 if (leasterr <= criterion)
break;
696 if (bestdenom * whole > (
double)INT_MAX)
704 bestnum += bestdenom * (
long int)whole;
705 *numerator = bestnum;
706 *denominator = bestdenom;
711 const long int numeratorMinutes,
const long int denominatorMinutes,
712 const long int numeratorSeconds,
long int denominatorSeconds,
713 const char directionReference)
726 if (denominatorSeconds == 0 && numeratorSeconds == 0)
727 denominatorSeconds = 1;
729 if (denominatorDegrees == 1 &&
730 denominatorMinutes == 1 &&
731 denominatorSeconds == 1)
735 coordinate = coordinate.
arg(numeratorDegrees).
arg(numeratorMinutes).
arg(numeratorSeconds).
arg(directionReference);
737 else if (denominatorDegrees == 1 &&
738 denominatorMinutes == 100 &&
739 denominatorSeconds == 1)
743 double minutes = (double)numeratorMinutes / (
double)denominatorMinutes;
744 minutes += (double)numeratorSeconds / 60.0;
749 minutesString.
chop(1);
752 coordinate = coordinate.
arg(numeratorDegrees).
arg(minutesString).
arg(directionReference);
754 else if (denominatorDegrees == 0 ||
755 denominatorMinutes == 0 ||
756 denominatorSeconds == 0)
765 double degrees = (double)numeratorDegrees / (
double)denominatorDegrees;
766 double wholeDegrees = trunc(degrees);
767 double minutes = (double)numeratorMinutes / (
double)denominatorMinutes;
768 minutes += (degrees - wholeDegrees) * 60.0;
769 minutes += ((double)numeratorSeconds / (double)denominatorSeconds) / 60.0;
774 minutesString.
chop(1);
777 coordinate = coordinate.
arg((
int)wholeDegrees).
arg(minutesString).
arg(directionReference);
785 if (coordinate < -360.0 || coordinate > 360.0)
790 char directionReference;
795 directionReference =
'S';
797 directionReference =
'N';
802 directionReference =
'W';
804 directionReference =
'E';
808 coordinate = fabs(coordinate);
810 int degrees = (int)floor(coordinate);
812 coordinate = coordinate - (double)(degrees);
814 double minutes = coordinate * 60.0;
818 coordinateString = coordinateString.
arg(degrees);
819 coordinateString = coordinateString.
arg(minutes, 0,
'f', 8).
arg(directionReference);
821 return coordinateString;
825 long int*
const numeratorDegrees,
long int*
const denominatorDegrees,
826 long int*
const numeratorMinutes,
long int*
const denominatorMinutes,
827 long int*
const numeratorSeconds,
long int*
const denominatorSeconds,
828 char*
const directionReference)
833 *directionReference = gpsString.
at(gpsString.
length() - 1).
toUpper().toLatin1();
837 if (parts.
size() == 2)
840 *denominatorDegrees = 1;
841 *denominatorMinutes = 1000000;
842 *denominatorSeconds = 1;
844 *numeratorDegrees = parts[0].toLong();
846 double minutes = parts[1].toDouble();
849 *numeratorMinutes = (long)round(minutes);
850 *numeratorSeconds = 0;
854 else if (parts.
size() == 3)
857 *denominatorDegrees = 1;
858 *denominatorMinutes = 1;
859 *denominatorSeconds = 1;
861 *numeratorDegrees = parts[0].toLong();
862 *numeratorMinutes = parts[1].toLong();
863 *numeratorSeconds = parts[2].toLong();
878 char directionReference = gpsString.
at(gpsString.
length() - 1).
toUpper().toLatin1();
882 if (parts.
size() == 2)
885 *degrees = parts[0].toLong();
886 *degrees += parts[1].toDouble() / 60.0;
888 if (directionReference ==
'W' || directionReference ==
'S')
893 else if (parts.
size() == 3)
897 *degrees = parts[0].toLong();
898 *degrees += parts[1].toLong() / 60.0;
899 *degrees += parts[2].toLong() / 3600.0;
901 if (directionReference ==
'W' || directionReference ==
'S')
913 int*
const degrees,
int*
const minutes,
914 double*
const seconds,
char*
const directionReference)
919 *directionReference = gpsString.
at(gpsString.
length() - 1).
toUpper().toLatin1();
923 if (parts.
size() == 2)
926 *degrees = parts[0].toInt();
927 double fractionalMinutes = parts[1].toDouble();
928 *minutes = (int)trunc(fractionalMinutes);
929 *seconds = (fractionalMinutes - (double)(*minutes)) * 60.0;
933 else if (parts.
size() == 3)
936 *degrees = parts[0].toInt();
937 *minutes = parts[1].toInt();
938 *seconds = (double)parts[2].toInt();
949 int*
const degrees,
int*
const minutes,
950 double*
const seconds,
char*
const directionReference)
955 *directionReference =
'S';
957 *directionReference =
'N';
962 *directionReference =
'W';
964 *directionReference =
'E';
968 coordinate = fabs(coordinate);
969 *degrees = (int)floor(coordinate);
971 coordinate = coordinate - (double)(*degrees);
974 *minutes = (int)floor(coordinate);
976 coordinate = coordinate - (double)(*minutes);
979 *seconds = coordinate;
QString getXmpTagString(const char *xmpTagName, bool escapeCR=true) const
Get a Xmp tag content like a string.
static bool convertFromGPSCoordinateString(const QString &coordinate, long int *const numeratorDegrees, long int *const denominatorDegrees, long int *const numeratorMinutes, long int *const denominatorMinutes, long int *const numeratorSeconds, long int *const denominatorSeconds, char *const directionReference)
Converts a GPSCoordinate string as defined by XMP to three rationals and the direction reference.
static void convertToRationalSmallDenominator(const double number, long int *const numerator, long int *const denominator)
This method convert a 'number' to a rational value, returned in 'numerator' and 'denominator' paramet...
virtual bool setProgramId(bool on=true) const
Re-implement this method to set automatically the Program Name and Program Version information in Exi...
QString getGPSLatitudeString() const
Get GPS location information set in the image, in the GPSCoordinate format as described in the XMP sp...
static QString convertToGPSCoordinateString(const long int numeratorDegrees, const long int denominatorDegrees, const long int numeratorMinutes, const long int denominatorMinutes, const long int numeratorSeconds, long int denominatorSeconds, const char directionReference)
Converts a GPS position stored as rationals in Exif to the form described as GPSCoordinate in the XMP...
static void convertToRational(const double number, long int *const numerator, long int *const denominator, const int rounding)
This method converts 'number' to a rational value, returned in the 'numerator' and 'denominator' para...
bool initializeGPSInfo(const bool setProgramName)
Make sure all static required GPS EXIF and XMP tags exist.
static bool convertToUserPresentableNumbers(const QString &coordinate, int *const degrees, int *const minutes, double *const seconds, char *const directionReference)
Converts a GPSCoordinate string to user presentable numbers, integer degrees and minutes and double f...
bool getGPSInfo(double &altitude, double &latitude, double &longitude) const
Get all GPS location information set in image.
bool setGPSInfo(const double altitude, const double latitude, const double longitude, const bool setProgramName=true)
Set all GPS location information into image.
bool getGPSAltitude(double *const altitude) const
Get GPS altitude information, in meters, relative to sea level (positive sign above sea level)
bool removeGPSInfo(const bool setProgramName=true)
Remove all Exif tags relevant of GPS location information.
bool getGPSLatitudeNumber(double *const latitude) const
Get GPS location information set in the image, as a double floating point number as in degrees where ...
QByteArray getExifTagData(const char *exifTagName) const
Get an Exif tag content like a bytes array.
bool removeXmpTag(const char *xmpTagName, bool setProgramName=true) const
Remove the Xmp tag 'xmpTagName' from Xmp metadata.
bool getGPSLongitudeNumber(double *const longitude) const
bool setXmpTagString(const char *xmpTagName, const QString &value, bool setProgramName=true) const
Set a Xmp tag content using a string.
KExiv2Iface - Exiv2 library interface.
bool isEmpty() const const
char32_t toUpper(char32_t ucs4)
void append(QList< T > &&value)
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype size() const const
QString arg(Args &&... args) const const
const QChar at(qsizetype position) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
QString fromLatin1(QByteArrayView str)
QString fromLocal8Bit(QByteArrayView str)
bool isEmpty() const const
QString left(qsizetype n) const const
qsizetype length() const const
QString number(double n, char format, int precision)
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
double toDouble(bool *ok) const const