【问题标题】:How to save edited System.Drawing.Bitmap to the same file如何将编辑后的 ​​System.Drawing.Bitmap 保存到同一个文件
【发布时间】:2020-05-01 22:57:11
【问题描述】:

我正在开发一个简单的图形应用程序:上传图像,对其进行编辑并保存。我尝试了各种方法,但都以某种方式失败了。

我首先尝试像这样加载位图:

imageFromName = new Bitmap(FileName1);

并像这样保存它:

imageFromName.Save(FileName1);

但它引发了“GDI + 中的一般错误”。异常。另外,此时Windows资源管理器不允许我删除文件,所以我认为问题是对象“imageFromName”保持文件打开并且不允许覆盖它,所以我修改了这样的代码:

imageFromName = new Bitmap(FileName1);
imageCloned = (Bitmap)imageFromName.Clone();
imageFromName.Dispose();
imageCloned.Save(FileName1);

程序在imageCloned.Save (FileName1)中不断抛出同样的异常 因此,我在 Stackoverflow 上寻求帮助,并看到了几个类似的问题,这些问题的答案建议检查应用程序是否具有写入权限。所以我修改了代码来检查它:

imageFromName = new Bitmap(FileName1);
imageFromName.Save(FileName2);

在这种情况下,程序在保存文件时没有抛出任何异常,但我仍然无法修改原始文件,也无法使用Windows资源管理器将其删除。它只是为我创建了文件的副本。

所以我考虑以另一种方式加载位图并修改如下代码:

 try
 {
       System.IO.FileStream fs = new System.IO.FileStream(FileName1, System.IO.FileMode.Open);
       imageFromStream = new System.Drawing.Bitmap(fs);
       fs.Close();
 }
 catch (Exception ex)
 {
       Console.WriteLine("Error loading Bitmap.", ex);
 }

在这种情况下,应用程序没有抛出任何异常,并且可以在 PictureBox 中很好地看到位图。此外,资源管理器允许我删除该文件。但是,当使用 imageFromStream.Save (imageFromStream) 保存文件时,它一直为我生成异常。

这次的不同是Save ()方法尽管抛出了异常,但是会覆盖原始文件,而是生成一个带有头信息的54字节文件。

使用十六进制编辑器打开两个文件,原始文件和副本,我验证了标题信息除了图像大小和 BITMAPINFOHEADER 的偏移量之外是相同的。只是缺少图纸的信息。

我已阅读有关 System.Drawing.Bitmap.Save () 方法的官方 Microsoft 文档,但没有发现任何限制。但我会说它在某些像素格式上存在问题。

但是,我不想将我的应用程序限制为 32bpp 文件,然后:

1-将System.Drawing.Bitmap 对象的图像保存到 24bpp 文件的最佳方法是什么?

2-System.Drawing.Bitmap.Save()还有什么我应该知道的限制吗?

【问题讨论】:

  • 你可以试试 save 的重载,它允许你指定一个ImageFormat

标签: c# file exception bitmap gdi+


【解决方案1】:

当您从存储在硬盘上的图像初始化 Bitmap 对象时,它会在底层图像文件上创建一个锁。由于在您尝试保存修改后的位图时锁定,它会引发此错误。

有两种方法可以解决此问题

  • 不要覆盖文件,而是使用不同的文件保存一个新文件 名称比原始文件
  • 仅当 Bitmap 对象被释放时, 文件上的底层锁被删除。解除锁后, 您可以覆盖该文件。如果您必须覆盖现有文件, 从现有位图对象创建一个单独的位图对象。现在 处置将释放锁定的旧位图对象 图像文件。继续并在新的位图对象中进行所需的更改 并使用原始图像文件名保存新的位图对象。

将图像保存为 24bpp 文件的最佳方法是将PixelFormat.Format24bppRgb 用于新的位图对象。

这是一个例子:

using Bitmap imageCopy = null;
using(var imageFromName = new Bitmap(FileName1))
{
    // you can modify your image here
    ...
    // Before this block ends we need to copy Bitmap
    imageCopy = new Bitmap(imageFromName); // or imageFromName.Clone with expected format
}

imageCopy.Save(FileName1);

另一种方法是在编辑时立即读取图像而无需文件系统锁定:

using(var ms = new MemoryStream(File.ReadAllBytes(FileName1))
using(var image = new Bitmap(ms))
{
    // you can modify your image here
    ...
    image.Save(FileName1); 
}

【讨论】:

  • 是的,但回答“System.Drawing.Bitmap.Save 是否有更多限制”它“这不是 Bitmap.Save 限制,它锁定在您的文件系统上”。将 System.Drawing.Bitmap 对象的图像保存到 24bpp 文件的最佳方法是使用 PixelFormat.Format24bppRgb 和 Save 方法
  • 另外,这里是克隆问题的一个很好的解释stackoverflow.com/a/13935966/5649561
  • 回复:“这不是 Bitmap.Save 限制,它锁定了您的文件系统”:如果您阅读了我的问题,您会阅读:“资源管理器允许我删除文件。”使用 System.IO.FileStream 加载位图后。回复:“是使用 PixelFormat.Format24bppRgb 和 Save 方法”是一个非常模糊的答案。 PixelFormat 只能与新的黑色位图或 Clone() 方法一起使用。你说的是这两种方法中的哪一种?
  • 1-Clone:如果您阅读了我的问题,您就会知道即使您使用 Dispose (),Clone () 也会锁定原始文件。 2-“新位图(宽度、高度、像素格式)”对我来说是什么...我是否使用 LockBits 或图形将原始 24bpp 位图复制到新的 24bpp 文件上?您的最佳答案已将我发送到另一个答案....如果您已阅读您发送给我的回复,您会知道将克隆与原始链接取消链接的唯一方法不是使用 PixelFormat.blahblahblah 而是执行某种对克隆进行写操作。
  • PD:StackOverflow 只需点击“编辑问题”按钮即可获得额外声誉?
猜你喜欢
  • 2017-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-09
  • 1970-01-01
  • 2016-06-11
  • 1970-01-01
相关资源
最近更新 更多