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

Mar*_*233 4 c# asp.net jpeg metadata

我已经建立了一个程序,可以通过它插入注释和图像的标题,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;      
     }
}
Run Code Online (Sandbox Code Playgroud)

显示的错误是:

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

附加信息:参数无效。

Nye*_*uds 7

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

确保不要using在测试代​​码中那样将图像对象放置在块内。该using块不仅完全存在,因此您不必手动处理,而且很难将映像保存到内存中不再存在的磁盘中。同样,您似乎两次从文件打开图像。我只是假设所有这些都是尝试解决该问题的实验,但是请确保将其清理干净。

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

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


注意,如果您实际上想要一个不包含在using块中的可用图像对象,则可以使用LockBits并将Marshal.Copy图像对象的字节数据复制到具有相同尺寸和相同大小的新图像中PixelFormat,从而有效地完成的完整数据克隆。原始图像。(注意:我认为这不适用于GIF动画文件)之后,您可以安全地处置原始文件,而只需使用全新的干净克隆版本即可。

还有其他一些变通办法可以实际取出图像,但是我见过的大多数变通办法都不是最佳的。这些是锁定问题的两种最常见的其他有效解决方法:

  • Bitmap使用Bitmap(Image image)构造函数根据从文件加载的图像创建新图像。这个新对象将没有指向该文件的链接,从而使您可以自由处置锁定该文件的对象。这可以很好地工作,但是可以将图像的颜色深度更改为32位ARGB,这可能是不希望的。但是,如果只需要在UI上显示图像,这是一个很好的解决方案。
  • MemoryStream按照我的代码所示创建一个,但不要在一个代码using块中创建一个,让流根据需要保持打开状态。在我看来,让流保持开放并不是一个好主意。尽管有人说过,由于a MemoryStream只是由一个简单的数组支持,而不是一些外部资源,所以垃圾收集器显然可以很好地处理这种情况。

我也看到有人用它System.Drawing.ImageConverter来转换字节,但是我研究了该过程的内部,实际上它的作用与这里的最后一个方法相同,后者使内存流保持打开状态。