Click here to Skip to main content
15,905,874 members
Articles / Programming Languages / Visual Basic
Article

The ExifWorks class

Rate me:
Please Sign up or sign in to vote.
4.43/5 (27 votes)
1 Feb 2006MIT2 min read 333.2K   8.9K   87   83
The ExifWorks is a class written in 100% pure managed VB.NET, which allows comfortable reading of embedded EXIF metadata.

What is EXIF

EXIF stands for Exchangeable Image File Format. This format is used for storing various metadata in images, and is widely used mainly in digital still cameras. More information about EXIF can be found here, or in the document Description of the EXIF file format by TsuruZoh Tachibanaya.

When I was trying to find any sources regarding comfort access from .NET environment to these data, I was not successful. So I wrote this class and gave it freely available as open source.

What is ExifWorks

ExifWorks is a class written in 100% pure managed VB.NET, which allows comfort reading and writing of embedded EXIF metadata. It has the following features:

  • Provides the TagNames Enum, which contains user-friendly constant names for all known EXIF parameter IDs.
  • Provides generic functions for reading EXIF parameters: GetInt16, GetInt32, GetString, and GetRational, as well as GetPropertyInt16, GetPropertyInt32, GetPropertyString, and GetPropertyRational. They may be used to simplify the access to all EXIF data from your custom application.
  • Provides a user-friendly abstraction layer for most of the common parameters, allowing easy work with EXIF data and their presentation to end users. The abstraction layer has been developed for presentation, so even if a value is not present, some data (in valid syntax) are provided. Either default values or values computed from other sources (i.e. shutter speed vs. exposure time) are provided. If you need exact data, use the generic functions instead.

The provided test application exread.exe shows working with the ExifWorks class.

Licensing

ExifReader/ExifWorks .NET library

Copyright (c) Michal A. Valášek - Altair Communícations, 2003-2006

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.

The text of the GNU Lesser General Public License (LGPL) is available online here.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer Altairis
Czech Republic Czech Republic

Software architect and developer in Altairis, dev shop in Czech republic. Microsoft Most Valuable Professional (MVP) since 2004.


See my open source project at Codeplex.


Comments and Discussions

 
GeneralRe: EXIF Thumbnail Pin
Drew Stegon18-Aug-09 13:37
Drew Stegon18-Aug-09 13:37 
Generalc# version with GPS feature (latitude, longitude) Pin
Member 425991919-Jun-09 22:41
Member 425991919-Jun-09 22:41 
GeneralOverwrite the existing file when saving. Pin
Drittsekken11-Jun-09 10:28
Drittsekken11-Jun-09 10:28 
GeneralLatitude/Longitude Pin
Melanie Hugglestone20-Mar-09 11:51
Melanie Hugglestone20-Mar-09 11:51 
GeneralRe: Latitude/Longitude Pin
Coffer7-Jun-09 6:49
Coffer7-Jun-09 6:49 
AnswerRe: Latitude/Longitude Pin
Member 425991919-Jun-09 22:43
Member 425991919-Jun-09 22:43 
GeneralRe: Latitude/Longitude Pin
Coffer20-Jun-09 9:26
Coffer20-Jun-09 9:26 
GeneralRe: Latitude/Longitude Pin
Mark Gray25-Nov-09 11:51
Mark Gray25-Nov-09 11:51 
Latitude and Longitude are new properties near the end of the C# version above.
I have converted them back to VB.Net and included the fixed Get* routines below:

''' <summary>
''' Read Int32 from EXIF bytearray.
''' </summary>
''' <param name="B">EXIF bytearray to process</param>
''' <returns></returns>
''' <remarks></remarks>
''' <history>
''' [altair] 10.09.2003 Created
''' [altair] 05.09.2005 Changed from public shared to private instance method
''' </history>
Private Shared Function GetInt32(ByVal B As Byte()) As Int32
    If B.Length < 4 Then
        Throw New ArgumentException("Data too short (4 bytes expected)", "B")
    End If
    Return System.BitConverter.ToInt32(B, 0)
End Function

''' <summary>
''' Read Int16 from EXIF bytearray.
''' </summary>
''' <param name="B">EXIF bytearray to process</param>
''' <returns></returns>
''' <remarks></remarks>
''' <history>
''' [altair] 10.09.2003 Created
''' [altair] 05.09.2005 Changed from public shared to private instance method
''' </history>
Private Shared Function GetInt16(ByVal B As Byte()) As Int16
    If B.Length < 2 Then
        Throw New ArgumentException("Data too short (2 bytes expected)", "B")
    End If

    Return System.BitConverter.ToInt16(B, 0)
End Function

''' <summary>
''' Read string from EXIF bytearray.
''' </summary>
''' <param name="B">EXIF bytearray to process</param>
''' <returns></returns>
''' <remarks></remarks>
''' <history>
''' [altair] 10.09.2003 Created
''' [altair] 05.09.2005 Changed from public shared to private instance method
''' </history>
Private Function GetString(ByVal B As Byte()) As String
    Dim R As String = _Encoding.GetString(B)
    If R.EndsWith(vbNullChar) Then
        R = R.Substring(0, R.Length - 1)
    End If
    Return R
End Function

''' <summary>
''' Read rational from EXIF bytearray.
''' </summary>
''' <param name="B">EXIF bytearray to process</param>
''' <returns></returns>
''' <remarks></remarks>
''' <history>
''' [altair] 10.09.2003 Created
''' [altair] 05.09.2005 Changed from public shared to private instance method
''' </history>
Private Shared Function GetRational(ByVal B As Byte()) As Rational
    Dim R As New Rational
    R.Denominator = System.BitConverter.ToInt32(B, 4)
    R.Numerator = System.BitConverter.ToInt32(B, 0)
    Return R
