如何在保存图像时找到Generic GDI +错误的原因?

Uwe*_*eim 29 .net c# system.drawing gdi+ image

拥有一个在加载和存储图像时可以使用多年的代码,我发现我有一个图像打破了这段代码:

const string i1Path = @"c:\my\i1.jpg";
const string i2Path = @"c:\my\i2.jpg";

var i = Image.FromFile(i1Path);
i.Save(i2Path, ImageFormat.Jpeg);
Run Code Online (Sandbox Code Playgroud)

例外是:

发生了System.Runtime.InteropServices.ExternalException

GDI +中发生了一般错误.

at System.Drawing.Image.Save(String filename,ImageCodecInfo encoder,EncoderParameters encoderParams)
at System.Drawing.Image.Save(String filename,ImageFormat format)
at ...

据我所知,图像没什么特别之处.它的大小约为250像素,可以在Windows Image Viewer或Paint.NET中打开:

在此输入图像描述

(由于上面的图片,上传到Stack Overflow后不再产生错误,我把原始图像放在这里)

我发现在调用Save方法时,目标图像文件是用零字节创建的.

我真的对导致错误的原因一无所知.

我的问题:

  • 你能想到任何阻碍.NET保存图像的特殊事物吗?
  • 有没有办法(除了惊慌失措)缩小这些错误?

Uwe*_*eim 39

虽然我仍然没有找到保存图像时确切导致错误的原因,但我找到了一个适用的解决方法:

const string i1Path = @"c:\my\i1.jpg";
const string i2Path = @"c:\my\i2.jpg";

var i = Image.FromFile(i1Path);

var i2 = new Bitmap(i);
i2.Save(i2Path, ImageFormat.Jpeg);
Run Code Online (Sandbox Code Playgroud)

即,通过将图像内部复制到Bitmap实例中并保存此图像而不是原始图像,错误消失了.

我假设通过复制它,导致原始Save调用失败的错误部分被删除和/或标准化,从而使保存操作成功.

保存的图像i2.jpg

有趣的是,如此存储的图像在磁盘上的文件(16 kB)比原始文件(26 kB)小.

  • 也为我工作 - 不知道为什么.只有jpg图像的问题(png等都很好) (3认同)
  • 我有.bmp,.jpg和.png这个问题,但我没有加载文件,我在内存中创建并试图保存它.`原因:`原始位图绑定到它加载的流(`FileStream`或`MemoryStream`).克隆的位图没有绑定到流,因为它复制了像素字节.在保存原始位图之前,_might_也曾"冻结"原始位图. (3认同)

小智 15

首先确保所需的文件夹具有读/写权限.更改权限为我解决了这个问题.

  • 这就像 90% 的情况:-) (2认同)

Aza*_*rsa 8

解决方法在这里,您必须配置图像对象以释放服务器上的内存.尝试使用using声明.确保服务器上的目标目录也存在.

  • 这听起来像是对我的_really_错误答案。 (2认同)
  • "确保服务器上的目标目录存在"是我的问题 (2认同)
  • @UweKeim - 临时`IDisposable`对象上的`using`只是确保在安全的情况下立即调用GC. (2认同)

Tho*_*mar 5

原因可能是图像被延迟加载,并且在尝试保存图像时加载过程尚未完成。

遵循此博客文章中的所说(假设您通过问题中链接的图片是德国人)提供了可能的解决方案。同样,此SO问题的可接受答案表明这是由于您要保存到的图像文件被锁定的事实所致。

编辑
对于尤利西斯·阿尔维斯(Ulysses Alves),来自链接的博客条目:如果使用图像加载图像,Image.FromFile()则该图像将保持锁定状态,直到将其丢弃。这样可以防止呼叫Save()

pictureBox1.Image = Image.FromFile("C:\\test\\test1.jpg");
pictureBox1.Image.Save("C:\\test\\test2.jpg");
Run Code Online (Sandbox Code Playgroud)

上面的代码抛出错误。

要使其正常工作,您需要复制图像。以下代码有效:

pictureBox1.Image = Image.FromFile("C:\\test\\test1.jpg");
Image copy = pictureBox1.Image;
copy.Save("C:\\test\\test2.jpg")
Run Code Online (Sandbox Code Playgroud)

  • 我的猜测是 Image copy = pictureBox1.Image; 行 不是创建副本,而只是创建新的引用。 (3认同)