What an amazing project - thanks to everyone involved in this! I have run into what I think is a logic problem with how setting & retrieving GPS coordinates works that degrades the accuracy of the coordinates.
The EXIF specification calls for 3 Rational values for deg, min & sec. Rational values are expressed as a fraction, having both a numerator and a denominator. As the specification states, in the case of EXIF data, this is often X/1 for deg & min.
When you use the library to retrieve GPS coordinates, what it retrieves are of type ExifLibrary.MathEx.UFraction32. In examining an instance's properties after reading image data, I see that it does return a numerator and denominator.
Since it is returning a UFraction32, I assumed you'd write one as well, but that's not the case. If I try to set UFraction32 values to the GPS coordinates, Intellisense tells me that it can't be converted to Float. In other words, it is reading Rational but writing Float.
This inconsistency creates multiplicative imprecision that will get worse over time each time you modify the image. What I mean by this is that when you set it, you instantly lose precision in requiring we provide a Float instead of Rational which is more precise, and if you were to read it back, make some other metadata change and rewrite the images, you now have additional loss of imprecision with every single write. Over multiple such read/write cycles, your values will become increasingly wrong.
I am ultimately consuming this from inside a VB.NET application so I've written my own test DLL in C# as a proxy. This is an example of the output which demonstrates the problem:
String conversion of complete lat/long Tag:
33.00°52.00'21.76" South, 151.00°12.00'20.50" East
String conversion of deg, min & sec:
LATITUDE: 33/1 52/1 979/45 South
LONGITUDE: 151/1 12/1 23306/1137 East
Numerator / Denominator:
LAT: 33/1 52/1 979/45 South
LONG: 151/1 12/1 23306/1137 East
Converting each component to Float:
LAT: 33 52 21.75556 South
LONG: 151 12 20.4978 South
On a calculator, the values 979/45 we got back divide into 21.75555556, which is different from the 21.75556 result from a Float conversion, like so:
var f = ((float)ilatd);
And my code for the display you see generated:
back += $"String conversion of complete lat/long Tag:\r\n";
back += $"{latTag} {ilatRef}, {longTag} {ilongRef}\r\n\r\n";
back += $"String conversion of deg, min & sec:\r\n";
back += $"LATITUDE: {ilatd} {ilatm} {ilats} {ilatRef}\r\n";
back += $"LONGITUDE: {ilongd} {ilongm} {ilongs} {ilongRef}\r\n\r\n";
back += "Numerator / Denominator:\r\n";
back += $"LAT: {num}/{denom} {ilatm.Numerator}/{ilatm.Denominator} {ilats.Numerator}/{ilats.Denominator} {ilatRef}\r\n";
back += $"LONG: {ilongd.Numerator}/{ilongd.Denominator} {ilongm.Numerator}/{ilongm.Denominator} {ilongs.Numerator}/{ilongs.Denominator} {ilongRef}\r\n\r\n";
back += "Converting each component to Float:\r\n";
back += $"LAT: {((float)ilatd)} {((float)ilatm)} {((float)ilats)} {ilatRef}\r\n";
back += $"LONG: {((float)ilongd)} {((float)ilongm)} {((float)ilongs)} {ilatRef}\r\n";
As I explained, in my DLL I have to declare the coordinate values as Float because that is what the Set method requires, so it has:
public float latdeg;
public float latmin;
public float latsec;
public float longdeg;
public float longmin;
public float longsec;
Over in my main UI program in VB.NET, I'm actually using this code to populating my own DLL class instance's properties (remember, my DLL is serving as a proxy), which works without any error or issue and is the correct, mathematically accurate Rational representation:
So in all of the conversions that take place, my originally supplied 217554/10000, or 21.7554, is never, ever what I get back.
I speculated that if I was to reload the image, get the now inaccurate values, make other changes to the metadata and then save it again, and do so multiple times, the GPS coordinates become increasingly wrong with each such read/write operation. In fact, that is not actually what happens. It actually maintained the same slightly incorrect 979/45 over 10 successive iterations of read/write, so it isn't getting worse, but it's still wrong.
What's the correct way to set the values so that you get back exactly what you put in? The whole point of Rational is exact precision, but I'm not seeing how to actually get it.
What an amazing project - thanks to everyone involved in this! I have run into what I think is a logic problem with how setting & retrieving GPS coordinates works that degrades the accuracy of the coordinates.
This inconsistency creates multiplicative imprecision that will get worse over time each time you modify the image. What I mean by this is that when you set it, you instantly lose precision in requiring we provide a Float instead of Rational which is more precise, and if you were to read it back, make some other metadata change and rewrite the images, you now have additional loss of imprecision with every single write. Over multiple such read/write cycles, your values will become increasingly wrong.
I am ultimately consuming this from inside a VB.NET application so I've written my own test DLL in C# as a proxy. This is an example of the output which demonstrates the problem:
On a calculator, the values 979/45 we got back divide into 21.75555556, which is different from the 21.75556 result from a Float conversion, like so:
And my code for the display you see generated:
As I explained, in my DLL I have to declare the coordinate values as Float because that is what the Set method requires, so it has:
Also from my own DLL just for reference:
It's those numerators and denominators that I grab from VB.NET, set the properties and save it again:
Over in my main UI program in VB.NET, I'm actually using this code to populating my own DLL class instance's properties (remember, my DLL is serving as a proxy), which works without any error or issue and is the correct, mathematically accurate Rational representation:
So in all of the conversions that take place, my originally supplied 217554/10000, or 21.7554, is never, ever what I get back.
I speculated that if I was to reload the image, get the now inaccurate values, make other changes to the metadata and then save it again, and do so multiple times, the GPS coordinates become increasingly wrong with each such read/write operation. In fact, that is not actually what happens. It actually maintained the same slightly incorrect 979/45 over 10 successive iterations of read/write, so it isn't getting worse, but it's still wrong.
What's the correct way to set the values so that you get back exactly what you put in? The whole point of Rational is exact precision, but I'm not seeing how to actually get it.