EXIF. Referencia rápida

Descripción general

Este documento muestra la forma de acceder a los datos Exif en el nuevo formato Wpf.

[TOC] Tabla de Contenidos


↑↑↑

Introduccion

He estado realizando un programa de tratamiento de imágenes y he necesitado acceder a la fecha de toma de la imagen. Algo que en principio debía ser fácil se ha vuelto más complicado de lo que parece a primera vista.


↑↑↑

Exif en Net

El marco de trabajo ".Net" proporciona dos formas ¿fáciles? de acceder a los metadatos Exif, el espacio de nombres [System.Drawing] y el espacio de nombres [System.Windows.Media.Imaging]. Por otra parte existen toda una serie de bibliotecas realizadas por terceros que son bastante mas difíciles (si cabe) de usar que las clases de .Net, sobre todo si solo se pretende acceder a uno o dos datos de las imágenes.

¿Cuál de los dos espacios de nombres es el mejor? Pues al parecer son exactamente iguales y proporcionan la misma estructura de acceso a los datos, aunque el espacio de nombres System.Windows.Media.Imaging proporciona propiedades para permitir la lectura de algunos valores directamente. Entonces, ¿cual escoger?


↑↑↑

Acceso a los datos EXIF


↑↑↑

Acceso Form

Si utilizamos [System.Drawing / Windows Forms] El acceso a los datos Exif es sencillo, : cargar la imagen, solicitar una propiedad por número, y luego analizar los bytes de propiedad en el formato deseado (cadena o un entero)

Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Text

Class EXIF
    Private Shared Sub Main()
        ' Create an Image object
        Using photo As Image = Image.FromFile(filename)
            ' Read out the date taken property (string)
            Dim dateProperty As PropertyItem = photo.GetPropertyItem(&H9003)
            Dim dateTaken As String = (New UTF8Encoding()).GetString(dateProperty.Value)
            ' And the ISO (unsigned short integer)
            Dim isoProperty As PropertyItem = photo.GetPropertyItem(&H8827)
                ' other properties can be read using similar methods...
            Dim iso As UShort = BitConverter.ToUInt16(isoProperty.Value, 0)
        End Using
    End Sub
End Class


↑↑↑

Acceso Wpf

El acceso a los datos EXIF con System.Windows.Media.Imaging / WPF es relativamente fácil y sigue un patrón similar. Sin embargo, en este caso la clase BitmapMetadata expone algunos de los valores EXIF través de propiedades del objeto BitmapMetadata. Al resto ( y también a las predefinidas) se debe acceder mediante el método GetQuery, utilizando el WIC lenguaje de consulta de metadatos . Este lenguaje de consulta unifica, en una sintaxis de uso general, las cadenas de acceso a los datos (EXIF, XMP, IPTC, ID3, etc.).

En este documento nos ocupamos del acceso a los datos EXIF, y el formato de la cadena es el siguiente:

En general, las etiquetas de menos de 1000 (decimal) se accede utilizando la primera forma de sintaxis, para los valores de 1000 o mayores se usa la segunda forma.

Imports System.IO
Imports System.Windows.Media.Imaging
 
Class EXIF
    Private Shared Sub Main()
        ' Load and decode the photo
        Using stream As New FileStream(filename, FileMode.Open)
            Dim decoder As New JpegBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None)
            ' Extract the photo's metadata
            Dim metadata As BitmapMetadata = DirectCast(decoder.Frames(0).Metadata, BitmapMetadata)
            ' Read out the date taken property...
            ' ...  via the built-in property (as a System.DateTime)
            Dim dateTaken1 As DateTime = DateTime.Parse(metadata.DateTaken)
            ' ... or via a query (as a string)
            Dim dateTaken2 As String = DirectCast(metadata.GetQuery("/app1/ifd/exif/subifd:{uint=36867}"), String)
            ' And the ISO (unsigned short integer)
            ' other properties can be read using similar methods...
            Dim iso As UShort = CUShort(metadata.GetQuery("/app1/ifd/exif/subifd:{uint=34855}"))
        End Using
    End Sub
End Class


↑↑↑

Otra forma de acceder a los datos


↑↑↑

La clase que obtiene la informacion

