zoukankan      html  css  js  c++  java
  • 用js生成PDF的方案

    在java里,我们常用Itext来生成pdf,在pdf文件里组合图片,文字,画表格,画线等操作,还会遇到中文支持的问题。

    那好,现在想直接在web前端就生成pdf怎么办,目前有以下几个解决方案

    1:JSPDF.js

    这个库支持不同类型的PDF文件格式,包括:文本,数字,图形,图片,同时你可以自由的编辑标题或者其它类型元素。

    还支持互动的内容制作,例如,你可以输入文字或者数字,然后jsPDF帮助生成最后的PDF内容。

    缺点,不支持中文,不支持svg导入(解决方案:svg+html转换成canvas)

    http://jspdf.com/

    示例代码如下:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
    <head>
    <title>Downloadify</title>
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
    <style type="text/css" media="screen">
    body {background: #fff; 500px; margin: 20px auto;}
    input, textarea, p { font-family: 宋体, 黑体; font-size: 12pt;}
    input, textarea { border: solid 1px #aaa; padding: 4px; 98%;}
    </style>
    <script type="text/javascript" src="js/swfobject.js"></script>
    <script type="text/javascript" src="js/downloadify.js"></script>
    <script type="text/javascript" src="js/jspdf.js"></script>
    <!-- <script type="text/javascript" src="js/downloadify.min.js"></script> -->
    <script type="text/javascript">
    window.load=function(){
    Downloadify.create('downloadify',{
    filename: function(){
    return document.getElementById('filename').value;
    },
    data: function(){
    var doc = new jsPDF();
    doc.text(20, 20, document.getElementById('data').value);
    doc.addPage();
    doc.text(20, 20, document.getElementById('data').value);
    return doc.output();
    },
    onComplete: function(){ alert('成功保存文件!'); },
    onCancel: function(){ alert('您已经取消保存文件'); },
    onError: function(){ alert('出现错误了'); },
    swf: 'js/downloadify.swf',
    downloadImage: 'js/download.png',
    100,
    height: 30,
    transparent: true,
    append: false
    });
    }
    </script>
    </head>
    <body onload="load();">
    <input type="text" name="filename" value="文件名.pdf" id="filename" /><br />
    <textarea cols="60" rows="10" name="data" id="data">it seem do not support to Chinese</textarea>
    <p id="downloadify">You must have Flash 10 installed to download this file.</p>
    </body>
    </html>

    2:pdfmake

    pdfmake的基本使用方法

    1.包含以下两个文件

    1
    2
    <script src="build/pdfmake.min.js"></script>
     <script src="build/vfs_fonts.js"></script>

    2.在JS代码中声明一个Document-definition对象,这个是pdfmake自己的术语。简单点说,就是创建一个至少包含content属性的对象。然后就可以调用pdfMake的方法导出PDF,具体见如下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <script type="text/javascript">
     //创建Document-definition对象 
     var dd = {
          content: [
           'One paragraph',
           'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines'
           ]
        };
     //导出PDF
     pdfMake.createPdf(dd).download();
     </script>

    pdfmake支持中文

    三个步骤:

    1.到pdfmake项目网站,把工程都下载下来,然后进入工程目录将字体文件(比如微软雅黑.ttf)放到examples/fonts目录下,然后使用grunt dump_dir生成新的vfs_fonts.js文件;

    从上面描述可知该工程是通过grunt管理的,如果无相关知识,请上网先补习下。

    grunt dump_dir命令会将fonts目录下所有文件都打包,因此无用文件请别放进去。

    微软雅黑.ttf网上一搜一大把,WINDOWS电脑系统盘下存放字体的目录也找得到。

    2.回到自己的例子代码中,JS代码中修改pdfMake的fonts对象,声明当前要用到字体:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    pdfMake.fonts = {
         Roboto: {
           normal: 'Roboto-Regular.ttf',
           bold: 'Roboto-Medium.ttf',
           italics: 'Roboto-Italic.ttf',
           bolditalics: 'Roboto-Italic.ttf'
         },
         微软雅黑: {
           normal: '微软雅黑.ttf',
           bold: '微软雅黑.ttf',
           italics: '微软雅黑.ttf',
           bolditalics: '微软雅黑.ttf',
         }
       };

    3.Document-definition对象中声明默认要使用的字体,具体来说:就是声明一个对象,除了content属性,还要有一个defaultStyle属性,该defaultStyle下面还有再有一个font属性:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var dd = {
          content: [
           '中英文测试',
           'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines'
           ],
           defaultStyle: {
             font: '微软雅黑'
           }
        };

    以下为根据如上步骤做的一个完整例子源码:

    <!DOCTYPE html>
    <html lang="zh-CN">
      <head>
      <meta charset="utf-8">
      <title>my first export PDF</title>
      <script src="build/pdfmake.min.js"></script>
      <script src="build/vfs_fonts.js"></script>
      <script>
      function down() {
        var dd = {
          content: [
           '中英文测试',
           'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines'
           ],
           defaultStyle: {
             font: '微软雅黑'
           }
        };
        pdfMake.fonts = {
          Roboto: {
            normal: 'Roboto-Regular.ttf',
            bold: 'Roboto-Medium.ttf',
            italics: 'Roboto-Italic.ttf',
            bolditalics: 'Roboto-Italic.ttf'
          },
          微软雅黑: {
            normal: '微软雅黑.ttf',
            bold: '微软雅黑.ttf',
            italics: '微软雅黑.ttf',
            bolditalics: '微软雅黑.ttf',
          }
        };
        pdfMake.createPdf(dd).download();
      }
      </script>
      </head>
      <body>
      <button onclick="down()">下载</button>
      </body>
    </html>

    插入图片

    在插入图片方面,jsPDF要求先将图片转换成Data URL才行,而pdfmake允许直接指定路径,看起来是很方便,但这是有条件的,必须是以node.js作为服务器,或者将图片放到vfs_fonts.js中,所以总的来说,用处不大,还是一样得将图片转换成Data URL形式才行。

    为解决此问题,我写了一个ImageDataURL的函数对象,可同时传入多个图片地址。在图片都加载完成后,ImageDataURL.oncomplete将被触发,在回调中通过this.imgdata取出各个图片的Data URL,根据pdfmake的要求组织下,就可正确生成pdf了。

    ImageDataURL的原理是通过H5的canvas标签,将图片绘制在canvas上,然后通过canvas的toDataURL得到图像的Data URL。使用时请注意浏览器兼容性问题。

    以下为将sampleImage.jpg, sampleage.jpg, sampleImage.jpg依次写入PDF的例子,测试时sampleage.jpg不存在,PDF直接忽略。

    <!DOCTYPE html>
    <html lang="zh-CN">
      <head>
      <meta charset="utf-8">
      <title>my second export PDF</title>
      <script src="build/pdfmake.min.js"></script>
      <script src="build/vfs_fonts.js"></script>
      <script>
        
      function down() {
        var x = new ImageDataURL(["sampleImage.jpg", "samplage.jpg", "sampleImage.jpg"]);
        x.oncomplete = function() {
          var imgs = new Array();
          console.log("complete");
          for (key in this.imgdata) {
            if (this.imgdata[key] == this.emptyobj)//不存在的图片直接忽略
              continue;
            imgs.push({image:this.imgdata[key]});//pdfmake的图片格式{image:image dataurl}
          }
          var dd = {
            content: [
             'Title',
             imgs,
             ],
          };
          pdfMake.createPdf(dd).download();
        }
      }
      </script>
      </head>
      <body>
      <button onclick="down()">下载</button>
      <script>
      function ImageDataURL(urls) {//urls必须是字符串或字符串数组
        this.completenum = 0;
        this.totalnum = 0;
        this.imgdata = new Array();
        this.emptyobj = new Object();
        this.oncomplete = function(){};
        this.getDataURL = function(url, index) {
          var c = document.createElement("canvas");
          var cxt = c.getContext("2d");
          var img = new Image();
          var dataurl;
          var p;
          p = this;
          img.src = url;
          img.onload = function() {
            var i;
            var maxwidth = 500;
            var scale = 1.0;
            if (img.width > maxwidth) {
              scale = maxwidth / img.width;
              c.width = maxwidth;
              c.height = Math.floor(img.height * scale);
            } else {
              c.width= img.width;
              c.height= img.height;
            }
            cxt.drawImage(img, 0, 0, c.width, c.height);
      
            p.imgdata[index] = c.toDataURL('image/jpeg');
            for (i = 0; i < p.totalnum; ++i) {
              if (p.imgdata[i] == null)
                break;
            }
            if (i == p.totalnum) {
              p.oncomplete();
            }
          };
          img.onerror = function() {
            p.imgdata[index] = p.emptyobj;
            for (i = 0; i < p.totalnum; ++i) {
              if (p.imgdata[i] == null)
                break;
            }
            if (i == p.totalnum) {
              p.oncomplete();
            }
          };
        }
        if (urls instanceof Array) {
          this.totalnum = urls.length; 
          this.imgdata = new Array(this.totalnum);
          for (key in urls) {
            this.getDataURL(urls[key], key);
          }
        } else {
          this.imgdata = new Array(1);
          this.totalnum = 1;
          this.getDataURL(urls, 0);
        }
      }
      
      </script>
      </body>
    </html>
  • 相关阅读:
    SpringBoot Actuator
    Mysql中实现row_number
    .添加索引和类型,同时设定edgengram分词和charsplit分词
    mysql临时禁用触发器
    centos6.7下安装mvn 、安装elasticsearch下ik分词
    ElasticSearch 自定义排序处理
    ElasticSearch返回不同的type的序列化
    Elasticsearch判断多列存在、bool条件组合查询示例
    C#多线程环境下调用 HttpWebRequest 并发连接限制
    centos6.7安装Redis
  • 原文地址:https://www.cnblogs.com/marszhw/p/5985235.html
Copyright © 2011-2022 走看看