带中文的网页下载为PDF格式的文件(jsPDF)

1、调研

          主要需要用到插件jsPDF,jsPDF可以将html下载为pdf格式的文件,但无法支持中文字形,下载带中文的网页会有乱码,经验证可以通过如下3种方案下载中文网页。

2、方案

       2.1、方案一(jsPDF + html2canvas):html元素通过html2canvas生成canvas,再将canvas添加到pdf文档上。

                 优点: 文档清晰度可控制,下载的PDF文件上不会有乱码,html样式还原度100%。

                 缺点: 分页不好控制,适合不长或者每页内容比较规律(比如table数据)的页面下载。

                 项目下载jsPDF和html2canvas依赖,引入依赖,下面按不分页与分页的2种情况给出代码示例。

        2.1.1 不分页

js源码如下:

import { jsPDF } from 'jspdf';
import html2canvas from 'html2canvas';
let element = document.body; //下载整个页面,也可以下载页面的部分html
let scale = 0.5;
let pageFormat = [element.scrollWidth * scale, element.scrollHeight * scale];
const pdf = new jsPDF({
  orientation: 'l',
  unit: 'pt', // pdf大小计量单位
  format: pageFormat // 自定义第一页pdf页面大小,按html元素的比例设定
});
let opt = {
  scale: 4 // 保证pdf文档内容清晰度,放大4倍,网上说这种方案文档清晰度不高,经验证可以这么解决清晰度问题 
};
let width = pageFormat[0];
let height = pageFormat[1];
// 将html元素绘制为cancas
html2canvas(element, opt).then(canvas => {
  // cancas添加到pdf文档上
  pdf.addImage(canvas, 0, 0, width, height);
  // 下载
  pdf.save('下载' + '.pdf');
});

       2.1.2 分页

                html:提前规划每月pdf内容

<div v-for="(data, index) in pageData" :key="index" :ref="'page' + index" class="pdf-page">
  第{{ index + 1 }} 页
  ......
</div>

                  js代码:将每一块的html转化为canvas,再将canvas添加到pdf的一页上

        // pageCount: 总共的页数
        if (this.pageCount === 0) return;
        let elScale = 0.5;
        // 将每一块的html转化为canvas,再将canvas添加到pdf的一页上
        let canvasPage = (pdf, index) => {
          let element = this.$refs['page' + index][0];
          let width = element.scrollWidth * elScale;
          let height = element.scrollHeight * elScale;
          html2canvas(element, { scale: 4 }).then(canvas => {
            (index > 0) && pdf.addPage();
            pdf.addImage(canvas, 0, 0, width, height);
            if ((index + 1) === this.pageCount) {
              pdf.save('demp.pdf');
              return;
            }
          index++;
          canvasPage(pdf, index);
        });
      };
      const pdf = new jsPDF({orientation: 'p', unit: 'pt', format: 'a4'});
      this.$nextTick(() => {
        canvasPage(pdf, 0);
      });
    }

       2.2、方案二(jsPDF添加ttf中文字形文件)

                 优点:pdf文档可以自动分页。

                 缺点:需要保证带中文的html元素的字体(font-family)和新添加的ttf文件字体一致,不然中文也为乱码,会和你用的插件字体有冲突(比如你用到了iconfont),html中如果有图片会无法下载成功。

                 步骤如下:

                a、下载ttf文件。

                b、通过jsPDF提供的网页将ttf文件转为js文件(文件较大),网页地址:https://rawgit.com/MrRio/jsPDF/master/fontconverter/fontconverter.html,转化后的js文件内容如下:

                c、将font字符串复制粘贴到json文件(js文件内容很大,最好用记事本打开会快一些),放在前端项目的文件夹下,通过http请求json文件内容(不直接引入js文件,因为字体文件很大,直接引入node会报错)。

                 d、示例使用的ttf文件和json文件下载地址:https://download.csdn.net/download/buler_sky/15417402

                 e、html元素修改字体:style="font-family:chinese"。

                 f、项目下载jsPDF和axios依赖(或者其他可以发送请求的插件),引入依赖,js源码如下: 

import { jsPDF } from 'jspdf';
import axios from 'axios';
axios.get('/jspdf/chinese.json').then(res => {
  var callAddFont = function () {
    this.addFileToVFS('chinese.ttf', res.data.font);
    this.addFont('chinese.ttf', 'chinese', 'normal');
  };
  jsPDF.API.events.push(['addFonts', callAddFont]);
  download(jsPDF);
});
download(jsPDF) {
  let element = document.body; //下载整个页面,也可以下载页面的部分html
  let pdf = new jsPDF({
     orientation: 'l',
     unit: 'pt',
     format: 'a4',
     compress: true
  });
  pdf.setFont('chinese');
  pdf.setFontSize(14);
  let pWidth = pdf.internal.pageSize.width; // 595.28 is the width of a4
  let srcWidth = element.scrollWidth;
  let margin = 18; // narrow margin - 1.27 cm (36);
  let scale = (pWidth - margin * 2) / srcWidth;
  pdf.html(element, {
    x: margin,
    y: margin,
    html2canvas: {
      scale: scale
    },
    callback: function (doc) {
       doc.save();
    }
  });
}

        2.3、 方案三(jsPdf + jsPDF-CustomFonts-support)

                   优点: 示例为非包管理的项目、和方案二原理差不多,都是替换字体源,引入很简单;

                   缺点: 对应jsPDF版本比较老、和jsPdf文档的api很多都不一致

                   a、通过script引入插件:      

                  <script src="/jspdf/jspdf.es.min.js"></script> 

                  <script src="/jspdf/jspdf.customfonts.min.js"></script> 

                   <script src="/jspdf/default_vfs.js"></script> 

                   b、js代码:

      let element = document.body; //下载整个页面,也可以下载页面的部分html
      const doc = new jsPDF({format: 'a4'});
      doc.addFont('NotoSansCJKtc-Regular.ttf', 'NotoSansCJKtc-Regular', 'normal');
      doc.setFont('NotoSansCJKtc-Regular');
      console.log(doc.getFont());
      //最新的jsPdf的api为doc.html()
      doc.addHTML(element , {
        callback: function (doc) {
          doc.save();
        },
        x: 10,
        y: 10,
        margin: 10
      });

             c、示例文件下载地址:https://download.csdn.net/download/buler_sky/15501445

 3、总结

           1、寻找方法的过程中淘汰的方法:

                方案三和方案二的原理差不多,但是不适合通过包管理的项目,需要通过script引入插件,且对应jsPDF版本比较老。

           2、寻找最佳解决方案的过程中遇见很多坑,这里依然没有完美的解决问题(pdf分页不完美和背景图片无法下载),后续有突破会继续更新,大家在实践过程中如果有问题欢迎留言讨论。

      

                          

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值