C#如何从图像中删除XPKeywords(PropertyItem 0x9c9e)

时间:2015-11-24 17:51:05

标签: c# image jpeg exif

我在编辑或删除照片中的关键字时遇到问题。以下是成功替换关键字的方法:

...
string s_keywords = "tag1;tag2;tag3";
PropertyItem item_keyword = (PropertyItem)FormatterServices.GetUninitializedObject(typeof(PropertyItem));
item_keyword.Id = 0x9c9e; // XPKeywords
item_keyword.Type = 1;
item_keyword.Value = System.Text.Encoding.Unicode.GetBytes(s_keywords + "\0");
item_keyword.Len = item_keyword.Value.Length;
image.SetPropertyItem(item_keyword);
...

请注意,我的实验表明image.RemovePropertyItem(0x9c9e);似乎对保存的图像没有影响。而是将上述代码与s_keywords = "";

一起使用

不要这样做:以下代码可以删除关键字,但会导致jpeg被重新编码并失去一些质量(图像文件从大约4MB变为< ; 2MB,我可以看到一些轻微的视觉差异):

...
Image image_copy = new Bitmap(image);
foreach (var pi in image.PropertyItems)
{
    if (pi.Id != 0x9c9e) image_copy.SetPropertyItem(pi);
}
image.Dispose();
image = (Image)image_copy.Clone();
...

我在设置XPTitle时遇到了类似的问题 - 设置propertyItem 0x9c9b似乎对保存的图像没有影响,而是我必须打开文件作为BitmapFrame,提取BitmapMetadata并使用Title属性,然后使用JpegBitmapEncoder构建一个新的jpeg - 从而重新编码并失去图像质量。

...
BitmapFrame bf_title = BitmapFrame.Create(new Uri(tmp_file, UriKind.Relative));
BitmapMetadata bmd_title = (BitmapMetadata)bf_title.Metadata.Clone();
bmd_title.Title = new_title;
BitmapFrame bf_new = BitmapFrame.Create(bf_title, bf_title.Thumbnail, bmd_title, bf_title.ColorContexts);
JpegBitmapEncoder je = new JpegBitmapEncoder();
je.Frames.Add(bf_new);
FileStream fs = new FileStream(tmp_file, FileMode.Create);
je.Save(fs);
fs.Close();
...

请参阅下面的答案,了解更改标题的正确方法。

这让我发疯,我希望这可以帮助别人...

1 个答案:

答案 0 :(得分:0)

请注意,上述关键字代码现在效果很好。

我正在回答这个问题,因为我在搜索时找不到示例代码 - 所以希望其他人会觉得这很有用。

要更改标题,请使用以下代码。问题是有两个标签影响窗口显示标题的方式 - 其中一个(0x010e)优先于XPTitle(0xc9b)标签......

...
string new_value = "New title for the image";
PropertyItem item_title = (PropertyItem)FormatterServices.GetUninitializedObject(typeof(PropertyItem));
item_title.Id = 0x9c9b; // XPTitle 0x9c9b
item_title.Type = 1;
item_title.Value = System.Text.Encoding.Unicode.GetBytes(new_value + "\0");
item_title.Len = item_title.Value.Length;
image.SetPropertyItem(item_title);
PropertyItem item_title2 = (PropertyItem)FormatterServices.GetUninitializedObject(typeof(PropertyItem));
item_title2.Id = 0x010e; // ImageDescription 0x010e
item_title2.Type = 2;
item_title2.Value = System.Text.Encoding.UTF8.GetBytes(new_value + "\0");
item_title2.Len = item_title2.Value.Length;
image.SetPropertyItem(item_title2);

image.Save("new_filename.jpg", ImageFormat.Jpeg)
image.Dispose();
...

注意 - 另一个潜在问题,您需要将图像保存到新位置。然后,您可以根据需要处理图像并将其复制到原始位置。