Skip to content

Commit

Permalink
Merge pull request #223 from devongovett/browser
Browse files Browse the repository at this point in the history
Support using PDFKit in the Browser, thanks to Browserify!
  • Loading branch information
devongovett committed Apr 14, 2014
2 parents 047110e + 701ba34 commit 968f2c7
Show file tree
Hide file tree
Showing 20 changed files with 439 additions and 124 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ lib/font/tables/.DS_Store
node-zlib/
src/
playground/
*.html
build/
js/
demo/bundle.js
*.html
!demo/browser.html
28 changes: 28 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
js: lib/**/*.coffee
./node_modules/.bin/coffee -o js -c lib/
cp -r lib/font/data js/font/data

browser: lib/**/*.coffee
mkdir -p build/
./node_modules/.bin/browserify \
--standalone PDFDocument \
--debug \
--transform coffeeify \
--extension .coffee \
lib/document.coffee \
| ./node_modules/.bin/exorcist build/pdfkit.js.map > build/pdfkit.js

browser-demo: js demo/browser.js
./node_modules/.bin/browserify demo/browser.js > demo/bundle.js

docs: pdf-guide website browser-demo

pdf-guide:
./node_modules/.bin/coffee docs/generate.coffee

website:
mkdir -p docs/img
./node_modules/.bin/coffee docs/generate_website.coffee

clean:
rm -rf js build demo/bundle.js
138 changes: 94 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# PDFKit
### A PDF generation library for Node.js.

A JavaScript PDF generation library for Node and the browser.

## Description

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

## Example

PDFDocument = require 'pdfkit'

# Create a document
doc = new PDFDocument

# Pipe it's output somewhere, like to a file or HTTP response
doc.pipe fs.createWriteStream('output.pdf')

# Embed a font, set the font size, and render some text
doc.font('fonts/PalatinoBold.ttf')
.fontSize(25)
.text('Some text with an embedded font!', 100, 100)

# Add another page
doc.addPage()
.fontSize(25)
.text('Here is some vector graphics...', 100, 100)

# Draw a triangle
doc.save()
.moveTo(100, 150)
.lineTo(100, 250)
.lineTo(200, 250)
.fill("#FF3300")

# Apply some transforms and render an SVG path with the 'even-odd' fill rule
doc.scale(0.6)
.translate(470, -380)
.path('M 250,75 L 323,301 131,161 369,161 177,301 z')
.fill('red', 'even-odd')
.restore()

# Add some text with annotations
doc.addPage()
.fillColor("blue")
.text('Here is a link!', 100, 100)
.underline(100, 100, 160, 27, color: "#0000FF")
.link(100, 100, 160, 27, 'http://google.com/')

# Finalize PDF file
doc.end()
```coffeescript
PDFDocument = require 'pdfkit'

# Create a document
doc = new PDFDocument

# Pipe it's output somewhere, like to a file or HTTP response
# See below for browser usage
doc.pipe fs.createWriteStream('output.pdf')

# Embed a font, set the font size, and render some text
doc.font('fonts/PalatinoBold.ttf')
.fontSize(25)
.text('Some text with an embedded font!', 100, 100)

# Add another page
doc.addPage()
.fontSize(25)
.text('Here is some vector graphics...', 100, 100)

# Draw a triangle
doc.save()
.moveTo(100, 150)
.lineTo(100, 250)
.lineTo(200, 250)
.fill("#FF3300")

# Apply some transforms and render an SVG path with the 'even-odd' fill rule
doc.scale(0.6)
.translate(470, -380)
.path('M 250,75 L 323,301 131,161 369,161 177,301 z')
.fill('red', 'even-odd')
.restore()

# Add some text with annotations
doc.addPage()
.fillColor("blue")
.text('Here is a link!', 100, 100)
.underline(100, 100, 160, 27, color: "#0000FF")
.link(100, 100, 160, 27, 'http://google.com/')

# Finalize PDF file
doc.end()
```

