c# - 将带有元数据的图像写入 MemoryStream 时,JpegBitmapEncoder.Save() 抛出异常

标签 c# wpf metadata exif

我正在尝试在 JPG 图像上设置没有元数据的元数据。在这种情况下,您不能使用就地编写器 (InPlaceBitmapMetadataWriter),因为图像中没有元数据的位置。

如果我使用 FileStream 作为输出 - 一切正常。但是,如果我尝试使用 MemoryStream 作为输出 - JpegBitmapEncoder.Save() 会引发异常(来自 HRESULT 的异常:0xC0000005)。 经过一番调查后,我还发现如果我提供 null 而不是元数据,什么编码器可以将图像保存到内存流。

我制作了一个非常简单且简短的示例来重现问题:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Media.Imaging;

namespace JpegSaveTest
{
    class Program
    {
        public static JpegBitmapEncoder SetUpMetadataOnStream(Stream src, string title)
        {
            uint padding = 2048;
            BitmapDecoder original;
            BitmapFrame framecopy, newframe;
            BitmapMetadata metadata;
            JpegBitmapEncoder output = new JpegBitmapEncoder();
            src.Seek(0, SeekOrigin.Begin);
            original = JpegBitmapDecoder.Create(src, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
            if (original.Frames[0] != null) {
                framecopy = (BitmapFrame)original.Frames[0].Clone();
                if (original.Frames[0].Metadata != null) metadata = original.Frames[0].Metadata.Clone() as BitmapMetadata;
                else metadata = new BitmapMetadata("jpeg");
                metadata.SetQuery("/app1/ifd/PaddingSchema:Padding", padding);
                metadata.SetQuery("/app1/ifd/exif/PaddingSchema:Padding", padding);
                metadata.SetQuery("/xmp/PaddingSchema:Padding", padding);
                metadata.SetQuery("System.Title", title);
                newframe = BitmapFrame.Create(framecopy, framecopy.Thumbnail, metadata, original.Frames[0].ColorContexts);
                output.Frames.Add(newframe);
            }
            else {
                Exception ex = new Exception("Image contains no frames.");
                throw ex;
            }
            return output;
        }

        public static MemoryStream SetTagsInMemory(string sfname, string title)
        {
            Stream src, dst;
            JpegBitmapEncoder output;
            src = File.Open(sfname, FileMode.Open, FileAccess.Read, FileShare.Read);
            output = SetUpMetadataOnStream(src, title);
            dst = new MemoryStream();
            output.Save(dst);
            src.Close();
            return (MemoryStream)dst;
        }

        static void Main(string[] args)
        {
            string filename = "Z:\\dotnet\\gnom4.jpg";
            MemoryStream s;
            s = SetTagsInMemory(filename, "test title");
        }
    }
}

这是一个简单的控制台应用程序。 要运行它,请将文件名变量内容替换为任何不带元数据的 .jpg 文件的路径(或使用 mine )。

Ofc 我可以先将图像保存到临时文件,关闭它,然后打开并复制到 MemoryStream,但它太肮脏且缓慢的解决方法。 欢迎任何有关实现此功能的想法:)

最佳答案

如果有人遇到同样的问题,解决方案如下:

如果您尝试从主应用程序线程 .Save() jpeg,请在 Main() 之前添加 [STAThread]。

如果没有,则为调用 JpegBitmapEncoder.Save() 的线程调用 .SetApartmentState(ApartmentState.STA)

WinXP 和 WinVista 版本的 windowscodecs.dll 不可重新输入,因此如果您对调用 JpegBitmapEncoder.Save() 函数的线程使用默认 MTA 模型(自 .NET Framework 2.0 起默认),它可能会表现得很奇怪并抛出描述的错误异常(exception)。 Win7版本的windowscodecs.dll没有这个问题。

关于c# - 将带有元数据的图像写入 MemoryStream 时,JpegBitmapEncoder.Save() 抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2705409/

相关文章:

c# - 多线程机制可从winforms代码运行一些冗长的操作,并与GUI进行通信

没有嵌套在父类中的 C# 私有(private)类

c# - 如何使用 IValidatableObject?

c# - 带有 Prism 的 MVVM 编码是否与 MVVM 本身不同?

sql-server - Entity Framework - 如何从元数据获取数据库列数据类型

c# - IntelliTrace 捕获的静默异常

wpf - UI 自动化和 WPF 的经验

wpf - WPF:不带下拉按钮的组合框

angular - 如何获取 Angular 2 中当前模块的元数据?

php - PHP自动生成META标签