Repository Public
1// A minimal PDF writer for tests: one text page per entry (lines of ASCII text, Helvetica, US Letter).2// `padding` adds that many bytes of filler per page, to obtain files large enough for Range loading.3export function makePdf(pages, { padding = 0 } = {}) {4 const objects = [];5 const add = (body) => { objects.push(body); return objects.length; };6 const esc = (s) => s.replace(/[\\()]/g, (c) => `\\${c}`);7 const catalog = add(''), tree = add('');8 const font = add('<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >>');9 const kids = [];10 for (const lines of pages) {11 const text = ['BT', '/F1 14 Tf', '72 720 Td', '20 TL', ...lines.map((l) => `(${esc(l)}) Tj T*`), 'ET'].join('\n') + (padding ? `\n%${'x'.repeat(padding)}` : '');12 const content = add(`<< /Length ${Buffer.byteLength(text, 'latin1')} >>\nstream\n${text}\nendstream`);13 kids.push(add(`<< /Type /Page /Parent ${tree} 0 R /MediaBox [0 0 612 792] /Resources << /Font << /F1 ${font} 0 R >> >> /Contents ${content} 0 R >>`));14 }15 objects[catalog - 1] = `<< /Type /Catalog /Pages ${tree} 0 R >>`;16 objects[tree - 1] = `<< /Type /Pages /Count ${kids.length} /Kids [${kids.map((k) => `${k} 0 R`).join(' ')}] >>`;17 let out = '%PDF-1.4\n%\xe2\xe3\xcf\xd3\n';18 const offsets = [];19 objects.forEach((body, i) => { offsets.push(out.length); out += `${i + 1} 0 obj\n${body}\nendobj\n`; });20 const xref = out.length;21 out += `xref\n0 ${objects.length + 1}\n0000000000 65535 f \n${offsets.map((o) => `${String(o).padStart(10, '0')} 00000 n \n`).join('')}`;22 out += `trailer\n<< /Size ${objects.length + 1} /Root ${catalog} 0 R >>\nstartxref\n${xref}\n%%EOF\n`;23 return Buffer.from(out, 'latin1');24}25