FileSystemAPI fails due to SecurityError

32 Views Asked by At

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 try logic inside the savePDFFile function

  • if 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?

0

There are 0 best solutions below