WebP

6 5月

简单的图片处理汇总。

  • 图片比较
    • JPEG / JPG
    • PNG8 / PNG24
    • SVG
    • 雪碧图(CSS Sprites)
    • Base64
    • WebP
  • 图片压缩 & 转换
  • 优雅降级

图片比较

JPEG / JPG

特点是有损压缩,体积小,不支持透明。适用于呈现色彩丰富的图片,常作为大的背景图,轮播图,banner图。

JPG以24位存储图,可以呈现多达1600万种颜色,足以应对绝大多数场景下对色彩的要求。

最大的特点是有损压缩。压缩算法非常高效,即使是“有损”压缩,仍然是一种高质量的压缩方式。当图片体积被压缩到50%以下时,JPG仍然可以保持住60%的品质。有损压缩在如轮播图上确实很难露出马脚,但处理矢量图形,logo等线条感强,颜色对比强烈的图像时,压缩导致的图片模糊会相当明显。

另外,JPEG不支持透明度处理,透明图片需要用PNG。

PNG8 / PNG24

特点是无损压缩,体积大,支持透明。适用于小logo,颜色简单对比强烈的图片或背景(复杂的,色彩层次丰富的图片一般会用JPG)。

8和24都是二进制位数,8位最多支持256种颜色,24位可以呈现1600万种颜色。

PNG是无损压缩的高保真图片格式,有比JPG更强的色彩表现力,对线条的处理更加细腻,对透明度有良好的支持。弥补了JPG的局限性。

唯一的缺点是体积大。

SVG

特点是支持独立文本文件,体积小,不失真,兼容性好。

SVG(可缩放矢量图形)是一种基于XML语法的图像格式,对图像的处理不是基于像素点,而是基于对图像的形状描述,和其他图片种类有本质的区别。

可以写代码一样定义SVG,将它写在HTML里,成为DOM的一部分。也可以写入.svg后缀的独立文件中(.svg的使用方式和其他普通图片无异)。.svg文件可以被其他工具读取和修改,具有较强的灵活性。

相比PNG和JPG,SVG的体积更小,可压缩性更强。最显著的优点是:作为矢量图,可以无限放大而不失真。所以SVG在视网膜显示屏上,也可以展现出很好的成像品质。一张SVG足以适配n种分辨率。

缺点是渲染成本比较高,对性能来说不利。而且存在学习成本(因为它是可编程的)。

雪碧图(CSS Sprites)

将各种小图标和小背景合并到一张图片上,用CSS定位来显示其中的每一部分,可以减少加载网页图片的HTTP请求数,从而提升网页性能。

Base64

是一种基于8bit字节码的编码方式,可以直接将编码结果写入HTML或CSS中。

可以理解为雪碧图的补充,同样可以减少图片的HTTP请求数。适用于一些更新频率非常低的小图片。

缺点是编码后的体积通常会比图片的原始体积大1/3,如果将大图进行base64,体积增大的更加明显,即使减少了HTTP请求,但文件体积的增加可能导致得不偿失。

WebP

旨在加快图片的加载速度,像JPEG一样对细节丰富的图片信手捏来,像PNG一样支持透明,像GIF一样可以显示动图,集各种图片格式的优点于一身。

缺点是新推出,存在浏览器兼容性问题,需要考虑优雅降级。还会增加服务器的负担,和编码JPG文件相比,编码同样质量的WebP文件会占用更多的计算资源。

Android和iOS的app只要引入Google提供的解码库,都可以很轻松的支持WebP格式。不过在web上,WebP的支持还不是很广泛,具体可查Can I Use。

图片压缩 & 转换

大多图片云服务都支持上传的图片转成webp格式(如果不支持,放弃它^_^),或者你在本地用imagemin将图片转成webp格式,无脑上传到静态服务器上也行。

imagemin提供了很多插件,例如:

格式 有损 无损
JPEG imagemin-mozjpeg imagemin-jpegtran
PNG imagemin-pngquant imagemin-optipng
GIF imagemin-giflossy imagemin-gifsicle
SVG imagemin-svgo
WebP imagemin-webp

用例参照官网也很简单,按官网示例将功能实现,是我们底层码农的尊严:

const fse = require('fs-extra');
const path = require('path');
const imagemin = require('imagemin');
const imageminMozjpeg = require('imagemin-mozjpeg');
const imageminPngquant = require('imagemin-pngquant');
const imageminWebp = require('imagemin-webp');

const srcDir = path.resolve(__dirname, '../tmp/images');
const distDir = path.resolve(__dirname, '../tmp/build/images');

(async() => {
    await imagemin([`${srcDir}/*.{jpg,png}`], distDir, {
        plugins: [
            imageminMozjpeg({ quality: 70 }),
            imageminPngquant({ quality: [0.6, 0.8] })
        ]
    });

    await imagemin([`${distDir}/*.{jpg,png}`], distDir, {
        use: [
            imageminWebp({ quality: 50 })
            // imageminWebp({lossless: true})    // 无损压缩
        ]
    });
})();

优雅降级

HTML端可以使用<picture>标签,指定多种格式的图片,保证优雅降级。

<picture class="picture">
    <source type="image/webp" srcset="image.webp"> 
    <img class="image" src="image.jpg">
</picture>

除了上面<picture>标签指定多种格式的图片外,很多懒加载的页面常见的做法是:将图片的URL放在img元素的一个自定义data属性中,如data-src,然后在适当的时机,例如页面滑动到可视区域内,将URL放入src属性。

同理,我们可以根据浏览器是否支持WebP格式,给img元素赋予不同的src值:

function checkWebp(callback) {
    var img = new Image();
    img.onload = function () {
        var result = (img.width > 0) && (img.height > 0);  //通过图片宽度值判断图片是否可以显示
        callback(result);
    };
    img.onerror = function () {
        callback(false);
    };
    img.src = 'data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA';
}

function showImage(useWebp){
    var imgs = Array.from(document.querySelectorAll('img'));

    imgs.forEach(function(i){
        var src = i.attributes['data-src'].value;
        if (useWebp){
            src = src.replace(/\.jpg$/, '.webp');
        }
        i.src = src;
    });
}

checkWebp(showImage);

不想像上面这样全部img都替换的话,可以将判断是否支持webp的结果,存入localStorage,每次要替换时,从localStorage中读取浏览器是否支持,不用每次都检查一遍。

其他方式,如引入js版webp的解码器,将所有的webp图片用JS解码后转换为base64,然后替换掉原来的URL,但考虑到JS解码较慢,暂不推荐。

发表评论

电子邮件地址不会被公开。 必填项已用*标注