Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

Common Problems with rendering Bitmaps into ASP.NET OutputStream


:P
On this page:

Raise your hand if you’ve loaded an image from a Resource (or a BLOB database field):

 

Bitmap bm2 = this.GetGlobalResourceObject("Resources", "_BitMap") as Bitmap;

Response.ContentType = "image/jpeg";

bm2.Save(Response.OutputStream, ImageFormat.Jpeg);

Response.End();

 

and finding out that you can’t save the image! You get a not so happy error:

A generic error occurred in GDI+.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+.

Source Error:

Line 41: 
Line 42:         Response.ContentType = "image/jpeg";
Line 43:         bm2.Save(Response.OutputStream, ImageFormat.Jpeg);
Line 44:         Response.End();
Line 45:


Source File: c:\projects2005\Articles\Internationalization\Test.aspx.cs    Line: 43

 

I know this isn’t the first time I’ve done this and scratched my head and go WTF. The bitmap’s there but it won’t save, not to the output stream or to disk (even with permissions for it).

 

So what gives? The documentation is not real clear on this, although MSDN has a little blurp on not saving to the same stream:

 

Remarks

You should avoid saving an image to the same stream that was used to construct it. Doing so might damage the stream.

I don’t think this applies here – the Bitmap resource comes from a database field’s raw byte stream into a memory stream from which the image is loaded in my custom Resource Provider out of a database. The original stream is long gone, but maybe that’s just the problem…

 

Whatever the problem is, the code above doesn’t work.

 

The solution is to create a second bitmap and basically copy the image into a new Bitmap object and then save  to the outputstream:

 

Bitmap bm2 = this.GetGlobalResourceObject("Resources", "_BitMap") as Bitmap;

Bitmap bm3 = new Bitmap(bm2);

 

Response.ContentType = "image/jpeg";

bm3.Save(Response.OutputStream, ImageFormat.Jpeg);

 

bm2.Dispose();

bm3.Dispose();

 

Response.End();

 

Works but it really bites that this unobvious piece of code should be necessary especially since Bitmap objects are not exactly lightweight objects to load and keep around even for a short period of time.

 

Remember PNG Images are ‘special’

In addition to the above issue remember that you can’t save PNG images directly into the output stream because of some issues with that particular format. Instead you need to write the image first into a memory stream:

 

Bitmap bm2 = this.GetGlobalResourceObject("Resources", "_BitMap") as Bitmap;

Bitmap bm3 = new Bitmap(bm2);

 

MemoryStream ms = new MemoryStream();

      

Response.ContentType = "image/png";

bm3.Save(MemStream, System.Drawing.Imaging.ImageFormat.Png);

MemStream.WriteTo(Response.OutputStream);

 

bm2.Dispose();

bm3.Dispose();

Response.End();

 

Note that you still need to do the Bitmap swapping if the image is loaded a certain way (like from the ResourceProvider) as you can’t save to a memory stream without it either.

 

Posted in ASP.NET  Graphics  

The Voices of Reason


 

Steve from Pleasant Hill
October 20, 2006

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Rick, didn't try the example on the bottom of this page, but it seems they are doing something (vaguely) similar. The example has a Response.Clear and .BufferOutput = True however...

http://msdn2.microsoft.com/en-us/library/system.web.httpresponse.outputstream.aspx

David Douglass
October 23, 2006

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

I don't know if this is related to the difficulties you're having, but use of GDI+ (and thus the System.drawing namespace) isn't supported in ASP.NET. The MSDN page for the System.Drawing namespace states:

"Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions."

Peter Lapic
November 20, 2006

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

I have a similar problem. I have an ASP page which renders the PNG image from a webservice. The generic error occurs on .Save method. Any ideas?

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Try
Dim iImageID As Integer = Request.QueryString("id")
Dim oService As New ImageService.ImageService
Dim iResolution As Short = Request.QueryString("res")
Dim sSize As Single = Request.QueryString("size")
Dim oImageData As [Byte]() = oService.GetImage(iImageID, iResolution, sSize, True)
Dim oStream As New System.IO.MemoryStream(oImageData)
Dim obmpImage As New Bitmap(oStream)

Response.ContentType = "image/png"
obmpImage.Save(oStream, Imaging.ImageFormat.Png)
oStream.WriteTo(Response.OutputStream)
oStream.Close()

Catch ex As Exception
Throw ex
End Try
End Sub

Rick Strahl
November 21, 2006

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Peter you can't save PNG objects into the output stream. You have to manually stream them.