[The PDF output from this example](http://pdfkit.org/demo/out.pdf) (with a few additions) shows the power of PDFKit — producing
complex documents with a very small amount of code. For more, see the `demo` folder and the
[PDFKit programming guide](http://pdfkit.org/docs/getting_started.html).

## Browser Usage

There are two ways to use PDFKit in the browser. The first is to use [Browserify](http://browserify.org/),
which is a Node module packager for the browser with the familiar `require` syntax. The second is to use
a prebuilt version of PDFKit, which you can [download from Github](https://github.com/devongovett/pdfkit/releases).

In addition to PDFKit, you'll need somewhere to stream the output to. HTML5 has a
[Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) object which can be used to store binary data, and
get URLs to this data in order to display PDF output inside an iframe, or upload to a server, etc. In order to
get a Blob from the output of PDFKit, you can use the [blob-stream](https://github.com/devongovett/blob-stream)
module.

The following example uses Browserify to load `PDFKit` and `blob-stream`, but if you're not using Browserify,
you can load them in whatever way you'd like (e.g. script tags).

```coffeescript
# require dependencies
PDFDocument = require 'pdfkit'
blobStream = require 'blob-stream'

# create a document the same way as above
doc = new PDFDocument

# pipe the document to a blob
stream = doc.pipe(blobStream())

# add your content to the document here, as usual

# get a blob when you're done
doc.end()
stream.on 'finish', ->
# get a blob you can do whatever you like with
blob = stream.toBlob('application/pdf')

# or get a blob URL for display in the browser
url = stream.toBlobURL('application/pdf')
iframe.src = url
```

You can see an interactive in-browser demo of PDFKit [here](http://pdfkit.org/demo/browser.html).

Note that in order to Browserify a project using PDFKit, you need to install the `brfs` module with npm,
which is used to load built-in font data into the package. It is listed as a `devDependency` in
PDFKit's `package.json`, so it isn't installed by default for Node users.
If you forget to install it, Browserify will print an error message.

## Documentation

For complete API documentation and more examples, see the [PDFKit website](http://pdfkit.org/).
Expand Down
39 changes: 39 additions & 0 deletions demo/browser.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
width: 1230px;
margin: 20px auto;
font-family: Georgia;
}

h1 {
margin: 0;
}

a {
color: blue;
}

#editor {
width: 600px;
height: 775px;
margin-right: 20px;
display: inline-block;
}

iframe {
border: 1px solid black;
}
</style>
</head>
<body>
<h1>PDFKit Browser Demo</h1>
<p><a href="http://pdfkit.org/">Website</a> | <a href="http://github.com/devongovett/pdfkit">Github</a></p>
<div id="editor"></div>
<iframe width="600" height="775"></iframe>
<script src="bundle.js"></script>
</body>
</html>
76 changes: 76 additions & 0 deletions demo/browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
var PDFDocument = require('../');
var blobStream = require('blob-stream');
var ace = require('brace');
require('brace/mode/javascript');
require('brace/theme/monokai');

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.';

function makePDF(PDFDocument, blobStream, lorem, iframe) {
// create a document and pipe to a blob
var doc = new PDFDocument();
var stream = doc.pipe(blobStream());

// draw some text
doc.fontSize(25)
.text('Here is some vector graphics...', 100, 80);

// some vector graphics
doc.save()
.moveTo(100, 150)
.lineTo(100, 250)
.lineTo(200, 250)
.fill("#FF3300");

doc.circle(280, 200, 50)
.fill("#6600FF");

// an SVG path
doc.scale(0.6)
.translate(470, 130)
.path('M 250,75 L 323,301 131,161 369,161 177,301 z')
.fill('red', 'even-odd')
.restore();

// and some justified text wrapped into columns
doc.text('And here is some wrapped text...', 100, 300)
.font('Times-Roman', 13)
.moveDown()
.text(lorem, {
width: 412,
align: 'justify',
indent: 30,
columns: 2,
height: 300,
ellipsis: true
});

// end and display the document in the iframe to the right
doc.end();
stream.on('finish', function() {
iframe.src = stream.toBlobURL('application/pdf');
});
}

var editor = ace.edit('editor');
editor.setTheme('ace/theme/monokai');
editor.getSession().setMode('ace/mode/javascript');
editor.setValue(
makePDF
.toString()
.split('\n').slice(1, -1).join('\n')
.replace(/^ /mg, '')
);
editor.getSession().getSelection().clearSelection();

var iframe = document.querySelector('iframe');
makePDF(PDFDocument, blobStream, lorem, iframe);

editor.getSession().on('change', function() {
try {
var fn = new Function("PDFDocument", "blobStream", "lorem", "iframe", editor.getValue());
fn(PDFDocument, blobStream, lorem, iframe);
} catch (e) {
console.log(e)
};
});
2 changes: 2 additions & 0 deletions docs/generate.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ coffee = require 'coffee-script'
CodeMirror = require 'codemirror/addon/runmode/runmode.node'
PDFDocument = require '../'

process.chdir(__dirname)

# setup code mirror coffeescript mode
filename = require.resolve('codemirror/mode/coffeescript/coffeescript')
coffeeMode = fs.readFileSync filename, 'utf8'
Expand Down
7 changes: 7 additions & 0 deletions docs/generate_website.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ coffee = require 'coffee-script'
{exec} = require 'child_process'
PDFDocument = require '../'

process.chdir(__dirname)

files = [
'../README.md'
'getting_started.coffee.md'
Expand Down Expand Up @@ -79,6 +81,11 @@ generateImages = (tree) ->
pages = []
for file in files
content = fs.readFileSync file, 'utf8'

# turn github highlighted code blocks into normal markdown code blocks
content = content.replace /^```coffeescript\n((:?.|\n)*?)\n```/mg, (m, $1) ->
' ' + $1.split('\n').join('\n ')

tree = markdown.parse(content)
headers = extractHeaders(tree)
generateImages(tree)
Expand Down
Loading

0 comments on commit 968f2c7

Please sign in to comment.