.NET C#库用于无损重写Exif?

11

我找到了各种用于编辑Exif的代码和库。

但是当图像的宽度和高度是16的倍数时,它们才是无损的。

我正在寻找一个库(或者甚至是一种自己实现的方法),只编辑JPEG文件中的Exif部分(如果不存在Exif数据,则添加Exif数据),保持其他数据不变。这难道不可能吗?

到目前为止,我只能找到Exif部分(以0xFFE1开头),但是我不知道如何读取数据。


这听起来很有前途。 - TaW
4个回答

9

您可以不使用任何外部库来完成此操作:

// Create image.
Image image1 = Image.FromFile("c:\\Photo1.jpg");

// Get a PropertyItem from image1. Because PropertyItem does not
// have public constructor, you first need to get existing PropertyItem
PropertyItem propItem = image1.GetPropertyItem(20624);

// Change the ID of the PropertyItem.
propItem.Id = 20625;

// Set the new PropertyItem for image1.
image1.SetPropertyItem(propItem);

// Save the image.
image1.Save("c:\\Photo1.jpg", ImageFormat.Jpg);

您可以在此处找到所有可能的PropertyItem ids(包括exif)列表:链接
更新:同意,这种方法会在保存时重新编码图像。但我记得另一种方法,在WinXP SP2及更高版本中添加了新的图像组件-WIC,您可以使用它们来无损写入元数据-如何:重新编码带有元数据的JPEG图像

2
这将重新压缩图像。有一个解决方法可以避免重新压缩,即将图像旋转两次,但仅适用于宽度和高度是16的倍数的情况。 - Aximili
1
更新链接:http://msdn.microsoft.com/en-us/library/ee719794(v=VS.85).aspx - BlackICE

9

exif.org网站已经重新设计,所有超链接都加载相同的内容,实际上只是一些博客文章。规格链接现在不再链接到规格了。但是,您仍然可以通过https://www.exif.org/Exif2-2.PDF进行访问。如果无法访问,请使用Web Archive查看网站的旧版本,例如https://web.archive.org/web/20080422021217/http://www.exif.org/Exif2-2.PDF - Sina

4

exiv2net 库(基于 exiv2 的 .NET 封装)可能是您正在寻找的。


0

我写了一个小测试,其中我多次压缩一个文件以查看其质量退化,并且您可以在第三到第四次压缩中看到它,质量非常差。

但幸运的是,如果您始终使用JpegBitmapEncoder的相同QualityLevel,则没有退化。

在此示例中,我在元数据中重写关键字100次,质量似乎没有改变。

private void LosslessJpegTest() {
  var original = "d:\\!test\\TestInTest\\20150205_123011.jpg";
  var copy = original;
  const BitmapCreateOptions createOptions = BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile;

  for (int i = 0; i < 100; i++) {
    using (Stream originalFileStream = File.Open(copy, FileMode.Open, FileAccess.Read)) {
      BitmapDecoder decoder = BitmapDecoder.Create(originalFileStream, createOptions, BitmapCacheOption.None);

      if (decoder.CodecInfo == null || !decoder.CodecInfo.FileExtensions.Contains("jpg") || decoder.Frames[0] == null)
        continue;

      BitmapMetadata metadata = decoder.Frames[0].Metadata == null
        ? new BitmapMetadata("jpg")
        : decoder.Frames[0].Metadata.Clone() as BitmapMetadata;

      if (metadata == null) continue;

      var keywords = metadata.Keywords == null ? new List<string>() : new List<string>(metadata.Keywords);
      keywords.Add($"Keyword {i:000}");
      metadata.Keywords = new ReadOnlyCollection<string>(keywords);

      JpegBitmapEncoder encoder = new JpegBitmapEncoder {QualityLevel = 80};
      encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0], decoder.Frames[0].Thumbnail, metadata,
        decoder.Frames[0].ColorContexts));

      copy = original.Replace(".", $"_{i:000}.");

      using (Stream newFileStream = File.Open(copy, FileMode.Create, FileAccess.ReadWrite)) {
        encoder.Save(newFileStream);
      }
    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接