Thursday, 20 May 2010

It always amazes me how easy it is to find vb samples on the web, so imagine how frustrated I was when I couldn't find this vb code. Anyway now I've written it and geotagged my photos I'll probably never look at this again, so if this helps you tag your photos go ahead and cut and paste it.

'Usage: AdGPS2JPG jpgfilename decimal_Longditude  decimal_Lattitude

Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Collections.Generic
Imports System.IO

Public Class Main

    Sub convertDec2CoordAndBytes(ByVal dec As Decimal, ByRef coord() As UInt32, ByRef vBytes() As Byte)

        Dim degs As UInt32 = Decimal.Floor(dec)
        Dim mm As Decimal = 60 * (dec - degs)
        Dim mins As UInt32 = Decimal.Floor(mm)
        Dim ss As Integer = 60 * (mm - mins)
        Dim secs As UInt32 = Decimal.Round(ss)

        ' convert decimal into coords
        coord(0) = degs
        coord(1) = 1
        coord(2) = mins
        coord(3) = 1
        coord(4) = secs
        coord(5) = 1

        ' convert coords into bytes
        Dim bytes() As Byte
        For i = 0 To 5
            bytes = BitConverter.GetBytes(coord(i))
            For j = 0 To 3
                vBytes(j + (4 * i)) = bytes(j)
            Next j
        Next i

    End Sub

    Sub addImageItem(ByRef photoImage As Image, ByVal itemId As Integer, ByVal type As Integer, ByVal vBytes() As Byte, ByVal cBytes As Integer)

        Dim photoItems As PropertyItem()
        Dim photoItem As PropertyItem = Nothing
        photoItems = photoImage.PropertyItems

        Dim fItemExists As Boolean = False

        For Each photoItem In photoItems
            If photoItem.Id = itemId Then
                fItemExists = True
                Exit For
            End If

        If fItemExists = False Then
            photoItem.Id = itemId
        End If

        photoItem = photoImage.GetPropertyItem(itemId)
        photoItem.Id = itemId
        photoItem.Type = type
        photoItem.Len = cBytes
        photoItem.Value = vBytes

    End Sub

    Private Sub Main_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Dim photoFileName As String
        Dim photoImage As Image
        Dim decLatt As Decimal
        Dim decLong As Decimal
        Dim northOrSouth As String = "N"
        Dim eastOrWest As String = "E"

        If My.Application.CommandLineArgs.Count < 3 Then
            MsgBox("Error: parameters missing! Usage: AdGPS2JPG jpgfilename decimal_Longditude  decimal_Lattitude")
        End If

        photoFileName = My.Application.CommandLineArgs(0)

            decLong = Convert.ToDecimal(My.Application.CommandLineArgs(1))
            If decLong < 0 Then
                decLong = -1 * decLong
                eastOrWest = "W"
            End If
            decLatt = Convert.ToDecimal(My.Application.CommandLineArgs(2))
            If decLatt < 0 Then
                decLatt = -1 * decLatt
                northOrSouth = "S"
            End If
        Catch ex As Exception
            MessageBox.Show("Error: could not load latt/long data - " + ex.Message)
        End Try

            photoImage = Image.FromFile(photoFileName)
        Catch ex As Exception
            MessageBox.Show("Error: could not load jpg: " + photoFileName + " - " + ex.Message)
        End Try

        Dim coord(6) As UInt32
        Dim vBytes(24) As Byte

        ' Add latt
        Call convertDec2CoordAndBytes(decLatt, coord, vBytes)
        addImageItem(photoImage, 2, 5, vBytes, 24)

        ' Add long
        Call convertDec2CoordAndBytes(decLong, coord, vBytes)
        addImageItem(photoImage, 4, 5, vBytes, 24)

        ' Add lat ref
        vBytes(0) = Asc(northOrSouth)
        vBytes(1) = 0
        addImageItem(photoImage, 1, 2, vBytes, 2)

        ' Add long ref
        vBytes(0) = Asc(eastOrWest)
        vBytes(1) = 0
        addImageItem(photoImage, 3, 2, vBytes, 2)

        ' Add GPS Version
        vBytes(0) = 2
        vBytes(1) = 2
        vBytes(2) = 0
        vBytes(3) = 0
        addImageItem(photoImage, 0, 1, vBytes, 4)

        photoImage.Save(photoFileName + "__TEMP")

        File.Replace(photoFileName + "__TEMP", photoFileName, photoFileName + "__BAK")
        File.Delete(photoFileName + "__BAK")


    End Sub

End Class


  1. Dear Frankie66,
    Thanks for your code, this is very good to me.
    I use it in my web site.
    Best regards.
    Ali Kh.

  2. Thanks for your code, i need an information.
    When you convert de second you use a Uint32 var.
    For obtain more precision, I need to use the "Double var", but I'm encountered very problem during the conversion.
    I'm obtain a valid jpg file but the precision of seconds is similar to this 43; 32; 24.124558E.

    Any Idea?