在Angular 6中将HTML转换为PDF

30
我有一个组件(Angular 6),它是几个组件的聚合体。这会生成一段很长的HTML代码(我正在使用Bootstrap 4)。现在我想把这个HTML转换成PDF格式。我已经搜索了很多解决方案,发现jsPDF可以实现。要求产生的布局清晰,就像在HTML中一样(这样用户可以选择、复制等)。但我找到的解决方案要么尝试手动添加文本行(在我的情况下不可能),要么将HTML转换(光栅化?)为图像格式。此外,我想保留我的HTML的格式、字体和样式。
到目前为止,我尝试过:这个这个
7个回答

35

目前为止我能想到的最佳解决方案。

您需要从npm安装以下软件包

html2canvas

jspdf

import * as jsPDF from 'jspdf';
import html2canvas from 'html2canvas';

htmltoPDF()
{
    // parentdiv is the html element which has to be converted to PDF
    html2canvas(document.querySelector("#parentdiv")).then(canvas => {

      var pdf = new jsPDF('p', 'pt', [canvas.width, canvas.height]);

      var imgData  = canvas.toDataURL("image/jpeg", 1.0);
      pdf.addImage(imgData,0,0,canvas.width, canvas.height);
      pdf.save('converteddoc.pdf');

  });

}

更新:

想到了另一个解决方案。我无法将其拆分成A4大小的页面,但我能够制作单个PDF文件。

包:

dom-to-image

jspdf

import domtoimage from 'dom-to-image';
import * as jsPDF from 'jspdf';



            downloadPDF()
            {

              var node = document.getElementById('parentdiv');

              var img;
              var filename;
              var newImage;


              domtoimage.toPng(node, { bgcolor: '#fff' })

                .then(function(dataUrl) {

                  img = new Image();
                  img.src = dataUrl;
                  newImage = img.src;

                  img.onload = function(){

                  var pdfWidth = img.width;
                  var pdfHeight = img.height;

                    // FileSaver.saveAs(dataUrl, 'my-pdfimage.png'); // Save as Image

                    var doc;

                    if(pdfWidth > pdfHeight)
                    {
                      doc = new jsPDF('l', 'px', [pdfWidth , pdfHeight]);
                    }
                    else
                    {
                      doc = new jsPDF('p', 'px', [pdfWidth , pdfHeight]);
                    }


                    var width = doc.internal.pageSize.getWidth();
                    var height = doc.internal.pageSize.getHeight();


                    doc.addImage(newImage, 'PNG',  10, 10, width, height);
                    filename = 'mypdf_' + '.pdf';
                    doc.save(filename);

                  };


                })
                .catch(function(error) {

                 // Error Handling

                });



            }

1
这将直接将PDF保存到浏览器窗口。您如何将其分配给Angular6 Observable,因为html2canvas方法返回自己的promise方法? - Sean Halls

10
以下代码被使用并在我的项目中起了作用。
步骤1:运行以下命令以安装npm软件包。
> npm install jspdf
> npm install html2canvas

步骤2:在app.components.ts中导入已安装的包。我没有在constructor()中导入那些包。

> import * as jspdf from 'jspdf';
> import html2canvas from 'html2canvas';

第三步:为需要导出为PDF的HTML div添加一个id。同时添加一个按钮以激活该函数。

<div id="MyDIv" style="margin-left: 45px;" class="main-container">

</div>
<div class="icon_image " title="Share As PDF" (click)="exportAsPDF('MyDIv');"><img src="assets/img/pdf.png"></div>

步骤4:编写生成PDF的代码如下

exportAsPDF(div_id)
  {
    let data = document.getElementById(div_id);  
    html2canvas(data).then(canvas => {
      const contentDataURL = canvas.toDataURL('image/png')  
      let pdf = new jspdf('l', 'cm', 'a4'); //Generates PDF in landscape mode
      // let pdf = new jspdf('p', 'cm', 'a4'); Generates PDF in portrait mode
      pdf.addImage(contentDataURL, 'PNG', 0, 0, 29.7, 21.0);  
      pdf.save('Filename.pdf');   
    }); 
  }

这段代码期望从HTML文件中接收0个参数。或者是你在.ts/.js文件中省略了参数? - Brio Tech
另外,关于代码 pdf.addImage(contentDataURL, 'PNG', 0, 0, 29.7, 21.0) 的格式是什么? - Brio Tech

