Open lionel-rowe opened 1 month ago
Here's a hack that "fixes" such an SVG in any font (heck, it even works passably for most variable-width fonts), by means of wrapping each char in its own span:
outerHTML
) and save it in an .svg
fileScript:
for (const tspan of document.querySelectorAll('tspan')) {
if (tspan.querySelector('*')) continue
const tspans = [...tspan.textContent.trim()].map((char, i) => {
const t = tspan.cloneNode(true)
t.textContent = char
let x = parseFloat(tspan.getAttribute('x'))
x += i * 8.4
if (i) t.removeAttribute('dy')
t.setAttribute('x', x)
return t
})
tspan.replaceWith(...tspans)
}
Limitations:
@std
's cli/unicode-width
)Results applied to my thumbnail:
And here are the results with the font changed to the decidedly non-monospace Papyrus:
Less hacky fix: add a @font-face
at-rule targeting Consolas inside the <style>
tag:
@font-face {
font-family: "Consolas";
src: local("Consolas");
size-adjust: 109.5%;
}
As before, 109.5 is a magic number (109.5% of 14px ~= 15.3px).
Works perfectly in latest Chrome, Firefox, Edge, but notably fails (has no effect) if you open the SVG in Inkscape.
Result:
OK, here's a third fix, much better and less hacky than either of the others.
The x
property of <tspan>
s can accept a space-separated list of numbers, rather than just a single scalar number, with each number corresponding to one glyph. This feature is supported even in SVG 1.1, so it has very wide support.
In addition, CSS font-size-adjust
is now "newly available" in baseline, meaning it has decent (but not completely ubiquitous) browser support.
x
property to manually place each glyph (but without the need for additional elements, saving on file size and presumably rendering performance too).font-size-adjust
of ch-width 0.6
, meaning that (at font size 14 in a monospace font) each char is guaranteed to be 14 * 0.6 = 8.4 px wide. If this feature is unavailable, the result is a little less pretty (spacing wider/narrower than normal, as noted above) but still has proper column placement of chars, so it's still a passable result.Tested in latest Chrome, FF, Edge, and it even looks fine in Inkscape (despite no font-size-adjust
support). I found the second solution above suffers from a rendering bug in FF wherein zooming in and out sometimes messes up the layout, but this solution doesn't have that problem.
Also tested on an asciicast with different Unicode-width chars — no issues there either, as asciinema already renders each char with Unicode-width other than 1 in its own span, so they just stay where they are.
File size increase in my case is 10.2 -> 13.1 kB, though I cheated a little by rounding each x
value to 1 decimal place (no visual difference).
Dev-tools-based demo:
document.querySelector('svg style').textContent += `\n text { font-size-adjust: ch-width 0.6; }`
// https://github.com/asciinema/asciinema-server/blob/fbbb2ce35272d516ce2a6debfbc04c9a7c60a149/lib/asciinema_web/controllers/recording_svg.ex#L399
const CELL_WIDTH = 8.42333333
for (const tspan of document.querySelectorAll('tspan')) {
if (tspan.childElementCount) continue
const offset = parseFloat(tspan.getAttribute('x'))
const xPerGrapheme = [...new Intl.Segmenter('en-US', { granularity: 'grapheme' }).segment(tspan.textContent.trim())].map((_, i) => {
return offset + (i * CELL_WIDTH)
})
tspan.setAttribute('x', xPerGrapheme.map((x) => x.toFixed(1)).join(' '))
}
In addition, CSS font-size-adjust is now "newly available" in baseline, meaning it has decent (but not completely ubiquitous) browser support.
Turns out it breaks in Chrome when a width
or max-width
is applied to the img
element in which the SVG is rendered (issue) So unless there's a workaround, the least-worst option is probably the same fix but without the font-size-adjust
bit.
Edit: I realized this issue is in the wrong repo, feel free to move to asciinema/asciinema-server. PR at https://github.com/asciinema/asciinema-server/pull/450
Describe the bug
With this recording: https://asciinema.org/a/XxTbS0aAtTA6BZ9tdzKardxJs
The recording itself (including the freeze frame of the frame used for the thumbnail) looks perfect, stunning, gorgeous.
However, the spacing is off in the SVG used for the thumbnail/embed image when displayed on Windows 11 with the Consolas font installed (from examining the SVG, the font stack is "Consolas, Menlo, 'Bitstream Vera Sans Mono', monospace, 'Powerline Symbols'").
Changing the font to Courier New fixes the problem (but it also makes it kinda ugly cuz... Courier New). Changing the font size to
15.3px
(magic number) also seems to fix it, but presumably would break the other fonts.Screenshots:
Direct link to the SVG
To Reproduce Steps to reproduce the behavior:
There are prominent examples at https://asciinema.org/explore that also reproduce the problem, e.g. https://asciinema.org/a/666780
Expected behavior
Thumbnail to look identical (or near-identical) to screenshotted freeze frame, just crisper due to being an SVG.
Versions:
Additional context N/A