用于无损 Exif 重写的 .NET C# 库?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1038206/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
.NET C# library for lossless Exif rewriting?
提问by Aximili
I have found various code and libraries for editing Exif.
我找到了各种用于编辑Exif 的代码和库。
But they are only lossless when the image width and height is multiple of 16.
但是只有当图像宽度和高度是 16 的倍数时它们才是无损的。
I am looking for a library (or even a way to do it myself) to edit just the Exif portion in a JPEG file (or add Exif data if it doesn't exist yet), leaving the other data unmodified. Isn't that possible?
我正在寻找一个库(或什至是一种自己做的方法)来编辑 JPEG 文件中的 Exif 部分(或添加 Exif 数据,如果它尚不存在),而不修改其他数据。那不可能吗?
So far I could only locate the Exif portion (starts with 0xFFE1) but I don't understand how to read the data.
到目前为止,我只能找到 Exif 部分(以 0xFFE1 开头),但我不明白如何读取数据。
采纳答案by LBushkin
Here are the specifications for the Exif interchange format, if you plan to code your own library for editing tags.
如果您计划编写自己的库来编辑标签,这里是 Exif 交换格式的规范。
http://www.exif.org/specifications.html
http://www.exif.org/specifications.html
Here's a library written in Perl that meets your needs that you may be able to learn from:
这是一个用 Perl 编写的库,可以满足您的需求,您可以从中学习:
http://www.sno.phy.queensu.ca/~phil/exiftool/
http://www.sno.phy.queensu.ca/~phil/exiftool/
Here's a decent .NET library for Exif evaluation from The Code Project:
这是来自The Code Project的一个用于 Exif 评估的不错的 .NET 库:
回答by arbiter
You can do this without any external lib:
您可以在没有任何外部库的情况下执行此操作:
// 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);
List of all possible PropertyItem ids (including exif) you can found here.
您可以在此处找到的所有可能的 PropertyItem id(包括 exif)的列表。
Update:Agreed, this method will re-encode image on save. But I have remembered another method, in WinXP SP2 and later there is new imaging components added - WIC, and you can use them to lossless write metadate - How-to: Re-encode a JPEG Image with Metadata.
更新:同意,此方法将在保存时重新编码图像。但我记得另一种方法,在 WinXP SP2 和更高版本中添加了新的成像组件 - WIC,您可以使用它们来无损写入元数据 - How-to: Re-encode a JPEG Image with Metadata。
回答by Pawel Marciniak
回答by MartinHoly
I wrote a small test where I compress one file many times to see the quality degradation and you can see it in the third-fourth compression, which is very bad.
我写了一个小测试,我多次压缩一个文件,看到质量下降,在第三次第四次压缩时可以看到它,这是非常糟糕的。
But luckily, if you always use same QualityLevel with JpegBitmapEncoder there is no degradation.
但幸运的是,如果您始终使用与 JpegBitmapEncoder 相同的 QualityLevel,则不会降级。
In this example I rewrite keywords 100x in metadata and the quality seems not to change.
在这个例子中,我在元数据中重写了 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);
}
}
}
}