Files
wehub-resource-sync f1ba9c6c36
/ test (push) Failing after 1s
/ build-and-push-to-ghcr (push) Has been skipped
chore: import upstream snapshot with attribution
2026-07-13 12:23:39 +08:00

77 lines
2.5 KiB
TypeScript

/**
* Minimal PDF builder for fixtures. Produces a syntactically valid PDF 1.4
* with one Helvetica text object per page — small enough to build in-memory
* and ship through pdfjs-dist's loader the same way an uploaded file would.
*/
export function buildSimplePdf(pageTexts: string[]): Buffer {
const parts: Buffer[] = [];
const offsets: number[] = [];
let totalLen = 0;
function emit(s: string | Buffer) {
const buf = typeof s === 'string' ? Buffer.from(s, 'binary') : s;
parts.push(buf);
totalLen += buf.length;
}
function recordObj() {
offsets.push(totalLen);
}
emit('%PDF-1.4\n');
emit('%\xE2\xE3\xCF\xD3\n'); // 4-byte binary marker so readers treat it as binary
recordObj();
emit('1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n');
const numPages = pageTexts.length;
const pageObjIds: number[] = [];
const contentObjIds: number[] = [];
for (let i = 0; i < numPages; i++) {
pageObjIds.push(3 + i * 2);
contentObjIds.push(4 + i * 2);
}
recordObj();
emit(`2 0 obj\n<< /Type /Pages /Kids [${pageObjIds
.map((id) => `${id} 0 R`)
.join(' ')}] /Count ${numPages} >>\nendobj\n`);
for (let i = 0; i < numPages; i++) {
const text = escapePdfString(pageTexts[i]);
const streamContent = `BT /F1 24 Tf 72 720 Td (${text}) Tj ET`;
const streamLen = Buffer.byteLength(streamContent, 'binary');
recordObj();
emit(
`${pageObjIds[i]} 0 obj\n` +
`<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents ${contentObjIds[i]} 0 R ` +
`/Resources << /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> >> >>\n` +
`endobj\n`,
);
recordObj();
emit(
`${contentObjIds[i]} 0 obj\n` +
`<< /Length ${streamLen} >>\nstream\n${streamContent}\nendstream\nendobj\n`,
);
}
const xrefStart = totalLen;
const totalObjs = 1 + offsets.length;
emit(`xref\n0 ${totalObjs}\n`);
emit('0000000000 65535 f \n');
for (const offset of offsets) {
emit(`${offset.toString().padStart(10, '0')} 00000 n \n`);
}
emit(`trailer\n<< /Size ${totalObjs} /Root 1 0 R >>\n`);
emit(`startxref\n${xrefStart}\n`);
emit('%%EOF\n');
return Buffer.concat(parts);
}
function escapePdfString(s: string): string {
return s.replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
}