Private Sub SetJpgProperty(ByVal filename As String, ByVal Prop As JpgProperty, ByVal value As String)
Dim fs As New IO.BinaryReader(New IO.FileStream(filename, IO.FileMode.Open))
'Advances the FileStream to the position of the property and saves it
fs.BaseStream.Seek(&H30 + 12 * Prop, IO.SeekOrigin.Begin)
Dim startPos As UInteger = fs.ReadUInt32 + 30
fs.BaseStream.Seek(startPos, IO.SeekOrigin.Begin)
'Advances the stream to the end of the property to record its length
Do Until fs.ReadUInt16 = 0
Loop
Dim offsetLen As Integer = value.Length * 2 - CInt(fs.BaseStream.Position - startPos) + 2
'Backs up the jpg image data for when we insert the property
Dim jpgData(CInt(fs.BaseStream.Length - fs.BaseStream.Position - 1)) As Byte
fs.Read(jpgData, 0, CInt(fs.BaseStream.Length - fs.BaseStream.Position))
'Write new property data
fs.BaseStream.Seek(startPos, IO.SeekOrigin.Begin)
WriteString(fs.BaseStream, value)
fs.BaseStream.WriteByte(0)
fs.BaseStream.WriteByte(0)
'Write the preserved data
fs.BaseStream.Write(jpgData, 0, jpgData.Count)
'Update property data length
fs.BaseStream.Seek(&H2C + 12 * Prop, IO.SeekOrigin.Begin)
WriteUInteger(fs.BaseStream, value.Length * 2 + 2)
'Update data pointer
fs.BaseStream.Seek(&H16, IO.SeekOrigin.Begin)
IncUShortB(fs.BaseStream, offsetLen)
'Update property pointers
fs.BaseStream.Seek(&H30, IO.SeekOrigin.Begin)
Dim v As UInteger
For l As Integer = 0 To 4
v = fs.ReadUInt32
If v + 30 > startPos Then
fs.BaseStream.Seek(-4, IO.SeekOrigin.Current)
WriteUInteger(fs.BaseStream, v + offsetLen)
End If
fs.BaseStream.Seek(8, IO.SeekOrigin.Current)
Next
fs.Close()
End Sub
Private Sub WriteUInteger(ByVal fs As IO.Stream, ByVal value As UInteger)
fs.WriteByte(CByte(value Mod &H100))
fs.WriteByte(CByte(value \ &H100 Mod &H10000))
fs.WriteByte(CByte(value \ &H10000 Mod &H1000000))
fs.WriteByte(CByte(value \ &H1000000))
End Sub
Private Sub IncUShortB(ByVal fs As IO.Stream, ByVal value As Integer)
Dim v As UShort = fs.ReadByte() * 256
v += fs.ReadByte
v += value
fs.Seek(-2, IO.SeekOrigin.Current)
fs.WriteByte(CByte(v \ &H100))
fs.WriteByte(CByte(v Mod &H100))
End Sub
Private Sub WriteString(ByVal fs As IO.Stream, ByVal str As String)
For l As Integer = 0 To str.Length - 1
Dim v As Integer = Asc(str.Chars(l))
If v < &H100 Then
fs.WriteByte(CByte(v Mod &H100))
fs.WriteByte(0)
Else
fs.WriteByte(CByte(v Mod &H100))
fs.WriteByte(CByte(v Mod &H10000 \ &H100))
End If
Next
End Sub
Private Enum JpgProperty
Title = 0
Comments = 1
Author = 2
Keywords = 3
Subject = 4
End Enum