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); }