Search code examples
vb.netgpsjpegexifexifworks

Converting Lat / Long GPS coordinates to an EXIF Rational byte array


I am having problems converting GPS coordinates to a byte array that can be stored as EXIF information.

This questions states that EXIF coordinates should be expressed as three rational numbers: degrees/1, minutes/1, seconds/1. I'm having no trouble converting a decimal coordinate to that. For example 42.1234567 is easily converted to 42/1, 7/1, 24/1.

My problem is that I don't understand how to represent this as a byte array when I write it to the image EXIF information. The library that I'm using is called ExifWorks, and I'm using it in VB.NET.

The ExifWorks setProperty method takes three things: the EXIF field ID, an array of bytes as data, and the data type. Here's how I use it:

ew.SetProperty(TagNames.GpsLatitude, byteArrayHere, ExifWorks.ExifDataTypes.UnsignedRational)

I've also tried:

ew.SetPropertyString(TagNames.GpsLatitude, "42/1, 7/1, 24/1")

Which also doesn't work.

So, my question is, how do I convert my degree-minute-second coordinate into a byte array? Everything I've tried thus far ends up as invalid EXIF information, and doesn't work. A general solution is fine... doesn't necessarily have to work in VB.net.


Solution

  • I've figured it out. Here's the solution:

    Private Shared Function intToByteArray(ByVal int As Int32) As Byte()
        ' a necessary wrapper because of the cast to Int32
        Return BitConverter.GetBytes(int)
    End Function
    
    Private Shared Function doubleCoordinateToRationalByteArray(ByVal doubleVal As Double) As Byte()
        Dim temp As Double
    
        temp = Math.Abs(doubleVal)
        Dim degrees = Math.Truncate(temp)
    
        temp = (temp - degrees) * 60
        Dim minutes = Math.Truncate(temp)
    
        temp = (temp - minutes) * 60
        Dim seconds = Math.Truncate(temp)
    
        Dim result(24) As Byte
        Array.Copy(intToByteArray(degrees), 0, result, 0, 4)
        Array.Copy(intToByteArray(1), 0, result, 4, 4)
        Array.Copy(intToByteArray(minutes), 0, result, 8, 4)
        Array.Copy(intToByteArray(1), 0, result, 12, 4)
        Array.Copy(intToByteArray(seconds), 0, result, 16, 4)
        Array.Copy(intToByteArray(1), 0, result, 20, 4)
    
        Return result
    End Function