Reputation: 7228
I have some images in a SQL Server database. I want to display them when a user clicks a button, but I want them to load into the browser as a file so that when the user resizes the window the images automatically resize.
For example in Firefox if you go to File->Open File... and select an image on your computer, it will load it into a new window and resize it for you when you drag the scrollbars. My problem is, how do I get the image to load from a SQL Server database into the browser as a file? I have the following code on the form where the user clicks view within a GridView:
<script type="text/javascript">
function ShowImageInNewPage(url_add) {
window.open(url_add, 'ViewScreenshot', 'resizable=yes,scrollbars = yes');
}
</script>
<asp:GridView
ID="grdTrades"
runat="server"
<... removed some properties for brevity ...>
>
<Columns>
<asp:CommandField ShowSelectButton="true" ButtonType="Link" SelectText="Select" />
<.. removed some columns for brevity ...>
<asp:TemplateField HeaderText="Screenshot" >
<ItemTemplate>
<input type="button" size="x-small" value="View" onclick="javascript:ShowImageInNewPage('DisplayImage.aspx?screenshotId=<%# Eval("screenshotId") %>');" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
DisplayImage.aspx has this code:
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["screenshotId"] != null)
{
int screenshotId= int.Parse(Request.QueryString["screenshotId"]);
imgScreenshot.ImageUrl = "App_Handlers/ImageHandler.ashx?screenshotId=" + screenshotId;
}
}
</script>
<html>
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Image ID="imgScreenshot" runat="server" />
</div>
</form>
</body>
</html>
App_Handlers/ImageHandler.ashx has this code:
<%@ WebHandler Language="C#" Class="ImageHandler" %>
using System;
using System.Web;
using System.Data;
using DatabaseComponent;
public class ImageHandler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
if (context.Request.QueryString["screenshotId"] != null)
{
int screenshotId = int.Parse(context.Request.QueryString["screenshotId"]);
DBUtil DB = new DBUtil();
DataTable dt = DB.GetScreenshot(screenshotId);
if (dt != null)
{
Byte[] bytes = (Byte[])dt.Rows[0]["screenshot"];
context.Response.Buffer = true;
context.Response.Charset = "";
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.ContentType = dt.Rows[0]["contentType"].ToString();
context.Response.AddHeader("content-disposition", "attachment;filename=" + dt.Rows[0]["fileName"].ToString());
context.Response.BinaryWrite(bytes);
context.Response.Flush();
context.Response.End();
}
}
}
public bool IsReusable {
get {
return false;
}
}
}
Here are the response headers for DisplayImage.aspx
Server: ASP.NET Development Server/10.0.0.0
Date: Wed, 10 Nov 2010 13:13:37 GMT
X-AspNet-Version: 4.0.30319
Transfer-Encoding: chunked
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: image/JPG
Connection: Close
I've changed my original question to use an image handler now thanks @leppie. Thanks for looking!
UPDATE
I've now changed DisplayImage.aspx to this code, but now I get some real weird behavior. When I click on an image link, this page loads and firefox asks if I want to save DisplayImage.aspx. What is going on? How can I get Firefox to load the image as a file?
DisplayImage.aspx:
<%@ Page Language="C#" ContentType="image/*" %>
<script runat="server">
</script>
<html>
<head runat="server">
<title></title>
</head>
<body>
<img src="App_Handlers/ImageHandler.ashx?screenshotId=<%=Request.QueryString["screenshotId"]%>" />
</body>
</html>
If I remove ContentType from the Page declaration the image loads into a new window however the image won't zoom, and won't resize itself. Pulling my hair out...
Upvotes: 2
Views: 9753
Reputation: 7228
I've managed to work it out. I can remove DisplayImage.aspx completely and just call the image handler directly from my calling page, so my GridView now looks like this:
<script type="text/javascript">
function ShowImageInNewPage(url_add) {
window.open(url_add, 'ViewScreenshot', 'resizable=yes,scrollbars = yes');
}
</script>
<asp:GridView
ID="grdTrades"
runat="server"
<... removed some properties for brevity ...>
>
<Columns>
<asp:CommandField ShowSelectButton="true" ButtonType="Link" SelectText="Select" />
<.. removed some columns for brevity ...>
<asp:TemplateField HeaderText="Screenshot" >
<ItemTemplate>
<input runat="server" visible='<%# Eval("screenshotId") != DBNull.Value %>' type="button" value='View...' onclick='<%# "ShowImageInNewPage(\"App_Handlers/ImageHandler.ashx?screenshotId=" + Eval("screenshotId") + "\")" %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
When the user clicks the button, the image loads into a new window and can be resized on the client by dragging the window corner. Thanks for everyone's help on this.
Upvotes: 0
Reputation: 14783
If you want to do this using a page (e.g. ImageLoad.aspx) then something like this in Page_Load should suffice:
protected void Page_Load(object sender, EventArgs e)
{
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.ContentType = "image/png";
Image outputImage = (Load your image here)
MemoryStream ms = new MemoryStream();
outputImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ms.WriteTo(response.OutputStream);
outputImage.Dispose();
ms.Close();
response.End();
}
Alternatively with a handler:
public class ImageHandler : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
try
{
HttpResponse response = context.Response;
response.Clear();
response.ContentType = "image/png";
Image outputImage = (Load your image here)
MemoryStream ms = new MemoryStream();
outputImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ms.WriteTo(response.OutputStream);
outputImage.Dispose();
ms.Close();
response.End();
}
catch
{
context.Response.End();
}
}
}
Just replace (Load your image here) with the relevant code based on how you specify the image (presumably as a request parameter).
As suggested in other answers set relevant caching headers on the request if you want to save some clock cycles.
Upvotes: 1
Reputation: 9799
Once you have the byte[] from your database
Set the Response.MimeType to the appropriate value such as "image/jpg" for jpeg images Then do a Response.Write or Response.WriteBinary to write the byte[] out to the response.
Optionally set Caching headers if you want the browser to cache the file.
Upvotes: 0
Reputation: 120917
You should not use a page to return the image data. Instead you should use an HttpHandler. An HttpHandler is a class that implements the IHttpHandler
interface. The IHttpHandler
interface is more low-level than Page
. Page
does in fact implement IHttpHandler
itself, but the purpose of Page
is to return html, which is why you should not be using it for returning image data.
Upvotes: 3