用已编辑的jpeg文件覆盖现有的Jpeg文件/替换现有的Jpeg文件 [英] Overwrite Existing Jpeg File/Replace Existing Jpeg File with edited jpeg file

查看:87
本文介绍了用已编辑的jpeg文件覆盖现有的Jpeg文件/替换现有的Jpeg文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经构建了一个程序,允许我通过System.Image.Drawing插入注释和图像的标题,所以现在,我很难尝试用添加了注释和标题的文件覆盖现有的Jpeg文件,但是我在删除文件时遇到错误,所以我不确定该怎么做,因为我尝试处理该文件,但是由于这种情况我处理得太早了,所以我无法保存它,但是我无法保存因为没有删除现有文件名,所以我现在停留在中间位置.

I have build a program which allows me to insert comment and the title of an Image through System.Image.Drawing so right now, I have trouble trying to overwrite the existing Jpeg file with the one that has comment and title added into it, but I am encountering error while deleting the file, so I'm not sure what to do as I have tried disposing the file but I cant saved it in that case, due to the fact that I disposed it too early, but I cant saved it because the existing file name is not deleted so I'm kinda stuck in the middle right now.

这是我的代码:

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'类型的异常,但未在用户代码中处理

An exception of type 'System.ArgumentException' occurred in System.Drawing.dll but was not handled in user code

其他信息:参数无效.

推荐答案

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

The problem is that opening an image from file locks the file. You can get around that by reading the file into a byte array, creating a memory stream from that, and then opening the image from that stream:

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

Make sure you do not dispose your image object inside the using block as you did in your test code. Not only does the using block exist exactly so you don't have to dispose manually, but it's also rather hard to save an image to disk that no longer exists in memory. Similarly, you seem to open the image from file twice. I'm just going to assume all of those were experiments to try to get around the problem, but do make sure to clean those up.

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

The basic rules to remember when opening images are these:

  • An Image object created from a file will lock the file during the life cycle of the image object, preventing the file from being overwritten or deleted until the image is disposed.
  • An Image object created from a stream will need the stream to remain open for the entire life cycle of the image object. Unlike with files, there is nothing actively enforcing this, but after the stream is closed, the image will give errors when saved, cloned or otherwise manipulated.

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

Contrary to what some people believe, a basic .Clone() call on the image object will not change this behaviour. The cloned object will still keep the reference to the original source.

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

Note, if you actually want a usable image object that is not contained in a using block, 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, effectively making a full data clone of the original image. (Note: I don't think this works on animated GIF files) After doing that, you can safely dispose the original and just use the new cleanly-cloned version.

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

There are some other workarounds for actually getting the image out, but most of them I've seen aren't optimal. These are the two most common other valid workarounds for the locking problem:

  • 使用Bitmap(Image image)构造函数从文件加载的图像中创建新的Bitmap.这个新对象将没有指向该文件的链接,使您可以自由处置锁定该文件的对象.这可以很好地工作,但是可以将图像的颜色深度更改为32位ARGB,这可能是不希望的.但是,如果您只需要在UI上显示图像,这是一个很好的解决方案.
  • 如我的代码所示,
  • 创建一个MemoryStream,而不是在using块中,从而根据需要使流保持打开状态.在我看来,让流保持开放并不是一个好主意.尽管有人说过,由于MemoryStream仅由简单的数组支持,而不是外部资源,所以垃圾收集器显然可以很好地处理这种情况.
  • Create a new Bitmap from an image loaded from file using the Bitmap(Image image) constructor. This new object will not have the link to that file, leaving you free to dispose the one that's locking the file. This works perfectly, but it changes the image's colour depth to 32-bit ARGB, which might not be desired. If you just need to show an image on the UI, this is an excellent solution, though.
  • Create a MemoryStream as shown in my code, but not in a using block, leaving the stream open as required. Leaving streams open doesn't really seem like a good idea to me. Though some people have said that, since a MemoryStream is just backed by a simple array, and not some external resource, the garbage collector apparently handles this case fine...

我还看到有些人使用System.Drawing.ImageConverter从字节转换,但是

I've also seen some people use System.Drawing.ImageConverter to convert from bytes, but I looked into the internals of that process, and what it does is actually identical to the last method here, which leaves a memory stream open.

这篇关于用已编辑的jpeg文件覆盖现有的Jpeg文件/替换现有的Jpeg文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