thephysicsguy
thephysicsguy

Reputation: 405

Implementing an Image Download in VB.NET

I am trying to implement an image download in vb.net where the client clicks a button and the browser downloads an image for the client from a file in the server. I tried this:

Private Sub DownloadImage(ByVal ImageURL As String)
    Dim Buffer(6000000) As Byte
    Response.Clear()
    Response.AddHeader("content-disposition", "attachment;filename=" & ImageURL & ".jpg")
    Response.ContentType = "image/jpeg"
    Response.BinaryWrite(Buffer)
    Response.Flush()
    Response.End()
End Sub

But this has 2 problems. First, it doesn't actually show up the image when I download it so it doesn't work properly. Secondly I have to manually enter the size of the image to determine the size of the byte array.

Please help me out, I couldn't find any resources on internet and couldn't get my head around it. Thanks!

Upvotes: 1

Views: 1265

Answers (1)

InbetweenWeekends
InbetweenWeekends

Reputation: 1414

This is a sample image handler I've used for several years. It's probably got some room for improvement, but it is intended to be used as the src attribute for an img tag.

<img src="Thumbs.ashx?img=/ImagePath/BigImage.jpg&max=100" />

It's a direct copy-paste of my working code and it's got some references to private code - but it should give you a good start. It will create a thumbnail image so it doesn't have to be regenerated each time, if the thumbnail has already been generated. Hope this helps...

<%@ WebHandler Language="VB" Class="GetImage" %>

Imports Web.Utilities
Imports Common
Imports System
Imports System.Drawing
Imports System.Web
Imports System.IO

