Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Adding support for exif Altitude parsing #325

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added MetadataExtractor.Tests/Data/ABOVE_SEA_LEVEL.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added MetadataExtractor.Tests/Data/BELOW_SEA_LEVEL.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions MetadataExtractor.Tests/Formats/Exif/ExifDirectoryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,28 @@ public void GeoLocation()
Assert.Equal(-1.9141666666666666, geoLocation!.Longitude);
}

[Fact]
public void GeoLocationWithAltitude()
{
var metadata = ImageMetadataReader.ReadMetadata("Data/ABOVE_SEA_LEVEL.jpg");
var gpsDirectory = metadata.OfType<GpsDirectory>().First();
var geoLocation = gpsDirectory.GetGeoLocation();
Assert.NotNull(geoLocation);
Assert.True(geoLocation.Altitude > 1);
}

[Fact]
public void GetLocationWithAltitudeBelowSeaLevel()
{
var metadata = ImageMetadataReader.ReadMetadata("Data/BELOW_SEA_LEVEL.JPG");
var gpsDirectory = metadata.OfType<GpsDirectory>().First();
var geoLocation = gpsDirectory.GetGeoLocation();

Assert.NotNull(geoLocation);

Assert.True(geoLocation.Altitude < -1);
}

[Fact]
public void GpsDate()
{
Expand Down
14 changes: 13 additions & 1 deletion MetadataExtractor/Formats/Exif/GpsDirectory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,10 @@ public GpsDirectory() : base(_tagNameMap)
{
var latitudes = this.GetRationalArray(TagLatitude);
var longitudes = this.GetRationalArray(TagLongitude);
bool hasAltitude = this.TryGetRational(TagAltitude, out var altitude);
var latitudeRef = this.GetString(TagLatitudeRef);
var longitudeRef = this.GetString(TagLongitudeRef);
bool hasAltitudeRef = this.TryGetByte(TagAltitudeRef, out var altitudeRef);

// Make sure we have the required values
if (latitudes is null || latitudes.Length != 3)
Expand All @@ -183,7 +185,17 @@ public GpsDirectory() : base(_tagNameMap)
if (lat == null || lon == null)
return null;

return new GeoLocation((double)lat, (double)lon);
double? alt = null;

if (hasAltitude)
{
alt = altitude.ToDouble();

if (hasAltitudeRef && altitudeRef == 0x01) // Invert value when ref i 1, indicates that the value is below sea level
alt = -1.0 * alt;
}

return new GeoLocation((double)lat, (double)lon, alt);
}

/// <summary>
Expand Down
26 changes: 22 additions & 4 deletions MetadataExtractor/GeoLocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ public GeoLocation(double latitude, double longitude)
{
Latitude = latitude;
Longitude = longitude;
Altitude = null;
}

/// <summary>
/// Initialises an instance of <see cref="GeoLocation"/>.
/// </summary>
/// <param name="latitude">the latitude, in degrees</param>
/// <param name="longitude">the longitude, in degrees</param>
/// <param name="altitude">the altitude, in meters</param>
public GeoLocation(double latitude, double longitude, double? altitude)
{
Latitude = latitude;
Longitude = longitude;
Altitude = altitude;
}

/// <value>the latitudinal angle of this location, in degrees.</value>
Expand All @@ -31,6 +45,9 @@ public GeoLocation(double latitude, double longitude)
/// <value>the longitudinal angle of this location, in degrees.</value>
public double Longitude { get; }

/// <value>the altitude of this location, in meters, null indicates there is no altitude present in exif</value>
public double? Altitude { get; }

/// <value>true, if both latitude and longitude are equal to zero</value>
public bool IsZero => Latitude == 0 && Longitude == 0;

Expand Down Expand Up @@ -82,7 +99,8 @@ public static double[] DecimalToDegreesMinutesSeconds(double value)
#region Equality and Hashing

private bool Equals(GeoLocation other) => Latitude.Equals(other.Latitude) &&
Longitude.Equals(other.Longitude);
Longitude.Equals(other.Longitude) &&
Altitude.Equals(other.Altitude);

public override bool Equals(object? obj)
{
Expand All @@ -93,17 +111,17 @@ public override bool Equals(object? obj)
return obj is GeoLocation location && Equals(location);
}

public override int GetHashCode() => unchecked((Latitude.GetHashCode() * 397) ^ Longitude.GetHashCode());
public override int GetHashCode() => unchecked(((Latitude.GetHashCode() * 397) + (Altitude.GetHashCode() * 14)) ^ Longitude.GetHashCode());

#endregion

#region ToString

/// <returns>
/// Returns a string representation of this object, of format:
/// <c>1.23, 4.56</c>
/// <c>1.23, 4.56, 8M</c>
/// </returns>
public override string ToString() => Latitude + ", " + Longitude;
public override string ToString() => Latitude + ", " + Longitude + (Altitude == null ? string.Empty : $", {Altitude}M");

/// <returns>
/// a string representation of this location, of format:
Expand Down
3 changes: 3 additions & 0 deletions MetadataExtractor/PublicAPI/net35/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeYYY =
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeZZZ = 34869 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagModelTiePoint = 33922 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagPixelScale = 33550 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagRatingPercent = 18249 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagSampleFormat = 339 -> int
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMax = 6 -> int
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMin = 5 -> int
Expand Down Expand Up @@ -382,6 +383,8 @@ MetadataExtractor.Formats.Tiff.TiffStandard
MetadataExtractor.Formats.Tiff.TiffStandard.BigTiff = 1 -> MetadataExtractor.Formats.Tiff.TiffStandard
MetadataExtractor.Formats.Tiff.TiffStandard.Tiff = 0 -> MetadataExtractor.Formats.Tiff.TiffStandard
MetadataExtractor.Formats.WebP.WebPRiffHandler.AddError(string! errorMessage) -> void
MetadataExtractor.GeoLocation.Altitude.get -> double?
MetadataExtractor.GeoLocation.GeoLocation(double latitude, double longitude, double? altitude) -> void
MetadataExtractor.IO.IndexedReader.GetUInt64(int index) -> ulong
MetadataExtractor.Rational.Absolute.get -> MetadataExtractor.Rational
MetadataExtractor.Rational.IsPositive.get -> bool
Expand Down
3 changes: 3 additions & 0 deletions MetadataExtractor/PublicAPI/net45/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeYYY =
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeZZZ = 34869 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagModelTiePoint = 33922 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagPixelScale = 33550 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagRatingPercent = 18249 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagSampleFormat = 339 -> int
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMax = 6 -> int
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMin = 5 -> int
Expand Down Expand Up @@ -382,6 +383,8 @@ MetadataExtractor.Formats.Tiff.TiffStandard
MetadataExtractor.Formats.Tiff.TiffStandard.BigTiff = 1 -> MetadataExtractor.Formats.Tiff.TiffStandard
MetadataExtractor.Formats.Tiff.TiffStandard.Tiff = 0 -> MetadataExtractor.Formats.Tiff.TiffStandard
MetadataExtractor.Formats.WebP.WebPRiffHandler.AddError(string! errorMessage) -> void
MetadataExtractor.GeoLocation.Altitude.get -> double?
MetadataExtractor.GeoLocation.GeoLocation(double latitude, double longitude, double? altitude) -> void
MetadataExtractor.IO.IndexedReader.GetUInt64(int index) -> ulong
MetadataExtractor.Rational.Absolute.get -> MetadataExtractor.Rational
MetadataExtractor.Rational.IsPositive.get -> bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeYYY =
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeZZZ = 34869 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagModelTiePoint = 33922 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagPixelScale = 33550 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagRatingPercent = 18249 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagSampleFormat = 339 -> int
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMax = 6 -> int
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMin = 5 -> int
Expand Down Expand Up @@ -382,6 +383,8 @@ MetadataExtractor.Formats.Tiff.TiffStandard
MetadataExtractor.Formats.Tiff.TiffStandard.BigTiff = 1 -> MetadataExtractor.Formats.Tiff.TiffStandard
MetadataExtractor.Formats.Tiff.TiffStandard.Tiff = 0 -> MetadataExtractor.Formats.Tiff.TiffStandard
MetadataExtractor.Formats.WebP.WebPRiffHandler.AddError(string! errorMessage) -> void
MetadataExtractor.GeoLocation.Altitude.get -> double?
MetadataExtractor.GeoLocation.GeoLocation(double latitude, double longitude, double? altitude) -> void
MetadataExtractor.IO.IndexedReader.GetUInt64(int index) -> ulong
MetadataExtractor.Rational.Absolute.get -> MetadataExtractor.Rational
MetadataExtractor.Rational.IsPositive.get -> bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeYYY =
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeZZZ = 34869 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagModelTiePoint = 33922 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagPixelScale = 33550 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagRatingPercent = 18249 -> int
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagSampleFormat = 339 -> int
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMax = 6 -> int
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMin = 5 -> int
Expand Down Expand Up @@ -382,6 +383,8 @@ MetadataExtractor.Formats.Tiff.TiffStandard
MetadataExtractor.Formats.Tiff.TiffStandard.BigTiff = 1 -> MetadataExtractor.Formats.Tiff.TiffStandard
MetadataExtractor.Formats.Tiff.TiffStandard.Tiff = 0 -> MetadataExtractor.Formats.Tiff.TiffStandard
MetadataExtractor.Formats.WebP.WebPRiffHandler.AddError(string! errorMessage) -> void
MetadataExtractor.GeoLocation.Altitude.get -> double?
MetadataExtractor.GeoLocation.GeoLocation(double latitude, double longitude, double? altitude) -> void
MetadataExtractor.IO.IndexedReader.GetUInt64(int index) -> ulong
MetadataExtractor.Rational.Absolute.get -> MetadataExtractor.Rational
MetadataExtractor.Rational.IsPositive.get -> bool
Expand Down