Skip to content

Commit 968f2c7

Browse files
committed
Merge pull request #223 from devongovett/browser
Support using PDFKit in the Browser, thanks to Browserify!
2 parents 047110e + 701ba34 commit 968f2c7

20 files changed

+439
-124
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ lib/font/tables/.DS_Store
55
node-zlib/
66
src/
77
playground/
8-
*.html
8+
build/
9+
js/
10+
demo/bundle.js
11+
*.html
12+
!demo/browser.html

Makefile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
js: lib/**/*.coffee
2+
./node_modules/.bin/coffee -o js -c lib/
3+
cp -r lib/font/data js/font/data
4+
5+
browser: lib/**/*.coffee
6+
mkdir -p build/
7+
./node_modules/.bin/browserify \
8+
--standalone PDFDocument \
9+
--debug \
10+
--transform coffeeify \
11+
--extension .coffee \
12+
lib/document.coffee \
13+
| ./node_modules/.bin/exorcist build/pdfkit.js.map > build/pdfkit.js
14+
15+
browser-demo: js demo/browser.js
16+
./node_modules/.bin/browserify demo/browser.js > demo/bundle.js
17+
18+
docs: pdf-guide website browser-demo
19+
20+
pdf-guide:
21+
./node_modules/.bin/coffee docs/generate.coffee
22+
23+
website:
24+
mkdir -p docs/img
25+
./node_modules/.bin/coffee docs/generate_website.coffee
26+
27+
clean:
28+
rm -rf js build demo/bundle.js

README.md

Lines changed: 94 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
# PDFKit
2-
### A PDF generation library for Node.js.
2+
3+
A JavaScript PDF generation library for Node and the browser.
34

45
## Description
56

