Repository navigation
Releases
Releases · grigoriev/weasysvg
v0.6.2
Immutable
release. Only release title and notes can be modified.
Fixed
- A mask, a clip or a filter region in object bounding box units applies to an
<image>, and to a group that
holds one. WeasyPrint has no bounding box for an image: the mask was left out and the image drawn opaque.
The flat SVG writes the alpha of an image, since 0.6.1 each blur, as such a mask: weasysvg-convert, which
pandoc draws the SVG of a DOCX with, drew the shadow of the OpenStreetMap logo as a dark rectangle. - An element under a soft mask draws in a group, which the mask cuts once. PDFium and Poppler applied the mask
again inside the cell of a pattern: a gradient fill under a mask of 0.5 showed at 0.25, an SVG pattern fill
vanished. In PDF the soft mask of an image with alpha replaced the mask: a masked image drew unmasked. WeasyPrint
alone has these gaps too. feColorMatrixandfeComponentTransferrecolor the pixels of an image too, as they recolor the paint of a
shape, withinMAX_PIXEL_WORK. cairo turns a soft mask white through such a filter: the shading of the
flat SVG of Tux was missing.
Full changelog: v0.6.1...v0.6.2
v0.6.1
Immutable
release. Only release title and notes can be modified.
Changed
- In
weasysvg.portable()and the flat SVG, a blur becomes an image of its color with the blurred coverage as
its alpha, no longer levels of constant opacity. Word drew each level as a ring: the shadow of the
OpenStreetMap logo and the glare of Tux showed rings. An element that paints a gradient shows it through
that image as a soft mask. The flat SVG of Tux shrinks from 12.9 MB to 3.7 MB: each level of its blurred
gradients had cairo write the gradient again.band_pxsets the levels of gradients only. - In
weasysvg.portable(), a fill with a gradient of one color that fades fills each opacity level with that color,
where a level clipped the shading. A stroke keeps the shading: it paints through a pattern, and Poppler drew such
levels there washed out, over everything after them. cairo wrote a clip path, a group and a gradient per level, now one path. Word drew
the clipped levels of the OpenStreetMap lens wrongly: its digits came out sharp and opaque, where Chromium fades
them. - The flat SVG keeps the stops of a gradient that change it, within 0.1 % of a color channel and 0.001 of opacity:
cairo samples a shading into 257 stops. It rounds the coordinates of a path to two places, of a drawing eight
times as large. With both, the flat SVG of the OpenStreetMap logo shrinks from 6.6 MB to 2.9 MB, Tux from 3.7 MB
to 0.46 MB.
Fixed
- The flat SVG of
weasysvg-convertreports why pdftocairo wrote nothing. Killed by the kernel, it said only
"pdftocairo failed: "; under a memory limit, pdftocairo wrote an empty or cut file, exited with 0 and the flat
SVG passed. Now each case raises its ownConvertError: the signal, out of memory anywhere in the error output
(also an abort of Poppler or of C++), no output, and only the first line of the error output, which runs to
megabytes out of memory. - pdftocairo runs with at most 2 GB of address space on POSIX (
PDFTOCAIRO_MEMORY). cairo draws a soft mask of a
rotated radial shading with gigabytes: one such lens of the OpenStreetMap logo took 8.3 GB and 39 s, and the
whole logo was killed at 21 GB. It fails in a few seconds now. The flattening of weasysvg keeps no such soft
mask today, and stays under 50 MB.
Full changelog: v0.6.0...v0.6.1
v0.6.0
Immutable
release. Only release title and notes can be modified.
Added
- In
weasysvg.portable(), no opacity level of a gradient is narrower thanband_pxCSS px of the drawing as
shown, 1 by default, where its opacity changes most slowly. A small gradient gets fewer levels: a level per
1/64 was a third of a pixel over 20 px, and the flat SVG drew each one in full.weasysvg-convert --band-px
andto_svg(band_px=)set it; 0 keeps a level per 1/64. - The levels of a blur in
weasysvg.portable()followband_pxtoo: where the softest blurred edge rises
fastest, its contours lie at leastband_pxapart. A blur of 4 px takes 10 levels, not 64. The flat SVG of
the corpus shrinks from 261 MB to 25 MB and flattens in 6.4 s, not 84 s: Tux from 244 MB, which librsvg
refused to draw, to 12.9 MB, the Inkscape logo from 3.0 MB to 1.0 MB. Against the PDF none drifts further. - Both measure a length as shown along its own direction: a transform that stretches one axis and squeezes
the other keeps the levels along the stretched one.
Fixed
- The flat SVG of
weasysvg-convertwrites each clip path once. cairo wrote the clip of a shape again for every
paint inside it, and a gradient with a transparent stop is painted once per opacity level: the OpenStreetMap
logo came out at 29 MB, now 9.6 MB, and Word slowed down on it.
Full changelog: v0.5.0...v0.6.0
v0.5.0
Immutable
release. Only release title and notes can be modified.
Added
- In
weasysvg.portable(), a gradient with transparent stops or a fill opacity needs no soft mask. Its color stays
one shading; the opacity becomes its level sets along the gradient, strips or rings, each painted at a constant
opacity, within 1/64. cairo writes them as SVG gradients under clips, and Word draws the faded gradients of
draw.io. A radial gradient whose circles do not hold each other keeps its soft mask. - In
weasysvg.portable(), a blur and a drop shadow need no soft mask: the levels of the blurred coverage
are filled one over the other, each with a constant opacity, within 1/64 of the blur. The contours come from
the blurred coverage of the shape (levelsets.py), and a rect takes its exact blur, at any size. cairo
keeps them vector in a flat SVG, and Word draws the shadows of draw.io, Mermaid and blockdiag. - A clip path that one PDF clip could not express (a
<use>, several children, an even-odd child, bounding box
units) becomes one path of all its fills, each subpath turned so that nonzero fills their union. It was an alpha
soft mask, which Word does not draw and a printer may rasterize. Text, images, a child with a clip of its own
and a path that crosses itself keep the soft mask. Tux and the Inkscape logo now clip without one. - In
weasysvg.portable(), the blur of a<use>of one shape takes the exact blur of that shape, in any paint:
the glare of Tux, a shape filled with a gradient, needed a soft mask. - In
weasysvg.portable(), a mask of one gray or translucent shape is a clip to the shape and an opacity of the
element. A mask without a white area, or empty, hides the element without a soft mask. - The flat SVG of
weasysvg-convertwrites the opacity of a group as anopacity. cairo writes it as a mask of
one rect over the whole drawing, and Word draws only some masks.
Fixed
- Clip path children that turn opposite ways unite, as in Chromium. WeasyPrint added them to one nonzero path,
which cut a hole where they overlap. - The flat SVG of
weasysvg-convertkeeps the shape of each glyph. cairo writes a glyph as its outline hinted at
the size it is drawn: a bold label of 24 px came out wider and heavier in every viewer. The flat SVG is now
read from a PDF eight times as large, its size still the SVG's own. - A rect without a width or a height casts no shadow and no blur, as in Chromium: in a portable PDF its stroke
made a dot.
Full changelog: v0.4.0...v0.5.0
v0.4.0
Immutable
release. Only release title and notes can be modified.
Added
weasysvg-convert, a command line converter from SVG to PDF, PNG or a flat SVG. It accepts the options
ofrsvg-convertthat pandoc passes, so a service can install it under that name: pandoc then draws
<foreignObject>, filters and masks in a PDF and in the PNG fallback of a DOCX. Onlydata:URLs are
fetched. The PNG needs theconvertextra (PDFium), the flat SVG needspdftocairoof Poppler.weasysvg.portable(): inside it, a mask of opaque white areas, then opaque black ones, is a clip path
instead of a soft mask. cairo turns a soft mask into an image when it writes SVG, and lost the D2 cuts
under the edge labels. The flat SVG ofweasysvg-convertkeeps them vector, and Word draws them.
Full changelog: v0.3.1...v0.4.0
v0.3.1
Immutable
release. Only release title and notes can be modified.
Fixed
- In a
<foreignObject>, collapsible white space on either side of a<br>goes, as at the end and the start
of any line in Chromium. draw.io writes HTML labels indented, with a newline before each<br/>: WeasyPrint
kept a space at the end of each line, which moved centered text left by half a space, and white space after
the last<br/>made an empty line, which moved a label centered in a flex box up. A label of pdf-exporter
sat 10.8 px left and 5 px above Chromium, and now matches it.
Full changelog: v0.3.0...v0.3.1
v0.3.0
Immutable
release. Only release title and notes can be modified.
Changed
- Each SVG image is one Form XObject: an
<img>, an inline<svg>, a CSS image and an<image>inside an
SVG. Its/BBoxis the viewport, and the page paints it withDounder the matrix that places it, so a
PDF reader such as PDFBox or PyMuPDF finds each diagram with its size and position. WeasyPrint drew the
operators straight into the page. The form is no transparency group: it renders as before. The same
image drawn again at the same size, on the pages or within one group, reuses its form. The
form_xobjectargument ofinstall()turns it off. - An SVG background or list marker is clipped at its viewport, as in Chromium: content past it showed.
An inline<svg>withoverflow: visiblestill shows its overflow, and its form box grows to let it through.
Fixed
- SVG text in the generic
monospacefamily alone takes 13px as its medium size, as in Chromium and Firefox:
MathJax writes accented letters as<text font-family="monospace">with no size, and they came out 1.23
times too large. A size from a keyword reads the monospace table of Chromium (largeis 16px), and a size
relative to one (2em,50%,smaller) scales by 13/16 where the family turns monospace and back where
it leaves. A family list (monospace, serif) and an absolute length keep their size. - A tagged PDF (
pdf/ua-1,pdf/a-2a) of an SVG with a<foreignObject>renders: WeasyPrint failed on
the tags of its HTML, which belong to no box of the page. The Figure of the image marks the whole SVG. - A hole in a blurred shape keeps its size: it grew by one sample on each side, so the ring of the lens in
the OpenStreetMap logo came out thinner and its shadow lighter than in Chromium. - The shapes of a theme-aware draw.io export are white, as in Chromium, not black. weasysvg reads the CSS of
an SVG as Chromium does when it prints:@supportsblocks apply when their condition holds, custom
properties andvar()substitute, also in presentation attributes, andlight-dark()takes its light
color. A value thatvar()makes invalid is unset, and an invalid color declaration or attribute is
ignored, so the attribute or the parent value applies. WeasyPrint painted each of these black. Thecss
argument ofinstall()turns it off.
Removed
- Python 3.10, which reaches its end of life in October 2026. Pillow 13.0.0 requires Python 3.11, and it
fixes the vulnerabilities that Dependabot reports for Pillow 12.3.0 in the lock file. - PyPy. No known user runs weasysvg on it, and its CI job took five minutes, the longest of all.
Full changelog: v0.2.0...v0.3.0
v0.2.0
Immutable
release. Only release title and notes can be modified.
Added
paint-orderon shapes, markers, text and text decoration lines, as Chromium paints it: the stroke of
the boxes in the OSI model from Wikimedia (paint-order: stroke) shows its outer half only. The
paint_orderargument ofinstall()turns it off.
Changed
- Text decoration lines take their thickness and place from the font tables, as WeasyPrint draws
text-decorationon HTML text, so SVG text and HTML text in one PDF get the same lines. The underline and
the overline run straight through the glyphs: WeasyPrint skips no ink. This departs from Chromium on
purpose (a tenth of the font size, ink skipped) and matches resvg;text-decoration-thickness: auto
allows both.
Fixed
- A dash that runs through the start point of a closed shape is one dash, with its line join, as in
Chromium. PDFium drew two dashes that met there: a light seam across the stroke and a notch on its
outer edge, and no miter at the corner of a rectangle. Every dash keeps its place. - A translucent stroke over a fill shows the fill under it, as in Chromium. WeasyPrint filled and stroked
in one operator, a knockout object in PDF, so the stroke showed the white behind the shape. - Text laid out one character at a time draws its decoration lines character by character, as Chromium,
Safari and Firefox do: each character carries them over its advance and its letter-spacing, and the room
textLength,xanddxadd between characters stays bare. Text with severalyordyvalues gets its
lines too, under each character on its own baseline. On atextPaththe last character carries its
letter-spacing as well. - An arc of a zero radius in path data draws the straight line SVG asks for: WeasyPrint sent it off by the
current point, which broke every slice of a Highcharts pie. - The text after a child of a
<tspan>is drawn: WeasyPrint dropped it, soDon<wbr/>ein a Polarion chart
label read "Don". - Text in a
<foreignObject>sits on the line where Chromium and Safari put it: Blink rounds the font
metrics to whole px and paints the baseline on a whole px. Mermaid labels sat up to 1 px lower. - The noise of
feTurbulenceis computed at 2 px per CSS px: at 1 it came out blurred once printed or
viewed at 2x. - A blurred rect leaves no seam where its blurred edges meet its middle.
- The space that ends a text moves no anchor:
text-anchor="end"put the text a space too far left. - A wide arc in path data is drawn as curves of at most 90 degrees: WeasyPrint drew a half circle as one
curve, which bulged the band of the flag of Brazil. text-anchorplaces each text chunk of SVG 2 as one: a chunk starts only at a character with an absolute
xory, and the text after a positioned<tspan>belongs to it. WeasyPrint anchored that text with the
<text>, so the second line of a label in a Wikimedia OSI model diagram sat off its center.- A blurred filled shape other than a plain rect fades as in Chromium: its coverage is blurred and drawn
as a mesh of shaded triangles. The levels of the nearest edge left rings in the tail, made a shape
thinner than a few deviations dark and sharp (the lens ring of the OpenStreetMap logo, the chest of
Tux) and left white glints where the grown paint had holes (the Inkscape logo). - The blurred edge of a plain rect follows the Gaussian to about one level of 255, its tail included:
one shading over 8 deviations showed bands in PDFium, and the paint stopped at 2.15 deviations. - Any blurred content made of paths fades as in Chromium: a group, a stroke, several shapes and colors.
Its coverage per color is read back from the PDF operators, blurred and drawn as a mesh of shaded
triangles, each color mixed in by its share. The levels of the nearest edge drew a mitered corner on a
blurred square (resvgfilters-filter--on-the-root-svg) and a stroke in steps with a hard inner edge.
Text, images, gradients, patterns, masks, blend modes and dashes keep the levels. - The gradient of a blurred shape pads past the box of the shape: the pattern WeasyPrint makes of it
repeated there, which cut the shadow of the map in the OpenStreetMap logo with hard straight edges.
Full changelog: v0.1.0...v0.2.0
v0.1.0
Immutable
release. Only release title and notes can be modified.
Added
weasysvg.install()patches WeasyPrint 70.x to render SVG close to Chromium:<foreignObject>with
the list markers of Chromium and the white space of empty inline boxes collapsed as there,
conditional processing, vector filter chains (blur, exact for a plain rect, color matrices and
transfer functions included), masks set before the path, pattern and gradient fixes,mix-blend-mode, unclipped
opacity groups, marker orientation, text baselines from font metrics, text-anchor per text chunk, filters, masks and clips on text, circles of the right length, dots of zero-length dashes in place in PDFium, negative dash offsets of odd dash arrays, decorations placed as in Chromium with underlines that skip the ink of the glyphs (laid out whole or character by character), font-size
keywords, relative font sizes inherited as computed,exfrom the x-height of the font, and Chromium font selection. No SVG content is rasterized: the PDF stays vector.feTurbulence, drawn as an image of the noise, andfeCompositearithmetic.systemLanguagereads thelangof the document where the image sits, elseinstall(language=...),
enby default: a German document shows the German branch of a<switch>.- Arabic laid out one character at a time, on a path or down a column, takes its joining forms and runs
right to left, numbers in it read left to right. - Upright CJK in vertical text hangs from the vertical origin of its font (
VORG,vmtx), as in Chromium
and resvg, androtateturns it about that point. - Python 3.10 to 3.14 and PyPy 3.11, the versions WeasyPrint 70 supports.
- Releases on PyPI (
pip install weasysvg), with publish attestations, and on GitHub, with signed
build provenance of the same files. - Upstream tracking for WeasyPrint upgrades (UPGRADING.md): probes of the gaps weasysvg covers, a
snapshot of the internals it hooks, a bench baseline, and a weekly run against the newest WeasyPrint. - A visual regression corpus of 115 SVGs with Chromium and resvg references, and a bench that
compares weasysvg with Chromium. corpus/COMPARISON.mdand the interactivecorpus/comparison.htmlon GitHub Pages: every corpus SVG
in Chromium, resvg, WeasyPrint alone and with weasysvg, each panel at 2x as lossless WebP, sharp when zoomed.- Each corpus SVG names its reference (Chromium, resvg, or both). The verdicts say
whether a rendering is better than it, matches it, comes close or differs, and what differs, in a
table with an icon per status. The comparison page shows the SVG in your own browser too, and a swipe
between any two renderers. make review: the renderings of each corpus SVG compared region by region at twice the resolution of the
references, with sheets of the cells that differ, to judge the verdicts at full size.- The visual image has Trebuchet MS, the first font of Mermaid, as Safari has it: Mermaid labels fit their
boxes in the references. - Chromium prints the references with the Accept-Language list of a desktop Chrome in English
(en-US,en):systemLanguagematches English as there. corpus/fonts: the fonts the resvg tests ask for. The references, weasysvg, resvg and the browser panel of the comparison page all use them.