我已经构建了一个程序,该程序允许我通过System.Image.Drawing插入注释和图像标题,因此,现在很难尝试用添加了注释和标题的文件覆盖现有的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;
}
}
显示的错误是:
An exception of type ‘System.ArgumentException’ occurred in System.Drawing.dll but was not handled in user code
Additional information: Parameter is not valid.
解决方法:
问题是从文件打开图像会锁定文件.通过将文件读入字节数组,从中创建一个内存流,然后从该流中打开图像,可以解决此问题:
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块不仅完全存在,因此您不必手动处理,而且将映像保存到内存中不再存在的磁盘也相当困难.同样,您似乎两次从文件中打开图像.我只是假设所有这些都是尝试解决该问题的实验,但是请确保将其清理干净.
打开图像时要记住的基本规则如下:
>从文件will lock the file during the life cycle of the image object创建的Image对象,防止在处理图像之前文件被覆盖或删除.
>从流will need the stream to remain open for the entire life cycle of the image object创建的Image对象.与文件不同,没有有效地强制执行此操作的对象,但是在关闭流之后,在保存,克隆或进行其他操作时,图像将产生错误.
与某些人的看法相反,对图像对象进行基本的.Clone()调用不会更改此行为.克隆的对象仍将保留对原始源的引用.
请注意,如果您实际上想要一个不包含在using块you can use LockBits
and Marshal.Copy
to copy the byte data of the image object into a new image with the same dimensions and the same PixelFormat
中的可用图像对象,则可以有效地对原始图像进行完整的数据克隆. (注意:我认为这不适用于GIF动画文件)之后,您可以安全地处置原始文件,而只需使用全新的干净克隆版本即可.
还有其他一些变通办法可以实际取出图像,但是我见过的大多数变通办法都不是最佳的.这些是锁定问题的两种最常见的其他有效解决方法:
>使用Bitmap(Image image)构造函数从文件加载的图像中创建一个新的Bitmap.这个新对象将没有指向该文件的链接,从而使您可以*处置锁定该文件的对象.这可以很好地工作,但是可以将图像的颜色深度更改为32位ARGB,这可能是不希望的.
>如我的代码所示创建一个MemoryStream,但不在using块中创建,请根据需要将流保持打开状态.在我看来,让流保持开放并不是一个好主意.尽管有人说垃圾收集器显然可以处理这种情况.
我也看到有人使用System.Drawing.ImageConverter从字节转换,但是I looked into the internals of that process的作用实际上与这里的最后一个方法相同,后者保留了内存流.