1 Commits
Author SHA1 Message Date
clawbot f6a39f2e14 Save PNG compressed, WebP at effort 4 and AVIF at effort 1 (closes #232)
check / check (push) Waiting to run
Each output format now has its own govips export with its settings
named, in place of govips' generic Export, which sent libvips a zero for
some settings it was not given: PNG had no compression and WebP effort
0. PNG now gets libvips' default compression, 6, and WebP its default
effort, 4. GIF was already at libvips' default effort, and JPEG output
is unchanged.

AVIF was at libvips' default effort, 4, which takes minutes for an
8192x8192 image with one libvips thread, far past the default
downstream_timeout; effort 1 takes about 12 seconds. A 16-bit source,
which libvips would save with 12 bits per sample, gets 8: at effort 1,
12 bits take about 54 seconds.

Model: opus-5-5
2026-10-08 10:33:53 +00:00
3 changed files with 11 additions and 7 deletions
+4 -2
View File
@@ -38,8 +38,10 @@ P2: security: per-IP rate limiting on the image routes
libvips' default effort, 7, and JPEG output is unchanged. AVIF is saved at
effort 1, where it had libvips' default, 4: with one libvips thread, an
8192x8192 image takes minutes at 4, far past the default `downstream_timeout`,
and about 12 seconds at 1. govips sends the AVIF effort only with a bit depth,
so AVIF is always 8 bits per sample, and a 16-bit source no longer gets 12.
and about 12 seconds at 1. AVIF is also saved with 8 bits per sample from a
16-bit source, which libvips would save with 12: a 16-bit 8192x8192 image
takes about 54 seconds at effort 1 with 12 bits, nearly all of the default
`downstream_timeout`, and about 12 with 8.
- 2026-10-08 JPEG XL as an input and output format (part of #222): a source
whose bytes start with either JPEG XL signature, the bare codestream's `FF 0A`
or the container's, is detected as `image/jxl`, which the upstream fetch
@@ -105,11 +105,12 @@ func TestImageProcessor_WebPAtDefaultEffort(t *testing.T) {
// TestImageProcessor_AVIFAtEffort1 verifies that AVIF is saved at effort 1
// with 8 bits per sample: the output is the size of the same image saved
// with those settings. The source is 16-bit, which libvips saves with 12
// bits when it is not given a bit depth.
// bits when it is not given a bit depth, and 640x480: at smaller sizes,
// such as 256x192, efforts 1 and 2 give the same output.
func TestImageProcessor_AVIFAtEffort1(t *testing.T) {
t.Parallel()
const width, height = 64, 48
const width, height = 640, 480
source := image.NewRGBA64(image.Rect(0, 0, width, height))
for y := range height {
+4 -3
View File
@@ -594,9 +594,10 @@ func exportWebP(img *vips.ImageRef, quality int) ([]byte, error) {
// takes about 12 seconds, and 2 nearly a minute.
const avifEffort = 1
// avifBitdepth is the AVIF bit depth. govips sends the effort only together
// with a bit depth. 8 is what libvips chooses for an 8-bit image; a 16-bit
// image, which libvips would save with 12 bits, gets 8 too.
// avifBitdepth is the AVIF bit depth, 8 bits per sample for every image.
// libvips would save a 16-bit image with 12, but at avifEffort that takes
// about 54 seconds for a 16-bit 8192x8192 image, nearly all of the default
// downstream_timeout, and about 12 seconds with 8.
const avifBitdepth = 8
// exportAVIF encodes img as lossy AVIF at quality, avifEffort and