如何使用C#向JPEG文件添加“注释”

在JPEG图像的属性窗口中,有一个名为“摘要”的选项卡。 在这个标签中,有一个名为“评论”的字段我想写一些c#代码,它会在这个字段中添加一个给定的字符串,例如“这是一张照片”。

有些灵魂知道怎么做吗?

非常感谢。

基于其他答案,我编写了以下类,允许进行各种元数据操作。 你这样使用它:

var jpeg = new JpegMetadataAdapter(pathToJpeg); jpeg.Metadata.Comment = "Some comments"; jpeg.Metadata.Title = "A title"; jpeg.Save(); // Saves the jpeg in-place jpeg.SaveAs(someNewPath); // Saves with a new path 

我的解决方案与其他解决方案之间的差异并不大。 主要是我重构了这个更清洁。 我还使用BitmapMetadata的更高级属性,而不是SetQuery方法。

以下是完整代码,根据MIT许可证授权 。 您需要添加对PresentationCoreWindowsBaseSystem.Xaml引用。

 public class JpegMetadataAdapter { private readonly string path; private BitmapFrame frame; public readonly BitmapMetadata Metadata; public JpegMetadataAdapter(string path) { this.path = path; frame = getBitmapFrame(path); Metadata = (BitmapMetadata)frame.Metadata.Clone(); } public void Save() { SaveAs(path); } public void SaveAs(string path) { JpegBitmapEncoder encoder = new JpegBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(frame, frame.Thumbnail, Metadata, frame.ColorContexts)); using (Stream stream = File.Open(path, FileMode.Create, FileAccess.ReadWrite)) { encoder.Save(stream); } } private BitmapFrame getBitmapFrame(string path) { BitmapDecoder decoder = null; using (Stream stream = File.Open(path, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { decoder = new JpegBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); } return decoder.Frames[0]; } } 

以下代码解决了我的问题,并为给定的JPEG图像添加了注释:

 public void addImageComment(string imageFlePath, string comments) { string jpegDirectory = Path.GetDirectoryName(imageFlePath); string jpegFileName = Path.GetFileNameWithoutExtension(imageFlePath); BitmapDecoder decoder = null; BitmapFrame bitmapFrame = null; BitmapMetadata metadata = null; FileInfo originalImage = new FileInfo(imageFlePath); if (File.Exists(imageFlePath)) { // load the jpg file with a JpegBitmapDecoder using (Stream jpegStreamIn = File.Open(imageFlePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { decoder = new JpegBitmapDecoder(jpegStreamIn, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); } bitmapFrame = decoder.Frames[0]; metadata = (BitmapMetadata)bitmapFrame.Metadata; if (bitmapFrame != null) { BitmapMetadata metaData = (BitmapMetadata)bitmapFrame.Metadata.Clone(); if (metaData != null) { // modify the metadata metaData.SetQuery("/app1/ifd/exif:{uint=40092}", comments); // get an encoder to create a new jpg file with the new metadata. JpegBitmapEncoder encoder = new JpegBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmapFrame, bitmapFrame.Thumbnail, metaData, bitmapFrame.ColorContexts)); //string jpegNewFileName = Path.Combine(jpegDirectory, "JpegTemp.jpg"); // Delete the original originalImage.Delete(); // Save the new image using (Stream jpegStreamOut = File.Open(imageFlePath, FileMode.CreateNew, FileAccess.ReadWrite)) { encoder.Save(jpegStreamOut); } } } } } 

这实际上是Konamiman友情提供的链接下的代码的轻微修改版本。

请注意,为了完成这项工作,您需要向PresentationCoreWindowsBase添加.NET引用。 如果使用Visual Studio 2008,可以通过以下方式实现:

  1. 在解决方案资源管理器中右键单击您的项目

  2. 从下拉列表中,选择添加’参考…’

  3. 在打开的新框中,选择“.NET”选项卡

  4. 滚动到上面提到的两个引用,然后单击确定

非常感谢danbystrom和Konamiman对此事的帮助。 我非常感谢快速反应。

感谢之前的提示,我能够将以下内容放在一起。 我已经测试了它,它似乎工作。 最大的绊脚石之一是确定您要分配的字段所需的Id。

 string fileName = "c:/SomeImage.jpg"; // Retrieve the Image System.Drawing.Image originalImage = System.Drawing.Image.FromFile(fileName); // Get the list of existing PropertyItems. ie the metadata PropertyItem[] properties = originalImage.PropertyItems; // Create a bitmap image to assign attributes and do whatever else.. Bitmap bmpImage = new Bitmap((Bitmap)originalImage); // Don't need this anymore originalImage.Dispose(); // Get / setup a PropertyItem PropertyItem item = properties[0]; // We have to copy an existing one since no constructor exists // This will assign "Joe Doe" to the "Authors" metadata field string sTmp = "Joe DoeX"; // The X will be replaced with a null. String must be null terminated. var itemData = System.Text.Encoding.UTF8.GetBytes(sTmp); itemData[itemData.Length - 1] = 0;// Strings must be null terminated or they will run together item.Type = 2; //String (ASCII) item.Id = 315; // Author(s), 315 is mapped to the "Authors" field item.Len = itemData.Length; // Number of items in the byte array item.Value = itemData; // The byte array bmpImage.SetPropertyItem(item); // Assign / add to the bitmap // This will assign "MyApplication" to the "Program Name" field sTmp = "MyApplicationX"; itemData = System.Text.Encoding.UTF8.GetBytes(sTmp); itemData[itemData.Length - 1] = 0; // Strings must be null terminated or they will run together item.Type = 2; //String (ASCII) item.Id = 305; // Program Name, 305 is mapped to the "Program Name" field item.Len = itemData.Length; item.Value = itemData; bmpImage.SetPropertyItem(item); // Save the image bmpImage.Save(fileName, System.Drawing.Imaging.ImageFormat.Jpeg); //Clean up bmpImage.Dispose(); 

感谢这里的答案,我编写了一个解决方案,仅使用内存设置注释:

 public static Image SetImageComment(Image image, string comment) { using (var memStream = new MemoryStream()) { image.Save(memStream, ImageFormat.Jpeg); memStream.Position = 0; var decoder = new JpegBitmapDecoder(memStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); BitmapMetadata metadata; if (decoder.Metadata == null) { metadata = new BitmapMetadata("jpg"); } else { metadata = decoder.Metadata; } metadata.Comment = comment; var bitmapFrame = decoder.Frames[0]; BitmapEncoder encoder = new JpegBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmapFrame, bitmapFrame.Thumbnail, metadata, bitmapFrame.ColorContexts)); var imageStream = new MemoryStream(); encoder.Save(imageStream); imageStream.Position = 0; image.Dispose(); image = null; return Image.FromStream(imageStream); } } 

不要忘记处理此方法返回的图像。 (例如,将图像保存到文件后)

简单的部分:

添加此属性项:

 var data = System.Text.Encoding.UTF8.GetBytes( "Some comments" ); PropertyItem pi; *** create an empty PropertyItem here pi.Type = 2; pi.Id = 37510; pi.Len = data.Length; pi.Value = data; 

到Image的PropertItems集合。

更麻烦的部分:如何创建一个新的PropertyItem,因为它没有公共构造函数?

常见的“技巧”是在周围放置一个空图像,您可以从中窃取PropertyItem。