在JPEG图像的属性窗口中,有一个名为“摘要”的选项卡。在这个标签中,有一个名为“评论”的字段我想写一些c#代码,它会在这个字段中添加一个给定的字符串,例如“这是一张照片”。
有些灵魂知道怎么做吗?
非常感谢。
答案 0 :(得分:15)
根据其他答案,我编写了以下类,允许进行各种元数据操作。你这样使用它:
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
方法。
以下是完整代码,已在the MIT licence下获得许可。您需要添加对PresentationCore
,WindowsBase
和System.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];
}
}
答案 1 :(得分:12)
以下代码解决了我的问题并为给定的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友情提供的链接下的代码的轻微修改版本。
请注意,为了完成这项工作,您需要将.NET引用添加到 PresentationCore 和 WindowsBase 。如果使用Visual Studio 2008,可以通过以下方式实现:
在解决方案资源管理器中右键单击您的项目
从下拉列表中,选择添加'参考...'
在打开的新框中,选择“.NET”标签
滚动到上面提到的两个参考文献,然后单击“确定”
非常感谢danbystrom和Konamiman对此事的帮助。我非常感谢快速反应。
答案 2 :(得分:1)
简单的部分:
添加此属性项:
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。 叹息
答案 3 :(得分:1)
感谢之前的提示,我能够将以下内容放在一起。我测试过它似乎有效。最大的绊脚石之一是确定您想要分配的字段所需的ID。
string fileName = "c:/SomeImage.jpg";
// Retrieve the Image
System.Drawing.Image originalImage = System.Drawing.Image.FromFile(fileName);
// Get the list of existing PropertyItems. i.e. 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();
答案 4 :(得分:1)
感谢此处的答案,我编写了一个解决方案,仅使用内存设置注释:
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);
}
}
不要忘记处理此方法返回的图像。 (例如,将图像保存到文件后)
答案 5 :(得分:0)
Peter Kistler解决方案的一种变体,用于设置标题,主题和评论。我发现必须将项目创建为Unicode字节数组(类型1),并且Title,Subject和Comment的ID与EXIF XPTitle,XPSubject和XP Comment的ID相同。 sFileOut可以与sFile相同。
public static void SetWindowsTags2(string sFile, string sFileOut, string Title = "", string Subject = "", string Comment = "", bool bShowError = false)
{
try
{
// Retrieve the Image
System.Drawing.Image originalImage = System.Drawing.Image.FromFile(sFile);
// Get the list of existing PropertyItems. i.e. the metadata
PropertyItem[] properties = originalImage.PropertyItems;
/*foreach (PropertyItem propItem in properties)
{
string sTag = System.Text.Encoding.UTF8.GetString(propItem.Value);
string sItem = sTag.Replace("\0", string.Empty);
Debug.Print(propItem.Id.ToString() + ", " + propItem.Type + ", " + sItem);
}*/
// 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
var itemData = System.Text.Encoding.Unicode.GetBytes(Title);
itemData[itemData.Length - 1] = 0;// Strings must be null terminated or they will run together
item.Type = 1; //Unicode Byte Array
item.Id = 40091; // Title ID
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
itemData = System.Text.Encoding.Unicode.GetBytes(Subject);
itemData[itemData.Length - 1] = 0; // Strings must be null terminated or they will run together
item.Type = 1; //Unicode Byte Array
item.Id = 40095; // subject
item.Len = itemData.Length;
item.Value = itemData;
bmpImage.SetPropertyItem(item); // Assign / add to the bitmap
itemData = System.Text.Encoding.Unicode.GetBytes(Comment);
itemData[itemData.Length - 1] = 0; // Strings must be null terminated or they will run together
item.Type = 1; ////Unicode Byte Array
item.Id = 40092; // comment
item.Len = itemData.Length;
item.Value = itemData;
bmpImage.SetPropertyItem(item); // Assign / add to the bitmap
// Save the image
bmpImage.Save(sFileOut, System.Drawing.Imaging.ImageFormat.Jpeg);
//Clean up
bmpImage.Dispose();
}
catch (Exception Ex)
{
}
}