|
| 1 | +--- |
| 2 | +title: "当Hugo遇上AVIF,加速图片加载" |
| 3 | +date: 2024-09-30T22:01:45+08:00 |
| 4 | +draft: false |
| 5 | +tags: |
| 6 | + - 博客优化 |
| 7 | + - hugo |
| 8 | + - avif |
| 9 | + - imagemagic |
| 10 | + - github |
| 11 | +--- |
| 12 | + |
| 13 | + |
| 14 | + |
| 15 | +这篇文章会介绍基于Github Workflow使用ImageMagick生成AVIF图片,来优化Hugo站点的加载速度。 |
| 16 | + |
| 17 | +## 背景 |
| 18 | + |
| 19 | +AVIF是什么? |
| 20 | + |
| 21 | +> AVIF(AV1 Image File Format)是一种基于AV1视频编码标准的图像文件格式。 |
| 22 | +> |
| 23 | +> A modern image format based on the AV1 video format. |
| 24 | +> |
| 25 | +> AVIF generally has better compression than WebP, JPEG, PNG and GIF and is designed to supersede them. |
| 26 | +
|
| 27 | + |
| 28 | + |
| 29 | +在2024年,绝大部分浏览器都已经支持了AVIF格式。 |
| 30 | + |
| 31 | +ImageMagick是什么? |
| 32 | + |
| 33 | +> ImageMagick® is a free, open-source software suite, used for editing and manipulating digital images. |
| 34 | +> |
| 35 | +> It can be used to create, edit, compose, or convert bitmap images, and supports a wide range of file formats, including JPEG, PNG, GIF, TIFF, and Ultra HDR. |
| 36 | +
|
| 37 | +ImageMagick是一款用于图像处理的一个工具。 |
| 38 | + |
| 39 | +## 对比 |
| 40 | + |
| 41 | +AVIF说的这么好,我们来验证对比一下。 |
| 42 | + |
| 43 | +对于一张PNG的图片,使用ImageMagick分别生成WEBP和AVIF格式的图片,文件大小如下: |
| 44 | + |
| 45 | +``` |
| 46 | +-rw-r--r--@ 1 liudon staff 1.1M 9 29 23:02 20240922-170856.png |
| 47 | +-rw-r--r--@ 1 liudon staff 15K 9 29 23:08 20240922-170856.png.avif |
| 48 | +-rw-r--r--@ 1 liudon staff 25K 9 29 23:07 20240922-170856.png.webp |
| 49 | +``` |
| 50 | + |
| 51 | +WEBP比PNG要节省90%左右,AVIF要比WEBP再小40%左右。 |
| 52 | + |
| 53 | +效果出奇的好,开搞吧。 |
| 54 | + |
| 55 | +## 使用 |
| 56 | + |
| 57 | +### 1. 生成AVIF文件 |
| 58 | + |
| 59 | +博客使用了Github Workflow来进行部署,所以生成ImageMagick的工作也就放在了Github Workflow上。 |
| 60 | + |
| 61 | +``` |
| 62 | +- name: Compress Image |
| 63 | +run: | |
| 64 | + sudo apt-get update |
| 65 | + sudo apt-get install -y imagemagick libheif-dev |
| 66 | + find ./content/posts/ -type f \( -name "*.jpg" -o -name "*.png" -o -name "*.jpeg" \) -exec convert {} -resize 1080x\> -quality 75 -define webp:image-hint=photo {}_1080x.webp \; |
| 67 | + find ./content/posts/ -type f \( -name "*.jpg" -o -name "*.png" -o -name "*.jpeg" \) -exec convert {} -resize 1080x\> {}_1080x.avif \; |
| 68 | +``` |
| 69 | + |
| 70 | +新增压缩图片步骤,同时生成WEBP和AVIF格式文件。 |
| 71 | + |
| 72 | +含义说明,可以自行调整: |
| 73 | + |
| 74 | +``` |
| 75 | +-resize 1080x> 表示缩放到1080宽,>表示只有在原图宽大于1080时才进行缩放,小于不做处理。 |
| 76 | +-quality 75 表示处理后图片质量,值越小图越小,图片也越不清晰。 |
| 77 | +-define webp:image-hint=photo 这里是为了对齐Hugo自身的图片处理参数。 |
| 78 | +``` |
| 79 | + |
| 80 | +### 2. 使用AVIF文件 |
| 81 | + |
| 82 | +修改`layouts/_default/_markup/render-image.html`文件: |
| 83 | + |
| 84 | +``` |
| 85 | +{{- $respSizes := slice 1080 -}} |
| 86 | +{{- $dataSizes := "(min-width: 768px) 1080px, 100vw" -}} |
| 87 | +
|
| 88 | +{{- $holder := "GIP" -}} |
| 89 | +{{- $hint := "photo" -}} |
| 90 | +{{- $filter := "box" -}} |
| 91 | +
|
| 92 | +{{- $Destination := .Destination -}} |
| 93 | +{{- $Page := .Page -}} |
| 94 | +{{- $Text := .Text -}} |
| 95 | +{{- $Title := .Title -}} |
| 96 | +
|
| 97 | +{{- $responsiveImages := (.Page.Params.responsiveImages | default site.Params.responsiveImages) | default true }} |
| 98 | +
|
| 99 | +{{ with $src := .Page.Resources.GetMatch .Destination }} |
| 100 | + {{- if $responsiveImages -}} |
| 101 | + {{- $imageTypes := slice -}} |
| 102 | + {{- if and hugo.IsExtended (ne $src.MediaType.Type "image/webp") -}} |
| 103 | + {{- $imageTypes = $imageTypes | append "avif" -}} <!-- avif need the first --> |
| 104 | + {{- $imageTypes = $imageTypes | append "webp" -}} |
| 105 | + {{- end -}} |
| 106 | + {{- if gt (index $respSizes 0) $src.Width -}} |
| 107 | + {{- $respSizes = slice $src.Width -}} |
| 108 | + {{- end -}} |
| 109 | + <picture> |
| 110 | + {{- range $imageType := $imageTypes -}} |
| 111 | + <source type="image/{{ $imageType }}" srcset=" |
| 112 | + {{- $compressedImage := printf "%s_1080x.%s" $Destination $imageType -}} |
| 113 | + {{- $cmSrc := $Page.Resources.GetMatch $compressedImage -}} |
| 114 | + {{- if $cmSrc -}} |
| 115 | + <!--avif/webp file exist--> |
| 116 | + {{ $cmSrc.RelPermalink | absURL}} 1080w |
| 117 | + {{- else -}} |
| 118 | + <!-- hugo not support avif format --> |
| 119 | + {{ if ne $imageType "avif" }} |
| 120 | + {{- with $respSizes -}} |
| 121 | + {{- range $i, $e := . -}} |
| 122 | + {{- if ge $src.Width . -}} |
| 123 | + {{- if $i }}, {{ end -}}{{- ($src.Resize (print . "x " $imageType " " $filter) ).RelPermalink | absURL}} {{ . }}w |
| 124 | + {{- end -}} |
| 125 | + {{- end -}} |
| 126 | + {{- end -}} |
| 127 | + {{ end }} |
| 128 | + {{- end -}}" sizes="{{ $dataSizes }}" /> |
| 129 | + {{- end -}} |
| 130 | + <img src="{{ $Destination | safeURL }}" width="{{ .Width }}" height="{{ .Height }}" alt="{{ $Text }}" title="{{ $Title }}" loading="lazy" /> |
| 131 | + </picture> |
| 132 | + {{- else }} |
| 133 | + <img src="{{ $Destination | safeURL }}" width="{{ $src.Width }}" height="{{ $src.Height }}" alt="{{ $Text }}" title="{{ $Title }}" loading="lazy" /> |
| 134 | + {{- end }} |
| 135 | +{{ end }} |
| 136 | +``` |
| 137 | + |
| 138 | +这里如果AVIF/WEBP文件已经存在,那么直接使用对应文件(注意:我这里都是生成的1080宽,如果你有调整记得一起调整); |
| 139 | + |
| 140 | +否则会使用Hugo自身的Image Processing生成对应格式文件。 |
| 141 | + |
| 142 | +## 效果 |
| 143 | + |
| 144 | +优化前: |
| 145 | + |
| 146 | + |
| 147 | + |
| 148 | +优化后: |
| 149 | + |
| 150 | + |
| 151 | + |
| 152 | +从WEBP切换到AVIF,文件大小减少了30%左右。 |
| 153 | + |
| 154 | +哈哈,太棒了,效果杠杠滴。 |
| 155 | + |
| 156 | +唯一的缺点就是每次都是全量生成图片,Workflow执行略久些(我的要5分钟左右),这里后面再优化。 |
| 157 | + |
| 158 | +从23年11月开始有的想法,在24年9月最后一天终于实现了。🎉🎉🎉 |
| 159 | + |
0 commit comments