Common Problems with rendering Bitmaps into ASP.NET OutputStream
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: |
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:
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.
Other Posts you might also like
The Voices of Reason
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
"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."
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
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
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
http://www.west-wind.com/WebLog/posts/6008.aspx
Look in the comments.
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
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?
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
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);
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
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?
# 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....
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
Thank you.
Alasdair CS
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
keep it up, you help a lot of programmers!
Thank you, sir!
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
Thanks again!
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
Please give me some help!
Thanks in advance.
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
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
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
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();
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
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?
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
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
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
I then tried the following and it works :
context.Response.BinaryWrite(System.IO.File.ReadAllBytes(context.Server.MapPath(context.Request.Path)));
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
http://msdn.microsoft.com/en-us/library/system.drawing.aspx
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
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
# re: Common Problems with rendering Bitmaps into ASP.NET OutputStream
http://msdn2.microsoft.com/en-us/library/system.web.httpresponse.outputstream.aspx