图片体积太大咋办,AVIF格式真能省一半空间?

2,752字
12–17 分钟
in

网页加载慢很多时候是图片拖后腿。AVIF这种新格式能把JPG直接砍掉一半体积,画质还差不多。下面说说怎么用浏览器和命令行工具把普通图片转成AVIF,全程实操不废话。

目录

啥是AVIF

AVIF全称AV1图像文件格式,2019年由开放媒体联盟正式发布。这玩意儿主打压缩效率,跟JPG比能省50%空间,比WebP再省20%,同时支持10位、12位色深和多色彩空间。简单说就是:同体积下画质更好,同画质下体积更小。之前JPG压缩狠了会出现色带断层,WebP好点但仍有块状模糊,AVIF把这些毛病又压下去一截。

在线工具

Squoosh

Squoosh是个跑在浏览器里的图片压缩神器,完全免费,单张图片限制4MB。操作流程如下:

  1. 打开Squoosh官网(直接搜名字就能找到)
  2. 把本地图片拖进页面中间那个大方框,支持PNG、JPG、WebP等常见格式
  3. 图片加载后,右侧面板找到“Compress”下拉菜单,选择AVIF
  4. 下方会出现质量滑块,默认75,往左拉体积更小但画质下降,往右拉画质更好但体积变大。建议先拉到80,预览窗口看效果
  5. 右侧底部会显示压缩后的文件大小和节省百分比,比如“24KB ↓ 62%”
  6. 点击右下角的下载按钮,保存.avif文件

实际操作中注意:Squoosh的AVIF编码选项里有个“Effort”参数,范围0-9,数值越高压缩时间越长但体积越小。默认是4,电脑性能好的可以调到6或7,别直接上9,等得想摔鼠标。另外4MB限制意味着原图太大就先在外面用别的工具缩一下尺寸。

Cloudinary

Cloudinary提供免费在线转换,没有文件大小限制。步骤更简单:

  1. 访问Cloudinary的AVIF转换页面(搜“Cloudinary AVIF converter”)
  2. 点击上传区域,选取图片或直接拖进去
  3. 几秒后页面显示转换结果,旁边有下载按钮
  4. 点下载拿到AVIF文件

这个工具没啥可调的参数,纯傻瓜式。但要注意:上传的图片如果包含隐私内容就别用了,毕竟是云端处理。另外转换后的文件名是随机哈希值,下载后最好马上重命名,不然过两天自己都认不出是啥图。

命令行工具

avif-cli

avif-cli基于Node.js,适合批量处理一堆图片。需要Node版本12.13.0以上。

安装步骤:

打开终端(Windows用PowerShell或cmd,Mac/Linux用自带的终端),输入:

npm install avif

转换单张图片:

npx avif --input="./meinv.jpg" --output="./output/meinv.avif"

批量转换整个文件夹:

npx avif --input="./imgs/*" --output="./avif输出/" --verbose

--verbose参数让终端显示处理进度,哪张图成功了哪张失败了清清楚楚。

进阶玩法:--quality=65参数控制质量,默认75,范围0-100。加--speed=4控制压缩速度,0最慢体积最小,9最快体积稍大。日常用--quality=70 --speed=6组合拳,速度和效果平衡得不错。

跑命令前务必确认--output指定的文件夹已经存在,这工具不会自动建目录。要是忘了建,它直接报错“ENOENT”,小白一看直接懵。

sharp

sharp同样是Node.js生态的图片处理库,功能更猛,不仅能转AVIF,还能裁剪、旋转、模糊、调色。

安装:

npm install sharp

新建一个文件,比如zhuanhuan.js,写入以下代码:

const sharp = require('sharp')

// 单张转换函数
function baBaBianAVIF() {
  sharp('./原始图片/风景照.png')
    .toFormat('avif', { quality: 70 })
    .toFile('./压缩后的/风景照.avif')
    .then(info => console.log('搞定!体积:', info.size))
    .catch(err => console.error('翻车了:', err))
}

// 跑起来
baBaBianAVIF()

批量处理整个文件夹:

const sharp = require('sharp')
const fs = require('fs')
const path = require('path')

const inputDir = './待处理图片'
const outputDir = './AVIF成品'

// 确保输出文件夹存在
if (!fs.existsSync(outputDir)) {
  fs.mkdirSync(outputDir, { recursive: true })
}

// 读取输入文件夹里所有文件
fs.readdir(inputDir, (err, files) => {
  if (err) return console.error('读文件夹失败', err)

  files.forEach(file => {
    const ext = path.extname(file).toLowerCase()
    // 只处理图片格式
    if (['.jpg', '.jpeg', '.png', '.webp'].includes(ext)) {
      const inputPath = path.join(inputDir, file)
      const outputPath = path.join(outputDir, file.replace(ext, '.avif'))

      sharp(inputPath)
        .toFormat('avif', { quality: 75, effort: 6 })
        .toFile(outputPath)
        .then(() => console.log(`${file} → 转换成功`))
        .catch(e => console.error(`${file} 转换失败:`, e))
    }
  })
})

保存文件后在终端执行:

node zhuanhuan.js

sharp的effort参数跟Squoosh那个一样,0-9,默认4。写脚本时记得加错误捕获,不然碰到损坏的图片整个程序就炸了。另外sharp依赖libvips,Windows上偶尔安装报错,这时候用npm install --platform=win32 sharp强行指定平台重装一般能解。

一个小坑

AVIF虽然省空间,但不是所有浏览器都认得。老版Safari、IE(这玩意儿还没死透)直接打不开。线上用的话可以搞个回退方案:<picture>标签里先写AVIF,后面再写JPG或WebP当备胎。代码大概长这样:

<picture>
  <source srcset="拍立得.avif" type="image/avif">
  <img src="拍立得.jpg" alt="照片描述">
</picture>

这样新浏览器自动选AVIF,老浏览器乖乖下载JPG,两边不得罪。