Serializar Imagenes en XML
Como utilizar XML para almacenar imagenes

Fecha: 17/Ago/2004 (17/Ago/2004)
Autor: Christian Omar Bigentini - cbigentini@pectra.com


Muchas veces he tenido problemas sobre la mejor forma de almacenar las imágenes o cualquier otro elemento binario tanto en base de datos como en un archivo plano, sobre todo porque no siempre puedo utilizar la misma rutina para todos los casos. Como en mis proyecto uso XML extensivamente, se me ocurrió utilizarlo como herramienta de almacenamiento para muchas cosas y especialmente para imágenes y datos binarios, ya que me permiten llevar este documento como texto plano a cualquier base de datos en forma de String sin ningún problema, y obviamente puedo utilizar la misma rutina en todos los casos.

Tengo una Clase llamada Serialization que contiene dos (2) metodos Shared:

Aqui esta el codigo comentado de las funciones:

        'Serializa Imagen en XML
Public Shared Function ImageToXMLNode(ByVal Image As Image) As Xml.XmlNode
    Dim oStream As New System.IO.MemoryStream
    Dim oDom As New Xml.XmlDocument
    Dim mResult As New IO.MemoryStream
    Dim LenData As Long = 0
    Dim Buffer() As Byte
    Dim oBinaryReader As IO.BinaryReader
    Dim oXMLTextWriter As Xml.XmlTextWriter
    Dim oStreamReader As IO.StreamReader
    Dim StrResult As String

    'Verifico si existe imagen a serializar
    If Not Image Is Nothing Then

        'Se graba en Stream para almacenar la imagen en formato binario
        Image.Save(oStream, System.Drawing.Imaging.ImageFormat.Bmp)

        oStream.Position = 0

        LenData = oStream.Length - 1
        
        'Verifico la longitud de datos a serializar        
        If LenData > 0 Then 
            ReDim Buffer(LenData) 'Genero Buffer

            'Leo los datos binarios
            oBinaryReader = New IO.BinaryReader(oStream, System.Text.Encoding.UTF8)
            oBinaryReader.Read(Buffer, 0, Buffer.Length)

            'Creo XMLTextWriter y agrego nodo con la imagen
            oXMLTextWriter = New Xml.XmlTextWriter(mResult, System.Text.Encoding.UTF8)
            oXMLTextWriter.WriteStartDocument()
            oXMLTextWriter.WriteStartElement("BinaryData")
            oXMLTextWriter.WriteBase64(Buffer, 0, Buffer.Length)
            oXMLTextWriter.WriteEndElement()
            oXMLTextWriter.WriteEndDocument()
            oXMLTextWriter.Flush()

            'posiciono en 0 el resultado
            mResult.Position = 0

            'Pasa el Stream a String y retorna
            oStreamReader = New IO.StreamReader(mResult, System.Text.Encoding.UTF8)
            StrResult = oStreamReader.ReadToEnd()
            oStreamReader.Close()

            'Agrego Nuevo Nodo con imagen
            oDom.LoadXml(StrResult)
            Return oDom.DocumentElement
        Else
            'En caso de no existir datos retorno el XML con formato vacio
            oDom.LoadXml("<BinaryData/>")
            Return oDom.DocumentElement.CloneNode(True)
        End If

    Else
        'no hay imagen devuelvo el XML Vacio
        oDom.LoadXml("<BinaryData/>")
        Return oDom.DocumentElement.CloneNode(True)
    End If
End Function


'Desserializa XML y retorna la Imágen
Public Shared Function XMLNodeToImage(ByVal Nodo As Xml.XmlNode) As Image
    Dim IntResult As Integer = 0
    Dim IntPosition As Integer = 0
    Dim LenBytes As Integer = 1024 * 1024 '1024KB - 1MB Lee bloques de 1MB
    Dim myBytes(LenBytes - 1) As Byte
    Dim oMem As New IO.MemoryStream
    Dim oXMLTextReader As Xml.XmlTextReader
    Dim NodeFound As Boolean = False
    Dim oStreamReader As IO.StreamReader
    Dim oStreamWriter As IO.StreamWriter
    Dim oTempMem As New IO.MemoryStream

    Try
        'Cargo nodo de texto en Memory Stream para almacenar la imagen temporalmente en bytes
        oStreamWriter = New IO.StreamWriter(oTempMem, System.Text.Encoding.UTF8)
        oStreamWriter.Write(Nodo.OuterXml)
        oStreamWriter.Flush()
        oTempMem.Position = 0

        'Cargo un xmlReader con el Memory Stream para leer la imágen almacenada
        oXMLTextReader = New Xml.XmlTextReader(oTempMem)

        'Busco el Nodo en Binario
        Do While oXMLTextReader.Read
            If oXMLTextReader.Name = "BinaryData" Then
                NodeFound = True
                Exit Do
            End If
        Loop

        'Verifico si se encontró el Nodo con la imagen
        If NodeFound Then

            'Lo encontro, me muevo a la Posicion Inicial del Stream para leerlo
            IntPosition = 0

            'Intento Leer
            IntResult = oXMLTextReader.ReadBase64(myBytes, 0, LenBytes)
            Do While IntResult > 0

                'Escribe datos

                oMem.Write(myBytes, 0, IntResult)

                'Limpio el array
                Array.Clear(myBytes, 0, LenBytes)

                'Leo nuevamente
                IntResult = oXMLTextReader.ReadBase64(myBytes, 0, LenBytes)

            Loop
            Try
                'Intento crear la Imagen y retornarla si no devuelvo Nothing            
                Dim oBitmap As New Bitmap(oMem)
                Return oBitmap
            Catch
                Return Nothing
            End Try
        Else
            'No encontró el nodo de imágen
            Return Nothing
        End If

    Catch ex As Exception
            'Ocurrio un error no contemplado Retorno Nothing    
            Return Nothing
    End Try

End Function

'Funcion Auxiliar para agregar un nodo a otro
Private Shared Sub AddElement(ByRef pParentNode As Xml.XmlNode, ByVal pNewNodeName As String, ByVal pNewNodeValue As String)
    Dim oNodo As Xml.XmlNode
    oNodo = pParentNode.OwnerDocument.CreateElement(pNewNodeName)
    oNodo.InnerText = pNewNodeValue
    pParentNode.AppendChild(oNodo.CloneNode(True))
    oNodo = Nothing
End Sub

Para utilizar estas rutinas basta con llamarlas desde cualquier lugar del codigo y se obtiene una imagen o un nodo XML con la imagen serializada lista para ser guardada en una base de datos, en un archivo plano o bien para trasmitirse via WebService a donde se necesite.

Espero que les sea útil.

Saludos.


ir al índice

Fichero con el código de ejemplo: cbigentini_SerializarImagenesEnXML.zip - 52 KB