''' <summary>
'''   Busca y obtiene -si existen- (Algunos) metadatos de una imagen (no los obtiene todos)
''' </summary>
Public Class MetadatosExif
    Implements IDisposable


    Private _metadatos As System.Windows.Media.Imaging.BitmapMetadata



    Public Sub New(ByVal imageUri As Uri)
        Dim frame As BitmapFrame = BitmapFrame.Create(imageUri, BitmapCreateOptions.DelayCreation, BitmapCacheOption.None)

        _metadatos = DirectCast(frame.Metadata, BitmapMetadata)
    End Sub


    ''' <summary>Obtiene el metadato asociado a la clave</summary>
    ''' <param name=query">Cadena para obtener el metadato</param>"
    ''' <returns>Un objeto con el valor recuperado o el valor Nothing</returns>
    ''' <remarks>
    ''' <code>Metadata Query Language Overview - https://msdn.microsoft.com/en-us/library/ee719796(VS.85).aspx </code>
    ''' </remarks>
    Private Function QueryMetadata(query As String) As Object

        If _metadatos.ContainsQuery(query) Then
            Return _metadatos.GetQuery(query)
        Else
            Return Nothing
        End If
    End Function


    ''' <summary>
    '''  [MetadatosExif - (271)] - Equipo fabricante'Canon', 'Nikon', etc.
    ''' </summary>
    ''' <value>Un objeto [ExifTag] con la información o con valor Empty</value>
    ''' <remarks>
    '''   <para> Tag (Hex): 0x010f                       </para>
    '''   <para> Tag (Dec): 271                        </para>
    '''   <para> IFD .....: Image                        </para>
    '''   <para> Key .....: Exif.Image.Make   </para>
    '''   <para> Type ....: Ascii                         </para>
    '''   <para> Tag description : 
    '''          The manufacturer of the recording equipment. 
    '''          This is the manufacturer of the DSC, scanner, video digitizer or other equipment that generated the image.  
    '''          When the field is left blank, it is treated as unknown.  
    '''  </para>
    ''' <code>http://www.exiv2.org/tags.html</code>
    ''' </remarks>
    Public ReadOnly Property EquipoFabricante() As ExifTag
        Get
            ' obtener el valor y transformarlo en cadena
            Dim valor As Object = QueryMetadata("/app1/ifd/exif:{uint=271}")
            If Not (valor Is Nothing) Then
                Return New ExifTag(271,
                                   "Exif.Image.Make",
                                   "Fabricante del equipo",
                                   DirectCast(valor, String))
            End If
            ' si no existe devuelve un valor Empty
            Return ExifTag.Empty
        End Get
    End Property



    ''' <summary>
    '''  [MetadatosExif - (274)] - Orientación de la imagen
    ''' </summary>
    ''' <value>Un objeto [ExifTag] con la información o con valor Empty</value>
    ''' <remarks>
    '''   <para> Tag (Hex): 0x0112                        </para>
    '''   <para> Tag (Dec): 274                           </para>
    '''   <para> IFD .....: Image                         </para>
    '''   <para> Key .....: Exif.Image.Orientation              </para>
    '''   <para> Type ....: Short                         </para>
    '''   <para> Tag description : 
    '''          The image orientation viewed in terms of rows and columns.  
    '''  </para>
    '''  <para> Traducción del resultado </para>   '
    '''  <para>  1 = Horizontal (normal) </para> 
    '''  <para>  2 = Espejo horizontal </para> 
    '''  <para>  3 = Rotar 180 </para> 
    '''  <para>  4 = Espejo vertical </para> 
    '''  <para>  5 = Espejo horizontal y Rotar 270 en sentido horario </para> 
    '''  <para>  6 = Rotar 90 grados en sentido horario </para> 
    '''  <para>  7 = Espejo horizontal y Rotar 90 en sentido horario </para> 
    '''  <para>  8 = Rotar 270 grados en sentido horario </para> 
    ''' <code>http://www.exiv2.org/tags.html</code>
    ''' <code>http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html</code>
    ''' </remarks>
    Public ReadOnly Property Orientacion() As ExifTag
        Get
            ' variable para cálculos locales
            Dim parcial As String = String.Empty
            ' obtener el valor y transformarlo en cadena
            Dim valor As Object = QueryMetadata("/app1/ifd/exif:{uint=274}")
            If Not (valor Is Nothing) Then
                Dim mode As System.Nullable(Of UShort) = DirectCast(valor, System.Nullable(Of UShort))

                If mode Is Nothing Then
                    parcial = "Unknown"
                Else
                    Select Case CInt(mode)
                        Case 1
                            parcial = "Horizontal (normal)"
                        Case 2
                            parcial = "Espejo horizontal"
                        Case 3
                            parcial = "Rotar 180"
                        Case 4
                            parcial = "Espejo vertical"
                        Case 5
                            parcial = "Espejo horizontal y Rotar 270 en sentido horario"
                        Case 6
                            parcial = "Rotar 90 grados en sentido horario "
                        Case 7
                            parcial = "Espejo horizontal y Rotar 90 en sentido horario"
                        Case 8
                            parcial = "Rotar 270 grados en sentido horario"
                        Case Else
                            parcial = "Unknown"
                    End Select
                End If

                Return New ExifTag(274,
                                  "Exif.Image.Orientation",
                                  "Orientation",
                                   parcial)
            End If

            ' si no existe devuelve un valor Empty
            Return ExifTag.Empty
        End Get
    End Property




    ''' <summary>
    '''  [MetadatosExif - (282)] -Numero de pixels de resolución horizontal 
    ''' </summary>
    ''' <value>Un objeto [ExifTag] con la información o con valor Empty</value>
    ''' <remarks>
    '''   <para> Tag (Hex): 0x011a                       </para>
    '''   <para> Tag (Dec): 282                          </para>
    '''   <para> IFD .....: Image                        </para>
    '''   <para> Key .....: Exif.Image.XResolution       </para>
    '''   <para> Type ....: Rational                     </para>
    '''   <para> Tag description : 
    '''          The number of pixels per [ResolutionUnit] in the [ImageWidth] direction.
    '''          When the image resolution is unknown, 72 [dpi] is designated. 
    '''  </para>
    ''' <code>http://www.exiv2.org/tags.html</code>
    ''' </remarks>
    Public ReadOnly Property HorizontalResolution() As ExifTag
        Get
            ' obtener el valor y transformarlo en cadena
            Dim valor As Object = QueryMetadata("/app1/ifd/exif:{uint=282}")
            If Not (valor Is Nothing) Then
                'Dim tipo As Type = valor.[GetType]()
                'Stop

                If valor.[GetType]() = GetType(UInt64) Then
                    Dim NumerouInt64 As UInt64 = DirectCast(valor, UInt64)
                    Dim objRational As New ValorExifURational(NumerouInt64)
                    Dim parcial As Double = objRational.ToDouble
                    Return New ExifTag(282,
                                        "Exif.Image.XResolution",
                                        "Numero de pixels de resolución horizontal ",
                                        Convert.ToString(parcial))
                End If
            End If
            Return ExifTag.Empty
        End Get
    End Property



    ''' <summary>
    '''  [MetadatosExif - (306)] - The date And time of image creation
    ''' </summary>
    ''' <value>Un objeto [ExifTag] con la información o con valor Empty</value>
    ''' <remarks>
    '''   <para> Tag (Hex): 0x0132                        </para>
    '''   <para> Tag (Dec): 306                           </para>
    '''   <para> IFD .....: Image                         </para>
    '''   <para> Key .....: Exif.Image.DateTime           </para>
    '''   <para> Type ....: Ascii                         </para>
    '''   <para> Tag description : 
    '''          The date And time of image creation. In Exif standard, it Is the date And time the file was changed. 
    '''  </para>
    ''' <code>http://www.exiv2.org/tags.html</code>
    ''' </remarks>
    Public ReadOnly Property DateTimeImageCreation() As ExifTag
        Get
            ' obtener el valor y transformarlo en cadena
            Dim valor As Object = QueryMetadata("/app1/ifd/exif:{uint=306}")
            If Not (valor Is Nothing) Then
                ' cuidado la fecha Exif tiene el formato AAAA:MM:DD HH:MM:SS
                ' y la quiero con el formato Iso         AAAA/MM/DD HH:MM:SS
                '-------------------------
                '
                Dim auxLocal As String = DirectCast(valor, String)
                Dim objFecha As New ValorExifStringFecha(auxLocal)
                Return New ExifTag(306,
                                  "Exif.Image.DateTime",
                                  "Fecha y hora de creación de la imagen",
                                   objFecha.ToString)
            End If
            ' si no existe devuelve un valor Empty
            Return ExifTag.Empty
        End Get
    End Property


   ''' <summary>
    '''  [MetadatosExif - (33434)] - Tiempo de exposición en segundos
    ''' </summary>
    ''' <value>Un objeto [ExifTag] con la información o con valor Empty</value>
    ''' <remarks>
    '''   <para> Tag (Hex): 0x829a                        </para>
    '''   <para> Tag (Dec): 33434                           </para>
    '''   <para> IFD .....: Image                         </para>
    '''   <para> Key .....: Exif.Image.ExposureTime           </para>
    '''   <para> Type ....: Rational                         </para>
    '''   <para> Tag description : 
    '''      Tiempo de exposición 
    '''      En primer número entero dividido por el segundo número entero produce el tiempo de exposición en segundos; 
    '''      por ejemplo, un valor de 1" seguido por un valor de "50" es un tiempo de exposición de 1 / 50 th de un segundo."
    '''  </para>
    ''' <code>http://www.exiv2.org/tags.html</code>
    ''' </remarks>
    Public ReadOnly Property ExposureTime() As ExifTag
        Get
            Dim valor As Object = QueryMetadata("/app1/ifd/exif/subifd:{uint=33434}")
            If valor IsNot Nothing Then

                If valor.[GetType]() = GetType(UInt64) Then
                    Dim NumeroUInt64 As UInt64 = DirectCast(valor, UInt64)
                    Dim objURational As New ValorExifURational(NumeroUInt64)
                    Return New ExifTag(33434,
                                       "Exif.Image.ExposureTime",
                                       "Tiempo de exposición en segundos",
                                        objURational.ToString & " seg")
                    'ExposureTime1/80 sec
                End If
            End If
            ' si no existe devuelve un valor Empty
            Return ExifTag.Empty

        End Get
    End Property



    ''' <summary>
    '''  [MetadatosExif - (33437)] - Apertura del diafragma - Número F
    ''' </summary>
    ''' <value>Un objeto [ExifTag] con la información o con valor Empty</value>
    ''' <remarks>
    '''   <para> Tag (Hex): 0x829d                        </para>
    '''   <para> Tag (Dec): 33437                           </para>
    '''   <para> IFD .....: Image                         </para>
    '''   <para> Key .....: Exif.Image.FNumber           </para>
    '''   <para> Type ....: Rational                         </para>
    '''   <para> Tag description : 
    '''      Número F
    '''      En primer número entero dividido por el segundo número entero produce el número F; 
    '''      por ejemplo, un valor de 35" seguido por un valor de '10' es F / 3.5"
    '''  </para>
    ''' <code>http://www.exiv2.org/tags.html</code>
    ''' </remarks>
    Public ReadOnly Property FNumber() As ExifTag
        Get
            Dim valor As Object = QueryMetadata("/app1/ifd/exif/subifd:{uint=33437}")
            If valor IsNot Nothing Then

                If valor.[GetType]() = GetType(UInt64) Then
                    Dim NumeroUInt64 As UInt64 = DirectCast(valor, UInt64)
                    Dim objURational As New ValorExifURational(NumeroUInt64)
                    Dim numF As Decimal = Convert.ToDecimal(objURational.Numerador / objURational.Denominador)
                    Return New ExifTag(33437,
                                       "Exif.Image.FNumber",
                                       "Apertura del diafragma",
                                       "F/ " & numF.ToString)
                End If
            End If
            ' si no existe devuelve un valor Empty
            Return ExifTag.Empty

        End Get
    End Property



