Skip to content

v3.5.0: AVIF and JPEG XL encoding

Choose a tag to compare

@matmen matmen released this 25 Oct 13:45
Immutable release. Only release title and notes can be modified.

This release encodes AVIF and lossless JPEG XL, and decodes JPEG XL about 25% faster. Like every codec in ImageScript, both encoders are plain TypeScript: no WebAssembly and no native code. There are no breaking API changes.

await image.encodeAVIF();                                   // quality 60, like avifenc -q 60
await image.encodeAVIF({ quality: 80, subsampling: '4:2:0' });
await image.encodeAVIF({ quality: 100 });                   // lossless
await image.encodeJXL();                                    // lossless, like cjxl -e 1

New

AVIF encoding

encodeAVIF({ quality, alphaQuality, subsampling, effort }) encodes AVIFs with an AV1 encoder of its own. Its syntax mirrors the dav1d based decoder, so dav1d decodes the files to exactly the encoder's reconstruction.

  • Rate-distortion search: partitions from 64×64 to 8×8, the intra modes with their angle deltas, chroma from luma, palettes and the transform types, coefficients quantized by rate and distortion, and the deblocking level and CDEF strengths chosen by the filtered image
  • Screenshots and graphics get palettes: such images are often 10% to nearly 50% smaller
  • Greyscale images are encoded as monochrome
  • Transparency becomes a monochrome alpha image, lossless by default (alphaQuality). In lossy images, fully transparent pixels get smooth colors that cost fewer bits
  • quality (0-100, default 60) maps to the quantizer like avifenc's -q. 100 is lossless
  • subsampling: '4:4:4' (default) or '4:2:0'
  • effort (0-2, default 1): how many modes and partitions are tried. 0 is about a third faster, 2 takes about three times as long for files 1-3% smaller

On photos the files are within a few percent of libaom's (avifenc's default speed) at the same PSNR. Encoding is slower, about 3 seconds for a 1024×768 photo at the default effort.

JPEG XL encoding

encodeJXL() encodes lossless JPEG XLs with a port of libjxl's fast lossless encoder. The codestream is byte for byte what cjxl -e 1 writes on CPUs with AVX2 or NEON (libjxl's output depends on the CPU). Images of at most 511 colors besides black get a palette, others YCoCg. Greyscale images are encoded as one channel and alpha only if the image has transparency. Unlike libjxl, two colors whose hashes collide within 8 pixels don't end up as one: such images are encoded with YCoCg instead.

Performance

  • JPEG XL decoding is about 25% faster: lossy 2048×1536 images take about 0.87 s instead of 1.2 s, lossless ones of the default effort 2.6 s instead of 3.7 s. The output is the same, except for rounding: linear light becomes sRGB like libjxl does it.

The encoders grow the package from 1.8 MB to 1.9 MB unpacked (506 kB packed).