Measure reference logo placeholders and add slot-based logo placement
scripts/logo/measure-placeholders rasterises the reference 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.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
// Shared helpers for the logo scripts: rasterise a reference 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", "reference");
|
||||
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 reference 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;
|
||||
}
|
||||
|
||||
/** reference 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,
|
||||
};
|
||||
Reference in New Issue
Block a user