index.ts was written against assumed renderer signatures (render(req)) while typst.ts exposed render(resolved, jobDir, outPath). It type-checked -- only typeof === 'function' was ever asserted -- but would have failed at runtime. typst.ts now exports the request-shaped render()/renderAllFormats() the commands' Renderer interface declares; the low-level entry points are renderOne()/renderFormats(). smartCrop() likewise adopts retouch.ts's richer contract, returning the size read back from the written file. Verified e2e: a3-portrait -> PNG+PDF, ig-story -> PNG, Italian progress.
54 lines
2.6 KiB
JavaScript
54 lines
2.6 KiB
JavaScript
import { createJiti } from "jiti";
|
|
import { mkdtempSync, copyFileSync, existsSync, readFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
|
|
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
const R = "/home/moze/Sorgenti/pi-imgen";
|
|
const typst = await jiti.import(join(R, "extensions/imgen/render/typst.ts"));
|
|
const cfgMod = await jiti.import(join(R, "extensions/imgen/config.ts"));
|
|
|
|
const job = mkdtempSync(join(tmpdir(), "imgen-e2e-"));
|
|
copyFileSync(join(R, "tests/art.png"), join(job, "art.png"));
|
|
|
|
const cfg = { ...cfgMod.DEFAULTS, outputDir: job };
|
|
const spec = {
|
|
slug: "sagra-castagna", format: "a3-portrait", template: "hero-bottom",
|
|
palette: { bg: "#f4efe6", ink: "#101014", accent: "#b03a24", scrim: "#000000" },
|
|
fonts: { display: "Archivo", body: "Archivo" },
|
|
art: { prompt: "autumn chestnuts", negative: "text, letters", seed: 7, source: "generate" },
|
|
blocks: [
|
|
{ role: "title", text: "Sagra della Castagna" },
|
|
{ role: "date", text: "Sabato 12 settembre, ore 21:00" },
|
|
{ role: "venue", text: "Chiostro di San Domenico, Città Alta" },
|
|
],
|
|
};
|
|
|
|
const resolved = await typst.resolveSpec(spec, cfg, join(job, "art.png"), { format: "a3-portrait" });
|
|
console.log("resolved.art_file =", resolved.art_file);
|
|
console.log("resolved.ink_on_art =", resolved.ink_on_art);
|
|
console.log("resolved.ink_on_bg =", resolved.ink_on_bg);
|
|
console.log("resolved.needs_scrim =", resolved.needs_scrim);
|
|
console.log("resolved.page =", JSON.stringify(resolved.page));
|
|
console.log("resolved.font_axes =", JSON.stringify(resolved.font_axes));
|
|
|
|
const TY = process.env.TYPST;
|
|
const out = join(job, "poster.pdf");
|
|
await typst.renderOne(resolved, job, out, { binary: TY });
|
|
const d = readFileSync(out);
|
|
const tb = /\/TrimBox\s*\[([^\]]*)\]/.exec(d.toString("latin1"));
|
|
if (!tb) { console.log("TrimBox: ABSENT"); process.exit(1); }
|
|
const [x0,y0,x1,y1] = tb[1].split(/\s+/).map(Number);
|
|
console.log(`TrimBox mm = ${((x1-x0)/72*25.4).toFixed(1)} x ${((y1-y0)/72*25.4).toFixed(1)}`);
|
|
console.log("bundle staged =", existsSync(join(job, ".typst/lib.typ")), existsSync(join(job, ".typst/hero-bottom.typ")));
|
|
|
|
// The request-shaped API is what the commands actually call.
|
|
const outcome = await typst.render({
|
|
spec, artPath: join(job, "art.png"), outDir: job, config: cfg,
|
|
formats: ["a3-portrait", "ig-story"], pdf: true,
|
|
onProgress: (m) => console.log(" progresso:", m),
|
|
});
|
|
console.log("files =", outcome.files.map(f => f.split("/").pop()).join(", "));
|
|
console.log("warnings =", outcome.warnings ?? "(nessuno)");
|
|
console.log("OK");
|