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 puter, 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...
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 puter, 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...
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.
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.
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.
I've managed to work it out. I can remove DisplayImage.aspx pletely 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.