做了个 MozJPEG 的 GUI ٩(˃̶͈̀௰˂̶͈́)و

Author Avatar
✨小透明・宸✨ 2019-05-04 10:30:44
  • 在其它设备中阅读本文章

封面图:Pixiv ID: 21721272 「さーくらさきー」 by 結城辰也

MozJPEG 是 Mozilla 发布的一个基于 libjpeg-turbo 改进的 JPEG 格式图片编码器,号称文件大小与后者相比平均可以减少 5%

MozJPEG 的本体 cjpeg.exe 是一个需要在命令行下调用的程序。

cjpeg -quality 90 -outfile output.jpg input.bmp

因为想要试试 MozJPEG 是不是真的可以提高图片的压缩比,而且最近实在是闲得没什么事干,所以就尝试着做了一个 GUI 程序~

本来打算继续用 Visual Basic 做的,后来发现自己学了一学期 C 语言之后已经完全不习惯 Dim *** As Integer 这样的写法,写完每一行还习惯性地加分号,所以就……果断改用 C# 咯~虽然小透明根本就没学过 C# 怎么写,靠的是面向 Google 编程

顺便抛弃了 WinForm 而尝试使用 WPF 做界面。XAML 用起来真是舒服,Grid 布局和控件对齐什么的比 WinForm 下每个控件使用的绝对坐标不知道高到哪里去(´・ω・`)ノ

程序截图如下~

Readme

代码和程序已经丢上了 GitHub,这里是仓库地址,下载程序本体请直接前往 Release ٩( ‘ω’ )و

运行前请确定已经在电脑上安装了 .NET Framework 4.0。

顺便说一下在程序里折腾了哪些东西:

  • 只有单个文件,是绿色版程序。

    • cjpeg.exe 使用的是 GitHub 上找到的一个预编译版,并且使用 UPX 进行了压缩。
    • cjpeg.exe 是作为资源文件嵌入到程序本体中的。程序启动时会将 cjpeg.exe 释放到临时目录,退出时删除。
  • 支持打开 png 格式的图片。

    • MozJPEG 只支持输入 tgabmpppmjpg 四种格式的图片,不支持 png,程序会自动将打开的图片转换为 bmp,存储在临时目录。
    • JPEG 不支持透明度,所以 PNG 图片的透明部分会变成白色。
  • 参考了 Photoshop 的“存储为 Web 所用格式”界面,加入了预览编码后的图片保存图片时对图片进行缩放的功能。

    • 预览功能实际上是按照参数对图片进行编码后将输出的图片显示在窗口中,如果要保存的话将预览的图片复制粘贴即可。
    • 缩放功能是先对原图进行缩放,存储在临时目录,然后将缩放后的图片拿去编码,MozJPEG 本身没有缩放图片的功能。
  • 批处理功能,可以对一个文件夹的所有图片进行编码。编码设定使用的是窗口上的设定,还可以选择按宽度/高度/百分比对批处理中的图片进行缩放。

    • “批处理”选择“按百分比缩放”,将百分比设为 50%,缩放后的图片宽度和高度都是原图的一半,设为 100% 就是不进行缩放。
    • “批处理”选择“等比例缩放至宽度”,将宽度设为 1000,缩放后的图片将按纵横比缩放至宽度为 1000 的大小。例如一张 6000x4000 的图片(也就是 3:2 的比例)就会被缩放到 1000x667。“等比例缩放至高度”同理。
  • 图片格式的设定,可以根据需要编码不同类型的图片(不改变质量,会改变文件大小)。不同格式的图片在网页上加载时显示的加载过程也有所不同。

    • “基本式”(baseline),图片从上至下逐渐显示。
    • “渐进式”(progressive),图片从模糊逐渐变清晰。
    • “渐进式”又可以继续分为“交错式”(interleaved)和“非交错式”(non-interleaved)。在加载模糊部分时,前者同时加载所有色彩通道;后者先加载亮度通道再加载色度通道,表现为先显示黑白图片,再逐渐向图片上添加颜色。一般情况下“非交错式”的图片文件大小要略微小于“交错式”。
    • 不同格式的图片在加载过程中的具体效果可以参考下面的视频。录制此视频时使用了 Firefox 的开发者工具模拟在低速网络环境下打开图片的情景。

一些关于在网页上使用图片的事情

已经发布了二十多年的 JPEG 格式在今天仍然有广泛的使用,比如目前网页上能看到的绝大多数图片都是 JPEG 格式。虽然前几年有 Google 推出的 WebP 尝试抢 JPEG 的饭碗,Apple 也在 iOS 11 上大力推广 HEIF 格式,然鹅这两个格式到今天也没有在网页上被广泛使用——因为支持程度实在是比不上 JPEG 啊(摊手

WebP 的有损压图效果确实比 JPEG 不知道高到哪里去了,毕竟压缩算法是基于自家的 VP8 视频编码,而且在网页上的支持程度相对来说也是最好的(∀`)σ HEIF 也是基于 HEVC 视频编码折腾出来的玩意。但是高贵的 Apple 到现在也没有在自家的 Safari 浏览器上支持 WebP,而 HEIF 根本就没有人用,iOS 11 刚发布的时候广大高贵的 iPhone 用户怎么在 Windows 系统中打开从手机中导出的 HEIF 图片都是问题┓( ´∀` )┏

所以本站到目前为止仍然在大量使用 JPEG 图片,还没有把图片格式升级为 WebP。

其实还有一个原因是没有找到支持上传 WebP 图片的图床

屏幕截图除外,这种图片丢给 TinyPNG 就可以了。用 JPEG 压缩后截图上的文字边缘会有很难看的杂边。JPEG 更适合用于三次元照片之类的图片,即使有杂边也可以当成是现实中物体表面的纹理或拍摄时的噪点。

强行上 WebP 不是不行,比如可以用 HTML5 加入的 <picture> 标签让不支持 WebP 的设备加载 JPEG 图片:

<picture>
    <!-- 不支持WebP的话,就忽略这个<source>,尝试加载下面的<img> -->
    <source type="image/webp" srcset="image.webp">
    <img src="image.jpg">
</picture>

或者是用 Javascript 检查是否支持 WebP,如果支持的话就进一步替换:

function checkWebp(callback) {
    var img = new Image();
    img.onload = function () {
        //不支持WebP的话就不能读取到图片的尺寸
        var result = (img.width > 0) && (img.height > 0);
        callback(result);
    };
    img.onerror = function () {
        callback(false);
    };
    //尝试加载一张极小的WebP图片
    img.src = 'data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA';
}

//支持WebP的话就替换<img>的src
//也可以和懒加载结合使用,这时就是替换<img>的某个自定义属性(常用data-src)后把它设为src的值
function showImage(useWebp){
    Array.from(document.querySelectorAll('img')).forEach(function (i) {
        if (useWebp) {
            i.src = i.src.replace(/\.jpg$/, '.webp');
        }
    });
}

checkWebp(showImage);

不过为了用一张图片还要折腾这么多实在是太麻烦了……算了还是继续回去用 JPEG 吧(`^´)ノ

