Search code examples
javascripthtml5-canvasp5.jsjspdf

Download p5.js sketch canvas as PDF using jsPDF addImage JPEG


Trying to get a minimal script running to download a p5.js sketch canvas element as a PDF using jsPDF -- specifically the jsPDF addImage method, after converting the canvas to a JPEG using the JS toDataURL method.

I can get p5.js to draw on the canvas and jsPDF to download a PDF after launching the page, but the PDF is blank (black with JPEG, white with PNG, presumably b/c alpha channel). I'm guessing this is because of where I have the jsPDF code in the script, but anywhere else I put it, the download doesn't work.

Any advice?

(FWIW, I tried the solution to this: JsPDF addImage jpeg background is black, but I just end up with an all-white PDF, like when I go with PNG instead of JPEG)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Page 0</title>

    <link rel="stylesheet" type="text/css" href="style.css">

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.debug.js" integrity="sha384-NaWTHo/8YCBYJ59830LTz/P4aQZK1sS0SneOgAvhsIl3zBu8r9RevNg5lHCHAuQ/" crossorigin="anonymous"></script>
    <script src="libraries/p5.min.js"></script>
    <script src="libraries/p5.sound.min.js"></script>
  </head>

  <body>
    <script src="page0.js"></script>
  </body>
</html>
function  setup() {

  let     the_canvas  =     createCanvas(792, 612, P2D);

                            noLoop();

  let     doc         = new jsPDF("l", "pt", [792, 612]);

  let     the_img     =     the_canvas.elt.toDataURL("image/JPEG", 1.0);
                            doc.addImage(the_img, "JPEG", 0, 0, 792, 612);

                            doc.save("page0.pdf");
                          
}

function  draw() {

                            background(43);

                            stroke(200);
                            fill(200);
                            textSize(100);
                            text("Test", 500, 500);

}
html, body {
  margin: 0;
  padding: 0;
}

canvas {
  display: block;
}

Solution

  • Since setup runs first, then draw, you save the PDF before writing text to it.

    Try drawing and writing, then saving the PDF as the final step:

    <!doctype html>
    <html lang="en">
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Page 0</title>
    <style>
    html,
    body {
      margin: 0;
      padding: 0;
    }
    
    canvas {
      display: block;
    }
    </style>
    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.debug.js"
      integrity="sha384-NaWTHo/8YCBYJ59830LTz/P4aQZK1sS0SneOgAvhsIl3zBu8r9RevNg5lHCHAuQ/"
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.js"></script>
    </head>
    <body>
    <script>
    let canvas;
    
    function setup() {
      canvas = createCanvas(792, 612, P2D);
      noLoop();
    }
    
    function draw() {
      background(43);
      stroke(200);
      fill(200);
      textSize(100);
      text("Test", 500, 500);
      const doc = new jsPDF("l", "pt", [792, 612]);
      const img = canvas.elt.toDataURL("image/JPEG", 1.0);
      doc.addImage(img, "JPEG", 0, 0, 792, 612);
      doc.save("page0.pdf");
    }
    </script>
    </body>
    </html>
    

    Note that separating setup and draw functions as shown above isn't strictly necessary since you're doing a one-shot operation. You could put all of the code in setup, or all of the code in draw (with noLoop() so it only runs once).