11

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

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

我正在寻找一个库(甚至是一种自己做的方法)来仅编辑 JPEG 文件中的 Exif 部分(或者如果 Exif 数据尚不存在,则添加它),而不修改其他数据。这不可能吗?

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

4

4 回答 4

9

如果您打算编写自己的库来编辑标签,这里是 Exif 交换格式的规范。

http://www.exif.org/specifications.html

这是一个用 Perl 编写的库,可以满足您的需求,您可以从中学习:

http://www.sno.phy.queensu.ca/~phil/exiftool/

这是来自The Code Project 的用于 Exif 评估的不错的 .NET 库:

http://www.codeproject.com/KB/graphics/exiftagcol.aspx

于 2009-06-24T13:30:07.967 回答
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 id(包括 exif)的列表。

更新:同意,此方法将在保存时重新编码图像。但我记得另一种方法,在 WinXP SP2 及更高版本中添加了新的成像组件 - WIC,您可以使用它们无损写入元数据 - How-to: Re-encode a JPEG Image with Metadata

于 2009-06-24T19:12:52.093 回答
4

exiv2net库(exiv2 之上的 .NET 包装器)可能是您正在寻找的。

于 2009-11-30T22:03:17.430 回答
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);
      }
    }
  }
}
于 2016-02-11T21:37:34.477 回答