Question

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.

Was it helpful?

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

OTHER TIPS

You would get better accuracy (to 0.001 arc seconds, which is an inch) doing

     Dim milliseconds = Math.Truncate(temp* 1000.0)

     ...

     Array.Copy(intToByteArray(milliseconds), 0, result, 16, 4)
     Array.Copy(intToByteArray(1000), 0, result, 20, 4)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top