使用 c# 进行高质量 JPEG 压缩
Posted
技术标签:
【中文标题】使用 c# 进行高质量 JPEG 压缩【英文标题】:High quality JPEG compression with c# 【发布时间】:2010-12-12 19:04:03 【问题描述】:我正在使用 C# 并希望使用 JPEG 格式保存图像。但是 .NET 会降低图像的质量并以不够的压缩方式保存它们。
我想以原始质量和大小保存文件。我正在使用以下代码,但压缩和质量与原始代码不同。
Bitmap bm = (Bitmap)Image.FromFile(FilePath);
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo ici = null;
foreach (ImageCodecInfo codec in codecs)
if (codec.MimeType == "image/jpeg")
ici = codec;
EncoderParameters ep = new EncoderParameters();
ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)100);
bm.Save("C:\\quality" + x.ToString() + ".jpg", ici, ep);
我正在归档工作室照片,质量和压缩非常重要。谢谢。
【问题讨论】:
【参考方案1】:库中内置的 .Net 编码器(至少是微软提供的默认 Windows 库)非常糟糕:
http://b9dev.blogspot.com/2013/06/nets-built-in-jpeg-encoder-convenient.html
部分更新
我现在使用an approach outlined here,它使用 ImageMagick 进行调整大小,然后使用 jpegoptim 进行最终压缩,效果要好得多。我意识到这是部分答案,但一旦时间允许,我将对此进行扩展。
旧答案
ImageMagick 是迄今为止我找到的最佳选择。它执行相对可靠的 jpeg 压缩。
http://magick.codeplex.com/
它有几个缺点:
它更好,但并不完美。特别是,它的色度子采样设置为 90% 或更高的高细节,然后跳到较低的细节水平——这会引入很多伪影。如果您想忽略二次采样,这实际上非常方便。但是,如果您想要 50% 的高细节二次抽样,您将面临更大的挑战。它也不会完全达到 Photoshop 或 Google PageSpeed 的质量/压缩级别。
它在服务器上具有特殊的部署负担,很容易被忽略。它需要安装 Visual Studio 2008 SDK 库。这个库在任何装有 Visual Studio 的开发机器上都可用,但是当你第一次访问服务器时,它会因一个模糊的错误而崩溃。这是大多数人不会编写/自动化脚本的潜伏陷阱之一,在未来的服务器迁移过程中你会遇到它。
最早的答案
我翻遍了一个项目,通过翻译一个 C 项目来实现一个 C# JPEG 编码器:
http://www.codeproject.com/Articles/83225/A-Simple-JPEG-Encoder-in-C
我已经稍微简化了:
https://github.com/b9chris/ArpanJpegEncoder
它生成的 JPEG 比内置的 .Net 高得多,但仍不如 Gimp 或 Photoshop。文件大小也往往更大。
BitMiracle's implementation 实际上与 .Net 内置 - 相同的质量问题。
很可能只封装一个现有的开源实现,比如Google's jpeg_optimizer in PageSpeed Tools - 看似libjpeg ,将是最有效的选择。
更新
ArpanJpegEncoder 在部署后似乎出现问题 - 也许我需要提高代码的信任级别,或者可能发生了其他事情。在本地它可以很好地写入图像,但是一旦部署,我每次都会从中得到一个空白的黑色图像。如果我确定原因,我会更新。只是对考虑它的其他人的警告。
【讨论】:
+1 提到内置的 .NET JPEG 编码器很糟糕。即使在质量 100 上,它仍然会明显降低质量。质量 100 会产生低质量的大文件。使用这个 .NET 内置编码器,我发现最好(即合理的文件大小以最小化质量损失)在 70(大图像)到 90(小图像)之间使用 Encoder.Quality。 我是 Magick.NET 的创建者,我想通知您,我最近添加了一个 JpegOptimizer 类,可用于获得与 Google PageSpeed 相同的大小。您可能想更新答案。 很好的答案。我使用了 .Net 库,压缩级别损坏了图像的质量。然后我尝试了Magick,它非常简单,压缩图像后质量好多了。 您为 .net jpeg 编码器不好的原因提供的链接非常陈旧且过时,并且该博客中用于证明该概念的图像不是一个很好的例子。我制作了一个应用程序并使用真实照片(不是几何照片)测试了magick.net 和内置.net 编码器,结果对于Magick.net 和.net 内置编码器几乎相同。 @ChrisMoschini 最新版本的 Magick.NET 支持从流中压缩图像。【参考方案2】:您似乎将质量设置为 100%。这意味着不会有压缩。
如果您更改压缩级别(80、50 等)并且对质量不满意,您可能需要尝试其他图片库。 LEADTools 有一个很好的(非免费的)引擎。
更新:正如评论者所提到的,100% 的质量仍然不意味着使用 JPEG 时的无损压缩。加载图像,对其进行处理,然后再次保存,最终会导致图像质量下降。如果您需要在不丢失任何数据的情况下更改和保存图像,则需要使用无损格式,例如 TIFF、PNG 或 BMP。我会使用压缩的 TIFF(因为即使压缩它仍然是无损的)或 PNG。
【讨论】:
在 .NET JPG 编码方面,将质量设置为 100% 并不意味着它是无损的。我个人使用我的 .NET 代码中的上述 LEADTools(免费!)JPG 编码器。它是一个可执行文件,我向其提供图像源,启动可执行文件,然后将结果读回内存以进行进一步操作。 不仅如此,.Net 内置的 JPEG 编码器也很糟糕。您可以在蓝色背景上绘制一个黄色框,将编码器设置为 jpeg 100%,并且不重新保存仍然会得到非常糟糕的结果。 brass9.com/test/netjpeg/comparison.png(我意识到几何图形在 JPEG 中并不是最好的;想象一下在加载的照片上使用 .Net 绘制几何形状并希望将其保存出来;这张照片使 jpeg 成为最佳候选,.Net 即使在100%。)【参考方案3】:压缩和质量始终是一种权衡。
JPEG 总是有损的。
您可能需要考虑使用 PNG 并使用 PNGCrush 或 PNGauntlet 缩小文件
【讨论】:
【参考方案4】:关于 .NET 中压缩级别的设置,请查看此链接(包括所有内容):http://msdn.microsoft.com/en-us/library/bb882583.aspx
听到您的问题: 通常,您会将用户上传的图像保存为 PNG,然后使用此 PNG 作为基础来生成不同大小的 JPG(并且您只在 JPG 上放置水印,而不是在原始 PNG 上!) 这样做的好处是:如果您稍后为您的平台更改图像尺寸,您将保存原始 PNG,并且您可以在此基础上重新计算任何新的图像尺寸。
【讨论】:
【参考方案5】:它必须像原始质量和大小一样保存文件
这没有多大意义。当您使用有损压缩时,根据定义,您将丢失一些信息。压缩图像的目的是减小文件大小。如果您需要高质量并且 jpeg 不适合您,您可能必须使用某种类型的无损压缩,但您的文件大小不会减少太多。您可以随时尝试使用“标准”库压缩为 jpeg(libjpeg) 并查看是否会给您带来任何不同的结果(我对此表示怀疑,但我不知道 .NET 在后台使用的是什么。)
【讨论】:
【参考方案6】:压缩 jpeg 格式本质上会降低质量。也许您应该研究一下文件压缩,例如#ziplib。您可能能够对一组文件进行合理的压缩。
【讨论】:
JPEG 算法的一部分是 zip 压缩 - 压缩一个 jpeg 或许多 jpeg 通常不会为您带来有意义的节省。以上是关于使用 c# 进行高质量 JPEG 压缩的主要内容,如果未能解决你的问题,请参考以下文章