amb*_*800 2 c# wpf iptc exif metadata
我正在构建一个 WPF 桌面应用程序来帮助我组织照片以发布到 Facebook。以下是我在新位置创建照片副本并添加标题(EXIF + IPTC + XMP)的代码:
private void SaveImageAs(string currPath, string newPath, bool setCaption = false, string captionToSet = "")
{
System.IO.FileStream stream = new System.IO.FileStream(currPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
JpegBitmapDecoder decoder = new JpegBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.None);
BitmapFrame bitmapFrame = decoder.Frames[0];
BitmapMetadata metadata = bitmapFrame.Metadata.Clone() as BitmapMetadata;
stream.Close();
if (setCaption)
{
// if we want to set the caption, do it in EXIF, IPTC, and XMP
metadata.SetQuery("/app1/ifd/{uint=270}", captionToSet);
metadata.SetQuery("/app13/irb/8bimiptc/iptc/Caption", captionToSet);
metadata.SetQuery("/xmp/dc:description/x-default", captionToSet);
}
MemoryStream memstream = new MemoryStream(); // create temp storage in memory
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapFrame, bitmapFrame.Thumbnail, metadata, bitmapFrame.ColorContexts));
encoder.Save(memstream); // save in memory
stream.Close();
stream = new FileStream(newPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
memstream.Seek(0, System.IO.SeekOrigin.Begin); // go to stream start
byte[] bytes = new byte[memstream.Length + 1];
memstream.Read(bytes, 0, (int)memstream.Length);
stream.Write(bytes, 0, bytes.Length);
stream.Close();
memstream.Close();
}
Run Code Online (Sandbox Code Playgroud)
运行该程序,我得到一个“COMException was unhandled”异常,突出显示了这一行:
encoder.Save(memstream);
Run Code Online (Sandbox Code Playgroud)
在PresentationCore.dll中发生了类型为“System.Runtime.InteropServices.COMException”的未处理异常
附加信息:句柄无效。(HRESULT 异常:0x80070006 (E_HANDLE))
我在这里看到这可能是由于线程问题造成的,因此我没有直接从应用程序调用 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();
}
Run Code Online (Sandbox Code Playgroud)
我还尝试将 MemoryStream 替换为 FileStream 创建本地临时文件 - 这没有改变任何内容:
FileStream memstream = new FileStream(System.IO.Path.GetDirectoryName(newPath) + @"\" + "temp.jpg", System.IO.FileMode.OpenOrCreate);
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?
您的代码中有一些错误。
源流必须保持打开状态,直到 BitmapFrame 写入目标流。
来自 BitmapDecoder 的 BitmapFrame 的图像元数据是只读的。当您想要修改元数据时,必须从原始 BitmapFrame 创建一个新的 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);
}
}
}
Run Code Online (Sandbox Code Playgroud)