http://www.west-wind.com/WebLog/posts/6008.aspx

Look in the comments.

Peter Lapic
November 21, 2006

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Rick the link you directed me has the following code (translated VB.Net)
Dim MemStream As New MemoryStream()
Dim bitmap As New Bitmap(image)
' set the content type
Response.ContentType = "image/png"
'send the image to the memory stream then output
bitmap.Save(MemStream, System.Drawing.Imaging.ImageFormat.Png)
MemStream.WriteTo(Response.OutputStream)

This is the same method that I am using. The only difference is that I include a buffer object, which contains the image from the web service, in the memory stream. Then the bitmap object is created based on this memory stream.

The code I have works 99% of the time. We stream images in 2 colour (Magenta/Black) that works perfectly. Occassionally when the images are in 4 colour (CMYK) that's when the error can occur and that is what I am trying to resolve.

Any ideas?

ar
December 04, 2006

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

hi
i use this way, and until now i face no problem:


 Response.ContentType = "image/Png";
         Response.Buffer = false;
         Response.Clear();

        MemoryStream stream1 = new MemoryStream();
//DrawPie method return an Image
                this.DrawPie(table1).Save(stream1, ImageFormat.Png);

             Response.BinaryWrite(stream1.ToArray());
        
         base.OnPreInit(e);
.

Nostra
April 17, 2007

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Hello.

Thaks for the solution, I had problems with loading Png pictures in an ASP.Net website and a Winform app : there was always like a shadow on the picture.

I googled a lot of time and tryed a lot of tricks but nothing worked... Except the second solution, with the Bitmap copy.

I'm happy, it works! xD
But I'd like to understand why... Any idea?

kalyan
November 06, 2007

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream


Hello,

I want to save that optputstream image to a file. Please can anyone suggest me...

Thanks in Advance....

caloggins
May 31, 2008

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Thank you! I've been beating my head against this problem for two days.

Alasdair CS
June 25, 2008

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Congratulations once again, Sir! This irritated me (and still does), but at least it works now.

Thank you.

Alasdair CS

Marco Kummer
June 27, 2008

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Thank you so much for this helpful hint! I kept getting this strange exception when trying to save a bitmap to a MemoryStream. In my opinion this is definitely a bug in the framework.

Jed Silvestre
March 14, 2009

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Rick, google's been my common reference regarding my coding, and most of the time, i stumble on your blogs, it always hits my problem head-on and solves it!
keep it up, you help a lot of programmers!
Thank you, sir!

TheYetiMan
April 27, 2009

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Oh man.. you're totally my hero - I've been racking my brain all day about writing a PNG directly to response.outputstream and this is the only place on the Interwebs that actually mentions how to get around it - MARVELLOUS!

Thanks again!

Daniel
July 16, 2009

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Rick, when i click a button and download a file from server, then the browser popups a 'Open/sava/cancel' message box waiting users to choose, when i clicked 'save' then 'Save as' message box popup let me choose saving path and rename the file . How can i do on server side code to skip the first message box, directly popup the "Save as" message box?
Please give me some help!
Thanks in advance.

Rick Strahl
July 17, 2009

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

@Daniel - you can't control this behavior is controlled by the browser and I believe what you're seeing will behave differently on different browsers.

Daniel
July 20, 2009

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Rick, Thanks for your timely reply. It's true that it will behave differently on different browsers, luckly my

client just requests that it is normal on IE6 or IE7. One of their engineers shared me some C# code and told me that

it can resolve my problem, but i don't use C# in my project, so i want to know whether the code works normally on

IIS, if it works, I think there will be a way to resolve my problem by other program languages.

The code(two methods):

Directly export to excel when there is a result set

      Event driven, such as click a button
//********Direct Method*********//

   string attachment = "attachment; filename=OverheadReport.xls";
            Response.ClearContent();
            Response.AddHeader("content-disposition", attachment);
            Response.ContentType = "application/vnd.ms-excel";
            string tab = "";
            foreach (DataColumn dc in result.Columns)
            {
                Response.Write(tab + dc.ColumnName);
                tab = "\t";
            }
            Response.Write("\n");

            int i;
            foreach (DataRow dr in result.Rows)
            {
                tab = "";
                for (i = 0; i < result.Columns.Count; i++)
                {
                    Response.Write(tab + dr[i].ToString());
                    tab = "\t";
                }
                Response.Write("\n");
            }
            Response.End();


