我找到了各种用于编辑Exif的代码和库。
但是当图像的宽度和高度是16的倍数时,它们才是无损的。
我正在寻找一个库(或者甚至是一种自己实现的方法),只编辑JPEG文件中的Exif部分(如果不存在Exif数据,则添加Exif数据),保持其他数据不变。这难道不可能吗?
到目前为止,我只能找到Exif部分(以0xFFE1开头),但是我不知道如何读取数据。
您可以不使用任何外部库来完成此操作:
// 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);
http://www.exif.org/specifications.html
这是一个用Perl编写的库,可以满足您的需求,您可以从中学到一些知识:http://www.sno.phy.queensu.ca/~phil/exiftool/
这里有一个不错的 .NET 库,用于从 The Code Project 评估 Exif:
我写了一个小测试,其中我多次压缩一个文件以查看其质量退化,并且您可以在第三到第四次压缩中看到它,质量非常差。
但幸运的是,如果您始终使用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);
}
}
}
}