.NET Image.RemovePropertyItem没有明显效果

Ant*_*fer 5 .net image

我一直致力于从图像中删除 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)

现在两个大问题:

  • 为什么去掉属性项没有明显效果?我可以做些什么来让它发挥作用吗?
  • 为什么第二次保存时磁盘上的图像大小又回到原来的584kB?

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()很好奇,然后更深入地挖掘。仅供参考。