Thursday, February 03, 2005

Blogging on Demand #5

I was going through my referral logs this evening, as I sometimes do, and I came upon this search that piqued my interest a little bit:
how to display pictues with xml

Now I know it's spelt wrong, but that's the only reason it reached my blog in the first place.

So anyway, I interpreted this as meaning 'How can I retrieve and display images passed via an XML stream from, for example, a webservice?'

So I endeavored to find out.

First up I created the web service that was going to send the images across the wire. Now the System.Drawing.Bitmap class can't be serialized directly to a form that can be transmitted over http. You have to go around the houses a little bit.

So here are the two methods in my webservice:

<webmethod()> Public Function GetImageList() As String()
'This just gets a list of the files in the Images subdirectory in the
'webservice's home directory
Dim fs As DirectoryInfo = New DirectoryInfo(Server.MapPath("Images"))
GetImageList.CreateInstance(GetType(String), fs.GetFiles.Length)
Dim Imagelist As New ArrayList
For Each fi As FileInfo In fs.GetFiles()
GetImageList = Imagelist.ToArray(GetType(String))
End Function

<WebMethod()> Public Function GetImage(ByVal fileName As String) As Byte()
'This Method gets the image specified in the parameter string
Dim img As New Drawing.Bitmap(Server.MapPath("Images/" & fileName))
Dim ImgStream As New MemoryStream
img.Save(ImgStream, Drawing.Imaging.ImageFormat.Bmp)
GetImage.CreateInstance(GetType(Byte), ImgStream.Length)
GetImage = ImgStream.ToArray
End Function

The first method is easy - it just iterates through the images subdirectory and gets the names of the files in it. I use this method in my client app, so I don't have to remember filenames and stuff!

The second method does a bit more. First up, it loads the file specified up into memory as a bitmap.

It then creates a System.IO.MemoryStream to store the serialized image data in.

The next line saves the bitmap data into the MemoryStream. We now have a stream of serialized data representing the image. After it's stuffed the image into the stream, it then uses the stream's ToArray method to return an array of unsigned bytes. Now, to be honest, I don't know what unsigned bytes are. I mean, I know what bytes are, but what the difference is between unsigned and signed bytes, I dunno.

So once it's turned it into an array of bytes, it can be sent over the web to your client app. I won't show you what the response stream looks like, since it's really really long. And gobbledegook.

So that's how the image is sent over the wire.

To display the image at the other end, you just have to do the reverse.

This is the code that calls the webmethod and puts the image in a PictureBox control:

Private Sub GetImage()
Dim ImgServ As ImageService.ImageService
ImgServ = New ImageService.ImageService

Dim ImgArray As Byte()
'FileList is a ListBox containing the list of images available
ImgArray = ImgServ.GetImage(FileList.SelectedValue)
Dim ImgStream As New System.IO.MemoryStream(ImgArray)
'RetImage is the name of the picturebox image that displays the image
RetImage.Image = New Bitmap(ImgStream)
End Sub

As you can see, this takes the array of bytes from the Webservice and writes it out to a memorystream. This stream can then be read into a new bitmap and put into the PictureBox. Hey Presto.

The code's a bit rough and ready. In real life you'd add type checking, security stuff (possibly) and whatnot like that, but for this demo it's fine.

As a further note, images can be pushed and pulled about to be displayed for all sorts of situations. Most notably, if you have images saved in an Image column in SQL Server, you'll have to do this (or at least something like this) to push images into and pull them out of SQL Server.

Second-to-Lastly, I'm no expert. Although I've read about this, I've only done it once. And that was only so I could write this blog entry. If you know of a better way, or you see a glaring mistake in the code, please let me know. It's the only way I'll learn!

Lastly, if you got this far, well done you!. Just wanted to share.

No comments: