Task #588: PDF uses real DIN Next LT Arabic (and other branded fonts)
The HTML/puppeteer PDF renderer in artifacts/api-server/src/lib/pdf-html-renderer.ts mapped every branded sans family to NotoSansArabic-*.ttf — so even though the user picked "DIN Next LT Arabic" in settings, the embedded glyph shapes were Noto Sans Arabic. Same silent substitution applied to Tajawal, Helvetica Neue LT Arabic, and Majalla. (pdf-renderer.ts was already wired correctly to the real files in an earlier change; pdf-html-renderer.ts was missed.) Fix in pdf-html-renderer.ts FONT_FILES: DIN Next LT Arabic → DINNextLTArabic-Regular/Bold.ttf Tajawal → Tajawal-Regular/Bold.ttf Helvetica Neue LT Arabic → HelveticaNeueLTArabic-Regular/Bold.ttf Majalla → Majalla-Regular/Bold.ttf system → NotoNaskhArabic-Regular/Bold.ttf (unchanged) Helvetica Neue → HelveticaNeue-Regular/Bold.ttf (unchanged) All target .ttf files were already bundled in artifacts/api-server/assets/fonts/ — no asset changes needed. Updated the matching test assertions in artifacts/api-server/tests/executive-meetings.test.mjs so the DIN Next LT Arabic path now expects /DINNextLTArabic/ in the PDF bytes, and the Majalla path expects /Majalla/ instead of /NotoNaskhArabic/. Kept the negative assertion that Majalla never embeds a sans face. API workflow restarted clean. Mac rebuild: cd ~/Downloads/TX && git pull && docker compose up -d --build api
This commit is contained in:
@@ -51,36 +51,33 @@ function fontsDir(): string {
|
||||
}
|
||||
|
||||
// Map every supported user-facing font family to a concrete pair of
|
||||
// bundled font files. Sans-style families (DIN Next LT Arabic, Tajawal,
|
||||
// Helvetica Neue LT Arabic) embed NotoSansArabic; Naskh-style families
|
||||
// (Majalla, system default) embed NotoNaskhArabic. Using the bundled
|
||||
// Noto faces keeps the embedded PostScript names stable across the
|
||||
// matrix of user-facing family choices and matches the contract asserted
|
||||
// in tests/executive-meetings.test.mjs (PDF font-embed assertions).
|
||||
// bundled font files. Each branded family uses its own real OpenType
|
||||
// files so the embedded glyph shapes match what the user picked.
|
||||
// `system` is the safe fallback and ships NotoNaskhArabic.
|
||||
const FONT_FILES: Record<string, { regular: string; bold: string }> = {
|
||||
"DIN Next LT Arabic": {
|
||||
regular: "NotoSansArabic-Regular.ttf",
|
||||
bold: "NotoSansArabic-Bold.ttf",
|
||||
regular: "DINNextLTArabic-Regular.ttf",
|
||||
bold: "DINNextLTArabic-Bold.ttf",
|
||||
},
|
||||
system: {
|
||||
regular: "NotoNaskhArabic-Regular.ttf",
|
||||
bold: "NotoNaskhArabic-Bold.ttf",
|
||||
},
|
||||
Tajawal: {
|
||||
regular: "NotoSansArabic-Regular.ttf",
|
||||
bold: "NotoSansArabic-Bold.ttf",
|
||||
regular: "Tajawal-Regular.ttf",
|
||||
bold: "Tajawal-Bold.ttf",
|
||||
},
|
||||
"Helvetica Neue LT Arabic": {
|
||||
regular: "NotoSansArabic-Regular.ttf",
|
||||
bold: "NotoSansArabic-Bold.ttf",
|
||||
regular: "HelveticaNeueLTArabic-Regular.ttf",
|
||||
bold: "HelveticaNeueLTArabic-Bold.ttf",
|
||||
},
|
||||
"Helvetica Neue": {
|
||||
regular: "HelveticaNeue-Regular.ttf",
|
||||
bold: "HelveticaNeue-Bold.ttf",
|
||||
},
|
||||
Majalla: {
|
||||
regular: "NotoNaskhArabic-Regular.ttf",
|
||||
bold: "NotoNaskhArabic-Bold.ttf",
|
||||
regular: "Majalla-Regular.ttf",
|
||||
bold: "Majalla-Bold.ttf",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -846,9 +846,10 @@ test("PDF GET /executive-meetings/pdf returns a real PDF and archives it", async
|
||||
// Font-family must affect which font is embedded in the PDF. We render
|
||||
// the same day twice with different families and assert that:
|
||||
// 1) Both downloads succeed (200 + %PDF magic).
|
||||
// 2) The Sans family ("DIN Next LT Arabic") embeds NotoSansArabic,
|
||||
// while the Naskh-style family ("Majalla") embeds NotoNaskhArabic.
|
||||
// The PostScript name appears verbatim in the PDF font dictionary.
|
||||
// 2) The branded sans family ("DIN Next LT Arabic") embeds the real
|
||||
// DINNextLTArabic face, while the Naskh-style family ("Majalla")
|
||||
// embeds the real Majalla face. The PostScript name appears
|
||||
// verbatim in the PDF font dictionary.
|
||||
const setSans = await api(
|
||||
adminCookie,
|
||||
"PUT",
|
||||
@@ -872,8 +873,8 @@ test("PDF GET /executive-meetings/pdf returns a real PDF and archives it", async
|
||||
assert.equal(sansBuf.subarray(0, 4).toString("ascii"), "%PDF");
|
||||
const sansAscii = sansBuf.toString("latin1");
|
||||
assert.ok(
|
||||
/NotoSansArabic/i.test(sansAscii),
|
||||
"DIN Next LT Arabic family must embed NotoSansArabic in the PDF",
|
||||
/DINNextLTArabic/i.test(sansAscii),
|
||||
"DIN Next LT Arabic family must embed DINNextLTArabic in the PDF",
|
||||
);
|
||||
assert.ok(
|
||||
!/NotoNaskhArabic/i.test(sansAscii),
|
||||
@@ -902,12 +903,12 @@ test("PDF GET /executive-meetings/pdf returns a real PDF and archives it", async
|
||||
const naskhBuf = Buffer.from(await naskhRes.arrayBuffer());
|
||||
const naskhAscii = naskhBuf.toString("latin1");
|
||||
assert.ok(
|
||||
/NotoNaskhArabic/i.test(naskhAscii),
|
||||
"Majalla family must embed NotoNaskhArabic in the PDF",
|
||||
/Majalla/i.test(naskhAscii),
|
||||
"Majalla family must embed Majalla in the PDF",
|
||||
);
|
||||
assert.ok(
|
||||
!/NotoSansArabic/i.test(naskhAscii),
|
||||
"Majalla family must NOT embed NotoSansArabic",
|
||||
!/NotoSansArabic|DINNextLTArabic/i.test(naskhAscii),
|
||||
"Majalla family must NOT embed a sans face",
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user