这可行吗?使用zip库压缩JPEG文件

4

据我所知,JPEG文件在所有图像格式中具有最佳的压缩比。如果我没记错的话,我们无法再对JPEG文件进行更多压缩,因为它已经具有最佳压缩率。请帮助我确认一下。以下是我创建的一些JPEG文件:

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, _quality);

using(MemoryStream ms = new MemoryStream()) {
     Bitmap capture = GetImage();
     capture.Save(ms, ici, ep);
  }

我用SharpZipLib压缩了它们,每个JPEG的平均大小为130KB,在压缩后,每个文件的大小约为70KB。这是怎么做到的?我只能想到两个答案。
1.我们可以通过zip库将JPEG文件压缩得更加紧凑。
2.我的JPEG文件创建不正确,我们可以创建更好的JPEG(由于无法使用zip库进一步压缩它们,因此具有更高的压缩比)。
有人知道这方面的知识吗?如果我们可以创建更好的JPEG,请帮我解决这个问题。
编辑:这是我用来压缩JPEG的zip代码:
void addnewentry(MemoryStream stream, string pass,
                 string ZipFilePath, string entryname){

ICSharpCode.SharpZipLib.Zip.ZipFile zf = new ZipFile(ZipFilePath);

            if(!String.IsNullOrEmpty(pass))
                zf.Password = pass;

            StaticDataSource sds = new StaticDataSource(Stream);
            zf.BeginUpdate();
            zf.Add(sds, entryName);
            zf.CommitUpdate();
            zf.IsStreamOwner = true;
            zf.Close();
}

public class StaticDataSource : IStaticDataSource {

    public Stream stream { get; set; }

    public StaticDataSource() {
        this.stream.Position = 0; 
    }

    public StaticDataSource(Stream stream) {

            this.stream = stream;
            this.stream.Position = 0;
        }

    public Stream GetSource() {
            this.stream.Position = 0;
            return stream;

    }

}

它们已经被压缩了。你不需要再压缩它们。如果你想要一个更高度压缩的JPEG,那么在你使用保存JPEG的库中调高压缩级别设置即可。 - Cody Gray
@Saeid - 请记住,JPEG是有损压缩的,这意味着它被压缩得越多,结果的质量就越低。 - M.Babcock
@Saeid,你能发布你的压缩代码吗?你是否在图像数据结束后保存了很多未使用的空间? - IanNorton
当您使用内置的Windows压缩工具(右键单击->发送到->压缩文件夹)或其他zip实用程序压缩图像文件时,是否会得到相同的结果,还是只有使用SharpZipLib才能得到? - Shadow The Spring Wizard
我无法重现您所描述的问题,您能否将示例图像托管在某个地方并发布链接? - Shadow The Spring Wizard
显示剩余5条评论
5个回答

3
正如大多数人所说,你不能轻易地进一步压缩这些已经压缩过的文件。有些人在JPEG重新压缩上下了很大功夫(重新压缩=部分解码已经压缩过的文件,然后使用自定义更强的模型和熵编码器对这些数据进行压缩。重新压缩通常可确保位完全相同的结果)。即使使用高级的重新压缩技术,我只看到了最多25%的改进。PackJPG 就是其中之一。你可以看看其他压缩器这里。正如你所意识到的那样,即使是最高等级的压缩器也不能达到25%(尽管它非常复杂)。
考虑到这些事实,ZIP(实际上是deflate)无法提高压缩效果(如果与前10个压缩器相比,它非常老旧和低效)。我认为这个问题有两个可能的原因:
  1. 你可能会在JPEG流中意外添加一些额外的数据(可能添加在JPEG流之后)。
  2. .NET向JFIF文件输出了大量冗余数据。可能是一些大的EXIF数据等。
为了解决这个问题,你可以使用JFIF转储工具观察JFIF容器中的内容。此外,你可能需要尝试使用PackJPG来压缩JPEG文件。

