Files
Voiced/scripts/logo/lib.mjs
T
xavierk 86aaa1a790 Measure Canva logo placeholders and add slot-based logo placement
scripts/logo/measure-placeholders rasterises the Canva PDFs and measures
each logo placeholder's ink box and density into slots.generated.ts. The
new placement contains the logo in the measured box, shrinks denser logos
by up to 30 percent to match visual weight, picks knockout or a white chip
on dark surfaces, and passes an identity test per template. A contact
sheet compares each placeholder with the Test Vendor logo and three test logos.
2026-10-04 06:40:10 +05:30

51 lines
2.2 KiB
JavaScript

// Shared helpers for the logo scripts: rasterise a Canva PDF page with pdf.js and @napi-rs/canvas.
import { readFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
export const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
export const PDF_DIR = path.join(ROOT, "templates", "Modern Neutral Invoice Template");
export const SCALE = 4;
export const PAGE = { w: 595.5, h: 842.25 };
export const OUT_DIR = "/tmp/invoice-c2";
export async function loadCanvas() {
try {
return await import("@napi-rs/canvas");
} catch {
console.error("@napi-rs/canvas is not installed (it is an optional dev dependency); run npm install");
process.exit(1);
}
}
/** Renders page 1 of the Canva PDF `n` at SCALE x. Returns the canvas. */
export async function renderPage(n, scale = SCALE) {
const { createCanvas } = await loadCanvas();
const pdfjs = await import("pdfjs-dist/legacy/build/pdf.mjs");
const data = new Uint8Array(readFileSync(path.join(PDF_DIR, `${n}.pdf`)));
const doc = await pdfjs.getDocument({ data, isEvalSupported: false, verbosity: 0 }).promise;
const page = await doc.getPage(1);
const vp = page.getViewport({ scale });
const canvas = createCanvas(Math.round(vp.width), Math.round(vp.height));
await page.render({ canvasContext: canvas.getContext("2d"), viewport: vp, canvas }).promise;
return canvas;
}
/** Copies a pt rectangle of a page canvas into a new canvas (same scale). */
export async function cropCanvas(canvas, rect, scale = SCALE) {
const { createCanvas } = await loadCanvas();
const x = Math.round(rect.x * scale);
const y = Math.round(rect.y * scale);
const w = Math.round(rect.w * scale);
const h = Math.round(rect.h * scale);
const out = createCanvas(w, h);
out.getContext("2d").drawImage(canvas, x, y, w, h, 0, 0, w, h);
return out;
}
/** Canva PDF number of each template (docs/templates/README.md). */
export const TEMPLATE_PDF = {
marble: 1, highlighter: 2, monolith: 3, linea: 4, monogram: 5, serenity: 6, "crimson-grid": 7,
"cobalt-stripe": 8, "slate-band": 9, "teal-swoosh": 10, "tangerine-ledger": 11, "purple-pop": 12, "citrus-split": 13,
};