''' <summary>
''' Resizes the image supplied in the "img" querystring parameter and writes it to the OutputStream in jpg format.
''' The default dimension is a max of 90 pixels (H or W; whichever is larger).
''' The "max" querystring parameter can alter the maximum dimension by supplying a new dimension as an integer.
''' If the file name contains an ampersand, it should be replaced with [amp]. 
''' </summary>
''' <remarks></remarks>
Public Class GetImage : Implements IHttpHandler

    Private thumbFolder As String = "/images/Thumbs/"
    Private trapCount As Integer = 0

    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest

            'General.PreventClientCaching()
            'context.Response.Cache.SetCacheability(HttpCacheability.NoCache)

            Dim maxSize As Integer = 90

            Dim img As String = context.Request.QueryString("img")
            Dim strMax As String = context.Request.QueryString("max")
            If Not strMax.IsNullOrEmpty AndAlso IsNumeric(strMax) Then
                    maxSize = CInt(strMax)
            End If
            If maxSize > 1000 Then
                    maxSize = 1000
            End If
            If img.IsNullOrEmpty Then
                    img = "/images/PicUnavailable.jpg"
            End If

            Try
                    Dim uri As New System.Uri(img, UriKind.RelativeOrAbsolute)
                    img = uri.AbsolutePath
            Catch ex As Exception
            End Try

            General.SetContentType(General.FileType.Jpg)

            img = img.Replace("[amp]", "&")

            ServeImage(context, img, maxSize)

    End Sub

    Private Sub ServeImage(ByVal context As HttpContext, ByVal imagePath As String, ByVal maximumSize As Integer)


            Dim imgFile As Image = Nothing

            Dim existingThumb As String = imagePath.Replace("/", "{s}") & "_" & maximumSize.ToString & ".jpg"
            Dim doPurge As Boolean
            Boolean.TryParse(context.Request.QueryString("purge"), doPurge)

            ' Check to see if the thumbnail has already been generated and it's older than the source.
            ' If it is, delete it.
            If File.Exists(context.Server.MapPath(thumbFolder & existingThumb)) Then
                    If doPurge Then
                            File.Delete(context.Server.MapPath(thumbFolder & existingThumb))
                    Else
                            If File.GetLastWriteTime(context.Server.MapPath(thumbFolder & existingThumb)) < File.GetLastWriteTime(context.Server.MapPath(imagePath)) Then
                                    Try
                                            File.Delete(context.Server.MapPath(thumbFolder & existingThumb))
                                    Catch ex As Exception
                                    End Try
                            End If
                    End If
            End If


            ' If the thumbnail already exists, write the byte array to the output stream
            If File.Exists(context.Server.MapPath(thumbFolder & existingThumb)) Then

                    Dim fs As FileStream = Nothing
                    Try
                            fs = New FileStream(context.Server.MapPath(thumbFolder & existingThumb), IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
                            Dim imgLen As Long = fs.Length()
                            Dim imgData(imgLen) As Byte
                            fs.Read(imgData, 0, Integer.Parse(imgLen.ToString()))

                            context.Response.OutputStream.Write(imgData, 0, Integer.Parse(imgLen.ToString()))

                    Catch ex2 As UnauthorizedAccessException
                            'context.Server.Transfer(img)
                            Throw
                    Catch exIO As IOException
                            'context.Server.Transfer(img)
                            Throw
                    Finally
                            If Not fs Is Nothing Then
                                    fs.Dispose()
                                    fs = Nothing
                            End If
                    End Try

                    ' the file doesn't exist, so render it to the output stream and save it to the thumbnail
            Else
                    Try
                            imgFile = Image.FromFile(context.Server.MapPath(imagePath))

                            Dim maxDim As Integer = maximumSize
                            Dim maxH As Integer = maximumSize
                            Dim maxW As Integer = maximumSize

                            'If img.Height > maxH OrElse img.Width > maxW Then
                            Dim thumb As Image
                            Dim gfx As Graphics
                            Dim rect As Rectangle

                            If imgFile.Height >= imgFile.Width Then     'portrait or square

                                    Dim newW As Integer
                                    newW = CInt((maxH / imgFile.Height) * imgFile.Width)

                                    thumb = New Bitmap(newW, maxDim)
                                    gfx = Graphics.FromImage(thumb)
                                    gfx.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
                                    gfx.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
                                    gfx.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias

                                    rect = New Rectangle(0, 0, newW, maxDim)

                            Else 'landscape

                                    Dim newH As Integer
                                    newH = CInt((maxW / imgFile.Width) * imgFile.Height)

                                    thumb = New Bitmap(maxDim, newH)
                                    gfx = Graphics.FromImage(thumb)
                                    gfx.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
                                    gfx.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
                                    gfx.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias

                                    rect = New Rectangle(0, 0, maxDim, newH)

                            End If


                            gfx.DrawImage(imgFile, rect)
                            thumb.Save(context.Response.OutputStream, Drawing.Imaging.ImageFormat.Jpeg)
                            thumb.Save(context.Server.MapPath(thumbFolder & existingThumb), Drawing.Imaging.ImageFormat.Jpeg)

                            gfx.Dispose()
                            thumb.Dispose()

                            gfx = Nothing
                            thumb = Nothing


                    Catch ex As Exception
                            Dim fs As FileStream = Nothing
                            Try
                                    fs = New FileStream(context.Server.MapPath(imagePath), IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
                                    Dim imgLen As Long = fs.Length()
                                    Dim imgData(imgLen) As Byte
                                    fs.Read(imgData, 0, Integer.Parse(imgLen.ToString()))

                                    context.Response.OutputStream.Write(imgData, 0, Integer.Parse(imgLen.ToString()))

                            Catch ex2 As UnauthorizedAccessException
                                    'context.Server.Transfer(img)
                                    Throw
                            Catch exIO As IOException
                                    'context.Server.Transfer(img)
                                    If trapCount > 0 Then
                                            Throw
                                    End If
                                    trapCount += 1

                                    ServeImage(context, "/images/PicUnavailable.jpg", maximumSize)
                            Finally
                                    If Not fs Is Nothing Then
                                            fs.Dispose()
                                            fs = Nothing
                                    End If

                            End Try
                    Finally
                            If Not imgFile Is Nothing Then
                                    imgFile.Dispose()
                                    imgFile = Nothing
                            End If
                    End Try
            End If
    End Sub

    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
            Get
                    Return False
            End Get
    End Property


End Class

Upvotes: 1

Related Questions