Convert canvas to PDF

137,449

Solution 1

You can achieve this by utilizing the jsPDF library and the toDataURL function.

I made a little demonstration:

var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');

// draw a blue cloud
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
context.closePath();
context.lineWidth = 5;
context.fillStyle = '#8ED6FF';
context.fill();
context.strokeStyle = '#0000ff';
context.stroke();

download.addEventListener("click", function() {
  // only jpeg is supported by jsPDF
  var imgData = canvas.toDataURL("image/jpeg", 1.0);
  var pdf = new jsPDF();

  pdf.addImage(imgData, 'JPEG', 0, 0);
  pdf.save("download.pdf");
}, false);
<script src="//cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.3/jspdf.min.js"></script>


<canvas id="myCanvas" width="578" height="200"></canvas>
<button id="download">download</button>

Solution 2

Please see https://github.com/joshua-gould/canvas2pdf. This library creates a PDF representation of your canvas element, unlike the other proposed solutions which embed an image in a PDF document.

//Create a new PDF canvas context.
var ctx = new canvas2pdf.Context(blobStream());

//draw your canvas like you would normally
ctx.fillStyle='yellow';
ctx.fillRect(100,100,100,100);
// more canvas drawing, etc...

//convert your PDF to a Blob and save to file
ctx.stream.on('finish', function () {
    var blob = ctx.stream.toBlob('application/pdf');
    saveAs(blob, 'example.pdf', true);
});
ctx.end();

Solution 3

So for today, jspdf-1.5.3. To answer the question of having the pdf file page exactly same as the canvas. After many tries of different combinations, I figured you gotta do something like this. We first need to set the height and width for the output pdf file with correct orientation, otherwise the sides might be cut off. Then we get the dimensions from the 'pdf' file itself, if you tried to use the canvas's dimensions, the sides might be cut off again. I am not sure why that happens, my best guess is the jsPDF convert the dimensions in other units in the library.

  // Download button
  $("#download-image").on('click', function () {
    let width = __CANVAS.width; 
    let height = __CANVAS.height;

    //set the orientation
    if(width > height){
      pdf = new jsPDF('l', 'px', [width, height]);
    }
    else{
      pdf = new jsPDF('p', 'px', [height, width]);
    }
    //then we get the dimensions from the 'pdf' file itself
    width = pdf.internal.pageSize.getWidth();
    height = pdf.internal.pageSize.getHeight();
    pdf.addImage(__CANVAS, 'PNG', 0, 0,width,height);
    pdf.save("download.pdf");
  });

Learnt about switching orientations from here: https://github.com/MrRio/jsPDF/issues/476

Solution 4

A better solution would be using Kendo ui draw dom to export to pdf-

Suppose the following html file which contains the canvas tag:

<script src="http://kendo.cdn.telerik.com/2017.2.621/js/kendo.all.min.js"></script>

    <script type="x/kendo-template" id="page-template">
     <div class="page-template">
            <div class="header">
              
            </div>
            <div class="footer" style="text-align: center">
               
                <h2> #:pageNum# </h2>
            </div>
      </div>
    </script>
    <canvas id="myCanvas" width="500" height="500"></canvas>
    <button onclick="ExportPdf()">download</button>

Now after that in your script write down the following and it will be done:

function ExportPdf(){ 
kendo.drawing
    .drawDOM("#myCanvas", 
    { 
        forcePageBreak: ".page-break", 
        paperSize: "A4",
        margin: { top: "1cm", bottom: "1cm" },
        scale: 0.8,
        height: 500, 
        template: $("#page-template").html(),
        keepTogether: ".prevent-split"
    })
        .then(function(group){
        kendo.drawing.pdf.saveAs(group, "Exported_Itinerary.pdf")
    });
}

And that is it, Write anything in that canvas and simply press that download button all exported into PDF. Here is a link to Kendo UI - http://docs.telerik.com/kendo-ui/framework/drawing/drawing-dom

Share:
137,449
Kasta
Author by

Kasta

Updated on September 28, 2021

Comments

  • Kasta
    Kasta almost 3 years

    Is it possible to directly convert canvas to pdf using JavaScript (pdf.js or something like that)?

    Is there another possible way like canvas to img and then img to pdf?

    Can you give me an example?

  • Kasta
    Kasta about 10 years
    nice thank you :) and is there any way how to export pdf with same size(width/height) as img?
  • Fr3d
    Fr3d about 10 years
    It is possible, but you will have to edit the jsPDF library to do that.
  • lilHar
    lilHar almost 8 years
    Hmm... attempted, but addImage line returns an error... I think the function may have been replaced?
  • Ahmadov
    Ahmadov almost 8 years
    @Adil Waqar have you added the jspdf.js file as a script?
  • Lee Taylor
    Lee Taylor over 7 years
    Fixed to use CDN version of library. Previous link had died.
  • Mateusz Bartkowski
    Mateusz Bartkowski almost 7 years
    Why is the download variable being set in the event listener function?
  • Fr3d
    Fr3d almost 7 years
    @MateuszBartkowski As a mistake i presume. It was added when someone edited my answer to have a code snippet.
  • Ioulian Alexeev
    Ioulian Alexeev almost 7 years
    As this library does not simply render canvas to jpeg and put it inside a PDF, it creates a high quality/high resolution pdf
  • Mr Coder
    Mr Coder over 6 years
    good library but does not support drawmage() so you cannot add bitmap images on PDF
  • user1860166
    user1860166 over 6 years
    Support for images has been added. Please see image example at joshua-gould.github.io/canvas2pdf/demo.html.
  • Anthony Griggs
    Anthony Griggs over 6 years
    Worked perfect! If you prefer to download the JS like I did just visit the page and copy the text into an empty javascript file: cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.3/jspdf.min.js
  • ejectamenta
    ejectamenta about 6 years
    Shame that it doesnt support context transformation, ie ctx.setTransform(2,1,0.5,1,0,1); Image looks the same
  • ejectamenta
    ejectamenta about 6 years
    Cool, but prohibitively expensive
  • Sergiy Ostrovsky
    Sergiy Ostrovsky over 5 years
    Didn't work in Chrome 72.0 for me. PDF it produces was broken.
  • Harshan Morawaka
    Harshan Morawaka over 4 years
    this works fine but my client complain that it will take long time for big images to convert base64 to PDF any solution ?
  • Dror Bar
    Dror Bar over 4 years
    Thanks, your answer was helpful.
  • rahim.nagori
    rahim.nagori almost 4 years
    The image is always black background, can I change it to transparent or white?
  • airider74
    airider74 almost 4 years
    What about a multi-layer canvas?
  • OJB1
    OJB1 almost 3 years
    Absolutely awesome, thank you so much!
  • David rnk
    David rnk over 2 years
    With this library I can convert a div element with more elements within it, including background images and that respects the styles with CSS?