I recently started a new contract with a local company and their project is quite image intensive. One of the tasks set before me was to store custom data in an image. Things such as the title, comments and keywords. Turned out to be quite an extensive undertaking. With the help of some other sources, I came up with this code. Ironically as it turned out we can’t use my solution because of some issues with custom image formats that are not respected in Microsoft Windows. But it is here for you! I will post the C# version soon. Also pay attention to your encoding. This was an issue that tripped me up here for a while.
Imports System.Collections.Generic
Imports System.Text
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Reflection
Imports System.IO
Public Class clsReadMetaData
Public Function ReadEXIFMetadata(ByVal filepath As String) As ImageMetadata
Dim fs As New FileStream(filepath, FileMode.Open, FileAccess.Read)
Dim image__1 As Image = Image.FromStream(fs)
Dim imagePropertyItems As PropertyItem() = image__1.PropertyItems
Dim imageMetadata As New ImageMetadata()
For Each pi As PropertyItem In imagePropertyItems
Select Case CType(pi.Id, EXIFProperty)
Case EXIFProperty.Title
imageMetadata.Title = Encoding.Unicode.GetString(pi.Value)
‘imageMetadata.Title = Encoding.UTF32.GetString(pi.Value)
Exit Select
Case EXIFProperty.Author
imageMetadata.Author = Encoding.Unicode.GetString(pi.Value)
‘imageMetadata.Author = Encoding.UTF8.GetString(pi.Value)
Exit Select
Case EXIFProperty.Keywords
imageMetadata.Keywords = Encoding.Unicode.GetString(pi.Value)
‘imageMetadata.Keywords = Encoding.UTF8.GetString(pi.Value)
Exit Select
Case EXIFProperty.Comments
imageMetadata.Comments = Encoding.Unicode.GetString(pi.Value)
‘imageMetadata.Comments = Encoding.UTF8.GetString(pi.Value)
Exit Select
Case Else
Exit Select
End Select
Next
fs.Close()
Return imageMetadata
End Function
Public Sub SaveEXIFMetadata(ByVal image As Image, ByVal metadata As ImageMetadata, ByVal filepath As String)
SaveEXIFMetadataProperty(image, EXIFProperty.Title, metadata.Title, filepath)
SaveEXIFMetadataProperty(image, EXIFProperty.Author, metadata.Author, filepath)
SaveEXIFMetadataProperty(image, EXIFProperty.Keywords, metadata.Keywords, filepath)
SaveEXIFMetadataProperty(image, EXIFProperty.Comments, metadata.Comments, filepath)
End Sub
Private Sub SaveEXIFMetadataProperty(ByVal image As Image, ByVal [property] As EXIFProperty, ByVal propertyValue As String, ByVal filepath As String)
Dim propertyItem As PropertyItem = CreatePropertyItem()
propertyItem.Id = CInt([property])
‘ Type=1 means Array of Bytes.
propertyItem.Type = 2
propertyItem.Len = propertyValue.Length
‘propertyItem.Value = Encoding.Unicode.GetBytes(propertyValue)
propertyItem.Value = Encoding.UTF8.GetBytes(propertyValue)
image.SetPropertyItem(propertyItem)
image.Save(filepath)
End Sub
Private Function CreatePropertyItem() As PropertyItem
Dim ci As System.Reflection.ConstructorInfo = GetType(PropertyItem).GetConstructor(BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.[Public], Nothing, New Type() {}, Nothing)
Return DirectCast(ci.Invoke(Nothing), PropertyItem)
End Function
End Class
Public Enum EXIFProperty
Title = 40091
Author = 40093
Keywords = 40094
Comments = 40092
End Enum
Public Class ImageMetadata
Private _title As String = String.Empty
Private _author As String = String.Empty
Private _keywords As String = String.Empty
Private _comments As String = String.Empty
Public Sub New()
Me._title = String.Empty
Me._author = String.Empty
Me._keywords = String.Empty
Me._comments = String.Empty
End Sub
Public Sub New(ByVal title As String, ByVal author As String, ByVal keywords As String, ByVal comments As String)
Me._title = title
Me._author = author
Me._keywords = keywords
Me._comments = comments
End Sub
Public Property Title() As String
Get
Return Me._title
End Get
Set(ByVal value As String)
Me._title = value
End Set
End Property
Public Property Author() As String
Get
Return Me._author
End Get
Set(ByVal value As String)
Me._author = value
End Set
End Property
Public Property Keywords() As String
Get
Return Me._keywords
End Get
Set(ByVal value As String)
Me._keywords = value
End Set
End Property
Public Property Comments() As String
Get
Return Me._comments
End Get
Set(ByVal value As String)
Me._comments = value
End Set
End Property
End Class
.NET Framework, Array, author, BindingFlags, Bytes, Case, Class, Close, Collections, Comments, ConstructorInfo, CreatePropertyItem, custom, Data, DirectCast, Enum, FileMode, filepath, FileStream, FromStream, FUNCTION, Generic, GetBytes, GetConstructor, GetType, Image, ImageMetadata, imagePropertyItems, Imports, instance, Keywords, Length, Metadata, Microsoft, NonPublic, Open, Private, PropertyItem, PropertyItems, propertyValue, Public, Read, ReadEXIFMetadata, Reflection, Return, Save, Select, SetPropertyItem, solution, System, tasks, Text, Title, Type, Unicode, Value, vb.net, version, Windows, Write, _author, _comments, _keywords, _title
Get or Write Image Metadata with vb.net
Posted by Kelly's Chronicles in .NET, vb.net on September 1, 2011
I recently started a new contract with a local company and their project is quite image intensive. One of the tasks set before me was to store custom data in an image. Things such as the title, comments and keywords. Turned out to be quite an extensive undertaking. With the help of some other sources, I came up with this code. Ironically as it turned out we can’t use my solution because of some issues with custom image formats that are not respected in Microsoft Windows. But it is here for you! I will post the C# version soon. Also pay attention to your encoding. This was an issue that tripped me up here for a while.
Imports System.Collections.Generic
Imports System.Text
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Reflection
Imports System.IO
Public Class clsReadMetaData
Public Function ReadEXIFMetadata(ByVal filepath As String) As ImageMetadata
Dim fs As New FileStream(filepath, FileMode.Open, FileAccess.Read)
Dim image__1 As Image = Image.FromStream(fs)
Dim imagePropertyItems As PropertyItem() = image__1.PropertyItems
Dim imageMetadata As New ImageMetadata()
For Each pi As PropertyItem In imagePropertyItems
Select Case CType(pi.Id, EXIFProperty)
Case EXIFProperty.Title
imageMetadata.Title = Encoding.Unicode.GetString(pi.Value)
‘imageMetadata.Title = Encoding.UTF32.GetString(pi.Value)
Exit Select
Case EXIFProperty.Author
imageMetadata.Author = Encoding.Unicode.GetString(pi.Value)
‘imageMetadata.Author = Encoding.UTF8.GetString(pi.Value)
Exit Select
Case EXIFProperty.Keywords
imageMetadata.Keywords = Encoding.Unicode.GetString(pi.Value)
‘imageMetadata.Keywords = Encoding.UTF8.GetString(pi.Value)
Exit Select
Case EXIFProperty.Comments
imageMetadata.Comments = Encoding.Unicode.GetString(pi.Value)
‘imageMetadata.Comments = Encoding.UTF8.GetString(pi.Value)
Exit Select
Case Else
Exit Select
End Select
Next
fs.Close()
Return imageMetadata
End Function
Public Sub SaveEXIFMetadata(ByVal image As Image, ByVal metadata As ImageMetadata, ByVal filepath As String)
SaveEXIFMetadataProperty(image, EXIFProperty.Title, metadata.Title, filepath)
SaveEXIFMetadataProperty(image, EXIFProperty.Author, metadata.Author, filepath)
SaveEXIFMetadataProperty(image, EXIFProperty.Keywords, metadata.Keywords, filepath)
SaveEXIFMetadataProperty(image, EXIFProperty.Comments, metadata.Comments, filepath)
End Sub
Private Sub SaveEXIFMetadataProperty(ByVal image As Image, ByVal [property] As EXIFProperty, ByVal propertyValue As String, ByVal filepath As String)
Dim propertyItem As PropertyItem = CreatePropertyItem()
propertyItem.Id = CInt([property])
‘ Type=1 means Array of Bytes.
propertyItem.Type = 2
propertyItem.Len = propertyValue.Length
‘propertyItem.Value = Encoding.Unicode.GetBytes(propertyValue)
propertyItem.Value = Encoding.UTF8.GetBytes(propertyValue)
image.SetPropertyItem(propertyItem)
image.Save(filepath)
End Sub
Private Function CreatePropertyItem() As PropertyItem
Dim ci As System.Reflection.ConstructorInfo = GetType(PropertyItem).GetConstructor(BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.[Public], Nothing, New Type() {}, Nothing)
Return DirectCast(ci.Invoke(Nothing), PropertyItem)
End Function
End Class
Public Enum EXIFProperty
Title = 40091
Author = 40093
Keywords = 40094
Comments = 40092
End Enum
Public Class ImageMetadata
Private _title As String = String.Empty
Private _author As String = String.Empty
Private _keywords As String = String.Empty
Private _comments As String = String.Empty
Public Sub New()
Me._title = String.Empty
Me._author = String.Empty
Me._keywords = String.Empty
Me._comments = String.Empty
End Sub
Public Sub New(ByVal title As String, ByVal author As String, ByVal keywords As String, ByVal comments As String)
Me._title = title
Me._author = author
Me._keywords = keywords
Me._comments = comments
End Sub
Public Property Title() As String
Get
Return Me._title
End Get
Set(ByVal value As String)
Me._title = value
End Set
End Property
Public Property Author() As String
Get
Return Me._author
End Get
Set(ByVal value As String)
Me._author = value
End Set
End Property
Public Property Keywords() As String
Get
Return Me._keywords
End Get
Set(ByVal value As String)
Me._keywords = value
End Set
End Property
Public Property Comments() As String
Get
Return Me._comments
End Get
Set(ByVal value As String)
Me._comments = value
End Set
End Property
End Class
.NET Framework, Array, author, BindingFlags, Bytes, Case, Class, Close, Collections, Comments, ConstructorInfo, CreatePropertyItem, custom, Data, DirectCast, Enum, FileMode, filepath, FileStream, FromStream, FUNCTION, Generic, GetBytes, GetConstructor, GetType, Image, ImageMetadata, imagePropertyItems, Imports, instance, Keywords, Length, Metadata, Microsoft, NonPublic, Open, Private, PropertyItem, PropertyItems, propertyValue, Public, Read, ReadEXIFMetadata, Reflection, Return, Save, Select, SetPropertyItem, solution, System, tasks, Text, Title, Type, Unicode, Value, vb.net, version, Windows, Write, _author, _comments, _keywords, _title
8 Comments