用已编辑的 jpeg 文件覆盖现有的 Jpeg File/Replace 个现有的 Jpeg 文件
Overwrite Existing Jpeg File/Replace Existing Jpeg File with edited jpeg file
我已经构建了一个程序,允许我通过 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[=11=]");
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[=10=]");
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
。这个新对象将 not 具有该文件的 link,让您可以自由处置锁定文件的对象。这非常有效,但它会将图像的颜色深度更改为 32 位 ARGB,这可能不是您想要的。不过,如果您只需要在 UI 上显示图片,这是一个很好的解决方案。
- 如我的代码所示创建一个
MemoryStream
,但不在 using
块中,根据需要保持流打开。让流打开对我来说并不是一个好主意。尽管有些人说过,由于 MemoryStream
仅由一个简单的数组支持,而不是某些外部资源,垃圾收集器显然可以很好地处理这种情况...
我也看到有人使用System.Drawing.ImageConverter
从字节转换,但是I looked into the internals of that process,它所做的实际上与这里的最后一种方法相同,它打开了一个内存流。
我已经构建了一个程序,允许我通过 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[=11=]");
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[=10=]");
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
。这个新对象将 not 具有该文件的 link,让您可以自由处置锁定文件的对象。这非常有效,但它会将图像的颜色深度更改为 32 位 ARGB,这可能不是您想要的。不过,如果您只需要在 UI 上显示图片,这是一个很好的解决方案。 - 如我的代码所示创建一个
MemoryStream
,但不在using
块中,根据需要保持流打开。让流打开对我来说并不是一个好主意。尽管有些人说过,由于MemoryStream
仅由一个简单的数组支持,而不是某些外部资源,垃圾收集器显然可以很好地处理这种情况...
我也看到有人使用System.Drawing.ImageConverter
从字节转换,但是I looked into the internals of that process,它所做的实际上与这里的最后一种方法相同,它打开了一个内存流。