From d27182cfb1858a44afb62c5373021691a3f02224 Mon Sep 17 00:00:00 2001 From: Steven Date: Fri, 22 Nov 2024 09:46:50 -0500 Subject: [PATCH] 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 --- packages/next/src/server/image-optimizer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next/src/server/image-optimizer.ts b/packages/next/src/server/image-optimizer.ts index a7cb884dc5927..607bd9636b8dd 100644 --- a/packages/next/src/server/image-optimizer.ts +++ b/packages/next/src/server/image-optimizer.ts @@ -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 })