Repository navigation
3.14.0
·
70 commits
to master
since this release
Immutable
release. Only release title and notes can be modified.
3.14.0
New
- Lossless
encodeJXL()compresses like libjxl'scjxl -e 3(effort 3) by default: about 15% smaller files for
photos (a 1920x1080 photo: 1.17 MB instead of 1.39 MB) and 13% for graphics, within 1-2% of cjxl's sizes. It
uses a palette of up to 1024 colors where it fits (else palettes of the channels that use few of their values),
YCoCg and the weighted predictor in contexts of its error, and codes the groups in worker threads
(JXLEncodeOptions.threads, the same files): the photo takes 0.24 s with 8 threads, 0.65 s with one.effort: 0
keeps the fast mode, byte for byte whatcjxl -e 1writes (0.11 s for the photo);effortapplies to lossless
compression now too.
Performance
- Lossy
encodeJXL()is faster: a 1920x1080 photo at quality 90 takes 1.6 s instead of 2.3 s at effort 1 and 2.4 s
instead of 4.8 s at effort 2 on one thread; with 8 threads 0.72 s instead of 0.81 s and 0.95 s instead of 1.46 s
(3840x2160: 1.6 s instead of 2.0 s and 2.5 s instead of 4.1 s). The 4x8 and AFV transforms are computed directly
instead of by a 64x64 matrix, the varblock search rounds withoutMath.round()(slow in V8), patch search skips
large components after a quick labeling, and the search is split into smaller pieces for the threads. The files stay
the same, except for rare coefficients the new transforms round differently (2 of 108 test encodes, both the same
size).
Fixes
- Invalid options throw a
RangeErrornaming them before any work, instead of failing inside an encoder or being
ignored:encodeAVIF():effortother than 0, 1 or 2 failed with aTypeErrordeep in the encoder,qualityand
alphaQualityoutside 0-100 were accepted, and an unknownsubsamplingsilently meant 4:4:4 (now a
TypeError).encodeWebP(),Animation.encodeWebP()andAnimation.webpEncoder()checkeffortfor lossless images too
(which don't use it).NaNis refused as GIFqualityand APNGcompression(out of range values are still clamped, like PNG's), as
dominantColor()'sthresholdand asrenderSVG()'s size (which threw about the image's width); negative font
sizes inrenderText()(which rendered an empty image);maxPixelsthat isn't positive inImage.decode()and
Animation.decode()(which reported every image as too large); fractional loop counts innew Animation().
Animation.decode()reports invalidthreadsandmaxPixelsas such, not as damaged image data.Image.decode()refuses GIFs with a hint atAnimation.decode()instead of "Unsupported image type".- SVG
feDisplacementMapapplies itsscaleonce, like the specification and browsers (it multiplied by it twice, like
resvg, so at typical scales the whole input was displaced out of the filter region and disappeared), and reads the
map's colors unpremultiplied.