69 const QByteArray latRef =
getExifTagData(
"Exif.GPSInfo.GPSLatitudeRef");
71 if (!latRef.isEmpty())
73 Exiv2::ExifKey exifKey(
"Exif.GPSInfo.GPSLatitude");
75 Exiv2::ExifData::iterator it = exifData.findKey(exifKey);
77 if (it != exifData.end() && (*it).count() == 3)
80 double num, den, min, sec;
82 num = (double)((*it).toRational(0).first);
83 den = (double)((*it).toRational(0).second);
90 num = (double)((*it).toRational(1).first);
91 den = (double)((*it).toRational(1).second);
99 *latitude = *latitude + min/60.0;
101 num = (double)((*it).toRational(2).first);
102 den = (double)((*it).toRational(2).second);
116 *latitude = *latitude + sec/3600.0;
123 if (latRef[0] ==
'S')
129 catch( Exiv2::Error& e )
148 const QByteArray lngRef =
getExifTagData(
"Exif.GPSInfo.GPSLongitudeRef");
150 if (!lngRef.isEmpty())
154 Exiv2::ExifKey exifKey2(
"Exif.GPSInfo.GPSLongitude");
156 Exiv2::ExifData::iterator it = exifData.findKey(exifKey2);
158 if (it != exifData.end() && (*it).count() == 3)
164 num = (double)((*it).toRational(0).first);
165 den = (double)((*it).toRational(0).second);
172 *longitude = num/den;
174 num = (double)((*it).toRational(1).first);
175 den = (double)((*it).toRational(1).second);
182 const double min = num/den;
186 *longitude = *longitude + min/60.0;
189 num = (double)((*it).toRational(2).first);
190 den = (double)((*it).toRational(2).second);
201 const double sec = num/den;
205 *longitude = *longitude + sec/3600.0;
213 if (lngRef[0] ==
'W')
221 catch( Exiv2::Error& e )
239 if (!altRefXmp.isEmpty())
243 if (!altXmp.isEmpty())
245 num = altXmp.section(
'/', 0, 0).toDouble();
246 den = altXmp.section(
'/', 1, 1).toDouble();
253 if (altRefXmp == QString(
"1"))
261 const QByteArray altRef =
getExifTagData(
"Exif.GPSInfo.GPSAltitudeRef");
263 if (!altRef.isEmpty())
267 Exiv2::ExifKey exifKey3(
"Exif.GPSInfo.GPSAltitude");
269 Exiv2::ExifData::iterator it = exifData.findKey(exifKey3);
270 if (it != exifData.end() && (*it).count())
272 num = (double)((*it).toRational(0).first);
273 den = (double)((*it).toRational(0).second);
285 if (altRef[0] ==
'1')
291 catch( Exiv2::Error& e )
331 Exiv2::Value::AutoPtr value = Exiv2::Value::create(Exiv2::unsignedByte);
332 value->read(
"2 0 0 0");
333 d->
exifMetadata().add(Exiv2::ExifKey(
"Exif.GPSInfo.GPSVersionID"), value.get());
336 d->
exifMetadata()[
"Exif.GPSInfo.GPSMapDatum"] =
"WGS-84";
341 #endif // _XMP_SUPPORT_
345 catch( Exiv2::Error& e )
353 bool KExiv2::setGPSInfo(
const double altitude,
const double latitude,
const double longitude,
const bool setProgramName)
355 return setGPSInfo(&altitude, latitude, longitude, setProgramName);
358 bool KExiv2::setGPSInfo(
const double*
const altitude,
const double latitude,
const double longitude,
const bool setProgramName)
372 char scratchBuf[100];
382 Exiv2::Value::AutoPtr value = Exiv2::Value::create(Exiv2::unsignedByte);
384 if ((*altitude) >= 0) value->read(
"0");
385 else value->read(
"1");
387 d->
exifMetadata().add(Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitudeRef"), value.get());
391 snprintf(scratchBuf, 100,
"%ld/%ld", nom, denom);
392 d->
exifMetadata()[
"Exif.GPSInfo.GPSAltitude"] = scratchBuf;
395 setXmpTagString(
"Xmp.exif.GPSAltitudeRef", ((*altitude) >= 0) ? QString(
"0") : QString(
"1"),
false);
397 #endif // _XMP_SUPPORT_
405 d->
exifMetadata()[
"Exif.GPSInfo.GPSLatitudeRef"] = (latitude < 0 ) ?
"S" :
"N";
422 deg = (int)floor(fabs(latitude));
423 min = (int)floor((fabs(latitude) - floor(fabs(latitude))) * 60000000);
424 snprintf(scratchBuf, 100,
"%ld/1 %ld/1000000 0/1", deg, min);
425 d->
exifMetadata()[
"Exif.GPSInfo.GPSLatitude"] = scratchBuf;
432 setXmpTagString(
"Xmp.exif.GPSLatitudeRef", (latitude < 0) ? QString(
"S") : QString(
"N"),
false);
434 #endif // _XMP_SUPPORT_
440 d->
exifMetadata()[
"Exif.GPSInfo.GPSLongitudeRef"] = (longitude < 0 ) ?
"W" :
"E";
457 deg = (int)floor(fabs(longitude));
458 min = (int)floor((fabs(longitude) - floor(fabs(longitude))) * 60000000);
459 snprintf(scratchBuf, 100,
"%ld/1 %ld/1000000 0/1", deg, min);
460 d->
exifMetadata()[
"Exif.GPSInfo.GPSLongitude"] = scratchBuf;
467 setXmpTagString(
"Xmp.exif.GPSLongitudeRef", (longitude < 0) ? QString(
"W") : QString(
"E"),
false);
469 #endif // _XMP_SUPPORT_
473 catch( Exiv2::Error& e )
481 bool KExiv2::setGPSInfo(
const double altitude,
const QString& latitude,
const QString& longitude,
const bool setProgramName)
483 double longitudeValue, latitudeValue;
491 return setGPSInfo(&altitude, latitudeValue, longitudeValue, setProgramName);
501 QStringList gpsTagsKeys;
503 for (Exiv2::ExifData::iterator it = d->
exifMetadata().begin();
506 QString key = QString::fromLocal8Bit(it->key().c_str());
508 if (key.section(
'.', 1, 1) == QString(
"GPSInfo"))
509 gpsTagsKeys.append(key);
512 for(QStringList::const_iterator it2 = gpsTagsKeys.constBegin(); it2 != gpsTagsKeys.constEnd(); ++it2)
514 Exiv2::ExifKey gpsKey((*it2).toAscii().constData());
515 Exiv2::ExifData::iterator it3 = d->
exifMetadata().findKey(gpsKey);
554 #endif // _XMP_SUPPORT_
558 catch( Exiv2::Error& e )
567 long int*
const denominator,
const int rounding)
575 double whole = trunc(number);
576 double fractional = number - whole;
580 double rounder = pow(10.0, rounding);
587 fractional = round(fractional * rounder);
594 double numTemp = (whole * rounder) + fractional;
595 double denTemp = rounder;
603 if (trunc(numTemp / denTemp) == (numTemp / denTemp))
614 if ((numTemp / 2) != trunc(numTemp / 2))
break;
615 if ((denTemp / 2) != trunc(denTemp / 2))
break;
622 *numerator = (int)numTemp;
623 *denominator = (int)denTemp;
636 double whole = trunc(number);
637 double fractional = number - whole;
649 long int num, approx, bestnum=0, bestdenom=1;
650 double value, error, leasterr, criterion;
656 *numerator = (
long int)whole;
661 criterion = 2 * value * DBL_EPSILON;
663 for (leasterr = value, num = 1; num < lastnum; ++num)
665 approx = (int)(num / value + 0.5);
666 error = fabs((
double)num / approx - value);
668 if (error < leasterr)
674 if (leasterr <= criterion)
break;
679 if (bestdenom * whole > (
double)INT_MAX)
687 bestnum += bestdenom * (
long int)whole;
688 *numerator = bestnum;
689 *denominator = bestdenom;
694 const long int numeratorMinutes,
const long int denominatorMinutes,
695 const long int numeratorSeconds,
long int denominatorSeconds,
696 const char directionReference)
709 if (denominatorSeconds == 0 && numeratorSeconds == 0)
710 denominatorSeconds = 1;
712 if (denominatorDegrees == 1 &&
713 denominatorMinutes == 1 &&
714 denominatorSeconds == 1)
717 coordinate =
"%1,%2,%3%4";
718 coordinate = coordinate.arg(numeratorDegrees).arg(numeratorMinutes).arg(numeratorSeconds).arg(directionReference);
720 else if (denominatorDegrees == 1 &&
721 denominatorMinutes == 100 &&
722 denominatorSeconds == 1)
725 coordinate =
"%1,%2%3";
726 double minutes = (double)numeratorMinutes / (
double)denominatorMinutes;
727 minutes += (double)numeratorSeconds / 60.0;
728 QString minutesString = QString::number(minutes,
'f', 8);
730 while (minutesString.endsWith(
'0') && !minutesString.endsWith(
".0"))
732 minutesString.chop(1);
735 coordinate = coordinate.arg(numeratorDegrees).arg(minutesString).arg(directionReference);
737 else if (denominatorDegrees == 0 ||
738 denominatorMinutes == 0 ||
739 denominatorSeconds == 0)
747 coordinate =
"%1,%2%3";
748 double degrees = (double)numeratorDegrees / (
double)denominatorDegrees;
749 double wholeDegrees = trunc(degrees);
750 double minutes = (double)numeratorMinutes / (
double)denominatorMinutes;
751 minutes += (degrees - wholeDegrees) * 60.0;
752 minutes += ((double)numeratorSeconds / (
double)denominatorSeconds) / 60.0;
753 QString minutesString = QString::number(minutes,
'f', 8);
755 while (minutesString.endsWith(
'0') && !minutesString.endsWith(
".0"))
757 minutesString.chop(1);
760 coordinate = coordinate.arg((
int)wholeDegrees).arg(minutesString).arg(directionReference);
768 if (coordinate < -360.0 || coordinate > 360.0)
771 QString coordinateString;
773 char directionReference;
778 directionReference =
'S';
780 directionReference =
'N';
785 directionReference =
'W';
787 directionReference =
'E';
791 coordinate = fabs(coordinate);
793 int degrees = (int)floor(coordinate);
795 coordinate = coordinate - (double)(degrees);
797 double minutes = coordinate * 60.0;
800 coordinateString =
"%1,%2%3";
801 coordinateString = coordinateString.arg(degrees);
802 coordinateString = coordinateString.arg(minutes, 0,
'f', 8).arg(directionReference);
804 return coordinateString;
808 long int*
const numeratorDegrees,
long int*
const denominatorDegrees,
809 long int*
const numeratorMinutes,
long int*
const denominatorMinutes,
810 long int*
const numeratorSeconds,
long int*
const denominatorSeconds,
811 char*
const directionReference)
813 if (gpsString.isEmpty())
816 *directionReference = gpsString.at(gpsString.length() - 1).toUpper().toLatin1();
817 QString coordinate = gpsString.left(gpsString.length() - 1);
818 QStringList parts = coordinate.split(
',');
820 if (parts.size() == 2)
823 *denominatorDegrees = 1;
824 *denominatorMinutes = 1000000;
825 *denominatorSeconds = 1;
827 *numeratorDegrees = parts[0].toLong();
829 double minutes = parts[1].toDouble();
832 *numeratorMinutes = (long)round(minutes);
833 *numeratorSeconds = 0;
837 else if (parts.size() == 3)
840 *denominatorDegrees = 1;
841 *denominatorMinutes = 1;
842 *denominatorSeconds = 1;
844 *numeratorDegrees = parts[0].toLong();
845 *numeratorMinutes = parts[1].toLong();
846 *numeratorSeconds = parts[2].toLong();
858 if (gpsString.isEmpty())
861 char directionReference = gpsString.at(gpsString.length() - 1).toUpper().toLatin1();
862 QString coordinate = gpsString.left(gpsString.length() - 1);
863 QStringList parts = coordinate.split(
',');
865 if (parts.size() == 2)
868 *degrees = parts[0].toLong();
869 *degrees += parts[1].toDouble() / 60.0;
871 if (directionReference ==
'W' || directionReference ==
'S')
876 else if (parts.size() == 3)
880 *degrees = parts[0].toLong();
881 *degrees += parts[1].toLong() / 60.0;
882 *degrees += parts[2].toLong() / 3600.0;
884 if (directionReference ==
'W' || directionReference ==
'S')
896 int*
const degrees,
int*
const minutes,
897 double*
const seconds,
char*
const directionReference)
899 if (gpsString.isEmpty())
902 *directionReference = gpsString.at(gpsString.length() - 1).toUpper().toLatin1();
903 QString coordinate = gpsString.left(gpsString.length() - 1);
904 QStringList parts = coordinate.split(
',');
906 if (parts.size() == 2)
909 *degrees = parts[0].toInt();
910 double fractionalMinutes = parts[1].toDouble();
911 *minutes = (int)trunc(fractionalMinutes);
912 *seconds = (fractionalMinutes - (double)(*minutes)) * 60.0;
916 else if (parts.size() == 3)
919 *degrees = parts[0].toInt();
920 *minutes = parts[1].toInt();
921 *seconds = (double)parts[2].toInt();
932 int*
const degrees,
int*
const minutes,
933 double*
const seconds,
char*
const directionReference)
938 *directionReference =
'S';
940 *directionReference =
'N';
945 *directionReference =
'W';
947 *directionReference =
'E';
951 coordinate = fabs(coordinate);
952 *degrees = (int)floor(coordinate);
954 coordinate = coordinate - (double)(*degrees);
957 *minutes = (int)floor(coordinate);
959 coordinate = coordinate - (double)(*minutes);
962 *seconds = coordinate;
const Exiv2::ExifData & exifMetadata() const
bool getGPSLatitudeNumber(double *const latitude) const
Get GPS location information set in the image, as a double floating point number as in degrees where ...
bool setXmpTagString(const char *xmpTagName, const QString &value, bool setProgramName=true) const
Set a Xmp tag content using a string.
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...
bool removeGPSInfo(const bool setProgramName=true)
Remove all Exif tags relevant of GPS location information.
QString getGPSLongitudeString() const
bool getGPSInfo(double &altitude, double &latitude, double &longitude) const
Get all GPS location information set in image.
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 removeXmpTag(const char *xmpTagName, bool setProgramName=true) const
Remove the Xmp tag 'xmpTagName' from Xmp metadata.
QString getGPSLatitudeString() const
Get GPS location information set in the image, in the GPSCoordinate format as described in the XMP sp...
bool getGPSAltitude(double *const altitude) const
Get GPS altitude information, in meters, relative to sea level (positive sign above sea level) ...
virtual bool setProgramId(bool on=true) const
Re-implement this method to set automatically the Program Name and Program Version information in Exi...
bool setGPSInfo(const double altitude, const double latitude, const double longitude, const bool setProgramName=true)
Set all GPS location information into image.
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 printExiv2ExceptionError(const QString &msg, Exiv2::Error &e)
Generic method to print the Exiv2 C++ Exception error message from 'e'.
QByteArray getExifTagData(const char *exifTagName) const
Get an Exif tag content like a bytes array.
bool getGPSLongitudeNumber(double *const longitude) const
===========================================================This file is a part of digiKam project htt...
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 initializeGPSInfo(const bool setProgramName)
Make sure all static required GPS EXIF and XMP tags exist.
===========================================================This file is a part of digiKam project htt...