diff --git a/src/tag.ts b/src/tag.ts index acf7ad8..c0692a5 100644 --- a/src/tag.ts +++ b/src/tag.ts @@ -32,7 +32,9 @@ export function tag(pdf: Uint8Array, input: PagesInput, opts: TagOptions = {}, r const { doc } = src; // The old overlay's text is gone on purpose, so the text check compares against the source without it. // Pixels compare against the input itself: the restore must not change a pixel. - const baseline = src.restored ? save(doc, true) : pdf; + // The baseline is saved from a second copy: after a full save, mupdf writes the + // incremental update as an xref table with the xref stream's trailer, which Preview cannot open. + const baseline = src.restored ? save(openPdf(pdf, opts).doc, true) : pdf; const warn = (w: Warning) => report.warnings.push(w); src.warnings.forEach(warn); const pageCount = doc.countPages(); diff --git a/test/document.test.ts b/test/document.test.ts index 8c527f4..c57070c 100644 --- a/test/document.test.ts +++ b/test/document.test.ts @@ -84,6 +84,22 @@ test("retags a PDF that is already tagged", () => { assert.equal(report.verification.differingPixels, 0); }); +test("retagging a PDF with an xref stream appends an xref stream", () => { + // A classic table there, carrying the stream's trailer, is a file macOS Preview cannot open. + const src = new mupdf.PDFDocument(readFixture("text-simple.pdf")).saveToBuffer("compress,objstms").asUint8Array().slice(); + const lastXref = (pdf: Uint8Array) => { + const s = Buffer.from(pdf).toString("latin1"); + const at = Number(s.slice(s.lastIndexOf("startxref") + 9).trim().split(/\s/)[0]); + return s.startsWith("xref", at) ? "table" : "stream"; + }; + assert.equal(lastXref(src), "stream"); + const once = tag(src, simple); + const report = newReport(); + const twice = tag(once, simple, {}, report); + assert.ok(report.warnings.some((w) => w.code === "retagged")); + assert.deepEqual([lastXref(once), lastXref(twice)], ["stream", "stream"]); +}); + test("retagging drops a foreign tag tree and what points into it", () => { const pdf = blankPdf(1, (doc) => { const page = doc.findPage(0);