魔改的 JPEG 编码器,除了 Mozilla 的 MozJPEG 以外,还有 Google 的 Guetzli。不过后者效率实在是太低了,压一张图需要的时间是需要按分钟算的Σ(っ °Д °;)っ

Google 自己写了一份网页图像优化指南,其中“优化 JPEG 编码器”这一部分提到使用同一张 3000x3000 的图片对 MozJPEG 和 Guetzli 进行测试,后者在压缩比上可能有一点点优势,但是增加的时间成本嘛……

MozJPEG 和 Photoshop 的对比

上面提到过 Photoshop 也有个“存储为 Web 所用格式”可以将图片保存为一定质量的 JPEG 格式,不过和 MozJPEG 相比,哪一个的压缩效率更好呢?这里就做一个测试。

使用的测试图片是一张 512x512 的 Lenna 图

MozJPEG 的转码参数只设定 -quality N 一项,取值为 30、31、32……100。

Photoshop 使用“存储为 Web 所用格式”保存图片,“品质”取值为 0、5、10……100,打开“连续”(相当于 MozJPEG 默认开启的输出渐进式 JPEG 图片),“模糊”设为 0(相当于 MozJPEG 的参数 -smooth 0)。

两个软件的质量参数取值和输出文件大小之间的关系有较大差别,本例中 MozJPEG 的 -quality 30 输出的文件大小大致相当于 Photoshop 中“品质”取值为 0 的输出结果。

图片质量的统计是使用 ImageMagick 计算原图和编码后图片的 SSIM,范围是 0 到 1 的一个小数。SSIM 越接近 1,说明两张图片越相似,图片质量损失最少。

magick compare -channel all -metric ssim source.png converted.jpg difference.png

将统计结果做成 X 轴为文件大小,Y 轴为 SSIM 的折线统计图:

点击可以查看大图(。・ω・)ノ゙

相同文件大小下,SSIM 越高即为压缩效率更好。由图可知大多数情况下 MozJPEG 的压缩效率都高于 Photoshop。只要不是使用极高质量的 JPEG 图片(质量极高等于文件极大,在网页上一般也不会这么做),使用 MozJPEG 都是没问题的(›´ω`‹ )

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
本文链接:https://akarin.dev/2019/05/04/mozjpeg-gui/