Skip to content

Commit dcea058

Browse files
author
Rudde
committed
Adding altitude support to exif parser
1 parent d3ece94 commit dcea058

File tree

9 files changed

+69
-5
lines changed

9 files changed

+69
-5
lines changed
2.56 MB
Loading
1.17 MB
Loading

MetadataExtractor.Tests/Formats/Exif/ExifDirectoryTest.cs

+22
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,28 @@ public void GeoLocation()
5252
Assert.Equal(-1.9141666666666666, geoLocation!.Longitude);
5353
}
5454

55+
[Fact]
56+
public void GeoLocationWithAltitude()
57+
{
58+
var metadata = ImageMetadataReader.ReadMetadata("Data/ABOVE_SEA_LEVEL.jpg");
59+
var gpsDirectory = metadata.OfType<GpsDirectory>().First();
60+
var geoLocation = gpsDirectory.GetGeoLocation();
61+
Assert.NotNull(geoLocation);
62+
Assert.True(geoLocation.Altitude > 1);
63+
}
64+
65+
[Fact]
66+
public void GetLocationWithAltitudeBelowSeaLevel()
67+
{
68+
var metadata = ImageMetadataReader.ReadMetadata("Data/BELOW_SEA_LEVEL.JPG");
69+
var gpsDirectory = metadata.OfType<GpsDirectory>().First();
70+
var geoLocation = gpsDirectory.GetGeoLocation();
71+
72+
Assert.NotNull(geoLocation);
73+
74+
Assert.True(geoLocation.Altitude < -1);
75+
}
76+
5577
[Fact]
5678
public void GpsDate()
5779
{

MetadataExtractor/Formats/Exif/GpsDirectory.cs

+13-1
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,10 @@ public GpsDirectory() : base(_tagNameMap)
163163
{
164164
var latitudes = this.GetRationalArray(TagLatitude);
165165
var longitudes = this.GetRationalArray(TagLongitude);
166+
bool hasAltitude = this.TryGetRational(TagAltitude, out var altitude);
166167
var latitudeRef = this.GetString(TagLatitudeRef);
167168
var longitudeRef = this.GetString(TagLongitudeRef);
169+
bool hasAltitudeRef = this.TryGetByte(TagAltitudeRef, out var altitudeRef);
168170

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

186-
return new GeoLocation((double)lat, (double)lon);
188+
double? alt = null;
189+
190+
if (hasAltitude)
191+
{
192+
alt = altitude.ToDouble();
193+
194+
if (hasAltitudeRef && altitudeRef == 0x01) // Invert value when ref i 1, indicates that the value is below sea level
195+
alt = -1.0 * alt;
196+
}
197+
198+
return new GeoLocation((double)lat, (double)lon, alt);
187199
}
188200

189201
/// <summary>

MetadataExtractor/GeoLocation.cs

+22-4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ public GeoLocation(double latitude, double longitude)
2323
{
2424
Latitude = latitude;
2525
Longitude = longitude;
26+
Altitude = null;
27+
}
28+
29+
/// <summary>
30+
/// Initialises an instance of <see cref="GeoLocation"/>.
31+
/// </summary>
32+
/// <param name="latitude">the latitude, in degrees</param>
33+
/// <param name="longitude">the longitude, in degrees</param>
34+
/// <param name="altitude">the altitude, in meters</param>
35+
public GeoLocation(double latitude, double longitude, double? altitude)
36+
{
37+
Latitude = latitude;
38+
Longitude = longitude;
39+
Altitude = altitude;
2640
}
2741

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

48+
/// <value>the altitude of this location, in meters, null indicates there is no altitude present in exif</value>
49+
public double? Altitude { get; }
50+
3451
/// <value>true, if both latitude and longitude are equal to zero</value>
3552
public bool IsZero => Latitude == 0 && Longitude == 0;
3653

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

84101
private bool Equals(GeoLocation other) => Latitude.Equals(other.Latitude) &&
85-
Longitude.Equals(other.Longitude);
102+
Longitude.Equals(other.Longitude) &&
103+
Altitude.Equals(other.Altitude);
86104

87105
public override bool Equals(object? obj)
88106
{
@@ -93,17 +111,17 @@ public override bool Equals(object? obj)
93111
return obj is GeoLocation location && Equals(location);
94112
}
95113

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

98116
#endregion
99117

100118
#region ToString
101119

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

108126
/// <returns>
109127
/// a string representation of this location, of format:

MetadataExtractor/PublicAPI/net35/PublicAPI.Unshipped.txt

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeYYY =
1616
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeZZZ = 34869 -> int
1717
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagModelTiePoint = 33922 -> int
1818
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagPixelScale = 33550 -> int
19+
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagRatingPercent = 18249 -> int
1920
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagSampleFormat = 339 -> int
2021
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMax = 6 -> int
2122
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMin = 5 -> int
@@ -382,6 +383,8 @@ MetadataExtractor.Formats.Tiff.TiffStandard
382383
MetadataExtractor.Formats.Tiff.TiffStandard.BigTiff = 1 -> MetadataExtractor.Formats.Tiff.TiffStandard
383384
MetadataExtractor.Formats.Tiff.TiffStandard.Tiff = 0 -> MetadataExtractor.Formats.Tiff.TiffStandard
384385
MetadataExtractor.Formats.WebP.WebPRiffHandler.AddError(string! errorMessage) -> void
386+
MetadataExtractor.GeoLocation.Altitude.get -> double?
387+
MetadataExtractor.GeoLocation.GeoLocation(double latitude, double longitude, double? altitude) -> void
385388
MetadataExtractor.IO.IndexedReader.GetUInt64(int index) -> ulong
386389
MetadataExtractor.Rational.Absolute.get -> MetadataExtractor.Rational
387390
MetadataExtractor.Rational.IsPositive.get -> bool

MetadataExtractor/PublicAPI/net45/PublicAPI.Unshipped.txt

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeYYY =
1616
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeZZZ = 34869 -> int
1717
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagModelTiePoint = 33922 -> int
1818
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagPixelScale = 33550 -> int
19+
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagRatingPercent = 18249 -> int
1920
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagSampleFormat = 339 -> int
2021
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMax = 6 -> int
2122
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMin = 5 -> int
@@ -382,6 +383,8 @@ MetadataExtractor.Formats.Tiff.TiffStandard
382383
MetadataExtractor.Formats.Tiff.TiffStandard.BigTiff = 1 -> MetadataExtractor.Formats.Tiff.TiffStandard
383384
MetadataExtractor.Formats.Tiff.TiffStandard.Tiff = 0 -> MetadataExtractor.Formats.Tiff.TiffStandard
384385
MetadataExtractor.Formats.WebP.WebPRiffHandler.AddError(string! errorMessage) -> void
386+
MetadataExtractor.GeoLocation.Altitude.get -> double?
387+
MetadataExtractor.GeoLocation.GeoLocation(double latitude, double longitude, double? altitude) -> void
385388
MetadataExtractor.IO.IndexedReader.GetUInt64(int index) -> ulong
386389
MetadataExtractor.Rational.Absolute.get -> MetadataExtractor.Rational
387390
MetadataExtractor.Rational.IsPositive.get -> bool

MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Unshipped.txt

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeYYY =
1616
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeZZZ = 34869 -> int
1717
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagModelTiePoint = 33922 -> int
1818
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagPixelScale = 33550 -> int
19+
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagRatingPercent = 18249 -> int
1920
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagSampleFormat = 339 -> int
2021
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMax = 6 -> int
2122
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMin = 5 -> int
@@ -382,6 +383,8 @@ MetadataExtractor.Formats.Tiff.TiffStandard
382383
MetadataExtractor.Formats.Tiff.TiffStandard.BigTiff = 1 -> MetadataExtractor.Formats.Tiff.TiffStandard
383384
MetadataExtractor.Formats.Tiff.TiffStandard.Tiff = 0 -> MetadataExtractor.Formats.Tiff.TiffStandard
384385
MetadataExtractor.Formats.WebP.WebPRiffHandler.AddError(string! errorMessage) -> void
386+
MetadataExtractor.GeoLocation.Altitude.get -> double?
387+
MetadataExtractor.GeoLocation.GeoLocation(double latitude, double longitude, double? altitude) -> void
385388
MetadataExtractor.IO.IndexedReader.GetUInt64(int index) -> ulong
386389
MetadataExtractor.Rational.Absolute.get -> MetadataExtractor.Rational
387390
MetadataExtractor.Rational.IsPositive.get -> bool

MetadataExtractor/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeYYY =
1616
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagIsoSpeedLatitudeZZZ = 34869 -> int
1717
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagModelTiePoint = 33922 -> int
1818
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagPixelScale = 33550 -> int
19+
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagRatingPercent = 18249 -> int
1920
const MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagSampleFormat = 339 -> int
2021
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMax = 6 -> int
2122
const MetadataExtractor.Formats.Exif.Makernotes.FlirMakernoteDirectory.TagCameraTemperatureRangeMin = 5 -> int
@@ -382,6 +383,8 @@ MetadataExtractor.Formats.Tiff.TiffStandard
382383
MetadataExtractor.Formats.Tiff.TiffStandard.BigTiff = 1 -> MetadataExtractor.Formats.Tiff.TiffStandard
383384
MetadataExtractor.Formats.Tiff.TiffStandard.Tiff = 0 -> MetadataExtractor.Formats.Tiff.TiffStandard
384385
MetadataExtractor.Formats.WebP.WebPRiffHandler.AddError(string! errorMessage) -> void
386+
MetadataExtractor.GeoLocation.Altitude.get -> double?
387+
MetadataExtractor.GeoLocation.GeoLocation(double latitude, double longitude, double? altitude) -> void
385388
MetadataExtractor.IO.IndexedReader.GetUInt64(int index) -> ulong
386389
MetadataExtractor.Rational.Absolute.get -> MetadataExtractor.Rational
387390
MetadataExtractor.Rational.IsPositive.get -> bool

0 commit comments

Comments
 (0)