Add Ledger and Band template families with decor primitives
Crimson Grid, Tangerine Ledger, Slate Band and Teal Swoosh are rebuilt from the reference PDFs with grid and band tables that survive page breaks, full-bleed fixed bands, pennant tabs, gradient corner swooshes with keep-outs, Carbon icon circles, and the user's logo in the measured slot (knockout or white chip on the dark Slate band). Adds static Poppins 500-700 and Inter fonts. Thumbnails regenerated for all eight templates; the item-count sweeps run in their own test file.
This commit is contained in:
@@ -12,7 +12,7 @@ import { setupPdfTest } from "../testing/setup";
|
||||
|
||||
/** Fixtures and helpers shared by the template harness and the sample renderer. */
|
||||
|
||||
export type LogoKind = "none" | "real" | "wide" | "square";
|
||||
export type LogoKind = "none" | "real" | "wide" | "square" | "knockout";
|
||||
|
||||
export interface FixtureSpec {
|
||||
name: string;
|
||||
@@ -130,6 +130,33 @@ export function solidPng(w: number, h: number): Buffer {
|
||||
]);
|
||||
}
|
||||
|
||||
/** A transparent-margin w x h PNG in one colour: the shape of a logo that has alpha, so it can have a white knockout. */
|
||||
function inkPng(w: number, h: number, rgb: [number, number, number]): Buffer {
|
||||
const row = Buffer.alloc(1 + w * 4);
|
||||
const raw = Buffer.alloc(row.length * h);
|
||||
for (let y = 0; y < h; y++) {
|
||||
for (let x = 0; x < w; x++) {
|
||||
const inside = x >= w * 0.08 && x < w * 0.92 && y >= h * 0.12 && y < h * 0.88;
|
||||
const o = y * row.length + 1 + x * 4;
|
||||
raw[o] = rgb[0];
|
||||
raw[o + 1] = rgb[1];
|
||||
raw[o + 2] = rgb[2];
|
||||
raw[o + 3] = inside ? 255 : 0;
|
||||
}
|
||||
}
|
||||
const ihdr = Buffer.alloc(13);
|
||||
ihdr.writeUInt32BE(w, 0);
|
||||
ihdr.writeUInt32BE(h, 4);
|
||||
ihdr[8] = 8;
|
||||
ihdr[9] = 6;
|
||||
return Buffer.concat([
|
||||
Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
|
||||
chunk("IHDR", ihdr),
|
||||
chunk("IDAT", deflateSync(raw)),
|
||||
chunk("IEND", Buffer.alloc(0)),
|
||||
]);
|
||||
}
|
||||
|
||||
const dataUri = (png: Buffer) => `data:image/png;base64,${png.toString("base64")}`;
|
||||
|
||||
const cache = new Map<string, LogoInput>();
|
||||
@@ -142,6 +169,19 @@ export function fixtureLogo(kind: LogoKind): LogoInput | null {
|
||||
const png = readFileSync(path.resolve(process.cwd(), "public/brand/sample-wordmark-logo.png"));
|
||||
const [width, height] = [png.readUInt32BE(16), png.readUInt32BE(20)];
|
||||
hit = { dataUri: dataUri(png), width, height, aspect: width / height, density: 0.21, kind: "wordmark", includesName: true };
|
||||
} else if (kind === "knockout") {
|
||||
// A wordmark with alpha: navy print image plus its white knockout, as the logo pipeline writes them.
|
||||
hit = {
|
||||
dataUri: dataUri(inkPng(460, 100, [24, 52, 120])),
|
||||
knockoutDataUri: dataUri(inkPng(460, 100, [255, 255, 255])),
|
||||
hasKnockout: true,
|
||||
width: 460,
|
||||
height: 100,
|
||||
aspect: 4.6,
|
||||
density: 0.6,
|
||||
kind: "wordmark",
|
||||
includesName: true,
|
||||
};
|
||||
} else if (kind === "wide") {
|
||||
// The trimmed Test Vendor ink box is 4.6:1.
|
||||
hit = { dataUri: dataUri(solidPng(460, 100)), width: 460, height: 100, aspect: 4.6, density: 1, kind: "wordmark", includesName: true };
|
||||
|
||||
Reference in New Issue
Block a user