2

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...

5
  • It seems that no-one knows how to load an image from a database and load it into the browser as a file. This must be a common pattern, does anyone want to have another try? :-) Commented Nov 14, 2010 at 7:37
  • you need to change the content-disposition header to inline and include the content-length header as well Commented Nov 14, 2010 at 12:50
  • @leppie - it seems I don't need two pages. See my answer. Commented Nov 14, 2010 at 19:05
  • The handler is a 'still a page' effectively. Commented Nov 14, 2010 at 19:21
  • @leppie, yes but I've removed both GetImage.aspx AND DisplayImage.aspx Commented Nov 14, 2010 at 19:32

4 Answers 4

3

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.

Sign up to request clarification or add additional context in comments.

7 Comments

A page is just as good, and probably better seeing you do not need permissions to install handlers/modify the web.config.
@leppie, you don't need to edit web.config to install an httphandler. A .ashx file works just as well.
OK, I can rewrite using an ashx file, but back to the question. How do I load the image into the browser as a file, and not as an image on a page?
@leppie - I've edited my question so that I'm now using a handler. Please could you address the issue of loading the image into the browser as a file? Thanks.
To load the image as a file you need to return the image data in the response stream and set the mime type in the header to image/jpeg, or whatever format it is. The mime type is what tells the browser how to interpret the response.
|
1

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.

7 Comments

Thanks James, I've tried your code and it has the same effect as my code. Try this: with Firefox open an image from your local hard disk, now resize the window. The image gets resized automatically. I want my image to load from my database into the browser in the same way so the browser thinks its a file. The method you've just shown me, and my method shown in my question simply displays the image but when I resize the browser, the image does not get resized. Any ideas on how to fix this?
@James - here's an example of how I want my images to load. Click on an image on this page and then resize your browser to see what I mean. phpbb.com/community/viewtopic.php?f=6&t=2109563
I can't see what is special about the way this image is delivered. I've tried opening a few images in Firefox and they all open like this. They shrink if the browser window is smaller, but don't expand if it's bigger. You can run Live HTTP Headers in Firefox and see exactly what headers are sent with the image - which I've done here and again - nothing unusual there jumps out. Maybe try comparing header for header with the image you are serving.
@James, well if you open a file locally it doesn't have any headers because it's an image file, not a web page. I've changed my code as shown in the UPDATE section of my question. Any further ideas?
No many... I suppose there is no guarantee you can get Firefox to treat an image from the web in exactly the same way as it treats an image opened locally. But if (as you seem to say) you have found an image on the web that works the way you want it to, then add the Live HTTP Headers plugin into Firefox, look at the headers, and then duplicate both the headers and the HTML.... that way your image has to do exactly the same thing. If you can't find an image on the web that works the right way - probably means it's not possible.
|
0

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.

1 Comment

Thanks but how do I display the image? What changes do I need to make to the DisplayImage.aspx? Currently it is displayed in an image control but I don't want to do that.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.