oxedyne/daimond/dev/probe_typstsvg.mjs
3.3 KiB, 1 run
created by r2519314175:111, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | // probe_typstsvg.mjs — what the renderer actually hands back, whole against window. |
| 2 | // |
| 3 | // The author reported ghosted/double-struck glyphs on every line and solid black |
| 4 | // bars where the contents entries and three inline spans belong. Both are the shape |
| 5 | // of typst.ts's INVISIBLE TEXT LAYER becoming visible: it emits real `<text>` on top |
| 6 | // of the glyph outlines so a reader can select and search, and the only thing that |
| 7 | // makes it invisible is a rule in the stylesheet it emits beside it. So this asks |
| 8 | // the renderer for the same document twice — whole (`svg_data`) and windowed |
| 9 | // (`render_in_window`) — and reports what each one carries. |
| 10 | // |
| 11 | // It asserts nothing and is not a verifier. |
| 12 | // |
| 13 | // eval "$(bash dev/world.sh 5 --env)" |
| 14 | // node dev/probe_typstsvg.mjs |
| 15 | import fs from 'node:fs'; |
| 16 | import { open, scratch } from './harness.mjs'; |
| 17 | |
| 18 | const WORK = scratch('typstsvg'); |
| 19 | fs.mkdirSync(WORK, { recursive: true }); |
| 20 | |
| 21 | const DOC = `#set page(width: 400pt, height: 300pt, margin: 24pt) |
| 22 | #set text(size: 11pt) |
| 23 | = A heading |
| 24 | #outline() |
| 25 | Some ordinary body text, long enough to wrap onto a second line so that a |
| 26 | double-struck run would be obvious to anybody looking at it. |
| 27 | Created using #link("https://typst.app")[Typst] and #link("https://rust-lang.org")[Rust]. |
| 28 | == Another heading |
| 29 | More text under it. |
| 30 | `; |
| 31 | |
| 32 | const s = await open({ name: 'typstsvg' }); |
| 33 | const p = s.page; |
| 34 | await p.waitForTimeout(1200); |
| 35 | |
| 36 | const r = await p.evaluate(async (src) => { |
| 37 | const m = await import('/pkg/oxedyne_daimond.js'); |
| 38 | m.set_locked_packs(''); |
| 39 | await m.write_file('svgprobe/main.typ', src); |
| 40 | const out = await m.typst_compile_project_vector('svgprobe/main.typ'); |
| 41 | if (!out.vector) return { error: String(out.error || 'nothing').slice(0, 400) }; |
| 42 | const g = await import('/vendor/typst/typst_ts_renderer.mjs'); |
| 43 | await g.default('/vendor/typst/typst_ts_renderer_bg.wasm'); |
| 44 | const rr = await new g.TypstRendererBuilder().build(); |
| 45 | const ses = rr.session_from_artifact(out.vector, 'vector'); |
| 46 | const info = ses.pages_info; |
| 47 | const whole = rr.svg_data(ses); |
| 48 | const ses2 = rr.session_from_artifact(out.vector, 'vector'); |
| 49 | const win = ses2.render_in_window(0, 0, info.width(), info.height()); |
| 50 | ses.free(); ses2.free(); |
| 51 | return { whole, win, w: info.width(), h: info.height(), pages: info.page_count }; |
| 52 | }, DOC); |
| 53 | |
| 54 | if (r.error) { console.log('REFUSED: ' + r.error); await s.close(); process.exit(1); } |
| 55 | |
| 56 | const look = (name, svg) => { |
| 57 | fs.writeFileSync(`${WORK}/${name}.svg`, svg); |
| 58 | const styles = svg.match(/<style[\s\S]*?<\/style>/g) || []; |
| 59 | console.log(`\n=== ${name} — ${(svg.length / 1024).toFixed(1)} KB ===`); |
| 60 | console.log(` <style> blocks: ${styles.length}`); |
| 61 | for (const st of styles) console.log(' ' + st.replace(/\s+/g, ' ').slice(0, 300)); |
| 62 | for (const k of ['tsel', 'typst-text', 'typst-doc', '<text', 'class="typst', 'data-tid', |
| 63 | '<script', 'pseudo-link', 'typst-link', 'fill="#000000"', 'fill: none']) { |
| 64 | const n = svg.split(k).length - 1; |
| 65 | if (n) console.log(` ${JSON.stringify(k)} x${n}`); |
| 66 | } |
| 67 | const t = svg.match(/<text[^>]*>[\s\S]{0,80}/); |
| 68 | if (t) console.log(' first <text>: ' + t[0].replace(/\s+/g, ' ').slice(0, 240)); |
| 69 | console.log(' head: ' + svg.slice(0, 400).replace(/\s+/g, ' ')); |
| 70 | }; |
| 71 | |
| 72 | console.log(`document ${r.w.toFixed(1)} x ${r.h.toFixed(1)} pt, ${r.pages} page(s)`); |
| 73 | look('whole', r.whole); |
| 74 | look('window', r.win); |
| 75 | console.log(`\nwrote ${WORK}/whole.svg and ${WORK}/window.svg`); |
| 76 | await s.close(); |