前端对PDF文件操作总结

1,749 阅读3分钟

主要讲一下,在日常项目中用到的关于PDF的一些操作

  一、动态生成PDF

1、使用jsPDF + html2canvas

整体流程大致是:

  1. 安装jsPDF

    npm install jspdf

代码中:

import jsPDF from 'jspdf';
import Html2canvas from "html2canvas";

2)  在HTML中绘制DOM

将你需要绘制的PDF内容,在一个区域内通过DOM绘制下来。这个过程中需要注意的是,对于页面中跨域的图片,需要转成base64格式。

// 将跨域图片转换为base64格式    
toBase64List = (srcList, typeUrl, _this) => {        
 function getBase64Image(img, i, description) {            
    let canvas = document.createElement("canvas");            
    canvas.width = img.width;            
    canvas.height = img.height;            
    let ctx = canvas.getContext("2d");            
    ctx.drawImage(img, 0, 0, canvas.width, canvas.height);            
    let result = _this.state[typeUrl] || [];            
    result[i] = { url: canvas.toDataURL(), description } ;            
    _this.setState({ [typeUrl]: result });        
 }        
 srcList.forEach((item, i) => {            
   let image = new Image();            
   image.crossOrigin = '';            
   image.src = item.url;            
     if (item.url) {                
       image.onload = function () {                    
          getBase64Image(image, i, item.description);                
       }            
     }        
 });   
}

3) 通过 html2canvas 将页面DOM转换成图片;

let canvas = await Html2canvas(document.querySelector("#cover"),  { scale: 1 });

这个转换的方法写起来很简单,但是html2canvas其实做了很多工作,包括一些资源的下载,例如字体等,如果字体非常大,可以明显看到这个过程非常的慢。

  1. 通过jspdf将图片导出为pdf文件;

指定需要的PDF是横版还是竖版,使用的单位,以及是A4还是其他板式。

let doc = new jsPDF('l', 'pt', 'a4');
 doc.addPage(); // 新增一页

通过addPage新增一页,然后将图片添加到doc中

const [x, y, width, height] = [0, 0, 1000.63, 708.66];
doc.addImage(canvas.toDataURL("image/jpg"), 'JPEG', x, y, width, height);

最后通过save方法直接唤起浏览器的保存PDF的界面

let result = await doc.save(`我是一个PDF文件.pdf`, { returnPromise: true });

整体流程清晰明了,就是先中转为图片,再通过图片转换成PDF文件。

因为jsPDf的官方文档并不稳定,很多时候无法访问,这里建议还是直接看jsPDf的源码,其实很简单。

2、其他方式待补充

当然还有其他的一些方式,以后有所尝试会在这里补充。

  二、PDF文件在页面的展示

1 打印PDF文件

先在页面中通过iframe引入pdf文件,然后通过print方法唤起打印。

<iframe style={{width: '100%', height: '80vh'}} title='第1份文件' id="iframeName" src={url} />
const printIframe = document.getElementById('iframeName');    
printIframe.contentWindow.print();

注意:如果PDF文件跨域,需要事先去通过ajax请求获取文件,然后转换成Blob格式。

如果只是需要打印功能,PDF文件不想在页面展示,只要把iframe的样式display设置为none,就能在更为友好的情况下实现PDF的打印功能

const blob = new Blob([res.data], { type: 'application/pdf' });        
let url = URL.createObjectURL(blob)

2 展示PDF文件

1)iframe元素,如上例子,不多讲。ios手机端不能缩放,需要通过修改CSS样式来调整。

<iframe
  style={{ width: '100%',  height: '80vh'}}
  title="PDF文件"
  id="Iframe"
  src={pdfUrl}
 />

如果只是纯展示,直接使用PDF路径,如果需要在外部对PDF文件进行打印,可以通过js获取PDF文件流,转成base64格式的路径来使用,避免iframe的跨域问题,视情况而定。

new Promise((resolve, reject): void => {
    axios({
      baseURL: XXX,
      method: 'GET',
      url,
      params,
      responseType: 'blob'
    }).then((res): void => {
        let blob = new Blob([res.data], { type: 'application/pdf' });
        resolve(URL.createObjectURL(blob));    }).catch((err): void => {
        reject(err);
      });
  });

2)embed元素,但是手机端浏览器有兼容问题,可能无法使用。

HTML <embed> 元素将外部内容嵌入文档中的指定位置,但是MDN上有提到,大多数现代浏览器已经弃用并取消了对浏览器插件的支持,所以建议尽量少用或者不用<embed>元素。

<embed
  type="application/pdf"
  src={pdfUrl}
  title={pdfName}
  style={{ height: '100vh' }}
/>

适合纯PDF文件展示。

3)PDFjs库 ,将PDF文件转换成canvas,然后可以正常展示在HTML页面中。

pdf.js库是一款功能强大的PDF文件操作库,这里就不细讲,可以关注官网的相关例子,原理是通过canvas实现展示效果,这是和上面几个例子不同的地方,好处就是,可以进一步对PDF文件进行修改,比较灵活。

如果想要进一步实现打印效果,就需要比较好的CSS功底,通过样式的调整,来实现打印页面与当前预览界面区别。

@media print {    
    @page {      
        margin: 7mm 0 !important;      
        padding: 0;   
}}