miércoles, 2 de septiembre de 2009

Serializar imagenes en XML

He aqui las funciones para serializar imagenes con VB.NET

'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("")
Return oDom.DocumentElement.CloneNode(True)
End If

Else
'no hay imagen devuelvo el XML Vacio
oDom.LoadXml("")
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

2 comentarios:

Oscar dijo...

Hola, mi nombre es Oscar.
Esta muy interesante su publicación y creo que algo similar es lo que busco para solucionar un inconveniente que tengo con una aplicación.
Te comento; necesito almacenar una imágen (formato png) en un búfer de memoria temporal una vez seleccionada por una función que retorna la imágen desde los recursos de la aplicación para poderla utilizar en un método que visualiza dicha imágen, pero que al cerrarse el formulario que la contiene o cambiar su valor (item seleccionado desde un ToolStripMenuItem) se libere nuevamente.

Cualquier información por favor enviármela a: mauro840321@hotmail.com o publicarla en su Blog que estaré visitando.
Gracias! XD

Marrufman dijo...

Saludos Oscar

el enfoque de la funcion que publique es un poco diferente, sin embargo me parece que si utilizas un objeto de tipo streambuilder o MemoryStream para almacenar tus datos binarios podrias obtener el resultado que buscas