Files
Sybil-2/server/tests/pdf-fixture.ts
T

38 lines
1.9 KiB
TypeScript

export function createPdf(pages: string[], encrypted = false): Uint8Array {
const fontId = 3 + pages.length * 2;
const objects = [
"<< /Type /Catalog /Pages 2 0 R >>",
`<< /Type /Pages /Kids [${pages.map((_, index) => `${3 + index * 2} 0 R`).join(" ")}] /Count ${pages.length} >>`,
];
for (let index = 0; index < pages.length; index += 1) {
const pageId = 3 + index * 2;
const contentId = pageId + 1;
const text = pages[index]!;
const operators = Array.from({ length: Math.ceil(text.length / 100) }, (_, partIndex) => {
const part = text.slice(partIndex * 100, (partIndex + 1) * 100);
const escaped = part.replaceAll("\\", "\\\\").replaceAll("(", "\\(").replaceAll(")", "\\)");
return `(${escaped}) Tj`;
});
const content = text ? `BT /F1 12 Tf 72 720 Td ${operators.join(" ")} ET` : "";
objects.push(
`<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Resources << /Font << /F1 ${fontId} 0 R >> >> /Contents ${contentId} 0 R >>`,
`<< /Length ${Buffer.byteLength(content)} >>\nstream\n${content}\nendstream`,
);
}
objects.push("<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>");
const encryptionId = objects.length + 1;
if (encrypted) objects.push(`<< /Filter /Standard /V 1 /R 2 /O <${"00".repeat(32)}> /U <${"00".repeat(32)}> /P -4 >>`);
let output = "%PDF-1.4\n";
const offsets = [0];
objects.forEach((object, index) => {
offsets.push(Buffer.byteLength(output));
output += `${index + 1} 0 obj\n${object}\nendobj\n`;
});
const xrefOffset = Buffer.byteLength(output);
output += `xref\n0 ${objects.length + 1}\n0000000000 65535 f \n`;
for (const offset of offsets.slice(1)) output += `${String(offset).padStart(10, "0")} 00000 n \n`;
output += `trailer\n<< /Size ${objects.length + 1} /Root 1 0 R${encrypted ? ` /Encrypt ${encryptionId} 0 R` : ""} >>\nstartxref\n${xrefOffset}\n%%EOF`;
return new TextEncoder().encode(output);
}