fix(next/image): reduce avif sharp effort from 4 to 3 for faster encoding (#73030)

## History
In a previous PR https://github.com/vercel/next.js/pull/65846 the chroma
subsampling setting was removed for AVIF images. This caused the default
of `4:4:4` to be used which increased the image size and CPU a lot.

I considered switching back to `4:2:0` but found that reducing the
`effort: 3` actually yielded significantly better performance with only
a slight difference in size.

## Benchmark

For example, take this PNG that has a width of 1805.

```
curl -JO https://images.bookroo.com/site/landing/homepage/book-collection.png
```

Using `w=1850` and `q=75`:
```
Current: 2_778ms and 153_364 bytes
 Chroma: 2_214ms and 132_927 bytes
This PR: 1_265ms and 158_862 bytes
```

Using `w=1500` and `q=75`:
```
Current: 625ms and 95_810 bytes
 Chroma: 524ms and 89_500 bytes
This PR: 185ms and 99_127 bytes
```

Using `w=1200` and `q=75`:
```
Current: 506ms and 74_738 bytes
 Chroma: 407ms and 68_998 bytes
This PR: 144ms and 77_955 bytes
```

For this particular image, the size will increase a bit but there are
other images I tested where the size was actually smaller. So its a big
improve in CPU usage compared to reverting to the chroma subsampling
setting.

We also are keeping AVIF smaller than WebP which is the expected
behavior.

## Learn More
[Chroma subsampling](https://en.wikipedia.org/wiki/Chroma_subsampling)
is the practice of encoding images by implementing less resolution for
[chroma](https://en.wikipedia.org/wiki/Chrominance)
[information](https://en.wikipedia.org/wiki/Information) than for
[luma](https://en.wikipedia.org/wiki/Luma_(video)) information, taking
advantage of the human visual system's lower acuity for color
differences than for luminance

Image compression deep-dive video:
https://www.youtube.com/watch?v=F1kYBnY6mwg

Sharp Options: https://sharp.pixelplumbing.com/api-output#avif
This commit is contained in:
Steven
2024-11-22 14:46:50 +00:00
committed by GitHub
parent d07422f931
commit d27182cfb1
+2 -2
View File
@@ -546,9 +546,9 @@ export async function optimizeImage({
}
if (contentType === AVIF) {
const avifQuality = quality - 20
transformer.avif({
quality: Math.max(avifQuality, 1),
quality: Math.max(quality - 20, 1),
effort: 3,
})
} else if (contentType === WEBP) {
transformer.webp({ quality })