我一直致力于从图像中删除 Exif 元数据,然后将它们输入到一些机器学习算法中。
我的示例图像是这个,一个 100x100 的小图像,包含超过 500kB 的元数据,下载为backpack.jpg. 磁盘上的文件大小为 584kB。
第一件事:加载图像,将其保存回磁盘:
open System
open System.Drawing
open System.Drawing.Imaging
// Image from http://www.aedsuperstore.com/assets/images/PAD-BAG-02-T-Thumb.jpg
// downloaded as c:/temp/backpack.jpg, File size 584kB
let img = Bitmap.FromFile "c:/temp/backpack.jpg"
// Saves into a file of 563kB
img.Save "c:/temp/backpack_unchanged.jpg"
Run Code Online (Sandbox Code Playgroud)
很奇怪的是,文件大小下降了 20kB,降至 563kB,但我最初忽略了这一点(我归咎于默认编码器质量)
该镜像有一项元数据占用超过500000字节:
> img.GetPropertyItem 34675;;
val it : PropertyItem =
System.Drawing.Imaging.PropertyItem
{Id = 34675;
Len = 557168;
Type = 1s;
...
Run Code Online (Sandbox Code Playgroud)
为了删除元数据,我检查了所有属性项,并调用RemovePropertyItem:
let ids = img.PropertyIdList
for id in ids do
img.RemovePropertyItem id
if img.PropertyIdList.Length <> 0 then
failwith "There are properties left?"
Run Code Online (Sandbox Code Playgroud)
没有抛出异常,所有属性似乎都已被删除。
然后保存到磁盘 - 我得到一个 584kB 的文件:
// Saves into a file of 584 kB
img.Save("c:/temp/backpack_removed.jpg")
Run Code Online (Sandbox Code Playgroud)
现在两个大问题:
MSDN 上有两个相关问题,一个有我认为没有帮助的答案,另一个没有答案。.NET 文档也RemovePropertyItems没有说明任何具体内容。有一个类似的问题提供了解决方法,但没有解释。
Fwiw,可靠地删除元数据是重新绘制图像,如下所示:
// Saves into a file of 19kB
let reDrawn = new Bitmap(img)
reDrawn.Save("c:/temp/backpack_reDrawn.jpg")
Run Code Online (Sandbox Code Playgroud)
小智 3
我也遇到了这个问题。看起来,如果您尝试删除 PropertyItems 中的所有项目,它们将在内存中删除一次,但是当您将图像保存到磁盘时,所有属性项目都会回来。我不知道为什么,但作为一种解决方法,当您删除项目时,可以保持其中一个不变。如果您对其值不满意,可以简单地将其值设置为空白字节[]。
foreach (var prop in bm.PropertyItems)
{
if (prop.Id == 0x10F)//PropertyTagEquipMake
{//I picked 0x10F because I assume it exists in most images.
PropertyItem pi = bm.GetPropertyItem(prop.Id);
pi.Value = new byte[] { 0 };
bm.SetPropertyItem(pi);
}
else
{
bm.RemovePropertyItem(prop.Id);
}
}
Run Code Online (Sandbox Code Playgroud)
但最终我选择使用与你相同的解决方案,它看起来更可靠和干净。我对RemovePropertyItem()很好奇,然后更深入地挖掘。仅供参考。