⤴Top⤴

图片压缩

博客分类: 前端

图片压缩

图片压缩

首先介绍一个众所周知、肥肠牛逼的在线图片压缩工具 TinyPNG 👈

图片格式

客户端与服务端压缩处理的区别

图像质量评估算法

对于压缩我们常常使用的办法是直接设置一个压缩系数,但会面临几个问题。

  1. 小图片(尺寸小或图片色彩不够丰富)如果按照统一的压缩系数,没法保证压缩后的视觉效果;
  2. 大图片可能压缩的力度不够(依旧有压缩空间)。

如何寻找最佳压缩比?图像质量评估算法。图片在压缩过程中不可避免的会出现失真的情况,所以需要一种能够评价图像在转换之后的质量损失程度,称为图像评估标准。它在图像的压缩、视频编解码领域都有非常重要的作用。

评估方式介绍:

综合方案概述:

  1. JPG/JPEG 类型采用结构相似性算法智能压缩;
  2. PNG 类型采用 PNG 量化算法压缩;
  3. Webp 类型一般体积不会太大,如果过大的可选择一个合适的压缩系数压缩;
  4. GIF 类型借助 gifsicle 库或者转 webp 处理;
  5. 图片本身体积太小(如小于 50KB)或尺寸太小的情况,可以选择不处理。因为这种情况下处理可能会导致图片失真过多;
  6. 算法处理的图片,如算法认为图片本身没有优化空间,可能会输出比原图还大的图,这种情况直接返回原图。

对于不同图片的处理

jpg/jpeg

针对于 jpg/jpeg,原图压缩的话可以使用 mozjpeg 或者 jpeg-recompress 都可,经实测,一般两者区别不大,都支持 ssim/ms-ssim:

Name Option Description
MPE -m mpe Mean pixel error (as used by imgmin)
SSIM -m ssim Structural similarity DEFAULT
MS-SSIM* -m ms-ssim Multi-scale structural similarity (slow!) (2008 paper)
SmallFry -m smallfry Linear-weighted BBCQ-like (original project, 2011 BBCQ paper)
# Default settings
jpeg-recompress image.jpg compressed.jpg

# High quality example settings
jpeg-recompress --quality high --min 60 image.jpg compressed.jpg

# Slow high quality settings (3-4x slower than above, slightly more accurate)
jpeg-recompress --accurate --quality high --min 60 image.jpg compressed.jpg

# Use SmallFry instead of SSIM
jpeg-recompress --method smallfry image.jpg compressed.jpg

# Use 4:4:4 sampling (disables subsampling).
jpeg-recompress --subsample disable image.jpg compressed.jpg

# Remove fisheye distortion (Tokina 10-17mm on APS-C @ 10mm)
jpeg-recompress --defish 2.6 --zoom 1.2 image.jpg defished.jpg

# Read from stdin and write to stdout with '-' as the filename
jpeg-recompress - - <image.jpg >compressed.jpg

# Convert RAW to JPEG via PPM from stdin
dcraw -w -q 3 -c IMG_1234.CR2 | jpeg-recompress --ppm - compressed.jpg

# Disable progressive mode (not recommended)
jpeg-recompress --no-progressive image.jpg compressed.jpg

# Disable all output except for errors
jpeg-recompress --quiet image.jpg compressed.jpg

jpg/jpeg

针对于压缩过的 jpg,我们还可以通过 jpeg-compare 来比较相似度,值为 0-100,0 为一致:

# Do a fast compare of two images
jpeg-compare image1.jpg image2.jpg

# Calculate PSNR
jpeg-compare --method psnr image1.jpg image2.jpg

# Calculate SSIM
jpeg-compare --method ssim image1.jpg image2.jpg

png

针对于 png,原图压缩的话可以使用 pngquant,To further reduce file size, try oxipng, imageOptim, or zopflipng.

pngquant --quality=65-80 image.png

webp

针对上述 jpg/jpeg/png,我们还可以通过 cwebp 转换为 webp。cwebp 本身也有压缩操作:

cwebp -mt -q 70 x.jpg -o x.webp

# 使用 -m 6 效果更佳,默认值为 4
cwebp -mt -q 70 -m 6 x.jpg -o x.webp
# 批量转换 jpg 为 webp
# -*- coding: utf-8 -*-  
import os 
q = 70
for root, dirs, files in os.walk(".", topdown=False):
  for name in files:
    fileName = os.path.join(root, name)
    if (fileName.endswith('.jpg')):
      stem, suffix = os.path.splitext(fileName)
      os.system("cwebp -mt -q %d '%s' -o '%s'"%(q, fileName, stem + ' - q%d'%(q) + '.webp'))

针对于 gif,我们则通过 gif2webp 来转换,具体示例如下一节。

gif

一般 gif 动图可以通过以下几种方式去处理,具体可以讨论下,以下均以同一张 1.8M gif 为示例,对比下效果:

  1. APNG(Animated PNG) 替代
  2. Webp - 通过 gif2webp
  3. gifsicle 压缩

三者比较可以参考下这个地址 👈

APNG

直接通过 gif 转 apng 经测试不行,可能体积会更大。可以在设计源头上去做处理,具体需要测试。和 webp 一样仍然有兼容性问题。

gif2webp

# 最终结果 1.8M -> 1.2M
gif2webp -mt -q=70 x.gif -o y.gif

需要注意的是,gif2webp 默认是采用无损压缩的,所以压缩下来体积仍然很大,尝试一下方案:

# 最终结果 1.8M -> 453kb
gif2webp -mt -q=70 -lossy x.gif -o y.gif

另外 gif2webp 命令行默认是使用 4 个压缩方法的,上限可以到 6 个:

# 最终结果 1.8M -> 402kb
gif2webp -mt -q=70 -lossy -m 6 x.gif -o y.gif

gifsicle

# 最终结果 1.8M -> 983kb
gifsicle -O3 --lossy=100 x.gif -o y.gif

总结下:

  1. gif2webp/gifsicle 最终压缩出来的结果体积相差还比较大,但是看起来几乎无区别
  2. 大部分情况下,gif2webp 压缩出来的效果要强于 gifsicle。建议 gif 同 jpg 一样分别走两道压缩,客户端仍然优先取 webp
  3. 如果需要通过 gif2webp 转格式的话,没必要再经过 gifsicle 压缩一道了,两者体积差不多
  4. 存在那种人为将普通 jpg/png 拓展名直接改为 gif 的行为,这时候 gif2webp/gifsicle 就转不了了,要么压不出来,要么压出来的质量会更大

ssim 算法对比图片匹配度

压缩出来的图片,一般只能肉眼去判断质量,这样子不太可靠,姿势也不雅观。除了上述针对于 jpg 的 jpeg-compare,也可更全面通过 ssim 算法来计算图片匹配度,从而得到最理想的图片。在官方演示中,号称比 PSNR 或 MSE 更好:

ssim

MSE(Mean Squared Error) 为均方误差,各测量值误差的平方和的平均值的平方根。

需要注意文本占比较大的图片

如上,需要注意文本占比较大的图片,有写算法或者参数不适合的话,可能会过于模糊,一定要针对这类图片进行测试。一些示例:

jpg 对比举例 👈

png 对比举例 👈