用编辑过的jpeg文件覆盖现有的Jpeg文件/替换现有的Jpeg文件
我已经构建了一个程序,允许我通过System.Image.Drawing
插入注释和Image的标题,所以现在,我很难尝试用添加了注释和标题的文件覆盖现有的Jpeg文件,但是我在删除文件时遇到错误,所以我不知道该怎么办,因为我已经尝试处理该文件但是在那种情况下我无法保存它,因为我太早处理了它,但我无法保存它因为现有的文件名没有删除所以我现在卡在中间。
这是我的代码:
public string EditComment(string OriginalFilepath, string newFilename) { image = System.Drawing.Image.FromFile(OriginalFilepath); PropertyItem propItem = image.PropertyItems[0]; using (var file = System.Drawing.Image.FromFile(OriginalFilepath)) { propItem.Id = 0x9286; // this is the id for 'UserComment' propItem.Type = 2; propItem.Value = System.Text.Encoding.UTF8.GetBytes("HelloWorld\0"); propItem.Len = propItem.Value.Length; file.SetPropertyItem(propItem); PropertyItem propItem1 = file.PropertyItems[file.PropertyItems.Count() - 1]; file.Dispose(); image.Dispose(); string filepath = Filepath; if (File.Exists(@"C:\Desktop\Metadata")) { System.IO.File.Delete(@"C:\Desktop\Metadata"); } string newFilepath = filepath + newFilename; file.Save(newFilepath, ImageFormat.Jpeg);//error appears here return filepath; } }
显示的错误是:
System.Drawing.dll中出现“System.ArgumentException”类型的exception,但未在用户代码中处理
附加信息:参数无效。
问题是从文件打开图像会锁定文件。 您可以通过将文件读入字节数组,从中创建内存流,然后从该流中打开图像来解决这个问题:
public string EditComment(string originalFilepath, string newFilename) { Byte[] bytes = File.ReadAllBytes(originalFilepath); using (MemoryStream stream = new MemoryStream(bytes)) using (Bitmap image = new Bitmap(stream)) { PropertyItem propItem = image.PropertyItems[0]; // Processing code propItem.Id = 0x9286; // this is the id for 'UserComment' propItem.Type = 2; propItem.Value = System.Text.Encoding.UTF8.GetBytes("HelloWorld\0"); propItem.Len = propItem.Value.Length; image.SetPropertyItem(propItem); // Not sure where your FilePath comes from but I'm just // putting it in the same folder with the new name. String newFilepath; if (newFilename == null) newFilepath = originalFilePath; else newFilepath = Path.Combine(Path.GetDirectory(originalFilepath), newFilename); image.Save(newFilepath, ImageFormat.Jpeg); return newFilepath; } }
确保不像在测试代码中那样将图像对象放在using
块内。 不仅using
块完全存在,因此您不必手动处理,但是将图像保存到内存中不再存在的磁盘也相当困难。 同样,您似乎从文件中打开图像两次 。 我只是假设所有这些都是尝试解决问题的实验,但确保清理它们。
打开图像时要记住的基本规则如下:
- 从文件创建的
Image
对象将在图像对象的生命周期中锁定文件 ,从而防止文件被覆盖或删除,直到图像被丢弃。 - 从流创建的
Image
对象将需要流在图像对象的整个生命周期中保持打开状态 。 与文件不同,没有任何主动强制执行此操作,但在关闭流后,图像将在保存,克隆或以其他方式操作时出错。
与某些人认为的相反,对图像对象的基本.Clone()
调用不会改变这种行为。 克隆的对象仍将保留对原始源的引用。
请注意,如果您确实需要一个未包含在using
块中的可用图像对象,则可以使用LockBits
和Marshal.Copy
将图像对象的字节数据复制到具有相同尺寸和相同PixelFormat
的新图像中 ,制作原始图像的完整数据克隆。 (注意:我不认为这适用于动画GIF文件)执行此操作后,您可以安全地处理原始文件并使用新的干净克隆版本。
还有一些其他解决方法可以实际获取图像,但我见过的大多数都不是最佳的。 这些是锁定问题的两个最常见的其他有效解决方法:
- 使用
Bitmap(Image image)
构造函数从文件加载的图像创建新的Bitmap
。 这个新对象将没有该文件的链接,让您可以自由地处置锁定文件的文件。 这非常有效,但它会将图像的颜色深度更改为32位ARGB,这可能并不理想。 - 创建一个MemoryStream,如我的代码所示,但不是在
using
块中,根据需要打开流。 让溪流开放对我来说似乎不是一个好主意。 虽然有些人说垃圾收集器显然处理这个案子很好……
我也看到有些人使用System.Drawing.ImageConverter
从字节转换,但我查看了该进程的内部,它的作用实际上与这里的最后一个方法完全相同,这使得内存流保持打开状态。