Rendering Images in ASP.NET Directly from Your Database, Page 2
Listing 2: The abridged ProductPhoto class (that contains enough information for demonstration purposes).
Imports Microsoft.VisualBasic
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.IO
Public Class ProductPhoto
Public Sub New(ByVal ProductPhotoID As Integer, _
ByVal LargePhoto As Byte())
Me.FProductPhotoID = ProductPhotoID
SetLargePhoto(LargePhoto)
End Sub
Private Sub SetLargePhoto(ByVal photo As Byte())
Dim stream As MemoryStream = New MemoryStream(photo)
LargePhoto = Image.FromStream(stream)
End Sub
Private FProductPhotoID As Integer
Public ReadOnly Property ProductPhotoID() As Integer
Get
Return FProductPhotoID
End Get
End Property
Private FLargePhoto As Image
Public Property LargePhoto() As Image
Get
Return FLargePhoto
End Get
Set(ByVal value As Image)
FLargePhoto = value
End Set
End Property
End Class
The key to getting the SQL Server Image type into a System.Drawing.Image type is to load a stream and construct the image from the stream, as shown in SetLargePhoto. The problem is not getting a viewable image; the problem is actually display the viewable image. If you initialize a GridView of List(Of ProductPhoto) to a GridView right now, it looks empty—no image, as illustrated in Figure 1.

Click here for a larger image.
Figure 1: There is no mechanism for assigning an Image field to an Image control (as represented by the Image field in the GridView shown). HTML and web controls want URLs.
Rendering an Image to a UserControl
Now that you have the Image in an object, you have to figure out how to render it. The answer is to insert the image into the HttpResponse stream. You'll add a UserControl to your project and have the UserControl render the image for you (see Listing 3).
Listing 3: You render the graphic to the HttpResponse stream in a UserControl.
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.IO
Partial Class ImageControl
Inherits System.Web.UI.UserControl
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
End Sub
Private FImage As Image
Public Property TheImage() As Image
Get
Return FImage
End Get
Set(ByVal value As Image)
FImage = value
End Set
End Property
Private Sub RenderImage()
#Const BestForGif = True
If (FImage Is Nothing) Then Return
#If BestForGif Then
' this approach seems to work best for gifs - so we are
' switching back to a byte array - jpegs can use the code below
Dim stream As MemoryStream = New MemoryStream()
FImage.Save(stream, ImageFormat.Gif)
Response.BinaryWrite(stream.ToArray())
#ElseIf ResolvesGifPoorQuality Then
' resolves: "A Graphics object cannot be created from
' an image that has an indexed pixel format too" for gifs
' but yields a poor result. Use for jpegs or bmps
Dim b As Bitmap = New Bitmap(FImage.Width, FImage.Height)
Dim g As Graphics = Graphics.FromImage(b)
g.DrawImage(FImage, 0, 0)
Response.ContentType = "image/gif"
b.Save(Response.OutputStream, ImageFormat.Gif)
Response.End()
#Else ' simple for something like gifs
Response.ContentType = "image/jpeg"
FImage.Save(Response.OutputStream, IMageFormat.Jpeg)
Response.End
#End If
End Sub
Protected Sub Page_PreRender(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.PreRender
RenderImage()
End Sub
End Class
