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

C# How to remove XPKeywords (PropertyItem 0x9c9e) from an image

我在编辑或删除照片中的关键字时遇到问题。成功替换关键字的工作如下:

...
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 + "[=10=]");
item_keyword.Len = item_keyword.Value.Length;
image.SetPropertyItem(item_keyword);
...

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

一起使用

不要这样做: 下面的代码可以删除关键字,但会导致 jpeg 成为 re-encoded 并失去一些质量(图像文件从大约 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 时遇到了类似的问题 - 设置 属性Item 0x9c9b 似乎对保存的图像没有影响,相反我不得不将文件作为 BitmapFrame 打开,提取 BitmapMetadata并使用标题 属性,然后使用 JpegBitmapEncoder 构建一个新的 jpeg - 因此 re-encoding 并降低图像质量。

...
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();
...

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

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

请注意,上面的关键字代码现在可以完美运行了。

我回答这个问题是因为我在搜索时找不到执行此操作的示例代码 - 所以希望其他人会发现它有用。

要更改标题,请使用以下代码。问题是有两个标签会影响 windows 显示标题的方式 - 其中一个 (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 + "[=10=]");
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 + "[=10=]");
item_title2.Len = item_title2.Value.Length;
image.SetPropertyItem(item_title2);

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

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