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

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

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

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

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

以下是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

您可以在没有任何外部库的情况下执

// 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,你可以将它们用于无损写入元数据 – 操作方法:用元数据重新编码JPEG图像 。

exiv2net库( exiv2上的.NET包装器)可能就是你要找的东西。

我写了一个小测试,我多次压缩一个文件以查看质量下降,你可以在第三次压缩中看到它,这是非常糟糕的。

但幸运的是,如果您始终使用与JpegBitmapEncoder相同的QualityLevel,则不会降级。

在这个例子中,我在元数据中重写关键字100x,质量似乎没有改变。

 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() : new List(metadata.Keywords); keywords.Add($"Keyword {i:000}"); metadata.Keywords = new ReadOnlyCollection(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); } } } }