End Class


↑↑↑

a clase VO que contiene la informacion devuelta

''' <summary>
'''    <para> Un valor Exif de una imagen </para> 
''' </summary>
Public NotInheritable Class ExifTag

#Region "Variables y propiedades de la clase"

    Private _id As Integer = 0
    Private _fieldName As String = String.Empty
    Private _description As String = String.Empty
    Private _value As String = String.Empty

    Public ReadOnly Property Id() As Integer
        Get
            Return _id
        End Get
    End Property

    Public ReadOnly Property Description() As String
        Get
            Return _description
        End Get
    End Property

    Public ReadOnly Property FieldName() As String
        Get
            Return _fieldName
        End Get
    End Property

    Public Property Value() As String
        Get
            Return _value
        End Get
        Set
            Me._value = Value
        End Set
    End Property

#End Region

#Region "Constructores"

    ''' <summary>
    '''  Constructor estándar. Inicializa una nueva instancia de la clase [ExifTag] 
    ''' </summary>
    Public Sub New(id As Integer, fieldName As String, description As String, value As String)
        Me._id = id
        Me._description = description
        Me._fieldName = fieldName
        Me._value = value
    End Sub


    ''' <summary>
    '''  Constructor estándar. Inicializa una nueva instancia de la clase [ExifTag] 
    ''' </summary>
    Protected Sub New()
        MyBase.New()
        ' El constructor estándar para clases derivadas. No hacer nada
    End Sub


    ''' <summary>
    '''   Constructor [Shared] Crea un Objeto [ExifTag] los valores iniciales en sus campos
    ''' </summary>
    ''' <returns>Devuelve un objeto [ExifTag] 
    '''          con los valores iniciales en sus campos
    ''' </returns>
    Public Shared Function CreateNew() As ExifTag
        Return New ExifTag()
    End Function

#End Region

#Region "Funciones Comunes, Reset, Empty, IsEmpty, ToString, ToInforme"

    ''' <summary>
    ''' Pone las variables miembro de la clase con sus valores por defecto
    ''' </summary>
    Public Sub Reset()
        _id = 0
        _fieldName = String.Empty
        _description = String.Empty
        _value = String.Empty
    End Sub

  
    ''' <summary>
    '''   Devuelve un Objeto vacío [Empty]
    ''' </summary>
    Public Shared Function Empty() As ExifTag
        Return ExifTag.CreateNew
    End Function


    ''' <summary>
    '''   ¿¿ La clase tiene el valor Empty?? 
    '''   ¿¿ Todos sus campos tienen el valor empty??
    ''' </summary>
    ''' <returns>
    ''' <para> Un valor lógico que indica:</para>
    ''' <para> True.: Si la clase tiene el valor empty 
    '''              (todas sus campos miembros tienen su valor Empty</para>
    ''' <para> False: La clase no esta vacía. Alguno (uno o varios)de los
    '''               campos miembro de la clase tienen valores
    '''              (algún valor distinto del valor por defecto el valor Empty)
    ''' </para>
    ''' </returns>
    Public Function IsEmpty() As Boolean
        If _id = 0 AndAlso
           _fieldName = String.Empty AndAlso
           _description = String.Empty AndAlso
           _value = String.Empty Then
            Return True
        Else
            Return False
        End If
    End Function

    Public Overrides Function ToString() As String
        Return String.Format("{0} ({1}) = {2}", Description, FieldName, Value)
    End Function

