*引用自2018.12.27版本的github README.md, 但现在是29号了,作者update了一个非常清晰的文档,不过还是把老版本放出来让大家看看吧。
pdfMake
同步滚动:关
pdfmake ![Build Status] [travis_img] ![GitHub] [github_img] ![npm] [npm_img] ![Bower] [bower_img] ![Packagist] [packagist_img] ![CDNJS] [cdnjs_img]
客户端/服务器端使用纯JavaScript进行PDF打印
看看游乐场和例子。
特征
- 换行,
- 文本对齐(左,右,居中,对齐),
- 编号和项目符号列表,
- 表和列
- 自动/固定/星号宽度,
- col-spans和row-span,
- 在分页时自动重复标题,
- 图像和矢量图形,
- 方便的造型和风格继承,
- 页眉和页脚:
- 静态或动态内容,
- 访问当前页码和页数,
- 背景层,
- 页面尺寸和方向,
- 利润,
- 自定义分页符,
- 字体嵌入,
- 支持复杂的多级(嵌套)结构,
- 目录,
- 打开/打印/下载生成的PDF的辅助方法,
- 设置PDF元数据(例如作者,主题)。
入门
本文档将向您介绍pdfmake的基础知识,并向您展示如何在浏览器中创建PDF文件。如果您对服务器端打印感兴趣,请查看示例文件夹。
要从默认配置开始,您应该包含两个文件:
- pdfmake.min.js,
- vfs_fonts.js - 默认字体定义(它包含Roboto,但您可以使用自定义字体)
my first pdfmake example
...
您可以使用npm(服务器端和客户端)获取这两个文件:
npm install pdfmake
- 用于服务器端
require('pdfmake');
- 供客户端使用
require('pdfmake/build/pdfmake.js');
和require('pdfmake/build/vfs_fonts.js');
或凉亭(客户端):
bower install pdfmake
或者直接从存储库中的构建目录中复制它们。否则,您始终可以从源构建它。
支持的浏览器
看问题。
文档定义对象
pdfmake遵循声明性方法。这基本上意味着,你永远不会有手动计算位置,或者使用命令,如:writeText(text, x, y)
,moveDown
等等,你将与其他很多图书馆。
要掌握的最基本的概念是文档定义对象,它可以简单到:
var docDefinition = { content: 'This is an sample PDF printed with pdfMake' };
或变得相当复杂(具有多级表,图像,列表,段落,边距,样式等...)。
只要您拥有document-definition-object,就可以创建并下载/打开/打印PDF了:
pdfMake.createPdf(docDefinition).download();
pdfMake.createPdf(docDefinition).open();
pdfMake.createPdf(docDefinition).print();
详见下一章。
下载PDF
pdfMake.createPdf(docDefinition).download();
参数:
-
defaultFileName
(可选) - 文件名 -
cb
(可选) - 回调函数 -
options
(可选的)
在新窗口中打开PDF
pdfMake.createPdf(docDefinition).open();
参数:
-
options
(可选的) -
win
(可选) - 窗口(异步操作时)
只能使用元数据title
属性定义名称(请参阅文档元数据)。
异步示例:
$scope.generatePdf = function() {
// create the window before the callback
var win = window.open('', '_blank');
$http.post('/someUrl', data).then(function(response) {
// pass the "win" argument
pdfMake.createPdf(docDefinition).open({}, win);
});
};
在同一个窗口中打开:
pdfMake.createPdf(docDefinition).open({}, window);
打印PDF
pdfMake.createPdf(docDefinition).print();
参数:
-
options
(可选的) -
win
(可选) - 窗口(异步操作时)
异步示例:
$scope.generatePdf = function() {
// create the window before the callback
var win = window.open('', '_blank');
$http.post('/someUrl', data).then(function(response) {
// pass the "win" argument
pdfMake.createPdf(docDefinition).print({}, win);
});
};
在同一窗口打印:
pdfMake.createPdf(docDefinition).print({}, window);
将PDF作为URL数据放入您自己的页面
const pdfDocGenerator = pdfMake.createPdf(docDefinition);
pdfDocGenerator.getDataUrl((dataUrl) => {
const targetElement = document.querySelector('#iframeContainer');
const iframe = document.createElement('iframe');
iframe.src = dataUrl;
targetElement.appendChild(iframe);
});
参数:
-
cb
- 回调函数 -
options
(可选的)
获取PDF作为base64数据
const pdfDocGenerator = pdfMake.createPdf(docDefinition);
pdfDocGenerator.getBase64((data) => {
alert(data);
});
参数:
-
cb
- 回调函数 -
options
(可选的)
获取PDF作为缓冲区
const pdfDocGenerator = pdfMake.createPdf(docDefinition);
pdfDocGenerator.getBuffer((buffer) => {
// ...
});
参数:
-
cb
- 回调函数 -
options
(可选的)
获取PDF格式的Blob
const pdfDocGenerator = pdfMake.createPdf(docDefinition);
pdfDocGenerator.getBlob((blob) => {
// ...
});
参数:
-
cb
- 回调函数 -
options
(可选的)
使用javascript框架
var pdfMake = require('pdfmake/build/pdfmake.js');
var pdfFonts = require('pdfmake/build/vfs_fonts.js');
pdfMake.vfs = pdfFonts.pdfMake.vfs;
要么
import pdfMake from "pdfmake/build/pdfmake";
import pdfFonts from "pdfmake/build/vfs_fonts";
pdfMake.vfs = pdfFonts.pdfMake.vfs;
对于Ionic和Angular,请参阅问题。
如果抛出了无法读取未定义错误的属性“TYPED_ARRAY_SUPPORT”,请将其添加到webpack配置:
exclude: [ /node_modules/, /pdfmake.js$/ ]
(见问题)
单位
所有数字均以点(pt)为单位(有时标记为PDF / PostScript点)。
服务器端
查看示例和dev-playground服务器脚本
造型
pdfmake可以设置任何段落或其部分的样式:
var docDefinition = {
content: [
// if you don't need styles, you can use a simple string to define a paragraph
'This is a standard paragraph, using default style',
// using a { text: '...' } object lets you set styling properties
{ text: 'This paragraph will have a bigger font', fontSize: 15 },
// if you set the value of text to an array instead of a string, you'll be able
// to style any part individually
{
text: [
'This paragraph is defined as an array of elements to make it possible to ',
{ text: 'restyle part of it and make it bigger ', fontSize: 15 },
'than the rest.'
]
}
]
};
风格词典
也可以定义可重用样式的字典:
var docDefinition = {
content: [
{ text: 'This is a header', style: 'header' },
'No styling here, this is a standard paragraph',
{ text: 'Another text', style: 'anotherStyle' },
{ text: 'Multiple styles applied', style: [ 'header', 'anotherStyle' ] }
],
styles: {
header: {
fontSize: 22,
bold: true
},
anotherStyle: {
italics: true,
alignment: 'right'
}
}
};
要更深入地了解pdfmake中的样式,样式继承和本地样式覆盖,请在操场中检查STYLES1,STYLES2和STYLES3示例。
默认样式
并且还可以定义默认样式:
var docDefinition = {
content: [
'Text styled by default style'
],
defaultStyle: {
fontSize: 15,
bold: true
}
};
列
默认情况下,段落呈现为垂直堆栈元素(一个在另一个下面)。但是,可以将可用空间划分为列。
var docDefinition = {
content: [
'This paragraph fills full width, as there are no columns. Next paragraph however consists of three columns',
{
columns: [
{
// auto-sized columns have their widths based on their content
width: 'auto',
text: 'First column'
},
{
// star-sized columns fill the remaining space
// if there's more than one star-column, available width is divided equally
width: '*',
text: 'Second column'
},
{
// fixed width
width: 100,
text: 'Third column'
},
{
// % width
width: '20%',
text: 'Fourth column'
}
],
// optional space between columns
columnGap: 10
},
'This paragraph goes below all columns and has full width'
]
};
列内容不限于简单文本。它实际上可以包含任何有效的pdfmake元素。一定要查看游乐场中的COLUMNS示例。
表
从概念上讲,表与列类似。但是,它们可以具有跨越多个列/行的标题,边框和单元格。
var docDefinition = {
content: [
{
layout: 'lightHorizontalLines', // optional
table: {
// headers are automatically repeated if the table spans over multiple pages
// you can declare how many rows should be treated as headers
headerRows: 1,
widths: [ '*', 'auto', 100, '*' ],
body: [
[ 'First', 'Second', 'Third', 'The last one' ],
[ 'Value 1', 'Value 2', 'Value 3', 'Value 4' ],
[ { text: 'Bold value', bold: true }, 'Val 2', 'Val 3', 'Val 4' ]
]
}
}
]
};
自己的表格布局
必须在调用之前定义自己的表布局pdfMake.createPdf(docDefinition)
。
pdfMake.tableLayouts = {
exampleLayout: {
hLineWidth: function (i, node) {
if (i === 0 || i === node.table.body.length) {
return 0;
}
return (i === node.table.headerRows) ? 2 : 1;
},
vLineWidth: function (i) {
return 0;
},
hLineColor: function (i) {
return i === 1 ? 'black' : '#aaa';
},
paddingLeft: function (i) {
return i === 0 ? 0 : 8;
},
paddingRight: function (i, node) {
return (i === node.table.widths.length - 1) ? 0 : 8;
}
}
};
// download the PDF
pdfMake.createPdf(docDefinition).download();
或者,您可以直接传递tableLayouts createPdf
而不更改全局值:
pdfMake.createPdf(docDefinition, tableLayouts).download();
// The full signature of createPdf looks like this.
// tableLayouts, fonts and vfs are all optional - falsy values will cause
// pdfMake.tableLayouts, pdfMake.fonts or pdfMake.vfs to be used.
pdfMake.createPdf(docDefinition, tableLayouts, fonts, vfs)
所有与表相关的概念都包含在操场上的TABLES示例中。
清单
pdfMake支持编号和项目符号列表:
var docDefinition = {
content: [
'Bulleted list example:',
{
// to treat a paragraph as a bulleted list, set an array of items under the ul key
ul: [
'Item 1',
'Item 2',
'Item 3',
{ text: 'Item 4', bold: true },
]
},
'Numbered list example:',
{
// for numbered lists set the ol key
ol: [
'Item 1',
'Item 2',
'Item 3'
]
}
]
};
页眉和页脚
pdfmake中的页眉和页脚可以是:静态或动态。
他们使用相同的语法:
var docDefinition = {
header: 'simple text',
footer: {
columns: [
'Left part',
{ text: 'Right part', alignment: 'right' }
]
},
content: (...)
};
对于动态生成的内容(包括页码,页数和页面大小),您可以将函数传递给页眉或页脚:
var docDefinition = {
footer: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; },
header: function(currentPage, pageCount, pageSize) {
// you can apply any logic and return any valid pdfmake element
return [
{ text: 'simple text', alignment: (currentPage % 2) ? 'left' : 'right' },
{ canvas: [ { type: 'rect', x: 170, y: 32, w: pageSize.width - 170, h: 40 } ] }
]
},
(...)
};
背景层
背景图层将添加到每个页面上。
var docDefinition = {
background: 'simple text',
content: (...)
};
它也可以包含任何其他对象(图像,表格,......)或动态生成:
var docDefinition = {
background: function(currentPage, pageSize) {
return `page ${currentPage} with size ${pageSize.width} x ${pageSize.height}`
},
content: (...)
};
边距
pdfMake中的任何元素都可以有一个余量:
(...)
// margin: [left, top, right, bottom]
{ text: 'sample', margin: [ 5, 2, 10, 20 ] },
// margin: [horizontal, vertical]
{ text: 'another text', margin: [5, 2] },
// margin: equalLeftTopRightBottom
{ text: 'last one', margin: 5 }
(...)
堆栈的段落
你现在可能已经想到了(从例子中),如果你将content
键设置为一个数组,那么文档就会变成一堆段落。
您经常会在嵌套元素中重用此结构,如下例所示:
var docDefinition = {
content: [
'paragraph 1',
'paragraph 2',
{
columns: [
'first column is a simple text',
[
// second column consists of paragraphs
'paragraph A',
'paragraph B',
'these paragraphs will be rendered one below another inside the column'
]
]
}
]
};
数组的问题是您无法向其添加样式属性(例如,更改fontSize)。
好消息是 - array只是pdfMake for {stack:[]}的一个快捷方式,所以如果你想重新整理整个堆栈,你可以使用扩展定义:
var docDefinition = {
content: [
'paragraph 1',
'paragraph 2',
{
columns: [
'first column is a simple text',
{
stack: [
// second column consists of paragraphs
'paragraph A',
'paragraph B',
'these paragraphs will be rendered one below another inside the column'
],
fontSize: 15
}
]
}
]
};
图片
这很简单。只需使用{ image: '...' }
节点类型。
支持JPEG和PNG格式。
var docDefinition = {
content: [
{
// you'll most often use dataURI images on the browser side
// if no width/height/fit is provided, the original size will be used
image: 'data:image/jpeg;base64,...encodedContent...'
},
{
// if you specify width, image will scale proportionally
image: 'data:image/jpeg;base64,...encodedContent...',
width: 150
},
{
// if you specify both width and height - image will be stretched
image: 'data:image/jpeg;base64,...encodedContent...',
width: 150,
height: 150
},
{
// you can also fit the image inside a rectangle
image: 'data:image/jpeg;base64,...encodedContent...',
fit: [100, 100]
},
{
// if you reuse the same image in multiple nodes,
// you should put it to to images dictionary and reference it by name
image: 'mySuperImage'
},
{
// under NodeJS (or in case you use virtual file system provided by pdfmake)
// you can also pass file names here
image: 'myImageDictionary/image1.jpg'
}
],
images: {
mySuperImage: 'data:image/jpeg;base64,...content...'
}
};
链接
要添加外部或内部链接,请使用以下语法:
{text: 'google', link: 'http://google.com'}
{text:'Go to page 2', linkToPage: 2}
目录
var docDefinition = {
content: [
{
toc: {
// id: 'mainToc' // optional
title: {text: 'INDEX', style: 'header'}
}
},
{
text: 'This is a header',
style: 'header',
tocItem: true, // or tocItem: 'mainToc' if is used id in toc
// or tocItem: ['mainToc', 'subToc'] for multiple tocs
}
]
}
页面尺寸,方向和边距
var docDefinition = {
// a string or { width: number, height: number }
pageSize: 'A5',
// by default we use portrait, you can change it to landscape if you wish
pageOrientation: 'landscape',
// [left, top, right, bottom] or [horizontal, vertical] or just a number for equal margins
pageMargins: [ 40, 60, 40, 60 ],
};
如果设置pageSize
为字符串,则可以使用以下值之一:
- '4A0','2A0','A0','A1','A2','A3','A4','A5','A6','A7','A8','A9','A10 ”,
- 'B0','B1','B2','B3','B4','B5','B6','B7','B8','B9','B10',
- 'C0','C1','C2','C3','C4','C5','C6','C7','C8','C9','C10',
- 'RA0','RA1','RA2','RA3','RA4',
- 'SRA0','SRA1','SRA2','SRA3','SRA4',
- '执行','FOLIO','法律','信','TABLOID'
要更改文档中的页面方向,请添加具有新页面方向的分页符。
{
pageOrientation: 'portrait',
content: [
{text: 'Text on Portrait'},
{text: 'Text on Landscape', pageOrientation: 'landscape', pageBreak: 'before'},
{text: 'Text on Landscape 2', pageOrientation: 'portrait', pageBreak: 'after'},
{text: 'Text on Portrait 2'},
]
}
动态控制分页符,例如避免孤儿
pageBreakBefore
可以指定一个函数,该函数可以确定是否应在节点之前插入分页符。要实现“无孤儿”规则,请使用如下定义:
var dd = {
content: [
{text: '1 Headline', headlineLevel: 1},
'Some long text of variable length ...',
{text: '2 Headline', headlineLevel: 1},
'Some long text of variable length ...',
{text: '3 Headline', headlineLevel: 1},
'Some long text of variable length ...',
],
pageBreakBefore: function(currentNode, followingNodesOnPage, nodesOnNextPage, previousNodesOnPage) {
return currentNode.headlineLevel === 1 && followingNodesOnPage.length === 0;
}
}
如果pageBreakBefore
返回true,则会在之前添加分页符currentNode
。当前节点附有以下信息:
{
id: '',
headlineLevel: '',
text: '',
ul: '',
ol: '',
table: '',
image: '',
qr: '',
canvas: '',
columns: '',
style: '',
pageOrientation '',
pageNumbers: [2, 3], // The pages this element is visible on (e.g. multi-line text could be on more than one page)
pages: 6, // the total number of pages of this document
stack: false, // if this is an element which encapsulates multiple sub-objects
startPosition: {
pageNumber: 2, // the page this node starts on
pageOrientation: 'landscape', // the orientation of this page
left: 60, // the left position
right: 60, // the right position
verticalRatio: 0.2, // the ratio of space used vertically in this document (excluding margins)
horizontalRatio: 0.0 // the ratio of space used horizontally in this document (excluding margins)
}
}
文档元数据
PDF文档可以具有与其相关联的各种元数据,例如标题或
文档的作者。您可以通过将其添加到文档定义来添加该信息
var docDefinition = {
info: {
title: 'awesome Document',
author: 'john doe',
subject: 'subject of document',
keywords: 'keywords for document',
},
content: 'This is an sample PDF printed with pdfMake'
}
标准属性:
- title - 文档的标题
- 作者 - 作者的姓名
- 主题 - 文件的主题
- keywords - 与文档关联的关键字
- creator - 文档的创建者(默认为'pdfmake')
- producer - 文档的制作者(默认为'pdfmake')
- creationDate - 文档创建的日期(由pdfmake自动添加)
- modDate - 上次修改文档的日期
- 被困 - PDF文档中的被困标志表示文件是否被“困住”
自定义属性:
您可以添加自定义属性。属性键不包含空格。
压缩
默认情况下启用PDF压缩,compress: false
用于禁用:
var docDefinition = {
compress: false,
content: (...)
};
从源头建立
使用npm:
git clone https://github.com/bpampuch/pdfmake.git
cd pdfmake
npm install
npm run build
使用纱线:
git clone https://github.com/bpampuch/pdfmake.git
cd pdfmake
yarn
yarn run build
快来了
嗯......让我知道你需要什么;)
目标非常简单 - 使pdfmake对人们的looooooooot很有用,并帮助构建具有打印支持的响应式HTML5应用程序。
v2的路线图上有一件事(但没有截止日期) - 使库可以破解,所以你可以编写插件来:
- 扩展文档定义模型(使用{chart:...}之类的东西),
- 添加语法翻译器(如提供的[...] - > {stack:[...]}
- 在文档定义模型之上构建自定义DSL(目前这实际上是可行的)。
执照
MIT
作者
- @bpampuch(创始人)
- @ liborm85
pdfmake基于一个真正令人惊叹的图书馆pdfkit(归功于@devongovett)。
感谢所有贡献者。