How to add a download button for image stored in GridBinaryImageColumn

1 Answer 306 Views
BinaryImage Grid
Skip
Top achievements
Rank 1
Skip asked on 30 Sep 2022, 02:29 PM | edited on 30 Sep 2022, 02:32 PM

I have a RadGrid that displays some images from a database.  I'm trying to add a button to the grid that allows the user to download the image using the original file name and extension saved in the ImageName column.

 


<telerik:RadGrid ID="RadGrid1" runat="server" DataSourceID="SqlDataSourceImageUpload" OnItemCommand="RadGrid1_ItemCommand"> <MasterTableView DataKeyNames="ImageID" DataSourceID="SqlDataSourceImageUpload" > <Columns> <telerik:GridButtonColumn ButtonType="ImageButton" CommandName="download_file" UniqueName="download" ></telerik:GridButtonColumn> <telerik:GridBoundColumn DataField="ImageName" UniqueName="ImageName" ></telerik:GridBoundColumn> <telerik:GridBinaryImageColumn DataField="ImageData" ></telerik:GridBinaryImageColumn> </Columns> </MasterTableView>

 


                <asp:SqlDataSource ID="SqlDataSourceImageUpload" runat="server"
                                   ConnectionString="<%$ ConnectionStrings:123ConnectionString %>" 
                                   SelectCommand="SELECT * FROM [tbl_Images]" 
                                   DeleteCommand="DELETE FROM [tbl_Images] WHERE [ImageID] = @ImageID" 
                                   InsertCommand="INSERT INTO [tbl_Images] ([ImageData], [ImageName], [Text]) 
                                   VALUES (@ImageData, @ImageName, @Text)" 
                                   UpdateCommand="UPDATE [tbl_Images] SET [Text] = @Text WHERE [ImageID] = @ImageID">
                    <DeleteParameters>
                        <asp:Parameter Name="ImageID" Type="Int32" />
                    </DeleteParameters>
                    <InsertParameters>
                        <asp:QueryStringParameter Name="IncidentID" QueryStringField="ID" Type="String" />
                        <asp:Parameter Name="Text" Type="String" />
                    </InsertParameters>
                    <UpdateParameters>
                        <asp:Parameter Name="Text" Type="String" />
                        <asp:Parameter Name="ImageID" Type="Int32" />
                    </UpdateParameters>
                </asp:SqlDataSource>

I found this code online, and honestly not sure how to make it all work with what I'm trying to do.  I really feel like I'm over complicating this whole thing.  Is there an easy button I'm missing somewhere?

The ultimate goal is for the user to click a download button and have the image download using the ImageName field as the file name.

    Protected Sub RadGrid1_ItemCommand(sender As Object, e As GridCommandEventArgs)
        If e.CommandName = "download_file" Then
            Dim ditem As GridDataItem = CType(e.Item, GridDataItem)
            Dim filename As String = ditem("ImageName").Text
            Dim path As String = MapPath("/sample/" & filename)
            Dim bts As Byte() = System.IO.File.ReadAllBytes(path)
            Response.Clear()
            Response.ClearHeaders()
            Response.AddHeader("Content-Type", "Application/octet-stream")
            Response.AddHeader("Content-Length", bts.Length.ToString())
            Response.AddHeader("Content-Disposition", "attachment; filename=" & filename)
            Response.BinaryWrite(bts)
            Response.Flush()
            Response.[End]()
        End If
    End Sub


1 Answer, 1 is accepted

Sort by
0
Attila Antal
Telerik team
answered on 05 Oct 2022, 11:39 AM

Hi Skip,

You are almost there. You just need to make a couple of adjustments.

 

If you have the image in the database and not on the disk, RadAllBytes will receive no file. Instead, you will need to use SqlClient and Query the database, get the bytes out from the ImageData field, and return those bytes back to download.

Here is an example (Note: I am using DataTable instead of database, but the same concept applies to the database)