#End Region

End Class


↑↑↑

La clase que trata un numero Racional

' /**
' --------------------------------------------------
' [- Versión     -]           = 16.02.14.17
' [- Class  Name -]           = ValorExifURational
' [- Descripción -]           = Trata un numero Exif UInt64 que en el formato Exif es un numero URational
' ---------------
' [- Código de ejemplo -]     = 
'    ''' <summary>Obtiene el metadato Tiempo de exposición</summary>
'    Public ReadOnly Property ExposureTime() As ExifTag
'        Get
'            Dim valor As Object = QueryMetadata("/app1/ifd/exif/subifd:{uint=33434}")
'            If valor IsNot Nothing Then
'                If valor.[GetType]() = GetType(UInt64) Then
'                    Dim NumeroUInt64 As UInt64 = DirectCast(valor, UInt64)
'                    Dim objURational As New ValorExifURational(NumeroUInt64)
'                    Return New ExifTag(33434,
'                                       "Exif.Image.ExposureTime",
'                                       "Tiempo de exposición en segundos",
'                                        objURational.ToString & " seg")
'                    ' ExposureTime = 1/80 seg
'                End If
'            End If
'            ' si no existe devuelve un valor Empty
'            Return ExifTag.Empty
'        End Get
'    End Property
'
'    ''' <summary>Obtiene el metadato asociado a la clave</summary>
'    ''' <param name=query">Cadena para obtener el metadato</param>"
'    ''' <returns>Un objeto con el valor recuperado o el valor Nothing</returns>
'    ''' <remarks>
'    ''' <code>Metadata Query Language Overview - https://msdn.microsoft.com/en-us/library/ee719796(VS.85).aspx </code>
'    ''' </remarks>
'    Private Function QueryMetadata(query As String) As Object
'        If _metadatos.ContainsQuery(query) Then
'            Return _metadatos.GetQuery(query)
'        Else
'            Return Nothing
'        End If
'    End Function
' --------------------------------------------------
' [- /Eof -]
' */



