0

I am trying to add a couple of images to a pdf. I am using the jspdf plugin for this. My code is as following:

document.getElementById("help").addEventListener("click",function(){
    var base1="";
    var base2="";
    var base3="";
    var doc = new jsPDF();
    var img=new Image();
    var img1=new Image();
    var img2=new Image();
    img.onload = function() {
        var canvas = document.createElement("canvas");
        ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0);
        base1 = canvas.toDataURL();
    }
    img.src='/Screenshot (1).png';
    img1.onload = function() {
        var canvas = document.createElement("canvas");
        ctx = canvas.getContext('2d');
        ctx.drawImage(img1, 0, 0);
        base2 = canvas.toDataURL();
    }
    img1.src='/Screenshot (2).png';
    img2.onload = function() {
        var canvas = document.createElement("canvas");
        ctx = canvas.getContext('2d');
        ctx.drawImage(img2, 0, 0);
        base3 = canvas.toDataURL();
    }
    img2.src='/Screenshot (3).png';

    doc.addImage(base1,'PNG',20,36,100,120);
    
    doc.addImage(base2,'PNG',20,158,100,120);
   
    doc.addImage(base3,'PNG',20,281,100,120);
    doc.save("example.pdf");
})

But when I execute the code, I get the following error in addImage():

Uncaught Error: Incomplete or corrupt PNG file

How do I fix this?

EDIT: After implementing @AKX's solution, the code works in the local machine. But when tested live, it throws this error:

Uncaught (in promise) Event {isTrusted: true, type: 'error', target: null, currentTarget: null, eventPhase: 0, …}

  • You're not waiting for the images to load before you create a PDF. – AKX Jan 21 '22 at 09:07
  • then should I use a `setTimeout()` function before `doc.addImage`? –  Jan 21 '22 at 09:09
  • A `setTimeout()` is not robust (unless you make it infinitely long, in which case it's quite useless). – AKX Jan 21 '22 at 09:11
  • Try this: https://jsfiddle.net/khrismuc/k6owv9ya/ (untested!) also: [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) –  Jan 21 '22 at 09:25
  • Duplicate: [Wait for multiple images to load](https://stackoverflow.com/questions/53707345/wait-for-multiple-images-to-load) –  Jan 21 '22 at 09:33

1 Answers1

0

You're not waiting for all the images to load. You can refactor things to use a promisified function to load an image and turn it into a data URI (though according to the docs for jspdf, a HTMLImageElement would also do, so you could skip the canvas bit), and then turn your handler into an async function to make it easy to just await for all the loads.

function loadImageAsDataURL(url) {
  return new Promise((resolve, reject) => {
    var img = new Image();
    img.onload = function () {
      var canvas = document.createElement('canvas');
      var ctx = canvas.getContext('2d');
      ctx.drawImage(img, 0, 0);
      resolve(canvas.toDataURL());
    }
    img.onerror = reject;
    img.src = url;
  });
}

document.getElementById('help').addEventListener('click', async function () {
  // Load all images first...
  var base1 = await loadImageAsDataURL("/Screenshot (1).png");
  var base2 = await loadImageAsDataURL("/Screenshot (2).png");
  var base3 = await loadImageAsDataURL("/Screenshot (3).png");
  // ... and then generate the PDF.
  var doc = new jsPDF();
  doc.addImage(base1, 'PNG', 20, 36, 100, 120);
  doc.addImage(base2, 'PNG', 20, 158, 100, 120);
  doc.addImage(base3, 'PNG', 20, 281, 100, 120);
  doc.save('example.pdf');
})
AKX
  • 152,115
  • 15
  • 115
  • 172
  • This is predictably a dupe, see https://stackoverflow.com/questions/53707345/wait-for-multiple-images-to-load –  Jan 21 '22 at 09:34
  • It works in `localhost`, but I keep getting an `Uncaught (in promise)` error, after uploading it live –  Jan 21 '22 at 11:15
  • Well, do those paths exist in your live environment? You'd get an error if they don't. – AKX Jan 21 '22 at 11:17
  • Yes they exist. The file hierarchy is the same as the `localhost` one –  Jan 21 '22 at 11:19
  • See your browser's network inspector to figure out what the error might be. – AKX Jan 21 '22 at 11:30
  • Ok, after renaming all the image names, the code's finally working. For some weird reason, it wasn't accepting the `(`,`)`,`_` special characters. –  Jan 21 '22 at 11:30