//**********Event driven********//

   protected void ExportToExcelButton_Click(object sender, EventArgs e)

    {
        Response.Clear();
        Response.AddHeader("content-disposition", "attachment;filename=Company50UploadError.xls");
        Response.Charset = "";
        // If you want the option to open the Excel file without saving then

        // comment out the line below
        //Response.Cache.SetCacheability(HttpCacheability.NoCache);
        Response.ContentType = "application/vnd.xls";
        System.IO.StringWriter stringWrite = new System.IO.StringWriter();
        System.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);
        ErrorGridView.AllowPaging = false;
        ErrorGridView.DataSource = (Company50Report.ErrorLogDataTable)Session["currentTable"];
        ErrorGridView.DataBind();
        ErrorGridView.RenderControl(htmlWrite);
        Response.Write(stringWrite.ToString());
        Response.End();
    }

    public override void VerifyRenderingInServerForm(Control control)
    {
        /* Confirms that an HtmlForm control is rendered for the specified ASP.NET
           server control at run time. */
    }

    public override bool EnableEventValidation
    {
        get
        {
            return false;
        }
        set
        {
            // DO NOTHING
        }
}
//*******End**********//
     

Looking forward to your reply.

Daniel

Pkeno
January 22, 2010

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Thank you. This article was very helpful

The IT Blog
March 23, 2010

# GDI Fehler "A generic error occurred in GDI " beim Erzeugen von PNG

GDI Fehler "A generic error occurred in GDI " beim Erzeugen von PNG

Sushil Kumar
April 26, 2010

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Stream _stream = new FileStream(path, System.IO.FileMode.Open);
MemoryStream storeStream = new MemoryStream();
storeStream.SetLength(_stream.Length);
_stream.Read(storeStream.GetBuffer(), 0, (int)_stream.Length);
storeStream.Flush();
_stream.Close();
Response.ContentType = "image/jpeg";
storeStream.WriteTo(Response.OutputStream);
SaveMemoryStream(storeStream, "C:\\text1" + ".jpeg");
storeStream.Close();
Response.End();

Dave
July 09, 2010

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

I'm always happy when your blog pops up when I'm looking into a problem. Thanks for the consistently good solutions.

Frasse
February 02, 2011

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Great stuff! Tanks alot Rick!
Your solution worked for me. My problem was that the GDI+ error did not happen on my development machine at all, while on the production server it happend every time. I still have two issues: The solution breaks animated gifs, that is they don't display as animated gifs. Secondly, I would really like to know what the actual problem is in the first place. Anyone?

Hashname
March 08, 2011

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Unfortunately none of this worked for me.
So I simply choose to write the Byte Stream directly to output(without first converting it to BitMap) using Response.BinaryWrite and voila it worked :)

Thanks anyways Rick

madper
April 02, 2011

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Thanks man, this solution was save me from this headache!!

Doogal
April 20, 2011

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Once again you've saved me, cheers! I wish somebody would sort out GDI+, just saying you can't use it in ASP.NET doesn't really cut it when it seems to be the only option. At the very least they should fix the awful error messages!

Allie
June 21, 2011

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

Tried the suggested solution and it seemed to work but unfortunately when loading a page with many PNG images, an error ocurred saying "out of memory", right on the place where the second Bitmap was created.
I then tried the following and it works :
context.Response.BinaryWrite(System.IO.File.ReadAllBytes(context.Server.MapPath(context.Request.Path)));

Rick Strahl
June 21, 2011

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

@Allie - If you have really large images and you're running in a low memory environment you may have problems with this because the images are loaded into memory. You might try explicitly calling ms.Dispose() to release the MemoryStream as well (should be automatic when it goes out of scope, but might save a few extra cycles of memory usage).

Coder
December 13, 2011

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

System.Drawing namespace isnt supported in ASP.NET at all:

http://msdn.microsoft.com/en-us/library/system.drawing.aspx

Rick Strahl
December 13, 2011

# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream

@Coder - that's what it says because not all of GDI+ is threadsafe. In reality though if you use image processing in low volume situations (ie. convert an uploaded image or something along those lines) I've never ever run into a problem with this. Not saying it can't happen but think that it's overrated.

WPF actually includes threadsafe drawing classes. Bertrand had a post on comparing drawing modes etc. a while back that might be helpful if you're worried about threadsafe operation:

http://weblogs.asp.net/bleroy/archive/2009/12/10/resizing-images-from-the-server-using-wpf-wic-instead-of-gdi.aspx

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024