''' <summary>
'''   Trata un numero Exif UInt64 que en el formato Exif es un numero URational
''' </summary>
Friend NotInheritable Class ValorExifURational
    Private _num As UInt32
    Private _denom As UInt32

    Public ReadOnly Property Numerador As UInt32
        Get
            Return _num
        End Get
    End Property

    Public ReadOnly Property Denominador As UInt32
        Get
            Return _denom
        End Get
    End Property



    Public Sub New(ByVal numeroUInt64 As UInt64)
        'Dim bytes As Byte() = BitConverter.GetBytes(numeroUInt64)
        Me.New(BitConverter.GetBytes(numeroUInt64))
    End Sub



    Public Sub New(bytes As Byte())
        Dim n As Byte() = New Byte(3) {}
        Dim d As Byte() = New Byte(3) {}
        Array.Copy(bytes, 0, n, 0, 4)
        Array.Copy(bytes, 4, d, 0, 4)
        _num = BitConverter.ToUInt32(n, 0)
        _denom = BitConverter.ToUInt32(d, 0)
    End Sub

    Public Function ToDouble() As Double
        Return Math.Round(Convert.ToDouble(_num) / Convert.ToDouble(_denom), 2)
    End Function

    Public Overrides Function ToString() As String
        Return Me.ToString("/")
    End Function

    Public Overloads Function ToString(separator As String) As String
        Return (_num.ToString() & separator) + _denom.ToString()
    End Function

End Class


↑↑↑

la clase que trata las fechas Exif

' /**
' --------------------------------------------------
' [- Versión     -]           = 16.02.14.17
' [- Class  Name -]           = ValorExifStringFecha
' [- Descripción -]           = 
'    trata y formatea una fecha. 
'    cuidado la fecha Exif tiene el formato AAAA:MM:DD HH:MM:SS
'    y la quiero con el formato Iso         AAAA/MM/DD HH:MM:SS
' ---------------
' [- Código de ejemplo -]     = 
'
'    ''' <summary>Obtiene el metadato Fecha y hora de creación de la imagen asociado a la clave 306</summary>
'    Public ReadOnly Property DateTimeImageCreation() As ExifTag
'        Get
'            ' obtener el valor y transformarlo en cadena
'            Dim valor As Object = QueryMetadata("/app1/ifd/exif:{uint=306}")
'            If Not (valor Is Nothing) Then
'                ' cuidado la fecha Exif tiene el formato AAAA:MM:DD HH:MM:SS
'                ' y la quiero con el formato Iso         AAAA/MM/DD HH:MM:SS
'                '-------------------------
'                '
'                Dim auxLocal As String = DirectCast(valor, String)
'                Dim objFecha As New ValorExifStringFecha(auxLocal)
'                Return New ExifTag(306,
'                                  "Exif.Image.DateTime",
'                                  "Fecha y hora de creación de la imagen",
'                                   objFecha.ToString)
'            End If
'            ' si no existe devuelve un valor Empty
'            Return ExifTag.Empty
'        End Get
'    End Property
'
'    ''' <summary>Obtiene el metadato asociado a la clave</summary>
'    ''' <param name=query">Cadena para obtener el metadato</param>"
'    ''' <returns>Un objeto con el valor recuperado o el valor Nothing</returns>
'    ''' <remarks>
'    ''' <code>Metadata Query Language Overview - https://msdn.microsoft.com/en-us/library/ee719796(VS.85).aspx </code>
'    ''' </remarks>
'    Private Function QueryMetadata(query As String) As Object
'        If _metadatos.ContainsQuery(query) Then
'            Return _metadatos.GetQuery(query)
'        Else
'            Return Nothing
'        End If
'    End Function
'
' --------------------------------------------------
' [- /Eof -]
' */



