在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; width: 500px; margin: 20px auto;}
input, textarea, p { font-family: 宋体, 黑体; font-size: 12pt;}
input, textarea { border: solid 1px #aaa; padding: 4px; width: 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',
width: 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>

用js生成PDF的方案的更多相关文章

  1. js生成pdf报表

    由于前台html已经动态生成报表,而且,前台有一个功能,一个date range组件,当你拖动的时候,报表会在不提交到后台的情况下动态变化.因此需要用到js生成生报表: 用到的组件: jquery.j ...

  2. js 生成 pdf 文件

    话不多说好吧, 直接上demo图: 直接上代码好吧:(要引入的两个js  链接我放最后) <!DOCTYPE html> <html> <head> <met ...

  3. JS生成PDF文件

    代码: var pdf = new jsPDF('p','pt','a4'); pdf.internal.scaleFactor = 1; //可以调整缩放比例 var options = { //p ...

  4. 前端生成pdf文件之pdfmake.js

    转载:点击查看原文 pdfmake.js是一个简单的生成pdf文件的插件. pdfmake.js     https://files.cnblogs.com/files/s313139232/pdfm ...

  5. js将 HTML 页面生成 PDF 并下载

    最近碰到个需求,需要把当前页面生成 pdf,并下载.弄了几天,自己整理整理,记录下来,我觉得应该会有人需要 :) 先来科普两个插件: html2Canvas 简介 我们可以直接在浏览器端使用html2 ...

  6. 在js内生成PDF文件并下载的功能实现(不调用后端),以及生成pdf时换行的格式不被渲染,word-break:break-all

    在js内生成PDF文件并下载的功能实现(不调用后端),以及生成pdf时换行的格式不被渲染,word-break:break-all 前天来了个新需求, 有一个授权书的文件要点击下载, 需要在前端生成, ...

  7. 在Vue&Element前端项目中,使用FastReport + pdf.js生成并展示自定义报表

    在我的<FastReport报表随笔>介绍过各种FastReport的报表设计和使用,FastReport报表可以弹性的独立设计格式,并可以在Asp.net网站上.Winform端上使用, ...

  8. Docker 快速验证 HTML 导出 PDF 高效方案

    需求分析 项目中用到了 Echarts,想要把图文混排,当然包括 echarts 生成的 Canvas 图也导出 PDF. 设计和实现时,分析了 POI.iText.freemaker.world 的 ...

  9. 内卷时代下的前端技术-使用JavaScript在浏览器中生成PDF文档

    背景 在计量领域中,计量检定是一种重要形式,主要用于评定计量器具的计量性能,确定其量值是否准确一致,实现手段包括计量检验.出具检定证书和加封盖印等. 在检定证书这一环节,存在一个难点,就是无法在线预览 ...

随机推荐

  1. Entity Framework7 有哪些不同?之具体功能

    Entity Framework7 有哪些不同?之具体功能 前面我们介绍了关于EF7的新特性.开发计划和入门介绍.今天,我们来看看EF7的具体新功能及用法.本文中的环境,为EF7入门里介绍的环境. 1 ...

  2. 【实践】js实现简易的四则运算计算器

    最近看了一个大神推荐的某公司面试程序员的js 面试题,题目是用js 做一个计算器于是跟着大神的思想自己做了一下 ps:功能还没有完善好毕竟自己还是一只菜鸟还在不断学习中. 闲话不多说先上css代码 & ...

  3. HttpEntity转换Inputstream(红色)加XmlPull解析

    package com.bawei.xml; import java.io.IOException; import java.io.InputStream; import java.util.Arra ...

  4. web系统开发为什么用asp.net MVC,为什么不用?

     向高手咨询下,现在asp.net MVC很流行,但我好像提不起兴趣.企业级Web应用,使用纯HTML+jquery交互+Http Handler(或WebAPI),不是挺好的吗?有很多优点:1.Ht ...

  5. Problems with MMM for mysql(译文)

    Problems with mmm for mysql posted in MySQL by shlomi 原文:http://code.openark.org/blog/mysql/problems ...

  6. MessageClient

    using Manager.Common; using System; using System.Collections.Generic; using System.Diagnostics; usin ...

  7. Android下添加新的自定义键值和按键处理流程

            Android下添加新的自定义键值和按键处理流程     说出来不怕大家笑话,我写这篇博客的原因在于前几天去一个小公司面试Android系统工程师,然后在面试的时候对方的技术总监问了我 ...

  8. MOCK DATA -- node路由

    前后端分离,有时候后端接口给的不是很及时,这就需要前端自己mock data, 本文讲的简单的node模拟数据 api路由跳转 首先有个data.js(json)文件, 路由: 配置在dev-serv ...

  9. Java集合面试题

    1.Java集合框架是什么?说出一些集合框架的优点? 每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector.Stack.HashTable和Array.随着集合的广泛使用,Java1 ...

  10. [TCPIP] 传输控制协议 Note

    TCPIP  TCP 传输控制协议 TCP提供一种面向连接的,可靠的字节流服务. 面向连接意味着两个使用TCP的应用在传输数据之前先建立一个TCP连接,这个过程跟打电话相似.在一个TCP连接中仅有两方 ...