Protected Sub RadGrid1_ItemCommand(ByVal sender As Object, ByVal e As GridCommandEventArgs)
    If e.CommandName = "download_file" Then
        'Get reference to the DataItem
        Dim dataItem As GridDataItem = CType(e.Item, GridDataItem)
        'Get the Item's DataKeyValue
        Dim dataKeyValue As Integer = CInt(dataItem.GetDataKeyValue("Id"))
        'Use the DataKeyValue to query the Database for the record with this unique id
        Dim selectedRow As DataRow = GridSource().Select(String.Format("Id = '{0}'", dataKeyValue)).FirstOrDefault()
        'Get the ImageName from the returned query
        Dim imageName As String = selectedRow("ImageName").ToString()
        'Get the ImageData bytes from the returned query
        Dim imageData As Byte() = CType(selectedRow("ImageData"), Byte())
        'Download the Image
        DownloadImage(imageData, imageName)
    End If
End Sub

Private Sub DownloadImage(ByVal output As Byte(), ByVal fileName As String, ByVal Optional shouldOpenInNewWindow As Boolean = True)
    Dim contentType = "image/png"
    Dim fileExtension = ".png"
    Response.Clear()
    Response.Buffer = True
    Response.ContentType = contentType
    Response.ContentEncoding = System.Text.Encoding.UTF8
    Response.Charset = ""

    If Request.Browser.Browser.IndexOf("IE") > -1 OrElse Request.Browser.Browser.IndexOf("InternetExplorer") > -1 Then
        fileName = System.Web.HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8)
    End If

    Dim responseFileName = fileName & (If(fileName.EndsWith(fileExtension), String.Empty, fileExtension))
    responseFileName = responseFileName.Replace(vbLf, " ").Replace(vbCr, " ")

    If shouldOpenInNewWindow Then
        Response.AddHeader("Content-Disposition", "attachment;filename=""" & responseFileName & """")
    Else
        Response.AddHeader("Content-Disposition", "inline;filename=""" & responseFileName & """")
    End If

    Response.BinaryWrite(output)
    Response.[End]()
End Sub

 

Below you can see how I am creating the Grid and binding it to the data

<telerik:RadGrid ID="RadGrid1" runat="server" AllowPaging="True" Width="400px" OnNeedDataSource="RadGrid1_NeedDataSource" OnItemDataBound="RadGrid1_ItemDataBound" OnItemCommand="RadGrid1_ItemCommand">
    <MasterTableView AutoGenerateColumns="False" DataKeyNames="Id">
        <Columns>
            <telerik:GridButtonColumn ButtonType="ImageButton" ImageUrl="Images/download.png" CommandName="download_file" UniqueName="download"></telerik:GridButtonColumn>
            <telerik:GridBoundColumn DataField="ImageName" UniqueName="ImageName"></telerik:GridBoundColumn>
            <telerik:GridBinaryImageColumn UniqueName="BinaryImageCol" DataField="ImageData" ImageHeight="24px" AutoAdjustImageControlSize="false">
            </telerik:GridBinaryImageColumn>
        </Columns>
    </MasterTableView>
</telerik:RadGrid>

 

VB

Protected Sub RadGrid1_NeedDataSource(ByVal sender As Object, ByVal e As GridNeedDataSourceEventArgs)
    CType(sender, RadGrid).DataSource = GridSource()
End Sub

Private Function GridSource() As DataTable
    Dim dt As DataTable = New DataTable()
    dt.Columns.Add(New DataColumn("Id", GetType(Integer)))
    dt.Columns.Add(New DataColumn("ImageName", GetType(String)))
    dt.Columns.Add(New DataColumn("ImageData", GetType(Byte())))
    dt.PrimaryKey = New DataColumn() {dt.Columns("Id")}

    For i As Integer = 0 To 3 - 1
        Dim index As Integer = i + 1
        Dim row As DataRow = dt.NewRow()
        row("Id") = index
        row("ImageName") = "Image Name " & index
        row("ImageData") = ImageToByteArray("~/Images/progress_logo.png")
        dt.Rows.Add(row)
    Next

    Return dt
End Function

Public Function ImageToByteArray(ByVal imagePath As String) As Byte()
    Dim imageIn As System.Drawing.Image = System.Drawing.Image.FromFile(Server.MapPath(imagePath))

    Using ms = New MemoryStream()
        imageIn.Save(ms, imageIn.RawFormat)
        Return ms.ToArray()
    End Using
End Function

 

Attached you can find the two images I used for the Grid.

 

I hope this will help resolve the issue.

 

Regards,
Attila Antal
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Tags
BinaryImage Grid
Asked by
Skip
Top achievements
Rank 1
Answers by
Attila Antal
Telerik team
Share this question
or