用编辑过的jpeg文件覆盖现有的Jpeg文件/替换现有的Jpeg文件

时间:2018-02-02 09:33:03

标签: c# asp.net metadata jpeg

我已经构建了一个允许我通过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;      
     }
}

显示的错误是:

  

System.Drawing.dll中发生了'System.ArgumentException'类型的异常,但未在用户代码中处理

     

附加信息:参数无效。

1 个答案:

答案 0 :(得分:4)

问题是从文件打开图像会锁定文件。您可以通过将文件读入字节数组,从中创建内存流,然后从该流中打开图像来解决这个问题:

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块不仅完全存在,因此您不必手动处理,但是将图像保存到内存中不再存在的磁盘也相当困难。同样,您似乎从文件两次打开图像。我只是假设所有这些都是尝试解决问题的实验,但确保清理它们。

打开图像时要记住的基本规则是:

与某些人认为的相反,对图像对象的基本.Clone()调用将更改此行为。克隆的对象仍将保留对原始源的引用。

注意,如果您确实想要一个未包含在usingyou 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构造函数从文件加载的图像中创建新的Bitmap(Image image)。这个新对象将具有该文件的链接,让您可以自由地处置锁定文件的那个文件。这很好用,但它会将图像的颜色深度更改为32位ARGB,这可能是不可取的。
  • 创建一个MemoryStream,如我的代码所示,但不在using块中,根据需要打开流。让溪流开放对我来说似乎不是一个好主意。虽然有些人说垃圾收集器显然处理这个案子很好......

我也看到有些人使用System.Drawing.ImageConverter从字节转换,但I looked into the internals of that process,它的作用实际上与此处的最后一个方法相同,这会使内存流保持打开状态。