''' <summary>
'''  Trata una cadena exif que contiene una fecha
''' </summary>
''' <remarks>
'''    <para> Cuidado la fecha Exif tiene el formato AAAA:MM:DD HH:MM:SS </para> 
'''    <para> y la necesito con el formato Iso       AAAA/MM/DD HH:MM:SS </para> 
'''</remarks>
Public Class ValorExifStringFecha

    Private _cadenaFechaExif As String

    Public Sub New(ByVal cadenaFechaExif As String)
        Me._cadenaFechaExif = cadenaFechaExif
    End Sub


    Public Overrides Function ToString() As String
        '-------------------------
        ' cuidado la fecha Exif tiene el formato AAAA:MM:DD HH:MM:SS
        ' y la quiero con el formato             AAAA/MM/DD HH:MM:SS
        '-------------------------
        Dim resultado As String = String.Empty
        Try
            If String.IsNullOrWhiteSpace(Me._cadenaFechaExif) = False Then
                Dim posicionEspacio As Integer = _cadenaFechaExif.IndexOf(" "c)
                If posicionEspacio > -1 Then
                    Dim laFecha As String = _cadenaFechaExif.Substring(0, posicionEspacio)
                    laFecha = laFecha.Replace(":"c, "/"c)
                    Dim laHora As String = _cadenaFechaExif.Substring(posicionEspacio, _cadenaFechaExif.Length - posicionEspacio)
                    Dim toJunto As String = laFecha & laHora

                    Dim objDateTime As DateTime = DateTime.Parse(toJunto)
                    ' -----------------------------
                    'Formatos compuestos
                    '{ index[,alignment][:formatString]}
                    ' https://msdn.microsoft.com/es-es/library/txafckwd(v=vs.110).aspx
                    ' -----------------------------
                    Dim cultura As System.Globalization.CultureInfo = System.Globalization.CultureInfo.CurrentCulture
                    Dim patron As String = "{0:0000}/{1:00}/{2:00} {3:00}:{4:00}:{5:00}"
                    resultado = String.Format(cultura, patron,
                                              objDateTime.Year, objDateTime.Month, objDateTime.Day,
                                              objDateTime.Hour, objDateTime.Minute, objDateTime.Second)
                End If
            End If
        Catch ex As Exception
            Throw
        End Try
        Return resultado
    End Function

End Class


↑↑↑

Algunas Referencias de etiquetas Exif

Los números utilizados en los ejemplos anteriores se pueden encontrar en la siguiente tabla. Esta tabla no pretende ser exhaustiva solo muestra alguna de los valores Exif a modo de información.

Si estas buscando información sobre todos los datos Exif puedes visitar el sitio de ExifTool de Phil Harvey [http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html ], o el sitio Exiv2.org [http://www.exiv2.org/tags.html

Debes tener en cuenta que además de los valores estándar cada fabricante implementa sus propios valores, (las cámaras Canon) no escriben en los metadatos de Nikon), y por otra parte, no todas las cámaras de escriben en todos los campos, y hay formatos no EXIF de almacenamiento que se utilizan, así (XMP, IPTC, ID3, y más).

Todos los números enteros son de 32 bits de longitud, excepto aquellos con la notación 'corta'; que son de 16 bits de longitud. Racionales enteros se almacenan en formato XY, donde el valor es igual a X / Y; la mayoría son de 64 bits de longitud (dos números enteros de 32 bits)

Decimal Value Hex Value Data Type Tag Name Notes
271 0x010f ASCII string Equipment Maker "Canon", "Nikon", etc.
272 0×0110 ASCII string Equipment Model "Canon PowerShot S5 IS", etc.
274 0×0112 integer
(unsigned short)
Orientation 1 = Horizontal
3 = Rotate 180 degrees
6 = Rotate 90 degrees clockwise
8 = Rotate 270 degrees clockwise
282 0x011a integer
(unsigned short)
X Resolution Unit in Resolution Unit field (for pixels, see Pixel X Dimension field)
283 0x011b integer
(unsigned short)
Y Resolution Unit in Resolution Unit field (for pixels, see Pixel Y Dimension field)
296 0×0128 integer
(unsigned short)
Resolution Unit 1 = None
2 = Inches
3 = Centimetres
306 0×0132 ASCII string Modified Date Time YYYY:MM:DD HH:MM:SS
33434 0x829a integer rational
(unsigned)
Exposure Time First integer divided by the second integer produces the exposure time in seconds; for example, a value of "1" followed by a value of "50" is an exposure time of 1/50th of a second.
33437 0x829d integer rational
(unsigned)
F Number First integer divided by the second integer produces the F number; for example, a value of "35" followed by a value of "10" is F/3.5.
34855 0×8827 integer
(unsigned short)
ISO Speed 100, 200, 400, etc.
36867 0×9003 ASCII string Date Taken YYYY:MM:DD HH:MM:SS
36868 0×9004 ASCII string Date Created YYYY:MM:DD HH:MM:SS
37377 0×9201 integer rational (signed) Shutter Speed
37378 0×9202 integer rational (unsigned) Aperture
37380 0×9204 integer rational (signed) Exposure Compensation First integer divided by the second integer produces the exposure compensation; for example, a value of "2" followed by a value of "3" is +2/3
37381 0×9205 integer rational (unsigned) Maximum Aperature
37383 0×9207 integer
(unsigned short)
Metering Mode 0 = Unknown
1 = Average
2 = Center-weighted average
3 = Spot4 = Multi-spot
5 = Multi-segment
6 = Partial
255 = Unknown
37385 0×9209 integer
(unsigned short)
Flash 0 = No Flash
LSB (8th bit) set = Flash Fired
bits 4&5, L-R:
10 = Flash off
01 = Flash on
11 = Flash auto
37386 0x920a integer rational
(unsigned)
Focal Length
37500 0x927c N/A Equipment Maker Note Camera Maker specific information
37510 0×9286 integer
(signed)
User Comment
40961 0xa001 integer
(unsigned short)
Color Space 1 = sRGB
40962 0xa002 integer
(unsigned short)
Pixel X Dimension In pixels
40963 0xa003 integer
(unsigned short)
Pixel Y Dimension In pixels
41486 0xa20e integer
(unsigned short)
Focal Plane X Resolution
41487 0xa20f integer
(unsigned short)
Focal Plane Y Resolution
41488 0xa210 integer
(unsigned short)
Focal Plane Resolution Unit 1 = None
2 = Inches
3 = Centimetres
4 = Millimetres
5 = Micrometres
41495 0xa217 integer
(unsigned short)
Sensing Method 1 = Not defined
2 = One-chip colour area
3 = Two-chip colour area
4 = Three-chip colour area
5 = Colour sequential area
7 = Trilinear
8 = Colour sequential linear
41728 0xa300 integer
(signed)
File Source 1 = Film scanner
2 = Reflection print scanner
3 = Digital camera
41985 0xa401 integer
(unsigned short)
Custom Rendered 0 = Normal
1 = Custom
41986 0xa402 integer
(unsigned short)
Exposure Mode 0 = Auto
1 = Manual
2 = Auto Bracket
41987 0xa403 integer
(unsigned short)
White Balance 0 = Auto
1 = Manual
41988 0xa404 integer rational
(unsigned)
Digital Zoom Ratio
41989 0xa405 integer
(unsigned short)
Focal Length in 35 mm Format
41990 0xa406 integer
(unsigned short)
Scene Capture Type 0 = Standard
1 = Landscape
2 = Portrait
3 = Night
41991 0xa407 integer
(unsigned short)
Gain Control 0 = None
1 =Low gain up
2 = High gain up
3 = Low gain down
4 = High gain down
41992 0xa408 integer
(unsigned short)
Contrast 0 = Normal
1 = Low
2 = High
41993 0xa409 integer
(unsigned short)
Saturation 0 = Normal
1 = Low
2 = High
41994 0xa40a integer
(unsigned short)
Sharpness 0 = Normal
1 = Soft
2 = Hard
41996 0xa40c integer
(unsigned short)
Subject Distance Range 0 = Unknown
1 = Macro
2 = Close
3 = Distant


↑↑↑

Bibliografia

NicholasArmstrong.com - EXIF Quick Reference


↑↑↑

A.2.Enlaces

[Para saber mas]
[Grupo de documentos]
[Documento Index]
[Documento Start]
[Imprimir el Documento]
© 1997 - - La Güeb de Joaquín
Joaquín Medina Serrano
Ésta página es española

Codificación
Fecha de creación
Última actualización
[HTML5 Desarrollado usando CSS3]