Reputation: 1
I created a PDF editor in my Angular / laravel application using: "fabric": "^6.5.3" and "pdf-lib": "^1.17.1". The thing is when I download the pdf, it is readable with all its edits in Chrome or Microsoft Edge, but when I try to read it using Adobe Acrobat Reader, the last page shows the following error: There was an error processing a page. There was a problem reading this document (18). But only if the last page is edited with a shape image or drawing, not with simple text or line. So why is that happening? here is the function responsible for downloading the edited pdf:
async downloadPdfWithEdits() {
if (!this.pdfDoc) return;
const pdfDoc = await PDFDocument.create();
const existingPdfBytes = await fetch(this.pdfURL).then(res => res.arrayBuffer());
const existingPdf = await PDFDocument.load(existingPdfBytes);
for (let i = 1; i <= this.totalPages; i++) {
const [copiedPage] = await pdfDoc.copyPages(existingPdf, [i - 1]);
const canvasState = this.pageStates[i];
if (canvasState) {
//console.log(`Loading canvas state for page ${i}:`, canvasState);
// Create an offscreen canvas element
const tempCanvasElement = document.createElement('canvas');
tempCanvasElement.width = copiedPage.getWidth();
tempCanvasElement.height = copiedPage.getHeight();
// Ensure it is added to the DOM (hidden) to avoid "ctx" undefined errors
document.body.appendChild(tempCanvasElement);
const tempCanvas = new fabric.StaticCanvas(tempCanvasElement);
console.log("Fabric.js canvas:", tempCanvas);
try {
await new Promise<void>((resolve, reject) => {
tempCanvas.loadFromJSON(canvasState, () => {
// 🔥 Ensure the canvas matches the PDF page size
tempCanvas.setDimensions({ width: this.pdfCanvas.nativeElement.width, height: this.pdfCanvas.nativeElement.height, });
tempCanvas.renderAll();
console.log("Fabric.js canvas:", tempCanvas);
setTimeout(async () => {
try {
// const imageData = tempCanvas.toDataURL({ format: 'png', multiplier: 1 });
const imageData = tempCanvas.toDataURL({ format: 'png', quality: 0.9, multiplier: 1 });
const img = await pdfDoc.embedPng(imageData);
const { width, height } = copiedPage.getSize(); // Get original PDF page size
copiedPage.drawImage(img, {
x: 0,
y: 0,
width: width, // Match width
height: height // Match height
});
console.log(`✅ Edits applied to page ${i}`);
resolve();
} catch (error) {
console.error("❌ Error embedding PNG image:", error);
reject(error);
}
}, 500);
});
});
} catch (error) {
console.error(`❌ Error processing page ${i}:`, error);
}
tempCanvas.dispose();
document.body.removeChild(tempCanvasElement);
} else {
console.log(`⚠️ No edits found for page ${i}`);
}
pdfDoc.addPage(copiedPage);
}
try {
const pdfBytes = await pdfDoc.save();
const blob = new Blob([pdfBytes], { type: 'application/pdf' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'edited.pdf';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
console.log('✅ PDF downloaded successfully');
} catch (error) {
console.error('❌ Error saving and downloading PDF:', error);
}
}
Upvotes: 0
Views: 56
Reputation: 96009
On the last page of your PDF you use an XObject Image-8784015711:
q
1 0 0 1 0 0 cm
1 0 0 1 0 0 cm
612 0 0 792 0 0 cm
1 0 0 1 0 0 cm
/Image-8784015711 Do
Q
but in the XObject resources
<<
/Type /Page
/Annots [ 307 0 R 308 0 R 309 0 R ]
/Contents [ 64 0 R 310 0 R 65 0 R 321 0 R ]
/MediaBox [ 0 0 612 792 ]
/Resources <<
/Font <<
/F92 312 0 R
>>
/ProcSet [ /PDF /Text ]
/XObject <<
/Image-735569487 320 0 R
/Image-8784015711 336 0 R
>>
/ExtGState <<
>>
>>
/Parent 1 0 R
>>
that name points to an object stream, not an XObject stream.
336 0 obj
<<
/Filter /FlateDecode
/Type /ObjStm
/N 50
/First 382
/Length 2815
>>
stream
...
endstream
endobj
Thus, that page content is indeed broken.
I don't know the libs used here and, therefore, cannot tell whether this is the result of wrong usage of them or a bug in them, but this should indicate what people who know the libs should look for.
Upvotes: 0