C# JpegBitmapEncoder.Save()在使用元数据写入图像时引发异常

C# JpegBitmapEncoder.Save()在使用元数据写入图像时引发异常,c#,wpf,metadata,exif,iptc,C#,Wpf,Metadata,Exif,Iptc,我正在构建一个WPF桌面应用程序,帮助我整理照片并发布到Facebook。以下是我在新位置创建照片副本的代码,添加了标题(EXIF+IPTC+XMP): 运行该命令后,我得到一个“COMException was unhandled”异常,突出显示这一行: encoder.Save(memstream); 中发生类型为“System.Runtime.InteropServices.COMException”的未处理异常 PresentationCore.dll 附加信息:句柄无效。(HRESU

我正在构建一个WPF桌面应用程序,帮助我整理照片并发布到Facebook。以下是我在新位置创建照片副本的代码,添加了标题(EXIF+IPTC+XMP):

运行该命令后,我得到一个“COMException was unhandled”异常,突出显示这一行:

encoder.Save(memstream);
中发生类型为“System.Runtime.InteropServices.COMException”的未处理异常 PresentationCore.dll

附加信息:句柄无效。(HRESULT的异常:0x80070006(E_句柄))

我发现这可能是由于线程问题,因此我没有直接从应用程序调用SaveImageAs,而是添加了以下内容,但没有任何效果:

        private void _SaveImageAs(string currPath, string newPath, bool setCaption = false, string captionToSet = "")
    {
        Thread saveThread = new Thread(() => SaveImageAs(currPath, newPath, setCaption, captionToSet));
        saveThread.SetApartmentState(ApartmentState.STA);
        saveThread.IsBackground = false;
        saveThread.Start();
    }
我还尝试将MemoryStream换成FileStream,创建一个本地临时文件,但没有改变任何东西:

FileStream memstream = new FileStream(System.IO.Path.GetDirectoryName(newPath) + @"\" + "temp.jpg", System.IO.FileMode.OpenOrCreate);

有什么想法吗?

您得到了异常,因为您关闭了用于加载原始jpeg的流。注释第一个stream.Close()(就在if(setCaption)的上方),它就可以工作了。就像处理映像实例一样,您必须在映像的生命周期内保持流的打开状态。

代码中有一些错误

  • 源流必须保持打开状态,直到BitmapFrame写入目标流

  • BitmapDecoder中BitmapFrame的图像元数据是只读的。要修改元数据,必须从原始位图帧创建新的位图帧

  • 第三个问题似乎被打破了。例外情况是“找不到属性”

  • 此代码适用于我:

    public static void SaveImageAs(string sourcePath, string targetPath, string caption)
    {
        using (var sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            var decoder = new JpegBitmapDecoder(sourceStream, BitmapCreateOptions.None, BitmapCacheOption.None);
            var frame = decoder.Frames[0];
    
            if (!string.IsNullOrWhiteSpace(caption))
            {
                frame = BitmapFrame.Create(frame);
                var metadata = (BitmapMetadata)frame.Metadata;
    
                metadata.SetQuery("/app1/ifd/{uint=270}", caption);
                metadata.SetQuery("/app13/irb/8bimiptc/iptc/Caption", caption);
                //metadata.SetQuery("/xmp/dc:description/x-default", caption);
            }
    
            var encoder = new JpegBitmapEncoder();
            encoder.Frames.Add(frame);
    
            using (var targetStream = new FileStream(targetPath, FileMode.Create))
            {
                encoder.Save(targetStream);
            }
        }
    }
    

    使用BitmapCacheOption.OnLoad而不是None会使代码运行速度慢10倍以上(在100个图像上测试,每个图像大约1M)。
    public static void SaveImageAs(string sourcePath, string targetPath, string caption)
    {
        using (var sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            var decoder = new JpegBitmapDecoder(sourceStream, BitmapCreateOptions.None, BitmapCacheOption.None);
            var frame = decoder.Frames[0];
    
            if (!string.IsNullOrWhiteSpace(caption))
            {
                frame = BitmapFrame.Create(frame);
                var metadata = (BitmapMetadata)frame.Metadata;
    
                metadata.SetQuery("/app1/ifd/{uint=270}", caption);
                metadata.SetQuery("/app13/irb/8bimiptc/iptc/Caption", caption);
                //metadata.SetQuery("/xmp/dc:description/x-default", caption);
            }
    
            var encoder = new JpegBitmapEncoder();
            encoder.Frames.Add(frame);
    
            using (var targetStream = new FileStream(targetPath, FileMode.Create))
            {
                encoder.Save(targetStream);
            }
        }
    }