在绘图时把image保存为PNG格式时出理的gdi+ general error

 最近在做图片缩放时遇到的一个问题,当我把缩放之后的图片另存为png格式时,出现gdi+ general 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 42:             catch (Exception ex)
Line 43: {
Line 44: throw ex;
Line 45: }
Line 46: finally

  这个异常什么消息都没提供给我,莫名其妙,ex.InnerException为null,看来MS对我们隐藏了具体的异常。

我的代码:

1 ...........
2 g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
3 g.DrawImage(bitmap, 0, 0, originWidth, originHeight);
4
5 try
6 {
7 bitmap.Save(stream, ImageFormat.Png);
8 }
9 catch (Exception ex)
10 {
11 throw ex;
12 }
13 finally
14 {
15 bitmap.Dispose();
16 g.Dispose();
17 originImg.Dispose();
18 }

  由于我是在一个handler中直接把输出图片至outputstream(这个是问题产生的根本原因)。题外话:刚开始还以为是bitmap锁住的原因导致不能保存,于是采用一个临时bitmap来过渡一下。看具体代码:

Bitmap tempBitmap = new Bitmap(originImage);
Bitmap bitmap
= new Bitmap(tempBitmap );



//释放临时bitmap后,再save
tempBitmap .Dispose();

bitmap.Save(bitmap ,
0,0,width,height)

这个方法不起效,我还想到是不是权限的问题,结果也被排除了!

既然不然保存为PNG,不妨试试其它的格式,当然换在Jpeg格式时,发现可以正常输出图片。这肯定有图片跟图片格式有关系了,搜索到一些东西:

Png's are a special case. Their encoder requires a bi-directional stream. The solution is to stream to a memory stream first and write the contents of that memory stream to OutputStream afterwards.

大概意思是对PNG解码器需要一个双向流,解决方法是先把数据写入memeory stream,然后再把memory stream写入至outputstream。

我们知道Response.OutputStream是一个单向流,无法向回读取数据(MS他的CanSeek属性为false),可能是png在解码的时候还需要往回写数据,由于CanSeek属性为false,所有不能往回写数据,导致这个问题吧。

用MemoryStream来中转一下

          using (MemoryStream ms =new MemoryStream())
{

bitmap.Save(ms,ImageFormat.Png);
ms.WriteTo(stream);
}

等比缩放代码:

private Size GetNewSize(int originWidth, int originHeight, int toWidth, int toHeight)
{

int w, h;
if ((double)originWidth / (double)toWidth < (double)originHeight / (double)toHeight)
{
h
= toHeight;
w
= originWidth * toHeight / originHeight;
}
else
{
w
= toWidth;
h
= originHeight * toWidth / originWidth ;
}
return new Size(w, h);
}

解决问题一定要一步一步来定位问题,然后再去尝试解决!

原文地址:https://www.cnblogs.com/repository/p/2019004.html