Repository navigation
This release renders SVG text, converts images with embedded ICC color profiles to sRGB when decoding, hints glyphs exactly like FreeType, and adds patches to lossy JPEG XL and alpha quality to lossy WebP. SVG rendering also gains blend modes, transform-origin, paint-order and context paints. Like every codec in ImageScript, it's plain TypeScript: no WebAssembly and no native code. There are no breaking API changes, but decoded pixels of images with a non-sRGB ICC profile change (see below).
await Image.renderSVG(svg, { fonts: [await fs.readFile('Inter.ttf')] }); // <text>, <tspan>, <textPath>, ...
await Image.decode(p3Photo); // now converted from Display P3 to sRGB
await Image.decode(p3Photo, { applyColorProfile: false }); // the stored values, as before
await image.encodeJXL({ quality: 90, effort: 2 }); // patches for screenshots and text
await image.encodeWebP({ quality: 80, alphaQuality: 50 });New
SVG text
Image.renderSVG() renders <text>, <tspan>, <tref> and <textPath> with the fonts passed as SVGOptions.fonts and the ones the SVG embeds with @font-face (TrueType, OpenType and WOFF data: URIs).
- Font matching like browsers match installed fonts:
font-family, thenfont-stretch,font-styleandfont-weightby CSS Fonts' algorithm, generic families by the fonts' panose and pitch flags, and missing characters from the other fonts - Layout ported from resvg (usvg): chunks shaped as a whole (kerning and ligatures across spans), bidirectional text,
x/y/dx/dy/rotatelists,text-anchor,letter-spacing,word-spacing,textLength,baseline-shift,dominant-baseline,text-decoration, text along paths, vertical text,font-variant: small-caps, thefontshorthand andxml:space - Painting like shapes (gradients, patterns, strokes,
paint-order), in clip paths and bounding boxes, with color glyphs (COLR v0/v1, CBDT, sbix, SVG) - 359 of resvg's 431 text tests pass, plus 41 of its other tests that contain text. Variable fonts aren't supported yet
ICC color profiles
Decoding converts images with an embedded ICC profile to sRGB, the way browsers display them: PNG (iCCP), JPEG (APP2), WebP (ICCP, animations too), AVIF (colr) and TIFF. Display P3 photos from phones and Adobe RGB or ProPhoto images no longer look washed out.
- Matrix/TRC profiles (RGB and gray) are applied relative colorimetric. The results are within 1 of LittleCMS's
- Profiles with only lookup tables, CMYK profiles and sRGB profiles leave the pixels as they are
applyColorProfile: false(inImage.decode()andAnimation.decode()options) keeps the stored values- A 1920x1080 image takes about 35 ms to convert
Patches in lossy JPEG XL
encodeJXL({ quality, effort: 2 }) stores repeated text-like features (glyphs on the flat backgrounds of screenshots) once in a reference frame and adds them back where they occur, like libjxl's patches (cjxl -e 7), ported from it. A page of text takes 62% fewer bytes, screenshots 1-2% fewer. Other images come out the same.
Alpha quality in lossy WebP
encodeWebP({ quality, alphaQuality }) (0-100, default 100; also for animations and Animation.webpEncoder()) keeps fewer alpha levels below 100, with the same alpha values as cwebp's -alpha_q. For example, potato.png's alpha plane takes 1.3 kB at 50 instead of 1.9 kB, and a gradient takes 4.3 kB instead of 16.7 kB.
SVG rendering
- Blending:
mix-blend-mode(all 16 modes andplus-lighter) andisolation: isolate. All 23 of resvg's tests for them pass transform-originon elements, clip paths, gradients and patterns (21 of 23 tests)paint-order(fill, stroke, markers; 12 of 14 tests)context-fill/context-strokein markers and<use>(13 of 16 tests)shape-rendering: crispEdges/optimizeSpeeddraw without antialiasing, and the root'sbackground-coloris usedfont-sizeresolvesem,ex, percentages and keywords against the parent's size everywhere;font-weightacceptsbolder/lighter
Text rendering
Hinting (renderText with hinting) now places every point exactly where FreeType's TrueType interpreter (v35) puts it. This was checked on 18 fonts at 8-48 px and on all 6190 glyphs of DejaVu Sans at 4 sizes. Before, up to 30% of the glyphs of some fonts were off by fractions of a pixel, and a few were off by up to 4 pixels.
Fixes
- SVG: zero-length dashes at the start of a path get caps (square ones turned along the path)
- SVG: shapes without a bounding box painted with an
objectBoundingBoxgradient or pattern use its fallback color - SVG:
display: noneelements no longer count towards group bounding boxes - SVG:
overflow="inherit"on markers and nested viewports takes the parent's value - SVG: path data ends at the first character that isn't part of it, instead of that character being skipped
- SVG: CR LF and CR line ends read as line feeds, like in XML parsers