将画布转换为PDF

55

是否可以使用JavaScript(例如pdf.js)直接将画布(Canvas)转换为PDF?

还有其他可能的方法吗,例如将Canvas转换为图像,然后将图像转换为PDF?

你能给我一个例子吗?

4个回答

99

您可以利用jsPDF库和toDataURL函数实现此功能。

我制作了一个小演示:

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>


3
谢谢你的好评 :) 有没有办法将PDF与图像具有相同的大小(宽度/高度)进行导出? - Kasta
可以实现,但您需要编辑jsPDF库才能完成。 - Fr3d
3
@MateuszBartkowski 我猜是一个错误。当有人编辑我的答案并添加代码片段时,它被添加进去了。 - Fr3d
1
图片总是黑色背景,我能把它改成透明或白色吗? - rahim.nagori
1
@rahim.nagori,您可以使用此答案中的函数来更改图像的背景:https://dev59.com/h6vka4cB1Zd3GeqPmgSX#50126796 - abggcv
显示剩余7条评论

18

请查看https://github.com/joshua-gould/canvas2pdf。该库可以创建您的画布元素的PDF表示,与其他建议的解决方案不同,其他方案在PDF文档中嵌入图像。

//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();

3
这个库不仅仅是将画布渲染成 JPEG 格式并放入 PDF 中,它会创建一个高质量/高分辨率的 PDF。 - Yulian
好的库,但不支持drawmage(),因此您无法在PDF上添加位图图像。 - Mr Coder
3
现已添加对图片的支持。请参见 https://joshua-gould.github.io/canvas2pdf/demo.html 上的图片示例。 - user1860166
很遗憾它不支持上下文转换,即ctx.setTransform(2,1,0.5,1,0,1); 图像看起来一样。 - ejectamenta
多层画布怎么样? - airider74
使用这个库,我可以将一个包含更多元素的 div 元素转换为包括背景图片并且保持 CSS 样式的元素吗? - David rnk

11

所以今天的话题是 jspdf-1.5.3。 回答关于让pdf文件页面与画布完全相同的问题。在尝试了不同组合后,我发现你需要像这样做。 我们首先需要为输出的pdf文件设置正确方向的高度和宽度,否则可能会裁剪边缘。然后我们从'pdf'文件本身获取尺寸,如果尝试使用画布的尺寸,则可能会再次裁剪边缘。我不确定为什么会发生这种情况,我最好的猜测是jsPDF在库中将尺寸转换为其他单位。

  // 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");
  });

从这里了解有关更改方向的信息:https://github.com/MrRio/jsPDF/issues/476


谢谢,你的回答很有帮助。 - Dror Bar
太棒了,非常感谢! - OJB1

3
更好的解决方案是使用Kendo UI绘制DOM来导出为PDF文件。假设以下HTML文件包含canvas标签:
<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>

现在,在您的脚本中写下以下内容,就可以完成了:
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")
    });
}

就是这样,只需在画布上写任何内容,然后按下下载按钮即可将所有内容导出为PDF格式。 这里是Kendo UI的链接-http://docs.telerik.com/kendo-ui/framework/drawing/drawing-dom


4
很酷,但价格过高。 - ejectamenta
这看起来很有前途,但是有几个问题:1)我的图表宽度大于高度,被裁剪了;2)这似乎导入了一个像素化的光栅表示;3)需要最低1000美元的许可证 - 所有这些只为了在我的应用程序中获得一个单独的下载链接和一个单独的图表...而这也可以使用免费库来完成 :/ "价格过高"没错。 - youcantryreachingme

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接