End Function

''' <summary>
''' Get specified rational property
''' </summary>
''' <param name="PID">Property ID</param>
''' <param name="rank"></param>
''' <returns>Value of property or 0/1 if not present</returns>
''' <history>
''' [altair] 10.09.2003 Created
''' </history>
Public Function GetPropertyRational(ByVal PID As TagNames, ByVal rank As Integer) As Rational
    If IsPropertyDefined(PID) Then
        Dim N As Byte() = New Byte(7) {}
        Array.Copy(_Image.GetPropertyItem(PID).Value, rank * 8, N, 0, 8)
        Return GetRational(N)
    Else
        Dim R As New Rational()
        Return R
    End If
End Function

''' <summary>
''' Degrees, Minutes, Seconds to Decimal Degrees
''' </summary>
''' <param name="Deg">Degrees</param>
''' <param name="Min">Minutes</param>
''' <param name="Sec">Seconds</param>
''' <returns>Decimal Degrees</returns>
''' <remarks>in EXIF, Deg is always positive, but added case for negative degrees in case this routine is reused</remarks>
Private Shared Function DMStoDD(ByVal Deg As Double, ByVal Min As Double, ByVal Sec As Double) As Double
    Dim lFraction As Double = (Min / 60) + (Sec / 3600)
    If Deg > 0 Then
        Return Deg + lFraction
    Else
        Return Deg - lFraction
    End If
End Function

''' <summary>
''' GPS Latitude
''' </summary>
''' <returns>Decimal degrees of latitude</returns>
Public ReadOnly Property Latitude() As Double
    Get
        If IsPropertyDefined(TagNames.GpsLatitude) Then
            Dim deg As Rational = GetPropertyRational(TagNames.GpsLatitude, 0)
            Dim min As Rational = GetPropertyRational(TagNames.GpsLatitude, 1)
            Dim sec As Rational = GetPropertyRational(TagNames.GpsLatitude, 2)
            Dim res As [Double] = DMStoDD(deg.ToDouble(), min.ToDouble(), sec.ToDouble())
            Dim Ref As [String] = GetPropertyString(TagNames.GpsLatitudeRef)
            If Ref <> "N" Then
                res = -res
            End If
            Return res
        Else
            Return [Double].NaN
        End If
    End Get
End Property

''' <summary>
''' GPS Longitude
''' </summary>
''' <returns>Decimal degrees of longitude</returns>
Public ReadOnly Property Longitude() As Double
    Get
        If IsPropertyDefined(TagNames.GpsLongitude) Then
            Dim deg As Rational = GetPropertyRational(TagNames.GpsLongitude, 0)
            Dim min As Rational = GetPropertyRational(TagNames.GpsLongitude, 1)
            Dim sec As Rational = GetPropertyRational(TagNames.GpsLongitude, 2)
            Dim res As [Double] = DMStoDD(deg.ToDouble(), min.ToDouble(), sec.ToDouble())
            Dim Ref As [String] = GetPropertyString(TagNames.GpsLongitudeRef)
            If Ref <> "E" Then
                res = -res
            End If
            Return res
        Else
            Return [Double].NaN
        End If
    End Get
End Property

GeneralRe: Latitude/Longitude Pin
MichaelCameron196128-Sep-11 23:51
MichaelCameron196128-Sep-11 23:51 
GeneralSome wrong values Pin
Onur Guzel4-Jan-09 0:28
Onur Guzel4-Jan-09 0:28 
GeneralRe: Some wrong values Pin
Onur Guzel23-May-10 0:20
Onur Guzel23-May-10 0:20 
QuestionHow do you change EXIF properties? Pin
abhi_here8-Sep-08 10:53
abhi_here8-Sep-08 10:53 
GeneralWritten Tags - Visibility ijn Other Products Pin
Philip Lippard7-Jul-08 11:35
Philip Lippard7-Jul-08 11:35 
GeneralIDisposable Pin
yvdh26-May-08 4:31
yvdh26-May-08 4:31 
QuestionFile Lock during Opening File Pin
marcolino730-Aug-07 10:28
marcolino730-Aug-07 10:28 
AnswerRe: File Lock during Opening File Pin
marcolino731-Aug-07 0:57
marcolino731-Aug-07 0:57 
GeneralPerformance improvement (x20) Pin
kounch17-Jun-07 4:30
kounch17-Jun-07 4:30 
GeneralRe: Performance improvement (x20) Pin
TheEscort2-Jul-07 7:03
TheEscort2-Jul-07 7:03 
GeneralRe: Performance improvement (x20) Pin
Rob241211-Sep-07 11:45
Rob241211-Sep-07 11:45 
GeneralRe: Performance improvement (x20) Pin
Member 459992410-Dec-07 3:28
Member 459992410-Dec-07 3:28 
GeneralRe: Performance improvement (x20) Pin
Mark Gray25-Nov-09 13:32
Mark Gray25-Nov-09 13:32 
GeneralUTF8 Pin
waimoehtun25-Jan-07 2:01
waimoehtun25-Jan-07 2:01 
QuestionHow to write tags Pin
dalib24-Jan-07 4:56
dalib24-Jan-07 4:56 
AnswerRe: How to write tags Pin
Sdolby7-Jun-16 4:58
Sdolby7-Jun-16 4:58 
GeneralAnybody extracted the MakerNotes Pin
Andy Hollis18-Jan-07 10:14
Andy Hollis18-Jan-07 10:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.