3
通过一些努力,我和我的团队为我们自己的Angular HTML转PDF问题想出了最佳解决方案,即将原始HTML发送到我们的Java API,然后利用wkhtmltopdf (https://github.com/wkhtmltopdf/wkhtmltopdf) 和Java封装器(https://github.com/jhonnymertz/java-wkhtmltopdf-wrapper)。克服了一些小问题(如确保服务器安装了正确的字体;一切都被正确编码;找出页面断点并使其工作),我们能够精确地复制我们的页面,并使用我们的Angular HTML作为通用模板(根据不同情况进行更改)。这不是一条容易的道路,但是一旦你弄清楚了,它会在企业级生产环境中产生很好的结果。
值得注意的是,我们还尝试过jspdf(和其他库),并得出了与您类似的结论:它们无法满足我们的需求。希望这可以帮到您。

你是如何将原始HTML发送到API的? - Meqwz
@Meqwz 好久不见了,但我记得我们将其作为64位编码的POST主体发送。 - MapLion

2

我在使用 html2canvas 时遇到了问题,因此不得不使用 html-to-image。我不知道为什么,但无论我尝试什么,html2canvas 都无法渲染出正确的图片。相比之下,html-to-image 让我轻松地获得了正确的渲染结果。

使用方法:

var node = <HTMLElement>document.getElementById('export');

htmlToImage.toPng(node)
           .then(function (dataUrl) {
                var img = new Image();
                img.src = dataUrl;

                var doc = new jsPDF('p', 'mm', 'a4');
                const bufferX = 5;
                const bufferY = 5;
                const imgProps = (<any>doc).getImageProperties(img);
                const pdfWidth = doc.internal.pageSize.getWidth() - 2 * bufferX;
                const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
                doc.addImage(img, 'PNG', bufferX, bufferY, pdfWidth, pdfHeight, undefined, 'FAST');
                doc.save('Bill_'+new Date().toDateString()); 
            })
            .catch(function (error) {
                console.error('oops, something went wrong!', error);
            });

1

首先安装以下内容: 1)npm install jspdf 2)npm install html2canvas

之后导入并使用以下代码。

 public captureScreen() {
      const data = document.getElementById('invoice');
      html2canvas(data).then(canvas => {
      const imgWidth = 208;
      const pageHeight = 295;
      const imgHeight = canvas.height * imgWidth / canvas.width;
      const heightLeft = imgHeight;
      const contentDataURL = canvas.toDataURL('image/png');
      const pdf = new jspdf('p', 'mm', 'a4'); 
      const position = 0;
      pdf.addImage(contentDataURL, 'PNG', 0, position, imgWidth, imgHeight);
      pdf.save('invoice.pdf'); 
      });
      }

0

0
第一步:安装所需软件包
npm install jspdf jspdf-autotable

步骤2:导入已安装的包以使用

 import jsPDF from 'jspdf';
 import 'jspdf-autotable';

步骤三:如果您的数据包含图片,请将图片转换为Base64格式

tabledata = [{
    img: 'https://i.picsum.photos/id/258/536/354.jpg',
    name: 'Joseph',
    domain: 'Angular 9'
  },
  {
    img: 'https://i.picsum.photos/id/258/536/354.jpg',
    name: 'Vani',
    domain: 'Angular 8'
  }, {
    img: 'https://i.picsum.photos/id/258/536/354.jpg',
    name: 'Raj',
    domain: 'React.js'
  },
];

上面是将图片转换为Base64后的数据。 转换函数如下:
convertImagetoBase64(url, callback) {
    const xhr = new XMLHttpRequest();
    xhr.onload = () => {
      const reader = new FileReader();
      reader.onloadend = () => {
        callback(reader.result);
      };
      reader.readAsDataURL(xhr.response);
    };
    xhr.open('GET', url);
    xhr.responseType = 'blob';
    xhr.send();
}

在将图像绑定到HTML表之前,让我们将图像URL转换为base64格式。

this.tabledata.forEach(elem => {
  this.convertImagetoBase64(elem.img, (b64Img) => {
    elem.img = b64Img;
});

现在将数据绑定到表格中。如果您不想在前端显示表格,只需使用以下代码样式来隐藏它:
<table id="imgTable" style=”display:none”>
<thead>
    <tr><th>Name</th>
    <th>Domain</th>
    <th>Image</th>
    </tr>
</thead>
<tbody>
    <tr *ngFor="let data of tabledata">
        <td>{{data.name}}</td>
        <td>{{data.domain}}</td>
        <td><img src="{{data.img}}" width="100" height="100" /></td>
    </tr>

</tbody>
</table>
<button (click)="generatePdf()">Generate Pdf</button>

生成PDF函数如下所示:

app.component.ts

generatePdf(){
 doc.autoTable({
  html: '#imgTable',
  bodyStyles: { minCellHeight: 20 },
  theme: 'grid',
  styles: { valign: 'middle', overflow: 'linebreak', halign: 'center', minCellHeight: 21 },
  pageBreak: 'avoid',
  columnStyles: {
    2: { cellWidth: 22, minCellHeight: 22 },
  },
  headStyles: { fillColor: '#f2f2f2', textColor: '#000', fontStyle: 'bold', lineWidth: 0.5, lineColor: '#ccc' },
  didDrawCell: (data) => {
    if (data.column.index === 2 && data.cell.section === 'body') {
      const td = data.cell.raw;
      const img = td.getElementsByTagName('img')[0];
      // let dim = data.cell.height - data.cell.padding('vertical');
      // let textPos = data.cell.textPos;
      doc.addImage(img.src, data.cell.x + 1, data.cell.y + 1, 19, 19);

    }
  }
});
 doc.save('yourpdfname.pdf');
}

生成PDF的示例如下:

如需更多不带表格的PDF格式,请访问helperscript.com


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