I'm facing a weird error with the File System API. I'm trying to download a PDF generated from a batch of images when the use clicks a button.
Here is my current code:
mainContainer.addEventListener('click', async function (event) {
if (event.target.id === 'dl-button') {
const selectedImgs = getSelectedImages();
let images = await getAllImageDataUrls(selectedImgs);
await triggerImagesDownload(images);
}
});
async function embedImage(pdfDoc, base64Image) {
let base64ImagePart = base64Image.split(';base64,')[1]
const isJPEG = base64ImagePart.startsWith("/9j/")
const imageBytes = Uint8Array.from(atob(base64ImagePart), c => c.charCodeAt(0));
if (isJPEG) {
return await pdfDoc.embedJpg(imageBytes);
} else {
return await pdfDoc.embedPng(imageBytes);
}
}
async function triggerImagesDownload(base64Images) {
// Create a new PDF document
const pdfDoc = await PDFLib.PDFDocument.create();
const embedImagesPromises = base64Images.map(base64Image => embedImage(pdfDoc, base64Image));
const images = await Promise.all(embedImagesPromises);
images.forEach(image => {
const page = pdfDoc.addPage([image.width, image.height]);
page.drawImage(image, {
x: 0,
y: 0,
width: image.width,
height: image.height,
});
});
// Serialize the PDFDocument to bytes
const pdfBytes = await pdfDoc.save();
await savePDFFile(new Blob([pdfBytes], {type: 'application/pdf'}));
chrome.storage.local.set({currentView: "home"}, function() {
window.location.reload();
});
}
async function savePDFFile(pdfBlob) {
let suggestedName = `images.pdf`
try {
const newHandle = await window.showSaveFilePicker({
suggestedName: suggestedName,
types: [{
description: 'PDF document from captured slides',
accept: {'application/pdf': ['.pdf']}
}],
});
const writableStream = await newHandle.createWritable();
await writableStream.write(pdfBlob);
await writableStream.close();
console.log('PDF saved successfully.');
} catch (err) {
alert(err)
}
}
The problem occurs when the number of images I convert into a PDF. I've tested with a batch of 13 images:
if I convert max 5 images and download the generated pdf, I get to use the file picker and basically the
trylogic inside thesavePDFFilefunctionif I try to exceed the 5 images limit I get a
SecurityError:SecurityError: Failed to execute 'showSaveFilePicker' on 'Window': Must be handling a user gesture to show a file picker.
A useful information is that the pdf generated from 5 images is 7.6MB
Does anyone know what am I doing wrong or what I've missed in the fs api documentation?
showSaveFilePickeris one of the methods guarded by Transient activation - "a window state that indicates a user has recently pressed a button, moved a mouse, used a menu, or performed some other user interaction. Transient activation expires after a timeout (if not renewed by further interaction)" (bold highlighting by me.) So apparently, your process simply takes too long, when you go over a certain amount of images.