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:
2026-10-04 06:40:10 +05:30
parent e1edf02448
commit eddf27629f
11 changed files with 984 additions and 21 deletions
+13 -13
View File
@@ -1,49 +1,49 @@
import { describe, expect, it } from "vitest";
import { computeLogoPlacement } from "./logo";
import { computeClassicLogoPlacement } from "./logo";
const BOX = { w: 170, h: 54 };
const base = { box: BOX, availableWidth: 299, minTextWidth: 160 };
describe("computeLogoPlacement", () => {
describe("computeClassicLogoPlacement", () => {
it("the Test Vendor trimmed 4.6:1 logo is width-limited and stacks above the text", () => {
const p = computeLogoPlacement({ ...base, aspect: 4.6 });
const p = computeClassicLogoPlacement({ ...base, aspect: 4.6 });
expect(p.w).toBeCloseTo(170, 6);
expect(p.h).toBeCloseTo(170 / 4.6, 6);
expect(p.stacked).toBe(true);
});
it("an untrimmed 3:1 logo is height-limited (54 pt) and still stacks", () => {
const p = computeLogoPlacement({ ...base, aspect: 3 });
const p = computeClassicLogoPlacement({ ...base, aspect: 3 });
expect(p.h).toBe(54);
expect(p.w).toBeCloseTo(162, 6);
expect(p.stacked).toBe(true);
});
it("a square logo is 54 x 54 and sits beside the text", () => {
const p = computeLogoPlacement({ ...base, aspect: 1 });
const p = computeClassicLogoPlacement({ ...base, aspect: 1 });
expect(p).toEqual({ w: 54, h: 54, stacked: false });
});
it("stacks exactly when the text beside the logo would drop under the minimum", () => {
// 299 - 54 - 14 = 231 beside a square; a 2:1 logo (108 wide) leaves 177; a 2.5:1 one (135) leaves 150.
expect(computeLogoPlacement({ ...base, aspect: 2 }).stacked).toBe(false);
expect(computeLogoPlacement({ ...base, aspect: 2.5 }).stacked).toBe(true);
expect(computeClassicLogoPlacement({ ...base, aspect: 2 }).stacked).toBe(false);
expect(computeClassicLogoPlacement({ ...base, aspect: 2.5 }).stacked).toBe(true);
// The boundary: leaves exactly 160.
const w = 299 - 14 - 160;
expect(computeLogoPlacement({ ...base, aspect: w / 54 }).stacked).toBe(false);
expect(computeLogoPlacement({ ...base, aspect: (w + 0.01) / 54 }).stacked).toBe(true);
expect(computeClassicLogoPlacement({ ...base, aspect: w / 54 }).stacked).toBe(false);
expect(computeClassicLogoPlacement({ ...base, aspect: (w + 0.01) / 54 }).stacked).toBe(true);
});
it("gives the logo more room on a wider column (Letter)", () => {
const a4 = computeLogoPlacement({ ...base, aspect: 2.4, availableWidth: 299.28 });
const letter = computeLogoPlacement({ ...base, aspect: 2.4, availableWidth: 316 });
const a4 = computeClassicLogoPlacement({ ...base, aspect: 2.4, availableWidth: 299.28 });
const letter = computeClassicLogoPlacement({ ...base, aspect: 2.4, availableWidth: 316 });
expect(a4.stacked).toBe(true);
expect(letter.stacked).toBe(false);
});
it("never exceeds the box, whatever the aspect", () => {
for (const aspect of [0.2, 0.5, 1, 1.5, 3, 4.6, 10, 40]) {
const p = computeLogoPlacement({ ...base, aspect });
const p = computeClassicLogoPlacement({ ...base, aspect });
expect(p.w).toBeLessThanOrEqual(170 + 1e-9);
expect(p.h).toBeLessThanOrEqual(54 + 1e-9);
expect(p.w / p.h).toBeCloseTo(aspect, 6);
@@ -51,7 +51,7 @@ describe("computeLogoPlacement", () => {
});
it("falls back to the box aspect for a bad aspect", () => {
const p = computeLogoPlacement({ ...base, aspect: Number.NaN });
const p = computeClassicLogoPlacement({ ...base, aspect: Number.NaN });
expect(p.w).toBeCloseTo(170, 6);
expect(p.h).toBeCloseTo(54, 6);
});