6-
PDFKit is a PDF document generation library for Node that makes creating complex, multi-page, printable documents easy.
7+
PDFKit is a PDF document generation library for Node and the browser that makes creating complex, multi-page, printable documents easy.
78
It's written in CoffeeScript, but you can choose to use the API in plain 'ol JavaScript if you like. The API embraces
89
chainability, and includes both low level functions as well as abstractions for higher level functionality. The PDFKit API
910
is designed to be simple, so generating complex documents is often as simple as a few function calls.
@@ -54,52 +55,101 @@ Installation uses the [npm](http://npmjs.org/) package manager. Just type the f
5455

5556
## Example
5657

57-
PDFDocument = require 'pdfkit'
58-
59-
# Create a document
60-
doc = new PDFDocument
61-
62-
# Pipe it's output somewhere, like to a file or HTTP response
63-
doc.pipe fs.createWriteStream('output.pdf')
64-
65-
# Embed a font, set the font size, and render some text
66-
doc.font('fonts/PalatinoBold.ttf')
67-
.fontSize(25)
68-
.text('Some text with an embedded font!', 100, 100)
69-
70-
# Add another page
71-
doc.addPage()
72-
.fontSize(25)
73-
.text('Here is some vector graphics...', 100, 100)
74-
75-
# Draw a triangle
76-
doc.save()
77-
.moveTo(100, 150)
78-
.lineTo(100, 250)
79-
.lineTo(200, 250)
80-
.fill("#FF3300")
81-
82-
# Apply some transforms and render an SVG path with the 'even-odd' fill rule
83-
doc.scale(0.6)
84-
.translate(470, -380)
85-
.path('M 250,75 L 323,301 131,161 369,161 177,301 z')
86-
.fill('red', 'even-odd')
87-
.restore()
88-
89-
# Add some text with annotations
90-
doc.addPage()
91-
.fillColor("blue")
92-
.text('Here is a link!', 100, 100)
93-
.underline(100, 100, 160, 27, color: "#0000FF")
94-
.link(100, 100, 160, 27, 'http://google.com/')
95-
96-
# Finalize PDF file
97-
doc.end()
98-
58+
```coffeescript
59+
PDFDocument = require 'pdfkit'
60+
61+
# Create a document
62+
doc = new PDFDocument
63+
64+
# Pipe it's output somewhere, like to a file or HTTP response
65+
# See below for browser usage
66+
doc.pipe fs.createWriteStream('output.pdf')
67+
68+
# Embed a font, set the font size, and render some text
69+
doc.font('fonts/PalatinoBold.ttf')
70+
.fontSize(25)
71+
.text('Some text with an embedded font!', 100, 100)
72+
73+
# Add another page
74+
doc.addPage()
75+
.fontSize(25)
76+
.text('Here is some vector graphics...', 100, 100)
77+
78+
# Draw a triangle
79+
doc.save()
80+
.moveTo(100, 150)
81+
.lineTo(100, 250)
82+
.lineTo(200, 250)
83+
.fill("#FF3300")
84+
85+
# Apply some transforms and render an SVG path with the 'even-odd' fill rule
86+
doc.scale(0.6)
87+
.translate(470, -380)
88+
.path('M 250,75 L 323,301 131,161 369,161 177,301 z')
89+
.fill('red', 'even-odd')
90+
.restore()
91+
92+
# Add some text with annotations
93+
doc.addPage()
94+
.fillColor("blue")
95+
.text('Here is a link!', 100, 100)
96+
.underline(100, 100, 160, 27, color: "#0000FF")
97+
.link(100, 100, 160, 27, 'http://google.com/')
98+
99+
# Finalize PDF file
100+
doc.end()
101+
```
102+
99103
[The PDF output from this example](http://pdfkit.org/demo/out.pdf) (with a few additions) shows the power of PDFKit — producing
100104
complex documents with a very small amount of code. For more, see the `demo` folder and the
101105
[PDFKit programming guide](http://pdfkit.org/docs/getting_started.html).
102106

107+
## Browser Usage
108+
109+
There are two ways to use PDFKit in the browser. The first is to use [Browserify](http://browserify.org/),
110+
which is a Node module packager for the browser with the familiar `require` syntax. The second is to use
111+
a prebuilt version of PDFKit, which you can [download from Github](https://github.com/devongovett/pdfkit/releases).
112+
113+
In addition to PDFKit, you'll need somewhere to stream the output to. HTML5 has a
114+
[Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) object which can be used to store binary data, and
115+
get URLs to this data in order to display PDF output inside an iframe, or upload to a server, etc. In order to
116+
get a Blob from the output of PDFKit, you can use the [blob-stream](https://github.com/devongovett/blob-stream)
117+
module.
118+
119+
The following example uses Browserify to load `PDFKit` and `blob-stream`, but if you're not using Browserify,
120+
you can load them in whatever way you'd like (e.g. script tags).
121+
122+
```coffeescript
123+
# require dependencies
124+
PDFDocument = require 'pdfkit'
125+
blobStream = require 'blob-stream'
126+
127+
# create a document the same way as above
128+
doc = new PDFDocument
129+
130+
# pipe the document to a blob
131+
stream = doc.pipe(blobStream())
132+
133+
# add your content to the document here, as usual
134+
135+
# get a blob when you're done
136+
doc.end()
137+
stream.on 'finish', ->
138+
# get a blob you can do whatever you like with
139+
blob = stream.toBlob('application/pdf')
140+
141+
# or get a blob URL for display in the browser
142+
url = stream.toBlobURL('application/pdf')
143+
iframe.src = url
144+
```
145+
146+
You can see an interactive in-browser demo of PDFKit [here](http://pdfkit.org/demo/browser.html).
147+
148+
Note that in order to Browserify a project using PDFKit, you need to install the `brfs` module with npm,
149+
which is used to load built-in font data into the package. It is listed as a `devDependency` in
150+
PDFKit's `package.json`, so it isn't installed by default for Node users.
151+
If you forget to install it, Browserify will print an error message.
152+
103153
## Documentation
104154

105155
For complete API documentation and more examples, see the [PDFKit website](http://pdfkit.org/).

demo/browser.html

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<style>
6+
body {
7+
width: 1230px;
8+
margin: 20px auto;
9+
font-family: Georgia;
10+
}
11+
12+
h1 {
13+
margin: 0;
14+
}
15+
16+
a {
17+
color: blue;
18+
}
19+
20+
#editor {
21+
width: 600px;
22+
height: 775px;
23+
margin-right: 20px;
24+
display: inline-block;
25+
}
26+
27+
iframe {
28+
border: 1px solid black;
29+
}
30+
</style>
31+
</head>
32+
<body>
33+
<h1>PDFKit Browser Demo</h1>
34+
<p><a href="http://pdfkit.org/">Website</a> | <a href="http://github.com/devongovett/pdfkit">Github</a></p>
35+
<div id="editor"></div>
36+
<iframe width="600" height="775"></iframe>
37+
<script src="bundle.js"></script>
38+
</body>
39+
</html>

demo/browser.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
var PDFDocument = require('../');
2+
var blobStream = require('blob-stream');
3+
var ace = require('brace');
4+
require('brace/mode/javascript');
5+
require('brace/theme/monokai');
6+
7+
var lorem = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam in suscipit purus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus nec hendrerit felis. Morbi aliquam facilisis risus eu lacinia. Sed eu leo in turpis fringilla hendrerit. Ut nec accumsan nisl. Suspendisse rhoncus nisl posuere tortor tempus et dapibus elit porta. Cras leo neque, elementum a rhoncus ut, vestibulum non nibh. Phasellus pretium justo turpis. Etiam vulputate, odio vitae tincidunt ultricies, eros odio dapibus nisi, ut tincidunt lacus arcu eu elit. Aenean velit erat, vehicula eget lacinia ut, dignissim non tellus. Aliquam nec lacus mi, sed vestibulum nunc. Suspendisse potenti. Curabitur vitae sem turpis. Vestibulum sed neque eget dolor dapibus porttitor at sit amet sem. Fusce a turpis lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;\nMauris at ante tellus. Vestibulum a metus lectus. Praesent tempor purus a lacus blandit eget gravida ante hendrerit. Cras et eros metus. Sed commodo malesuada eros, vitae interdum augue semper quis. Fusce id magna nunc. Curabitur sollicitudin placerat semper. Cras et mi neque, a dignissim risus. Nulla venenatis porta lacus, vel rhoncus lectus tempor vitae. Duis sagittis venenatis rutrum. Curabitur tempor massa tortor.';
8+
9+
function makePDF(PDFDocument, blobStream, lorem, iframe) {
10+
// create a document and pipe to a blob
11+
var doc = new PDFDocument();
12+
var stream = doc.pipe(blobStream());
13+
14+
// draw some text
15+
doc.fontSize(25)
16+
.text('Here is some vector graphics...', 100, 80);
17+
18+
// some vector graphics
19+
doc.save()
20+
.moveTo(100, 150)
21+
.lineTo(100, 250)
22+
.lineTo(200, 250)
23+
.fill("#FF3300");
24+
25+
doc.circle(280, 200, 50)
26+
.fill("#6600FF");
27+
28+
// an SVG path
29+
doc.scale(0.6)
30+
.translate(470, 130)
31+
.path('M 250,75 L 323,301 131,161 369,161 177,301 z')
32+
.fill('red', 'even-odd')
33+
.restore();
34+
35+
// and some justified text wrapped into columns
36+
doc.text('And here is some wrapped text...', 100, 300)
37+
.font('Times-Roman', 13)
38+
.moveDown()
39+
.text(lorem, {
40+
width: 412,
41+
align: 'justify',
42+
indent: 30,
43+
columns: 2,
44+
height: 300,
45+
ellipsis: true
46+
});
47+
48+
// end and display the document in the iframe to the right
49+
doc.end();
50+
stream.on('finish', function() {
51+
iframe.src = stream.toBlobURL('application/pdf');
52+
});
53+
}
54+
55+
var editor = ace.edit('editor');
56+
editor.setTheme('ace/theme/monokai');
57+
editor.getSession().setMode('ace/mode/javascript');
58+
editor.setValue(
59+
makePDF
60+
.toString()
61+
.split('\n').slice(1, -1).join('\n')
62+
.replace(/^ /mg, '')
63+
);
64+
editor.getSession().getSelection().clearSelection();
65+
66+
var iframe = document.querySelector('iframe');
67+
makePDF(PDFDocument, blobStream, lorem, iframe);
68+
69+
editor.getSession().on('change', function() {
70+
try {
71+
var fn = new Function("PDFDocument", "blobStream", "lorem", "iframe", editor.getValue());
72+
fn(PDFDocument, blobStream, lorem, iframe);
73+
} catch (e) {
74+
console.log(e)
75+
};
76+
});

docs/generate.coffee

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ coffee = require 'coffee-script'
55
CodeMirror = require 'codemirror/addon/runmode/runmode.node'
66
PDFDocument = require '../'
77

8+
process.chdir(__dirname)
9+
810
# setup code mirror coffeescript mode
911
filename = require.resolve('codemirror/mode/coffeescript/coffeescript')
1012
coffeeMode = fs.readFileSync filename, 'utf8'

docs/generate_website.coffee

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ coffee = require 'coffee-script'
66
{exec} = require 'child_process'
77
PDFDocument = require '../'
88

9+
process.chdir(__dirname)
10+
911
files = [
1012
'../README.md'
1113
'getting_started.coffee.md'
@@ -79,6 +81,11 @@ generateImages = (tree) ->
7981
pages = []
8082
for file in files
8183
content = fs.readFileSync file, 'utf8'
84+
85+
# turn github highlighted code blocks into normal markdown code blocks
86+
content = content.replace /^```coffeescript\n((:?.|\n)*?)\n```/mg, (m, $1) ->
87+
' ' + $1.split('\n').join('\n ')
88+
8289
tree = markdown.parse(content)
8390
headers = extractHeaders(tree)
8491
generateImages(tree)

0 commit comments

Comments
 (0)