我也用打印屏幕按钮截图并在画图中保存为JPEG格式得到了相同的结果。你如何解释这个问题? - Saeid
5
起初,我认为它们是一些具有平滑渐变的照片。但是,根据你的“证明”,我相信你正在压缩人工图像(例如,计算机生成的图像、桌面截图、图表等)。如果是这样的话,那么你能够进一步压缩这些图像也就不足为奇了。因为,JPEG 在这种类型的图像中保留了相当数量的熵。而且这可以通过简单的程序进一步减少。为了证明我的意思,只需使用 MS Paint 创建一个巨大的白色图像,并将其保存为 JPEG 格式。然后使用 ZIP 压缩器(特别是 7-zip 的 MAX 设置)压缩该文件。你会感到惊讶 :) - Osman Turan

2
JPEG压缩算法分为两个阶段:一个是“有损”阶段,其中会删除人眼无法察觉的视觉元素;另一个是“无损”阶段,该阶段使用一种称为Huffmann编码的技术对剩余数据进行压缩。在Huffmann编码之后,进一步的无损压缩技术(如ZIP)将无法显著减小图像文件的大小。
但是,如果您将多个相同的小图像一起压缩,ZIP(“DEFLATE”)算法将识别数据的重复,并利用它将总文件大小减少到小于各个单独文件大小的总和。这可能就是您在实验中看到的情况。
简而言之,无损压缩技术(如JPEG中的Huffman编码)和ZIP中使用的DEFLATE尝试发现原始数据中的重复模式,然后使用更短的代码表示这些重复模式。
总之,通过添加另一个无损压缩阶段,您将无法真正改善JPEG。

FYI,ZIP!= LZW。Zip通常使用deflate而不是LZW。 - IanNorton
根据你的回答,我进行了一个测试。首先,我压缩了一个JPEG文件,原始大小为99KB,压缩后大小为69KB(压缩比31%)。然后,我压缩了15个非常相似的JPEG文件(重复地进行屏幕截图),平均原始大小为99KB,所有文件都以31%的比率压缩到平均69KB。因此,我认为还有另一种描述方式。 - Saeid
有一个像那样小的文件,很可能你正在看到 @DanielS 在另一个答案中所描述的。JPEG容器允许您在压缩内容(EXIF数据)外部存储有关图像的额外信息。根据用于创建图像的程序/相机以及图像本身的大小,它可能是相当大量的未压缩数据。如果您不需要此信息,可以使用EXIF编辑工具或库将其从图像中删除。如果您确实需要大量的EXIF数据,则将JPEG文件一起压缩可能不是一个坏主意。 - G-J

2
没有人提到JPEG只是一个容器的事实。这个文件格式可以使用许多压缩方法(JFIF、JPEG-2000、JPEG-LS等)。进一步压缩该文件可能会产生不同的结果,这取决于内容。此外,一些相机存储大量的EXIF数据(有时约为20K),这可能解释了您看到的差异。

1

你可以尝试使用zlib压缩任何东西。但并不总是能减小文件大小。

通常情况下,压缩整个jpeg文件只会节省一些字节,因为它会压缩jpeg头部(包括任何纯文本注释或EXIF数据)

除非你有大量的头部数据或者你的jpeg数据中有很多重复的值,否则这可能无法完全解释你看到的40K压缩。


但我认为我的压缩文件不仅仅是头部压缩,从130KB到70KB,你说这只是头部压缩? - Saeid

0

压缩JPEG文件可以减小文件大小,因为:EXIF数据不会被压缩,JPEG优化了照片而不是GIF样式的数据,并且压缩文件会创建一个单一的数据流,允许跨多个文件进行模式匹配并消除每个文件必须与磁盘上特定块对齐的要求。仅后者就可以每个压缩文件节省约4KB。

压缩预先压缩的图像的主要问题是需要额外的工作(人力和CPU)来进行准备和查看,这可能不值得努力(除非您有数百万个很少访问的图像或正在开发某种自动化图像服务)。

更好的方法是最小化本机文件大小,忘记zip。有许多免费的库和应用程序可用于帮助实现此目的。例如,ImageOptim将几个库组合成一个(OptiPNG、PNGCrush、Zopfli、AdvPNG、Gifsicle、PNGOUT),以进行一系列激进的技巧来最小化大小。对于PNG来说效果很好;我没有在JPEG方面尝试过它。

但请记住,任何压缩都存在收益递减的点。由您决定在长期内是否真的需要几个额外的字节。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接