从System.Drawing.Image在文件系统上创建一个新图像?

好的,对不起,这可能是一个菜鸟问题,但我有点卡住了。

所以我正在做的(在我的asp.net应用程序上)是从文件系统加载图像:

System.Drawing.Image tempImage; tempImage = System.Drawing.Image.FromFile(HttpContext.Server.MapPath(originalPath)); 

然后我做了一些resize:

 tempImage = my awesomeResizingFunction(tempImage, newSize); 

并打算使用以下方法将其保存到另一个位置的文件系统:

 string newPath = "/myAwesomePath/newImageName.jpg"; tempImage.Save(newPath); 

而我得到的是这个错误:

 "A generic error occurred in GDI+." 

我知道图像是“正常”,因为我可以将它写入浏览器并查看已resize的图像,我只是在尝试保存时才收到错误。 我有点新手,我完全错了吗? (嗯,我猜这很明显,但你知道我的意思……)

请尝试此代码…我使用了相同的代码来调整图像和保存。 如果你有任何问题,请告诉我。

 System.Drawing.Bitmap bmpOut = new System.Drawing.Bitmap(NewWidth, NewHeight); System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmpOut); g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.FillRectangle(System.Drawing.Brushes.White, 0, 0, NewWidth, NewHeight); g.DrawImage(new System.Drawing.Bitmap(fupProduct.PostedFile.InputStream), 0, 0, NewWidth, NewHeight); MemoryStream stream = new MemoryStream(); switch (fupProduct.FileName.Substring(fupProduct.FileName.IndexOf('.') + 1).ToLower()) { case "jpg": bmpOut.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg); break; case "jpeg": bmpOut.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg); break; case "tiff": bmpOut.Save(stream, System.Drawing.Imaging.ImageFormat.Tiff); break; case "png": bmpOut.Save(stream, System.Drawing.Imaging.ImageFormat.Png); break; case "gif": bmpOut.Save(stream, System.Drawing.Imaging.ImageFormat.Gif); break; } String saveImagePath = Server.MapPath("../") + "Images/Thumbnail/" + fupProduct.FileName.Substring(fupProduct.FileName.IndexOf('.')); bmpOut.Save(saveImagePath); 

其中fupProduct是fileupload控件ID

您确定originalPath和newPath指向不同的文件吗? 当您使用Image.FromFile时,文件将保持锁定状态,直到您在Image上调用Dispose,这可能会导致您提到的exception。 您可以这样加载图像:

 Image tempImage = null; using (FileStream fs = new FileStream(originalPath, FileMode.Open, FileAccess.Read)) { tempImage = Image.FromStream(fs); } ... 

此方法可确保在使用块结束时关闭文件

支持原始图像的原始流是否可能已关闭? 如果Bitmap后面的流已关闭,则会开始出现GDI +错误。 当我们将图像处理添加到我们的网站时,我遇到了很多。

如果在Visual Studio调试器中打开Bitmap对象,是否会看到exception而不是属性的值? 如果是这样,它不是保存操作的问题,但是GDI +层已经失去了处理对象的能力。

我发现的是我需要跟踪属于我的位图的MemoryStream并将它们保存在一起。 调整图像大小会产生带有新位图图像的新MemoryStream。

我最终创建了这个简单的类(修剪了一些不需要的额外属性):

 public class UploadedImage : IDisposable { private Bitmap _img = null; private Stream _baseStream = null; ///  /// The image object. This must always belong to BaseStream, or weird things can happen. ///  public Bitmap Img { [DebuggerStepThrough] get { return _img; } [DebuggerStepThrough] set { _img = value; } } ///  /// The stream that stores the image. This must ALWAYS belong to Img, or weird things can happen. ///  public Stream BaseStream { [DebuggerStepThrough] get { return _baseStream; } [DebuggerStepThrough] set { _baseStream = value; } } [DebuggerStepThrough] public void Dispose() { if (Img != null) Img.Dispose(); if (BaseStream != null) BaseStream.Close(); _attached = false; } } 

现在,我正在处理上传到我们网站的图像,我发现当Asp.Net回收连接到请求的流时,所有突然的图像操作都开始翻转。 因此,我的解决方案,无论这是否是最佳方式,是将数据从上传流复制到我自己的MemoryStream,从中加载图像,并将两者都粘贴到此容器中。 无论我从旧的图像创建新图像,我总是将流和图像保持在一起。

我希望这有帮助。

编辑:我也有兴趣看到你如何调整图像大小。 这是我如何做到我们的片段:

 temp = new Bitmap(newWidth, newHeight, PIXEL_FORMAT); temp.SetResolution(newHorizontalRes, newVerticalRes); gr = Graphics.FromImage(temp); // // This copies the active frame from 'img' to the new 'temp' bitmap. // Also resizes it and makes it super shiny. Sparkle on, mr image dude. // Rectangle rect = new Rectangle(0, 0, newWidth, newHeight); gr.InterpolationMode = InterpolationMode.HighQualityBicubic; gr.SmoothingMode = SmoothingMode.HighSpeed; gr.PageUnit = GraphicsUnit.Pixel; gr.DrawImage(img, rect); // // Image copied onto the new bitmap. Save the bitmap to a fresh memory stream. // retval = new UploadedImage(); retval.BaseStream = (Stream)(new MemoryStream()); temp.Save(retval.BaseStream, ImageFormat.Jpeg); retval.Img = temp;