function PDFDocument(options1) { var key, ref1, ref2, val; this.options = options1 != null ? options1 : {}; PDFDocument.__super__.constructor.apply(this, arguments); this.version = 1.3; this.compress = (ref1 = this.options.compress) != null ? ref1 : true; this._pageBuffer = []; this._pageBufferStart = 0; this._offsets = []; this._waiting = 0; this._ended = false; this._offset = 0; this._root = this.ref({ Type: 'Catalog', Pages: this.ref({ Type: 'Pages', Count: 0, Kids: [] }) }); this.page = null; this.initColor(); this.initVector(); this.initFonts(); this.initText(); this.initImages(); this.info = { Producer: 'PDFKit', Creator: 'PDFKit', CreationDate: new Date() }; if (this.options.info) { ref2 = this.options.info; for (key in ref2) { val = ref2[key]; this.info[key] = val; } } this._write("%PDF-" + this.version); this._write("%\xFF\xFF\xFF\xFF"); if (this.options.autoFirstPage !== false) { this.addPage(); } }
n/a
function ReadableState(options, stream) { options = options || {}; // object stream flag. Used to make read(n) ignore n and to // make all the buffer merging and length checks go away this.objectMode = !!options.objectMode; if (stream instanceof Stream.Duplex) this.objectMode = this.objectMode || !!options.readableObjectMode; // the point at which it stops calling _read() to fill the buffer // Note: 0 is a valid value, means "don't call _read preemptively ever" var hwm = options.highWaterMark; var defaultHwm = this.objectMode ? 16 : 16 * 1024; this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm; // cast to ints. this.highWaterMark = ~~this.highWaterMark; // A linked list is used to store data chunks instead of an array because the // linked list can remove elements from the beginning faster than // array.shift() this.buffer = new BufferList(); this.length = 0; this.pipes = null; this.pipesCount = 0; this.flowing = null; this.ended = false; this.endEmitted = false; this.reading = false; // a flag to be able to tell if the onwrite cb is called immediately, // or on a later tick. We set this to true at first, because any // actions that shouldn't happen until "later" should generally also // not happen before the first write call. this.sync = true; // whenever we return null, then we set a flag to say // that we're awaiting a 'readable' event emission. this.needReadable = false; this.emittedReadable = false; this.readableListening = false; this.resumeScheduled = false; // Crypto is kind of old and crusty. Historically, its default string // encoding is 'binary' so we have to make this configurable. // Everything else in the universe uses 'utf8', though. this.defaultEncoding = options.defaultEncoding || 'utf8'; // when piping, we only care about 'readable' events that happen // after read()ing all the bytes and not getting any pushback. this.ranOut = false; // the number of writers that are awaiting a drain event in .pipe()s this.awaitDrain = 0; // if true, a maybeReadMore has been scheduled this.readingMore = false; this.decoder = null; this.encoding = null; if (options.encoding) { if (!StringDecoder) StringDecoder = require('string_decoder').StringDecoder; this.decoder = new StringDecoder(options.encoding); this.encoding = options.encoding; } }
n/a
function fromList(n, state) { // nothing buffered if (state.length === 0) return null; var ret; if (state.objectMode) ret = state.buffer.shift(); else if (!n || n >= state.length) { // read it all, truncate the list if (state.decoder) ret = state.buffer.join(''); else if (state.buffer.length === 1) ret = state.buffer.head.data; else ret = state.buffer.concat(state.length); state.buffer.clear(); } else { // read part of list ret = fromListPartial(n, state.buffer, state.decoder); } return ret; }
n/a
function AFMFont(contents) { var e, i; this.contents = contents; this.attributes = {}; this.glyphWidths = {}; this.boundingBoxes = {}; this.kernPairs = {}; this.parse(); this.charWidths = (function() { var j, results; results = []; for (i = j = 0; j <= 255; i = ++j) { results.push(this.glyphWidths[characters[i]]); } return results; }).call(this); this.bbox = (function() { var j, len, ref, results; ref = this.attributes['FontBBox'].split(/\s+/); results = []; for (j = 0, len = ref.length; j < len; j++) { e = ref[j]; results.push(+e); } return results; }).call(this); this.ascender = +(this.attributes['Ascender'] || 0); this.descender = +(this.attributes['Descender'] || 0); this.lineGap = (this.bbox[3] - this.bbox[1]) - (this.ascender - this.descender); }
n/a
function Data(data) { this.data = data != null ? data : []; this.pos = 0; this.length = this.data.length; }
n/a
function EmbeddedFont(document, font, id) { this.document = document; this.font = font; this.id = id; this.subset = this.font.createSubset(); this.unicode = [[0]]; this.widths = [this.font.getGlyph(0).advanceWidth]; this.name = this.font.postscriptName; this.scale = 1000 / this.font.unitsPerEm; this.ascender = this.font.ascent * this.scale; this.descender = this.font.descent * this.scale; this.lineGap = this.font.lineGap * this.scale; this.bbox = this.font.bbox; }
n/a
function PDFFont() { throw new Error('Cannot construct a PDFFont directly.'); }
...
doc = new PDFDocument
# Pipe its 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)
...
function PDFImage() {}
n/a
function JPEG(data, label) { var channels, marker, pos; this.data = data; this.label = label; if (this.data.readUInt16BE(0) !== 0xFFD8) { throw "SOI not found in JPEG"; } pos = 2; while (pos < this.data.length) { marker = this.data.readUInt16BE(pos); pos += 2; if (indexOf.call(MARKERS, marker) >= 0) { break; } pos += this.data.readUInt16BE(pos); } if (indexOf.call(MARKERS, marker) < 0) { throw "Invalid JPEG."; } pos += 2; this.bits = this.data[pos++]; this.height = this.data.readUInt16BE(pos); pos += 2; this.width = this.data.readUInt16BE(pos); pos += 2; channels = this.data[pos++]; this.colorSpace = (function() { switch (channels) { case 1: return 'DeviceGray'; case 3: return 'DeviceRGB'; case 4: return 'DeviceCMYK'; } })(); this.obj = null; }
n/a
function LineWrapper(document, options) { var ref; this.document = document; this.indent = options.indent || 0; this.characterSpacing = options.characterSpacing || 0; this.wordSpacing = options.wordSpacing === 0; this.columns = options.columns || 1; this.columnGap = (ref = options.columnGap) != null ? ref : 18; this.lineWidth = (options.width - (this.columnGap * (this.columns - 1))) / this.columns; this.spaceLeft = this.lineWidth; this.startX = this.document.x; this.startY = this.document.y; this.column = 1; this.ellipsis = options.ellipsis; this.continuedX = 0; this.features = options.features; if (options.height != null) { this.height = options.height; this.maxY = this.startY + options.height; } else { this.maxY = this.document.page.maxY(); } this.on('firstLine', (function(_this) { return function(options) { var indent; indent = _this.continuedX || _this.indent; _this.document.x += indent; _this.lineWidth -= indent; return _this.once('line', function() { _this.document.x -= indent; _this.lineWidth += indent; if (options.continued && !_this.continuedX) { _this.continuedX = _this.indent; } if (!options.continued) { return _this.continuedX = 0; } }); }; })(this)); this.on('lastLine', (function(_this) { return function(options) { var align; align = options.align; if (align === 'justify') { options.align = 'left'; } _this.lastLine = true; return _this.once('line', function() { _this.document.y += options.paragraphGap || 0; options.align = align; return _this.lastLine = false; }); }; })(this)); }
n/a
function PDFObject() {}
n/a
function PDFPage(document, options) { var dimensions; this.document = document; if (options == null) { options = {}; } this.size = options.size || 'letter'; this.layout = options.layout || 'portrait'; if (typeof options.margin === 'number') { this.margins = { top: options.margin, left: options.margin, bottom: options.margin, right: options.margin }; } else { this.margins = options.margins || DEFAULT_MARGINS; } dimensions = Array.isArray(this.size) ? this.size : SIZES[this.size.toUpperCase()]; this.width = dimensions[this.layout === 'portrait' ? 0 : 1]; this.height = dimensions[this.layout === 'portrait' ? 1 : 0]; this.content = this.document.ref(); this.resources = this.document.ref({ ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'] }); Object.defineProperties(this, { fonts: { get: (function(_this) { return function() { var base; return (base = _this.resources.data).Font != null ? base.Font : base.Font = {}; }; })(this) }, xobjects: { get: (function(_this) { return function() { var base; return (base = _this.resources.data).XObject != null ? base.XObject : base.XObject = {}; }; })(this) }, ext_gstates: { get: (function(_this) { return function() { var base; return (base = _this.resources.data).ExtGState != null ? base.ExtGState : base.ExtGState = {}; }; })(this) }, patterns: { get: (function(_this) { return function() { var base; return (base = _this.resources.data).Pattern != null ? base.Pattern : base.Pattern = {}; }; })(this) }, annotations: { get: (function(_this) { return function() { var base; return (base = _this.dictionary.data).Annots != null ? base.Annots : base.Annots = []; }; })(this) } }); this.dictionary = this.document.ref({ Type: 'Page', Parent: this.document._root.data.Pages, MediaBox: [0, 0, this.width, this.height], Contents: this.content, Resources: this.resources }); }
n/a
function SVGPath() {}
...
.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)
...
function PNGImage(data, label) { this.label = label; this.image = new PNG(data); this.width = this.image.width; this.height = this.image.height; this.imgData = this.image.imgData; this.obj = null; }
n/a
function PDFReference(document, id, data) { this.document = document; this.id = id; this.data = data != null ? data : {}; this.finalize = bind(this.finalize, this); PDFReference.__super__.constructor.call(this, { decodeStrings: false }); this.gen = 0; this.deflate = null; this.compress = this.document.compress && !this.data.Filter; this.uncompressedLength = 0; this.chunks = []; }
n/a
function StandardFont(document, name1, id) { var ref; this.document = document; this.name = name1; this.id = id; this.font = new AFMFont(STANDARD_FONTS[this.name]()); ref = this.font, this.ascender = ref.ascender, this.descender = ref.descender, this.bbox = ref.bbox, this.lineGap = ref.lineGap ; }
n/a
function Stream() { EE.call(this); }
n/a
function AFMFont(contents) { var e, i; this.contents = contents; this.attributes = {}; this.glyphWidths = {}; this.boundingBoxes = {}; this.kernPairs = {}; this.parse(); this.charWidths = (function() { var j, results; results = []; for (i = j = 0; j <= 255; i = ++j) { results.push(this.glyphWidths[characters[i]]); } return results; }).call(this); this.bbox = (function() { var j, len, ref, results; ref = this.attributes['FontBBox'].split(/\s+/); results = []; for (j = 0, len = ref.length; j < len; j++) { e = ref[j]; results.push(+e); } return results; }).call(this); this.ascender = +(this.attributes['Ascender'] || 0); this.descender = +(this.attributes['Descender'] || 0); this.lineGap = (this.bbox[3] - this.bbox[1]) - (this.ascender - this.descender); }
n/a
open = function (filename) { return new AFMFont(fs.readFileSync(filename, 'utf8')); }
...
this.fontSize(size);
}
if (font = this._fontFamilies[cacheKey]) {
this._font = font;
return this;
}
id = 'F' + (++this._fontCount);
this._font = PDFFont.open(this, src, family, id);
if (font = this._fontFamilies[this._font.name]) {
this._font = font;
return this;
}
if (cacheKey) {
this._fontFamilies[cacheKey] = this._font;
}
...
advancesForGlyphs = function (glyphs) { var advances, index, j, left, len, right; advances = []; for (index = j = 0, len = glyphs.length; j < len; index = ++j) { left = glyphs[index]; right = glyphs[index + 1]; advances.push(this.widthOfGlyph(left) + this.getKernPair(left, right)); } return advances; }
...
return this.dictionary.end();
};
StandardFont.prototype.encode = function(text) {
var advances, encoded, glyph, glyphs, i, j, len, positions;
encoded = this.font.encodeText(text);
glyphs = this.font.glyphsForString('' + text);
advances = this.font.advancesForGlyphs(glyphs);
positions = [];
for (i = j = 0, len = glyphs.length; j < len; i = ++j) {
glyph = glyphs[i];
positions.push({
xAdvance: advances[i],
yAdvance: 0,
xOffset: 0,
...
characterToGlyph = function (character) { return characters[WIN_ANSI_MAP[character] || character] || '.notdef'; }
...
};
AFMFont.prototype.glyphsForString = function(string) {
var charCode, glyphs, i, j, ref;
glyphs = [];
for (i = j = 0, ref = string.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
charCode = string.charCodeAt(i);
glyphs.push(this.characterToGlyph(charCode));
}
return glyphs;
};
AFMFont.prototype.characterToGlyph = function(character) {
return characters[WIN_ANSI_MAP[character] || character] || '.notdef';
};
...
encodeText = function (text) { var char, i, j, ref, res; res = []; for (i = j = 0, ref = text.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { char = text.charCodeAt(i); char = WIN_ANSI_MAP[char] || char; res.push(char.toString(16)); } return res; }
...
Encoding: 'WinAnsiEncoding'
};
return this.dictionary.end();
};
StandardFont.prototype.encode = function(text) {
var advances, encoded, glyph, glyphs, i, j, len, positions;
encoded = this.font.encodeText(text);
glyphs = this.font.glyphsForString('' + text);
advances = this.font.advancesForGlyphs(glyphs);
positions = [];
for (i = j = 0, len = glyphs.length; j < len; i = ++j) {
glyph = glyphs[i];
positions.push({
xAdvance: advances[i],
...
getKernPair = function (left, right) { return this.kernPairs[left + '\0' + right] || 0; }
...
AFMFont.prototype.advancesForGlyphs = function(glyphs) {
var advances, index, j, left, len, right;
advances = [];
for (index = j = 0, len = glyphs.length; j < len; index = ++j) {
left = glyphs[index];
right = glyphs[index + 1];
advances.push(this.widthOfGlyph(left) + this.getKernPair(left, right));
}
return advances;
};
characters = '.notdef .notdef .notdef .notdef\n.notdef .notdef .notdef .notdef\n.notdef
.notdef .notdef .notdef\n.notdef .notdef .notdef .notdef\n.notdef .notdef .notdef .notdef\n.notdef .notdef .notdef .notdef\n.notdef .notdef .notdef .notdef\n.notdef .notdef .notdef .notdef\n\nspace exclam quotedbl numbersign\ndollar percent ampersand quotesingle\nparenleft parenright asterisk plus\ncomma hyphen period slash\nzero one two three\nfour five six seven\neight nine colon semicolon\nless equal greater question\n\nat A B C\nD E F G\nH I J K\nL M N O\nP Q R S\nT U V W\nX Y Z bracketleft\nbackslash bracketright asciicircum underscore\n\ngrave a b c\nd e f g\nh i j k\nl m n o\np q r s\nt u v w\nx y z braceleft\nbar braceright asciitilde .notdef\n\nEuro .notdef quotesinglbase florin\nquotedblbase ellipsis dagger daggerdbl\ncircumflex perthousand Scaron guilsinglleft\nOE .notdef Zcaron .notdef\n.notdef quoteleft quoteright quotedblleft\nquotedblright bullet endash emdash\ntilde trademark scaron guilsinglright\noe .notdef zcaron ydieresis\n\nspace exclamdown cent sterling\ncurrency yen brokenbar section\ndieresis copyright ordfeminine guillemotleft\nlogicalnot hyphen registered macron\ndegree plusminus twosuperior threesuperior\nacute mu paragraph periodcentered\ncedilla onesuperior ordmasculine guillemotright\nonequarter onehalf threequarters questiondown\n\nAgrave Aacute Acircumflex Atilde\nAdieresis Aring AE Ccedilla\nEgrave Eacute Ecircumflex Edieresis\nIgrave Iacute Icircumflex Idieresis\nEth Ntilde Ograve Oacute\nOcircumflex Otilde Odieresis multiply\nOslash Ugrave Uacute Ucircumflex\nUdieresis Yacute Thorn germandbls\n\nagrave aacute acircumflex atilde\nadieresis aring ae ccedilla\negrave eacute ecircumflex edieresis\nigrave iacute icircumflex idieresis\neth ntilde ograve oacute\nocircumflex otilde odieresis divide\noslash ugrave uacute ucircumflex\nudieresis yacute thorn ydieresis'.split(/\s+/);
return AFMFont;
...
glyphsForString = function (string) { var charCode, glyphs, i, j, ref; glyphs = []; for (i = j = 0, ref = string.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { charCode = string.charCodeAt(i); glyphs.push(this.characterToGlyph(charCode)); } return glyphs; }
...
};
return this.dictionary.end();
};
StandardFont.prototype.encode = function(text) {
var advances, encoded, glyph, glyphs, i, j, len, positions;
encoded = this.font.encodeText(text);
glyphs = this.font.glyphsForString('' + text);
advances = this.font.advancesForGlyphs(glyphs);
positions = [];
for (i = j = 0, len = glyphs.length; j < len; i = ++j) {
glyph = glyphs[i];
positions.push({
xAdvance: advances[i],
yAdvance: 0,
...
parse = function () { var a, j, key, len, line, match, name, ref, section, value; section = ''; ref = this.contents.split('\n'); for (j = 0, len = ref.length; j < len; j++) { line = ref[j]; if (match = line.match(/^Start(\w+)/)) { section = match[1]; continue; } else if (match = line.match(/^End(\w+)/)) { section = ''; continue; } switch (section) { case 'FontMetrics': match = line.match(/(^\w+)\s+(.*)/); key = match[1]; value = match[2]; if (a = this.attributes[key]) { if (!Array.isArray(a)) { a = this.attributes[key] = [a]; } a.push(value); } else { this.attributes[key] = value; } break; case 'CharMetrics': if (!/^CH?\s/.test(line)) { continue; } name = line.match(/\bN\s+(\.?\w+)\s*;/)[1]; this.glyphWidths[name] = +line.match(/\bWX\s+(\d+)\s*;/)[1]; break; case 'KernPairs': match = line.match(/^KPX\s+(\.?\w+)\s+(\.?\w+)\s+(-?\d+)/); if (match) { this.kernPairs[match[1] + '\0' + match[2]] = parseInt(match[3]); } } } }
...
function AFMFont(contents) {
var e, i;
this.contents = contents;
this.attributes = {};
this.glyphWidths = {};
this.boundingBoxes = {};
this.kernPairs = {};
this.parse();
this.charWidths = (function() {
var j, results;
results = [];
for (i = j = 0; j <= 255; i = ++j) {
results.push(this.glyphWidths[characters[i]]);
}
return results;
...
widthOfGlyph = function (glyph) { return this.glyphWidths[glyph] || 0; }
...
AFMFont.prototype.advancesForGlyphs = function(glyphs) {
var advances, index, j, left, len, right;
advances = [];
for (index = j = 0, len = glyphs.length; j < len; index = ++j) {
left = glyphs[index];
right = glyphs[index + 1];
advances.push(this.widthOfGlyph(left) + this.getKernPair(left, right));
}
return advances;
};
characters = '.notdef .notdef .notdef .notdef\n.notdef .notdef .notdef .notdef\n.notdef
.notdef .notdef .notdef\n.notdef .notdef .notdef .notdef\n.notdef .notdef .notdef .notdef\n.notdef .notdef .notdef .notdef\n.notdef .notdef .notdef .notdef\n.notdef .notdef .notdef .notdef\n\nspace exclam quotedbl numbersign\ndollar percent ampersand quotesingle\nparenleft parenright asterisk plus\ncomma hyphen period slash\nzero one two three\nfour five six seven\neight nine colon semicolon\nless equal greater question\n\nat A B C\nD E F G\nH I J K\nL M N O\nP Q R S\nT U V W\nX Y Z bracketleft\nbackslash bracketright asciicircum underscore\n\ngrave a b c\nd e f g\nh i j k\nl m n o\np q r s\nt u v w\nx y z braceleft\nbar braceright asciitilde .notdef\n\nEuro .notdef quotesinglbase florin\nquotedblbase ellipsis dagger daggerdbl\ncircumflex perthousand Scaron guilsinglleft\nOE .notdef Zcaron .notdef\n.notdef quoteleft quoteright quotedblleft\nquotedblright bullet endash emdash\ntilde trademark scaron guilsinglright\noe .notdef zcaron ydieresis\n\nspace exclamdown cent sterling\ncurrency yen brokenbar section\ndieresis copyright ordfeminine guillemotleft\nlogicalnot hyphen registered macron\ndegree plusminus twosuperior threesuperior\nacute mu paragraph periodcentered\ncedilla onesuperior ordmasculine guillemotright\nonequarter onehalf threequarters questiondown\n\nAgrave Aacute Acircumflex Atilde\nAdieresis Aring AE Ccedilla\nEgrave Eacute Ecircumflex Edieresis\nIgrave Iacute Icircumflex Idieresis\nEth Ntilde Ograve Oacute\nOcircumflex Otilde Odieresis multiply\nOslash Ugrave Uacute Ucircumflex\nUdieresis Yacute Thorn germandbls\n\nagrave aacute acircumflex atilde\nadieresis aring ae ccedilla\negrave eacute ecircumflex edieresis\nigrave iacute icircumflex idieresis\neth ntilde ograve oacute\nocircumflex otilde odieresis divide\noslash ugrave uacute ucircumflex\nudieresis yacute thorn ydieresis'.split(/\s+/);
return AFMFont;
...
_convertRect = function (x1, y1, w, h) { var m0, m1, m2, m3, m4, m5, ref1, x2, y2; y2 = y1; y1 += h; x2 = x1 + w; ref1 = this._ctm, m0 = ref1[0], m1 = ref1[1], m2 = ref1[2], m3 = ref1[3], m4 = ref1[4], m5 = ref1[5]; x1 = m0 * x1 + m2 * y1 + m4; y1 = m1 * x1 + m3 * y1 + m5; x2 = m0 * x2 + m2 * y2 + m4; y2 = m1 * x2 + m3 * y2 + m5; return [x1, y1, x2, y2]; }
...
// Generated by CoffeeScript 1.10.0
(function() {
module.exports = {
annotate: function(x, y, w, h, options) {
var key, ref, val;
options.Type = 'Annot';
options.Rect = this._convertRect(x, y, w, h);
options.Border = [0, 0, 0];
if (options.Subtype !== 'Link') {
if (options.C == null) {
options.C = this._normalizeColor(options.color || [0, 0, 0]);
}
}
delete options.color;
...
_markup = function (x, y, w, h, options) { var ref1, x1, x2, y1, y2; if (options == null) { options = {}; } ref1 = this._convertRect(x, y, w, h), x1 = ref1[0], y1 = ref1[1], x2 = ref1[2], y2 = ref1[3]; options.QuadPoints = [x1, y2, x2, y2, x1, y1, x2, y1]; options.Contents = new String; return this.annotate(x, y, w, h, options); }
...
if (options == null) {
options = {};
}
options.Subtype = 'Highlight';
if (options.color == null) {
options.color = [241, 238, 148];
}
return this._markup(x, y, w, h, options);
},
underline: function(x, y, w, h, options) {
if (options == null) {
options = {};
}
options.Subtype = 'Underline';
return this._markup(x, y, w, h, options);
...
annotate = function (x, y, w, h, options) { var key, ref, val; options.Type = 'Annot'; options.Rect = this._convertRect(x, y, w, h); options.Border = [0, 0, 0]; if (options.Subtype !== 'Link') { if (options.C == null) { options.C = this._normalizeColor(options.color || [0, 0, 0]); } } delete options.color; if (typeof options.Dest === 'string') { options.Dest = new String(options.Dest); } for (key in options) { val = options[key]; options[key[0].toUpperCase() + key.slice(1)] = val; } ref = this.ref(options); this.page.annotations.push(ref); ref.end(); return this; }
...
}
options.Subtype = 'Text';
options.Contents = new String(contents);
options.Name = 'Comment';
if (options.color == null) {
options.color = [243, 223, 92];
}
return this.annotate(x, y, w, h, options);
},
link: function(x, y, w, h, url, options) {
if (options == null) {
options = {};
}
options.Subtype = 'Link';
options.A = this.ref({
...
ellipseAnnotation = function (x, y, w, h, options) { if (options == null) { options = {}; } options.Subtype = 'Circle'; options.Contents = new String; return this.annotate(x, y, w, h, options); }
n/a
highlight = function (x, y, w, h, options) { if (options == null) { options = {}; } options.Subtype = 'Highlight'; if (options.color == null) { options.color = [241, 238, 148]; } return this._markup(x, y, w, h, options); }
n/a
lineAnnotation = function (x1, y1, x2, y2, options) { if (options == null) { options = {}; } options.Subtype = 'Line'; options.Contents = new String; options.L = [x1, this.page.height - y1, x2, this.page.height - y2]; return this.annotate(x1, y1, x2, y2, options); }
n/a
link = function (x, y, w, h, url, options) { if (options == null) { options = {}; } options.Subtype = 'Link'; options.A = this.ref({ S: 'URI', URI: new String(url) }); options.A.end(); return this.annotate(x, y, w, h, options); }
...
.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
...
note = function (x, y, w, h, contents, options) { if (options == null) { options = {}; } options.Subtype = 'Text'; options.Contents = new String(contents); options.Name = 'Comment'; if (options.color == null) { options.color = [243, 223, 92]; } return this.annotate(x, y, w, h, options); }
n/a
rectAnnotation = function (x, y, w, h, options) { if (options == null) { options = {}; } options.Subtype = 'Square'; options.Contents = new String; return this.annotate(x, y, w, h, options); }
n/a
strike = function (x, y, w, h, options) { if (options == null) { options = {}; } options.Subtype = 'StrikeOut'; return this._markup(x, y, w, h, options); }
n/a
textAnnotation = function (x, y, w, h, text, options) { if (options == null) { options = {}; } options.Subtype = 'FreeText'; options.Contents = new String(text); options.DA = new String; return this.annotate(x, y, w, h, options); }
n/a
underline = function (x, y, w, h, options) { if (options == null) { options = {}; } options.Subtype = 'Underline'; return this._markup(x, y, w, h, options); }
...
.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
...
_doOpacity = function (fillOpacity, strokeOpacity) { var dictionary, id, key, name, ref1; if (!((fillOpacity != null) || (strokeOpacity != null))) { return; } if (fillOpacity != null) { fillOpacity = Math.max(0, Math.min(1, fillOpacity)); } if (strokeOpacity != null) { strokeOpacity = Math.max(0, Math.min(1, strokeOpacity)); } key = fillOpacity + "_" + strokeOpacity; if (this._opacityRegistry[key]) { ref1 = this._opacityRegistry[key], dictionary = ref1[0], name = ref1[1]; } else { dictionary = { Type: 'ExtGState' }; if (fillOpacity != null) { dictionary.ca = fillOpacity; } if (strokeOpacity != null) { dictionary.CA = strokeOpacity; } dictionary = this.ref(dictionary); dictionary.end(); id = ++this._opacityCount; name = "Gs" + id; this._opacityRegistry[key] = [dictionary, name]; } this.page.ext_gstates[name] = dictionary; return this.addContent("/" + name + " gs"); }
...
set = this._setColor(color, true);
if (set) {
this.strokeOpacity(opacity);
}
return this;
},
opacity: function(opacity) {
this._doOpacity(opacity, opacity);
return this;
},
fillOpacity: function(opacity) {
this._doOpacity(opacity, null);
return this;
},
strokeOpacity: function(opacity) {
...
_normalizeColor = function (color) { var hex, part; if (color instanceof PDFGradient) { return color; } if (typeof color === 'string') { if (color.charAt(0) === '#') { if (color.length === 4) { color = color.replace(/#([0-9A-F])([0-9A-F])([0-9A-F])/i, "#$1$1$2$2$3$3"); } hex = parseInt(color.slice(1), 16); color = [hex >> 16, hex >> 8 & 0xff, hex & 0xff]; } else if (namedColors[color]) { color = namedColors[color]; } } if (Array.isArray(color)) { if (color.length === 3) { color = (function() { var i, len, results; results = []; for (i = 0, len = color.length; i < len; i++) { part = color[i]; results.push(part / 255); } return results; })(); } else if (color.length === 4) { color = (function() { var i, len, results; results = []; for (i = 0, len = color.length; i < len; i++) { part = color[i]; results.push(part / 100); } return results; })(); } return color; } return null; }
...
}
PDFGradient.prototype.stop = function(pos, color, opacity) {
if (opacity == null) {
opacity = 1;
}
opacity = Math.max(0, Math.min(1, opacity));
this.stops.push([pos, this.doc._normalizeColor(color), opacity]);
return this;
};
PDFGradient.prototype.embed = function() {
var bounds, dx, dy, encode, fn, form, grad, group, gstate, i, j, k, last, len, m, m0, m1, m11, m12, m2, m21, m22, m3, m4, m5,
name, pattern, ref, ref1, ref2, resources, sMask, shader, stop, stops, v;
if (this.embedded || this.stops.length === 0) {
return;
...
_setColor = function (color, stroke) { var gstate, name, op, space; color = this._normalizeColor(color); if (!color) { return false; } if (this._sMasked) { gstate = this.ref({ Type: 'ExtGState', SMask: 'None' }); gstate.end(); name = "Gs" + (++this._opacityCount); this.page.ext_gstates[name] = gstate; this.addContent("/" + name + " gs"); this._sMasked = false; } op = stroke ? 'SCN' : 'scn'; if (color instanceof PDFGradient) { this._setColorSpace('Pattern', stroke); color.apply(op); } else { space = color.length === 4 ? 'DeviceCMYK' : 'DeviceRGB'; this._setColorSpace(space, stroke); color = color.join(' '); this.addContent(color + " " + op); } return true; }
...
return this.addContent("/" + space + " " + op);
},
fillColor: function(color, opacity) {
var set;
if (opacity == null) {
opacity = 1;
}
set = this._setColor(color, false);
if (set) {
this.fillOpacity(opacity);
}
this._fillColor = [color, opacity];
return this;
},
strokeColor: function(color, opacity) {
...
_setColorSpace = function (space, stroke) { var op; op = stroke ? 'CS' : 'cs'; return this.addContent("/" + space + " " + op); }
...
name = "Gs" + (++this._opacityCount);
this.page.ext_gstates[name] = gstate;
this.addContent("/" + name + " gs");
this._sMasked = false;
}
op = stroke ? 'SCN' : 'scn';
if (color instanceof PDFGradient) {
this._setColorSpace('Pattern', stroke);
color.apply(op);
} else {
space = color.length === 4 ? 'DeviceCMYK' : 'DeviceRGB';
this._setColorSpace(space, stroke);
color = color.join(' ');
this.addContent(color + " " + op);
}
...
fillColor = function (color, opacity) { var set; if (opacity == null) { opacity = 1; } set = this._setColor(color, false); if (set) { this.fillOpacity(opacity); } this._fillColor = [color, opacity]; return this; }
...
.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()
```
...
fillOpacity = function (opacity) { this._doOpacity(opacity, null); return this; }
...
fillColor: function(color, opacity) {
var set;
if (opacity == null) {
opacity = 1;
}
set = this._setColor(color, false);
if (set) {
this.fillOpacity(opacity);
}
this._fillColor = [color, opacity];
return this;
},
strokeColor: function(color, opacity) {
var set;
if (opacity == null) {
...
initColor = function () { this._opacityRegistry = {}; this._opacityCount = 0; return this._gradCount = 0; }
n/a
linearGradient = function (x1, y1, x2, y2) { return new PDFLinearGradient(this, x1, y1, x2, y2); }
n/a
opacity = function (opacity) { this._doOpacity(opacity, opacity); return this; }
n/a
radialGradient = function (x1, y1, r1, x2, y2, r2) { return new PDFRadialGradient(this, x1, y1, r1, x2, y2, r2); }
n/a
strokeColor = function (color, opacity) { var set; if (opacity == null) { opacity = 1; } set = this._setColor(color, true); if (set) { this.strokeOpacity(opacity); } return this; }
...
if (color) {
this.fillColor(color);
}
return this.addContent('f' + this._windingRule(rule));
},
stroke: function(color) {
if (color) {
this.strokeColor(color);
}
return this.addContent('S');
},
fillAndStroke: function(fillColor, strokeColor, rule) {
var isFillRule;
if (strokeColor == null) {
strokeColor = fillColor;
...
strokeOpacity = function (opacity) { this._doOpacity(null, opacity); return this; }
...
strokeColor: function(color, opacity) {
var set;
if (opacity == null) {
opacity = 1;
}
set = this._setColor(color, true);
if (set) {
this.strokeOpacity(opacity);
}
return this;
},
opacity: function(opacity) {
this._doOpacity(opacity, opacity);
return this;
},
...
function Data(data) { this.data = data != null ? data : []; this.pos = 0; this.length = this.data.length; }
n/a
byteAt = function (index) { return this.data[index]; }
n/a
read = function (bytes) { var buf, i, j, ref; buf = []; for (i = j = 0, ref = bytes; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { buf.push(this.readByte()); } return buf; }
n/a
readBool = function () { return !!this.readByte(); }
n/a
readByte = function () { return this.data[this.pos++]; }
...
};
Data.prototype.byteAt = function(index) {
return this.data[index];
};
Data.prototype.readBool = function() {
return !!this.readByte();
};
Data.prototype.writeBool = function(val) {
return this.writeByte(val ? 1 : 0);
};
Data.prototype.readUInt32 = function() {
...
readInt = function () { return this.readInt32(); }
n/a
readInt16 = function () { var int; int = this.readUInt16(); if (int >= 0x8000) { return int - 0x10000; } else { return int; } }
...
Data.prototype.stringAt = function(pos, length) {
this.pos = pos;
return this.readString(length);
};
Data.prototype.readShort = function() {
return this.readInt16();
};
Data.prototype.writeShort = function(val) {
return this.writeInt16(val);
};
Data.prototype.readLongLong = function() {
...
readInt32 = function () { var int; int = this.readUInt32(); if (int >= 0x80000000) { return int - 0x100000000; } else { return int; } }
...
this.writeByte((low >> 24) & 0xff);
this.writeByte((low >> 16) & 0xff);
this.writeByte((low >> 8) & 0xff);
return this.writeByte(low & 0xff);
};
Data.prototype.readInt = function() {
return this.readInt32();
};
Data.prototype.writeInt = function(val) {
return this.writeInt32(val);
};
Data.prototype.slice = function(start, end) {
...
readLongLong = function () { var b1, b2, b3, b4, b5, b6, b7, b8; b1 = this.readByte(); b2 = this.readByte(); b3 = this.readByte(); b4 = this.readByte(); b5 = this.readByte(); b6 = this.readByte(); b7 = this.readByte(); b8 = this.readByte(); if (b1 & 0x80) { return ((b1 ^ 0xff) * 0x100000000000000 + (b2 ^ 0xff) * 0x1000000000000 + (b3 ^ 0xff) * 0x10000000000 + (b4 ^ 0xff) * 0x100000000 + (b5 ^ 0xff) * 0x1000000 + (b6 ^ 0xff) * 0x10000 + (b7 ^ 0xff) * 0x100 + (b8 ^ 0xff) + 1) * -1; } return b1 * 0x100000000000000 + b2 * 0x1000000000000 + b3 * 0x10000000000 + b4 * 0x100000000 + b5 * 0x1000000 + b6 * 0x10000 + b7 * 0x100 + b8; }
n/a
readShort = function () { return this.readInt16(); }
n/a
readString = function (length) { var i, j, ref, ret; ret = []; for (i = j = 0, ref = length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { ret[i] = String.fromCharCode(this.readByte()); } return ret.join(''); }
...
results.push(this.writeByte(val.charCodeAt(i)));
}
return results;
};
Data.prototype.stringAt = function(pos, length) {
this.pos = pos;
return this.readString(length);
};
Data.prototype.readShort = function() {
return this.readInt16();
};
Data.prototype.writeShort = function(val) {
...
readUInt16 = function () { var b1, b2; b1 = this.readByte() << 8; b2 = this.readByte(); return b1 | b2; }
...
Data.prototype.writeUInt16 = function(val) {
this.writeByte((val >> 8) & 0xff);
return this.writeByte(val & 0xff);
};
Data.prototype.readInt16 = function() {
var int;
int = this.readUInt16();
if (int >= 0x8000) {
return int - 0x10000;
} else {
return int;
}
};
...
readUInt32 = function () { var b1, b2, b3, b4; b1 = this.readByte() * 0x1000000; b2 = this.readByte() << 16; b3 = this.readByte() << 8; b4 = this.readByte(); return b1 + b2 + b3 + b4; }
...
this.writeByte((val >> 16) & 0xff);
this.writeByte((val >> 8) & 0xff);
return this.writeByte(val & 0xff);
};
Data.prototype.readInt32 = function() {
var int;
int = this.readUInt32();
if (int >= 0x80000000) {
return int - 0x100000000;
} else {
return int;
}
};
...
slice = function (start, end) { return this.data.slice(start, end); }
...
};
Data.prototype.writeInt = function(val) {
return this.writeInt32(val);
};
Data.prototype.slice = function(start, end) {
return this.data.slice(start, end);
};
Data.prototype.read = function(bytes) {
var buf, i, j, ref;
buf = [];
for (i = j = 0, ref = bytes; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
buf.push(this.readByte());
...
stringAt = function (pos, length) { this.pos = pos; return this.readString(length); }
n/a
write = function (bytes) { var byte, j, len, results; results = []; for (j = 0, len = bytes.length; j < len; j++) { byte = bytes[j]; results.push(this.writeByte(byte)); } return results; }
...
}
PDFPage.prototype.maxY = function() {
return this.height - this.margins.bottom;
};
PDFPage.prototype.write = function(chunk) {
return this.content.write(chunk);
};
PDFPage.prototype.end = function() {
this.dictionary.end();
this.resources.end();
return this.content.end();
};
...
writeBool = function (val) { return this.writeByte(val ? 1 : 0); }
n/a
writeByte = function (byte) { return this.data[this.pos++] = byte; }
...
};
Data.prototype.readBool = function() {
return !!this.readByte();
};
Data.prototype.writeBool = function(val) {
return this.writeByte(val ? 1 : 0);
};
Data.prototype.readUInt32 = function() {
var b1, b2, b3, b4;
b1 = this.readByte() * 0x1000000;
b2 = this.readByte() << 16;
b3 = this.readByte() << 8;
...
writeInt = function (val) { return this.writeInt32(val); }
n/a
writeInt16 = function (val) { if (val < 0) { val += 0x10000; } return this.writeUInt16(val); }
...
};
Data.prototype.readShort = function() {
return this.readInt16();
};
Data.prototype.writeShort = function(val) {
return this.writeInt16(val);
};
Data.prototype.readLongLong = function() {
var b1, b2, b3, b4, b5, b6, b7, b8;
b1 = this.readByte();
b2 = this.readByte();
b3 = this.readByte();
...
writeInt32 = function (val) { if (val < 0) { val += 0x100000000; } return this.writeUInt32(val); }
...
};
Data.prototype.readInt = function() {
return this.readInt32();
};
Data.prototype.writeInt = function(val) {
return this.writeInt32(val);
};
Data.prototype.slice = function(start, end) {
return this.data.slice(start, end);
};
Data.prototype.read = function(bytes) {
...
writeLongLong = function (val) { var high, low; high = Math.floor(val / 0x100000000); low = val & 0xffffffff; this.writeByte((high >> 24) & 0xff); this.writeByte((high >> 16) & 0xff); this.writeByte((high >> 8) & 0xff); this.writeByte(high & 0xff); this.writeByte((low >> 24) & 0xff); this.writeByte((low >> 16) & 0xff); this.writeByte((low >> 8) & 0xff); return this.writeByte(low & 0xff); }
n/a
writeShort = function (val) { return this.writeInt16(val); }
n/a
writeString = function (val) { var i, j, ref, results; results = []; for (i = j = 0, ref = val.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { results.push(this.writeByte(val.charCodeAt(i))); } return results; }
n/a
writeUInt16 = function (val) { this.writeByte((val >> 8) & 0xff); return this.writeByte(val & 0xff); }
...
}
};
Data.prototype.writeInt16 = function(val) {
if (val < 0) {
val += 0x10000;
}
return this.writeUInt16(val);
};
Data.prototype.readString = function(length) {
var i, j, ref, ret;
ret = [];
for (i = j = 0, ref = length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
ret[i] = String.fromCharCode(this.readByte());
...
writeUInt32 = function (val) { this.writeByte((val >>> 24) & 0xff); this.writeByte((val >> 16) & 0xff); this.writeByte((val >> 8) & 0xff); return this.writeByte(val & 0xff); }
...
}
};
Data.prototype.writeInt32 = function(val) {
if (val < 0) {
val += 0x100000000;
}
return this.writeUInt32(val);
};
Data.prototype.readUInt16 = function() {
var b1, b2;
b1 = this.readByte() << 8;
b2 = this.readByte();
return b1 | b2;
...
function EmbeddedFont(document, font, id) { this.document = document; this.font = font; this.id = id; this.subset = this.font.createSubset(); this.unicode = [[0]]; this.widths = [this.font.getGlyph(0).advanceWidth]; this.name = this.font.postscriptName; this.scale = 1000 / this.font.unitsPerEm; this.ascender = this.font.ascent * this.scale; this.descender = this.font.descent * this.scale; this.lineGap = this.font.lineGap * this.scale; this.bbox = this.font.bbox; }
n/a
open = function (document, src, family, id) { var font; if (typeof src === 'string') { if (StandardFont.isStandardFont(src)) { return new StandardFont(document, src, id); } font = fontkit.openSync(src, family); } else if (Buffer.isBuffer(src)) { font = fontkit.create(src, family); } else if (src instanceof Uint8Array) { font = fontkit.create(new Buffer(src), family); } else if (src instanceof ArrayBuffer) { font = fontkit.create(new Buffer(new Uint8Array(src)), family); } if (font == null) { throw new Error('Not a supported font format or standard PDF font.'); } return new EmbeddedFont(document, font, id); }
...
this.fontSize(size);
}
if (font = this._fontFamilies[cacheKey]) {
this._font = font;
return this;
}
id = 'F' + (++this._fontCount);
this._font = PDFFont.open(this, src, family, id);
if (font = this._fontFamilies[this._font.name]) {
this._font = font;
return this;
}
if (cacheKey) {
this._fontFamilies[cacheKey] = this._font;
}
...
function EmbeddedFont(document, font, id) { this.document = document; this.font = font; this.id = id; this.subset = this.font.createSubset(); this.unicode = [[0]]; this.widths = [this.font.getGlyph(0).advanceWidth]; this.name = this.font.postscriptName; this.scale = 1000 / this.font.unitsPerEm; this.ascender = this.font.ascent * this.scale; this.descender = this.font.descent * this.scale; this.lineGap = this.font.lineGap * this.scale; this.bbox = this.font.bbox; }
n/a
embed = function () { var bbox, descendantFont, descriptor, familyClass, flags, fontFile, i, isCFF, name, ref, tag; isCFF = this.subset.cff != null; fontFile = this.document.ref(); if (isCFF) { fontFile.data.Subtype = 'CIDFontType0C'; } this.subset.encodeStream().pipe(fontFile); familyClass = (((ref = this.font['OS/2']) != null ? ref.sFamilyClass : void 0) || 0) >> 8; flags = 0; if (this.font.post.isFixedPitch) { flags |= 1 << 0; } if ((1 <= familyClass && familyClass <= 7)) { flags |= 1 << 1; } flags |= 1 << 2; if (familyClass === 10) { flags |= 1 << 3; } if (this.font.head.macStyle.italic) { flags |= 1 << 6; } tag = ((function() { var j, results; results = []; for (i = j = 0; j < 6; i = ++j) { results.push(String.fromCharCode(Math.random() * 26 + 65)); } return results; })()).join(''); name = tag + '+' + this.font.postscriptName; bbox = this.font.bbox; descriptor = this.document.ref({ Type: 'FontDescriptor', FontName: name, Flags: flags, FontBBox: [bbox.minX * this.scale, bbox.minY * this.scale, bbox.maxX * this.scale, bbox.maxY * this.scale], ItalicAngle: this.font.italicAngle, Ascent: this.ascender, Descent: this.descender, CapHeight: (this.font.capHeight || this.font.ascent) * this.scale, XHeight: (this.font.xHeight || 0) * this.scale, StemV: 0 }); if (isCFF) { descriptor.data.FontFile3 = fontFile; } else { descriptor.data.FontFile2 = fontFile; } descriptor.end(); descendantFont = this.document.ref({ Type: 'Font', Subtype: isCFF ? 'CIDFontType0' : 'CIDFontType2', BaseFont: name, CIDSystemInfo: { Registry: new String('Adobe'), Ordering: new String('Identity'), Supplement: 0 }, FontDescriptor: descriptor, W: [0, this.widths] }); descendantFont.end(); this.dictionary.data = { Type: 'Font', Subtype: 'Type0', BaseFont: name, Encoding: 'Identity-H', DescendantFonts: [descendantFont], ToUnicode: this.toUnicodeCmap() }; return this.dictionary.end(); }
...
return this.dictionary != null ? this.dictionary : this.dictionary = this.document.ref();
};
PDFFont.prototype.finalize = function() {
if (this.embedded || (this.dictionary == null)) {
return;
}
this.embed();
return this.embedded = true;
};
PDFFont.prototype.embed = function() {
throw new Error('Must be implemented by subclasses');
};
...
encode = function (text, features) { var base, base1, gid, glyph, glyphs, i, j, key, len, positions, ref, res; ref = this.font.layout(text, features), glyphs = ref.glyphs, positions = ref.positions; res = []; for (i = j = 0, len = glyphs.length; j < len; i = ++j) { glyph = glyphs[i]; gid = this.subset.includeGlyph(glyph.id); res.push(('0000' + gid.toString(16)).slice(-4)); if ((base = this.widths)[gid] == null) { base[gid] = glyph.advanceWidth * this.scale; } if ((base1 = this.unicode)[gid] == null) { base1[gid] = glyph.codePoints; } for (key in positions[i]) { positions[i][key] *= this.scale; } positions[i].advanceWidth = glyph.advanceWidth * this.scale; } return [res, positions]; }
...
words = text.trim().split(/\s+/);
wordSpacing += this.widthOfString(' ') + characterSpacing;
wordSpacing *= 1000 / this._fontSize;
encoded = [];
positions = [];
for (j = 0, len = words.length; j < len; j++) {
word = words[j];
ref = this._font.encode(word, options.features), encodedWord = ref[0], positionsWord
= ref[1];
encoded.push.apply(encoded, encodedWord);
positions.push.apply(positions, positionsWord);
positions[positions.length - 1].xAdvance += wordSpacing;
}
} else {
ref1 = this._font.encode(text, options.features), encoded = ref1[0], positions = ref1[1];
}
...
toUnicodeCmap = function () { var cmap, codePoints, encoded, entries, j, k, len, len1, ref, value; cmap = this.document.ref(); entries = []; ref = this.unicode; for (j = 0, len = ref.length; j < len; j++) { codePoints = ref[j]; encoded = []; for (k = 0, len1 = codePoints.length; k < len1; k++) { value = codePoints[k]; if (value > 0xffff) { value -= 0x10000; encoded.push(toHex(value >>> 10 & 0x3ff | 0xd800)); value = 0xdc00 | value & 0x3ff; } encoded.push(toHex(value)); } entries.push("<" + (encoded.join(' ')) + ">"); } cmap.end("/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n/CIDSystemInfo <<\n /Registry (Adobe)\n /Ordering ( UCS)\n /Supplement 0\n>> def\n/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n1 begincodespacerange\n<0000><ffff>\nendcodespacerange\n1 beginbfrange\n<0000> <" + (toHex(entries.length - 1)) + "> [" + (entries.join(' ')) + "]\nendbfrange\nendcmap\nCMapName currentdict /CMap defineresource pop\nend\nend"); return cmap; }
...
descendantFont.end();
this.dictionary.data = {
Type: 'Font',
Subtype: 'Type0',
BaseFont: name,
Encoding: 'Identity-H',
DescendantFonts: [descendantFont],
ToUnicode: this.toUnicodeCmap()
};
return this.dictionary.end();
};
toHex = function() {
var code, codePoints, codes;
codePoints = 1 <= arguments.length ? slice.call(arguments, 0) : [];
...
widthOfString = function (string, size, features) { var scale, width; width = this.font.layout(string, features).advanceWidth; scale = size / this.font.unitsPerEm; return width * scale; }
...
return _this.lastLine = false;
});
};
})(this));
}
LineWrapper.prototype.wordWidth = function(word) {
return this.document.widthOfString(word, this) + this.characterSpacing + this.wordSpacing
;
};
LineWrapper.prototype.eachWord = function(text, fn) {
var bk, breaker, fbk, l, last, lbk, shouldContinue, w, word, wordWidths;
breaker = new LineBreaker(text);
last = null;
wordWidths = Object.create(null);
...
function PDFFont() { throw new Error('Cannot construct a PDFFont directly.'); }
...
doc = new PDFDocument
# Pipe its 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)
...
open = function (document, src, family, id) { var font; if (typeof src === 'string') { if (StandardFont.isStandardFont(src)) { return new StandardFont(document, src, id); } font = fontkit.openSync(src, family); } else if (Buffer.isBuffer(src)) { font = fontkit.create(src, family); } else if (src instanceof Uint8Array) { font = fontkit.create(new Buffer(src), family); } else if (src instanceof ArrayBuffer) { font = fontkit.create(new Buffer(new Uint8Array(src)), family); } if (font == null) { throw new Error('Not a supported font format or standard PDF font.'); } return new EmbeddedFont(document, font, id); }
...
this.fontSize(size);
}
if (font = this._fontFamilies[cacheKey]) {
this._font = font;
return this;
}
id = 'F' + (++this._fontCount);
this._font = PDFFont.open(this, src, family, id);
if (font = this._fontFamilies[this._font.name]) {
this._font = font;
return this;
}
if (cacheKey) {
this._fontFamilies[cacheKey] = this._font;
}
...
embed = function () { throw new Error('Must be implemented by subclasses'); }
...
return this.dictionary != null ? this.dictionary : this.dictionary = this.document.ref();
};
PDFFont.prototype.finalize = function() {
if (this.embedded || (this.dictionary == null)) {
return;
}
this.embed();
return this.embedded = true;
};
PDFFont.prototype.embed = function() {
throw new Error('Must be implemented by subclasses');
};
...
encode = function (text) { throw new Error('Must be implemented by subclasses'); }
...
words = text.trim().split(/\s+/);
wordSpacing += this.widthOfString(' ') + characterSpacing;
wordSpacing *= 1000 / this._fontSize;
encoded = [];
positions = [];
for (j = 0, len = words.length; j < len; j++) {
word = words[j];
ref = this._font.encode(word, options.features), encodedWord = ref[0], positionsWord
= ref[1];
encoded.push.apply(encoded, encodedWord);
positions.push.apply(positions, positionsWord);
positions[positions.length - 1].xAdvance += wordSpacing;
}
} else {
ref1 = this._font.encode(text, options.features), encoded = ref1[0], positions = ref1[1];
}
...
finalize = function () { if (this.embedded || (this.dictionary == null)) { return; } this.embed(); return this.embedded = true; }
...
};
PDFReference.prototype.end = function(chunk) {
PDFReference.__super__.end.apply(this, arguments);
if (this.deflate) {
return this.deflate.end();
} else {
return this.finalize();
}
};
PDFReference.prototype.finalize = function() {
var chunk, i, len, ref;
this.offset = this.document._offset;
this.document._write(this.id + " " + this.gen + " obj");
...
lineHeight = function (size, includeGap) { var gap; if (includeGap == null) { includeGap = false; } gap = includeGap ? this.lineGap : 0; return (this.ascender + gap - this.descender) / 1000 * size; }
...
this._fontSize = _fontSize;
return this;
},
currentLineHeight: function(includeGap) {
if (includeGap == null) {
includeGap = false;
}
return this._font.lineHeight(this._fontSize, includeGap);
},
registerFont: function(name, src, family) {
this._registeredFonts[name] = {
src: src,
family: family
};
return this;
...
ref = function () { return this.dictionary != null ? this.dictionary : this.dictionary = this.document.ref(); }
...
};
PDFFont.prototype.widthOfString = function(text) {
throw new Error('Must be implemented by subclasses');
};
PDFFont.prototype.ref = function() {
return this.dictionary != null ? this.dictionary : this.dictionary = this.document.ref();
};
PDFFont.prototype.finalize = function() {
if (this.embedded || (this.dictionary == null)) {
return;
}
this.embed();
...
widthOfString = function (text) { throw new Error('Must be implemented by subclasses'); }
...
return _this.lastLine = false;
});
};
})(this));
}
LineWrapper.prototype.wordWidth = function(word) {
return this.document.widthOfString(word, this) + this.characterSpacing + this.wordSpacing
;
};
LineWrapper.prototype.eachWord = function(text, fn) {
var bk, breaker, fbk, l, last, lbk, shouldContinue, w, word, wordWidths;
breaker = new LineBreaker(text);
last = null;
wordWidths = Object.create(null);
...
currentLineHeight = function (includeGap) { if (includeGap == null) { includeGap = false; } return this._font.lineHeight(this._fontSize, includeGap); }
...
}
if (options.wordSpacing != null) {
this.wordSpacing = options.wordSpacing;
}
if (options.ellipsis != null) {
this.ellipsis = options.ellipsis;
}
nextY = this.document.y + this.document.currentLineHeight(true);
if (this.document.y > this.maxY || nextY > this.maxY) {
this.nextSection();
}
buffer = '';
textWidth = 0;
wc = 0;
lc = 0;
...
font = function (src, family, size) { var cacheKey, font, id, ref; if (typeof family === 'number') { size = family; family = null; } if (typeof src === 'string' && this._registeredFonts[src]) { cacheKey = src; ref = this._registeredFonts[src], src = ref.src, family = ref.family; } else { cacheKey = family || src; if (typeof cacheKey !== 'string') { cacheKey = null; } } if (size != null) { this.fontSize(size); } if (font = this._fontFamilies[cacheKey]) { this._font = font; return this; } id = 'F' + (++this._fontCount); this._font = PDFFont.open(this, src, family, id); if (font = this._fontFamilies[this._font.name]) { this._font = font; return this; } if (cacheKey) { this._fontFamilies[cacheKey] = this._font; } this._fontFamilies[this._font.name] = this._font; return this; }
...
doc = new PDFDocument
# Pipe its 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)
...
fontSize = function (_fontSize) { this._fontSize = _fontSize; return this; }
...
# Pipe its 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)
...
initFonts = function () { this._fontFamilies = {}; this._fontCount = 0; this._fontSize = 12; this._font = null; this._registeredFonts = {}; return this.font('Helvetica'); }
n/a
registerFont = function (name, src, family) { this._registeredFonts[name] = { src: src, family: family }; return this; }
n/a
function PDFGradient(doc) { this.doc = doc; this.stops = []; this.embedded = false; this.transform = [1, 0, 0, 1, 0, 0]; this._colorSpace = 'DeviceRGB'; }
n/a
function PDFLinearGradient(doc, x1, y1, x2, y2) { this.doc = doc; this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; PDFLinearGradient.__super__.constructor.apply(this, arguments); }
n/a
function PDFRadialGradient(doc, x1, y1, r1, x2, y2, r2) { this.doc = doc; this.x1 = x1; this.y1 = y1; this.r1 = r1; this.x2 = x2; this.y2 = y2; this.r2 = r2; PDFRadialGradient.__super__.constructor.apply(this, arguments); }
n/a
function PDFImage() {}
n/a
open = function (src, label) { var data, match; if (Buffer.isBuffer(src)) { data = src; } else if (src instanceof ArrayBuffer) { data = new Buffer(new Uint8Array(src)); } else { if (match = /^data:.+;base64,(.*)$/.exec(src)) { data = new Buffer(match[1], 'base64'); } else { data = fs.readFileSync(src); if (!data) { return; } } } if (data[0] === 0xff && data[1] === 0xd8) { return new JPEG(data, label); } else if (data[0] === 0x89 && data.toString('ascii', 1, 4) === 'PNG') { return new PNG(data, label); } else { throw new Error('Unknown image format.'); } }
...
this.fontSize(size);
}
if (font = this._fontFamilies[cacheKey]) {
this._font = font;
return this;
}
id = 'F' + (++this._fontCount);
this._font = PDFFont.open(this, src, family, id);
if (font = this._fontFamilies[this._font.name]) {
this._font = font;
return this;
}
if (cacheKey) {
this._fontFamilies[cacheKey] = this._font;
}
...
image = function (src, x, y, options) { var base, bh, bp, bw, h, hp, image, ip, name, ref, ref1, ref2, w, wp; if (options == null) { options = {}; } if (typeof x === 'object') { options = x; x = null; } x = (ref = x != null ? x : options.x) != null ? ref : this.x; y = (ref1 = y != null ? y : options.y) != null ? ref1 : this.y; if (!Buffer.isBuffer(src)) { image = this._imageRegistry[src]; } if (!image) { image = PDFImage.open(src, 'I' + (++this._imageCount)); image.embed(this); if (!Buffer.isBuffer(src)) { this._imageRegistry[src] = image; } } if ((base = this.page.xobjects)[name = image.label] == null) { base[name] = image.obj; } w = options.width || image.width; h = options.height || image.height; if (options.width && !options.height) { wp = w / image.width; w = image.width * wp; h = image.height * wp; } else if (options.height && !options.width) { hp = h / image.height; w = image.width * hp; h = image.height * hp; } else if (options.scale) { w = image.width * options.scale; h = image.height * options.scale; } else if (options.fit) { ref2 = options.fit, bw = ref2[0], bh = ref2[1]; bp = bw / bh; ip = image.width / image.height; if (ip > bp) { w = bw; h = bw / ip; } else { h = bh; w = bh * ip; } if (options.align === 'center') { x = x + bw / 2 - w / 2; } else if (options.align === 'right') { x = x + bw - w; } if (options.valign === 'center') { y = y + bh / 2 - h / 2; } else if (options.valign === 'bottom') { y = y + bh - h; } } if (this.y === y) { this.y += h; } this.save(); this.transform(w, 0, 0, -h, x, y + h); this.addContent("/" + image.label + " Do"); this.restore(); return this; }
n/a
initImages = function () { this._imageRegistry = {}; return this._imageCount = 0; }
n/a
function JPEG(data, label) { var channels, marker, pos; this.data = data; this.label = label; if (this.data.readUInt16BE(0) !== 0xFFD8) { throw "SOI not found in JPEG"; } pos = 2; while (pos < this.data.length) { marker = this.data.readUInt16BE(pos); pos += 2; if (indexOf.call(MARKERS, marker) >= 0) { break; } pos += this.data.readUInt16BE(pos); } if (indexOf.call(MARKERS, marker) < 0) { throw "Invalid JPEG."; } pos += 2; this.bits = this.data[pos++]; this.height = this.data.readUInt16BE(pos); pos += 2; this.width = this.data.readUInt16BE(pos); pos += 2; channels = this.data[pos++]; this.colorSpace = (function() { switch (channels) { case 1: return 'DeviceGray'; case 3: return 'DeviceRGB'; case 4: return 'DeviceCMYK'; } })(); this.obj = null; }
n/a
embed = function (document) { if (this.obj) { return; } this.obj = document.ref({ Type: 'XObject', Subtype: 'Image', BitsPerComponent: this.bits, Width: this.width, Height: this.height, ColorSpace: this.colorSpace, Filter: 'DCTDecode' }); if (this.colorSpace === 'DeviceCMYK') { this.obj.data['Decode'] = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0]; } this.obj.end(this.data); return this.data = null; }
...
return this.dictionary != null ? this.dictionary : this.dictionary = this.document.ref();
};
PDFFont.prototype.finalize = function() {
if (this.embedded || (this.dictionary == null)) {
return;
}
this.embed();
return this.embedded = true;
};
PDFFont.prototype.embed = function() {
throw new Error('Must be implemented by subclasses');
};
...
function LineWrapper(document, options) { var ref; this.document = document; this.indent = options.indent || 0; this.characterSpacing = options.characterSpacing || 0; this.wordSpacing = options.wordSpacing === 0; this.columns = options.columns || 1; this.columnGap = (ref = options.columnGap) != null ? ref : 18; this.lineWidth = (options.width - (this.columnGap * (this.columns - 1))) / this.columns; this.spaceLeft = this.lineWidth; this.startX = this.document.x; this.startY = this.document.y; this.column = 1; this.ellipsis = options.ellipsis; this.continuedX = 0; this.features = options.features; if (options.height != null) { this.height = options.height; this.maxY = this.startY + options.height; } else { this.maxY = this.document.page.maxY(); } this.on('firstLine', (function(_this) { return function(options) { var indent; indent = _this.continuedX || _this.indent; _this.document.x += indent; _this.lineWidth -= indent; return _this.once('line', function() { _this.document.x -= indent; _this.lineWidth += indent; if (options.continued && !_this.continuedX) { _this.continuedX = _this.indent; } if (!options.continued) { return _this.continuedX = 0; } }); }; })(this)); this.on('lastLine', (function(_this) { return function(options) { var align; align = options.align; if (align === 'justify') { options.align = 'left'; } _this.lastLine = true; return _this.once('line', function() { _this.document.y += options.paragraphGap || 0; options.align = align; return _this.lastLine = false; }); }; })(this)); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
init = function () { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. domain = domain || require('domain'); if (domain.active && !(this instanceof domain.Domain)) { this.domain = domain.active; } } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { this._events = new EventHandlers(); this._eventsCount = 0; } this._maxListeners = this._maxListeners || undefined; }
n/a
listenerCount = function (emitter, type) { if (typeof emitter.listenerCount === 'function') { return emitter.listenerCount(type); } else { return listenerCount.call(emitter, type); } }
n/a
function LineWrapper(document, options) { var ref; this.document = document; this.indent = options.indent || 0; this.characterSpacing = options.characterSpacing || 0; this.wordSpacing = options.wordSpacing === 0; this.columns = options.columns || 1; this.columnGap = (ref = options.columnGap) != null ? ref : 18; this.lineWidth = (options.width - (this.columnGap * (this.columns - 1))) / this.columns; this.spaceLeft = this.lineWidth; this.startX = this.document.x; this.startY = this.document.y; this.column = 1; this.ellipsis = options.ellipsis; this.continuedX = 0; this.features = options.features; if (options.height != null) { this.height = options.height; this.maxY = this.startY + options.height; } else { this.maxY = this.document.page.maxY(); } this.on('firstLine', (function(_this) { return function(options) { var indent; indent = _this.continuedX || _this.indent; _this.document.x += indent; _this.lineWidth -= indent; return _this.once('line', function() { _this.document.x -= indent; _this.lineWidth += indent; if (options.continued && !_this.continuedX) { _this.continuedX = _this.indent; } if (!options.continued) { return _this.continuedX = 0; } }); }; })(this)); this.on('lastLine', (function(_this) { return function(options) { var align; align = options.align; if (align === 'justify') { options.align = 'left'; } _this.lastLine = true; return _this.once('line', function() { _this.document.y += options.paragraphGap || 0; options.align = align; return _this.lastLine = false; }); }; })(this)); }
n/a
eachWord = function (text, fn) { var bk, breaker, fbk, l, last, lbk, shouldContinue, w, word, wordWidths; breaker = new LineBreaker(text); last = null; wordWidths = Object.create(null); while (bk = breaker.nextBreak()) { word = text.slice((last != null ? last.position : void 0) || 0, bk.position); w = wordWidths[word] != null ? wordWidths[word] : wordWidths[word] = this.wordWidth(word); if (w > this.lineWidth + this.continuedX) { lbk = last; fbk = {}; while (word.length) { l = word.length; while (w > this.spaceLeft) { w = this.wordWidth(word.slice(0, --l)); } fbk.required = l < word.length; shouldContinue = fn(word.slice(0, l), w, fbk, lbk); lbk = { required: false }; word = word.slice(l); w = this.wordWidth(word); if (shouldContinue === false) { break; } } } else { shouldContinue = fn(word, w, bk, last); } if (shouldContinue === false) { break; } last = bk; } }
...
options.lineWidth = _this.lineWidth;
y = _this.document.y;
_this.emit('line', buffer, options, _this);
return lc++;
};
})(this);
this.emit('sectionStart', options, this);
this.eachWord(text, (function(_this) {
return function(word, w, bk, last) {
var lh, shouldContinue;
if ((last == null) || last.required) {
_this.emit('firstLine', options, _this);
_this.spaceLeft = _this.lineWidth;
}
if (w <= _this.spaceLeft) {
...
nextSection = function (options) { var ref; this.emit('sectionEnd', options, this); if (++this.column > this.columns) { if (this.height != null) { return false; } this.document.addPage(); this.column = 1; this.startY = this.document.page.margins.top; this.maxY = this.document.page.maxY(); this.document.x = this.startX; if (this.document._fillColor) { (ref = this.document).fillColor.apply(ref, this.document._fillColor); } this.emit('pageBreak', options, this); } else { this.document.x += this.lineWidth + this.columnGap; this.document.y = this.startY; this.emit('columnBreak', options, this); } this.emit('sectionStart', options, this); return true; }
...
this.wordSpacing = options.wordSpacing;
}
if (options.ellipsis != null) {
this.ellipsis = options.ellipsis;
}
nextY = this.document.y + this.document.currentLineHeight(true);
if (this.document.y > this.maxY || nextY > this.maxY) {
this.nextSection();
}
buffer = '';
textWidth = 0;
wc = 0;
lc = 0;
y = this.document.y;
emitLine = (function(_this) {
...
wordWidth = function (word) { return this.document.widthOfString(word, this) + this.characterSpacing + this.wordSpacing; }
...
LineWrapper.prototype.eachWord = function(text, fn) {
var bk, breaker, fbk, l, last, lbk, shouldContinue, w, word, wordWidths;
breaker = new LineBreaker(text);
last = null;
wordWidths = Object.create(null);
while (bk = breaker.nextBreak()) {
word = text.slice((last != null ? last.position : void 0) || 0, bk.position);
w = wordWidths[word] != null ? wordWidths[word] : wordWidths[word] = this.wordWidth(
word);
if (w > this.lineWidth + this.continuedX) {
lbk = last;
fbk = {};
while (word.length) {
l = word.length;
while (w > this.spaceLeft) {
w = this.wordWidth(word.slice(0, --l));
...
wrap = function (text, options) { var buffer, emitLine, lc, nextY, textWidth, wc, y; if (options.indent != null) { this.indent = options.indent; } if (options.characterSpacing != null) { this.characterSpacing = options.characterSpacing; } if (options.wordSpacing != null) { this.wordSpacing = options.wordSpacing; } if (options.ellipsis != null) { this.ellipsis = options.ellipsis; } nextY = this.document.y + this.document.currentLineHeight(true); if (this.document.y > this.maxY || nextY > this.maxY) { this.nextSection(); } buffer = ''; textWidth = 0; wc = 0; lc = 0; y = this.document.y; emitLine = (function(_this) { return function() { options.textWidth = textWidth + _this.wordSpacing * (wc - 1); options.wordCount = wc; options.lineWidth = _this.lineWidth; y = _this.document.y; _this.emit('line', buffer, options, _this); return lc++; }; })(this); this.emit('sectionStart', options, this); this.eachWord(text, (function(_this) { return function(word, w, bk, last) { var lh, shouldContinue; if ((last == null) || last.required) { _this.emit('firstLine', options, _this); _this.spaceLeft = _this.lineWidth; } if (w <= _this.spaceLeft) { buffer += word; textWidth += w; wc++; } if (bk.required || w > _this.spaceLeft) { if (bk.required) { _this.emit('lastLine', options, _this); } lh = _this.document.currentLineHeight(true); if ((_this.height != null) && _this.ellipsis && _this.document.y + lh * 2 > _this.maxY && _this.column >= _this.columns) { if (_this.ellipsis === true) { _this.ellipsis = '…'; } buffer = buffer.replace(/\s+$/, ''); textWidth = _this.wordWidth(buffer + _this.ellipsis); while (textWidth > _this.lineWidth) { buffer = buffer.slice(0, -1).replace(/\s+$/, ''); textWidth = _this.wordWidth(buffer + _this.ellipsis); } buffer = buffer + _this.ellipsis; } emitLine(); if (_this.document.y + lh > _this.maxY) { shouldContinue = _this.nextSection(); if (!shouldContinue) { wc = 0; buffer = ''; return false; } } if (bk.required) { if (w > _this.spaceLeft) { buffer = word; textWidth = w; wc = 1; emitLine(); } _this.spaceLeft = _this.lineWidth; buffer = ''; textWidth = 0; return wc = 0; } else { _this.spaceLeft = _this.lineWidth - w; buffer = word; textWidth = w; return wc = 1; } } else { return _this.spaceLeft -= w; } }; })(this)); if (wc > 0) { this.emit('lastLine', options, this); emitLine(); } this.emit('sectionEnd', options, this); if (options.continued === true) { if (lc > 1) { this.continuedX = 0; } this.continuedX += options.textWidth; return this.document.y = y; } else { return this.document.x = this.startX; } }
...
wrapper = this._wrapper;
if (!wrapper) {
wrapper = new LineWrapper(this, options);
wrapper.on('line', lineCallback);
}
this._wrapper = options.continued ? wrapper : null;
this._textOptions = options.continued ? options : null;
wrapper.wrap(text, options);
} else {
ref = text.split('\n');
for (j = 0, len = ref.length; j < len; j++) {
line = ref[j];
lineCallback(line, options);
}
}
...
function PDFObject() {}
n/a
convert = function (object) { var e, i, isUnicode, items, j, key, out, ref, string, val; if (typeof object === 'string') { return '/' + object; } else if (object instanceof String) { string = object.replace(escapableRe, function(c) { return escapable[c]; }); isUnicode = false; for (i = j = 0, ref = string.length; j < ref; i = j += 1) { if (string.charCodeAt(i) > 0x7f) { isUnicode = true; break; } } if (isUnicode) { string = swapBytes(new Buffer('\ufeff' + string, 'utf16le')).toString('binary'); } return '(' + string + ')'; } else if (Buffer.isBuffer(object)) { return '<' + object.toString('hex') + '>'; } else if (object instanceof PDFReference) { return object.toString(); } else if (object instanceof Date) { return '(D:' + pad(object.getUTCFullYear(), 4) + pad(object.getUTCMonth() + 1, 2) + pad(object.getUTCDate(), 2) + pad(object .getUTCHours(), 2) + pad(object.getUTCMinutes(), 2) + pad(object.getUTCSeconds(), 2) + 'Z)'; } else if (Array.isArray(object)) { items = ((function() { var k, len, results; results = []; for (k = 0, len = object.length; k < len; k++) { e = object[k]; results.push(PDFObject.convert(e)); } return results; })()).join(' '); return '[' + items + ']'; } else if ({}.toString.call(object) === '[object Object]') { out = ['<<']; for (key in object) { val = object[key]; out.push('/' + key + ' ' + PDFObject.convert(val)); } out.push('>>'); return out.join('\n'); } else { return '' + object; } }
...
return '(D:' + pad(object.getUTCFullYear(), 4) + pad(object.getUTCMonth() + 1, 2) + pad(object.getUTCDate(), 2) + pad
(object.getUTCHours(), 2) + pad(object.getUTCMinutes(), 2) + pad(object.getUTCSeconds(), 2) + 'Z)';
} else if (Array.isArray(object)) {
items = ((function() {
var k, len, results;
results = [];
for (k = 0, len = object.length; k < len; k++) {
e = object[k];
results.push(PDFObject.convert(e));
}
return results;
})()).join(' ');
return '[' + items + ']';
} else if ({}.toString.call(object) === '[object Object]') {
out = ['<<'];
for (key in object) {
...
function PDFPage(document, options) { var dimensions; this.document = document; if (options == null) { options = {}; } this.size = options.size || 'letter'; this.layout = options.layout || 'portrait'; if (typeof options.margin === 'number') { this.margins = { top: options.margin, left: options.margin, bottom: options.margin, right: options.margin }; } else { this.margins = options.margins || DEFAULT_MARGINS; } dimensions = Array.isArray(this.size) ? this.size : SIZES[this.size.toUpperCase()]; this.width = dimensions[this.layout === 'portrait' ? 0 : 1]; this.height = dimensions[this.layout === 'portrait' ? 1 : 0]; this.content = this.document.ref(); this.resources = this.document.ref({ ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'] }); Object.defineProperties(this, { fonts: { get: (function(_this) { return function() { var base; return (base = _this.resources.data).Font != null ? base.Font : base.Font = {}; }; })(this) }, xobjects: { get: (function(_this) { return function() { var base; return (base = _this.resources.data).XObject != null ? base.XObject : base.XObject = {}; }; })(this) }, ext_gstates: { get: (function(_this) { return function() { var base; return (base = _this.resources.data).ExtGState != null ? base.ExtGState : base.ExtGState = {}; }; })(this) }, patterns: { get: (function(_this) { return function() { var base; return (base = _this.resources.data).Pattern != null ? base.Pattern : base.Pattern = {}; }; })(this) }, annotations: { get: (function(_this) { return function() { var base; return (base = _this.dictionary.data).Annots != null ? base.Annots : base.Annots = []; }; })(this) } }); this.dictionary = this.document.ref({ Type: 'Page', Parent: this.document._root.data.Pages, MediaBox: [0, 0, this.width, this.height], Contents: this.content, Resources: this.resources }); }
n/a
end = function () { this.dictionary.end(); this.resources.end(); return this.content.end(); }
...
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
...
maxY = function () { return this.height - this.margins.bottom; }
...
this.ellipsis = options.ellipsis;
this.continuedX = 0;
this.features = options.features;
if (options.height != null) {
this.height = options.height;
this.maxY = this.startY + options.height;
} else {
this.maxY = this.document.page.maxY();
}
this.on('firstLine', (function(_this) {
return function(options) {
var indent;
indent = _this.continuedX || _this.indent;
_this.document.x += indent;
_this.lineWidth -= indent;
...
write = function (chunk) { return this.content.write(chunk); }
...
}
PDFPage.prototype.maxY = function() {
return this.height - this.margins.bottom;
};
PDFPage.prototype.write = function(chunk) {
return this.content.write(chunk);
};
PDFPage.prototype.end = function() {
this.dictionary.end();
this.resources.end();
return this.content.end();
};
...
function SVGPath() {}
...
.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)
...
apply = function (doc, path) { var commands; commands = parse(path); return apply(commands, doc); }
...
function PDFLinearGradient(doc, x1, y1, x2, y2) {
this.doc = doc;
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
PDFLinearGradient.__super__.constructor.apply(this, arguments);
}
PDFLinearGradient.prototype.shader = function(fn) {
return this.doc.ref({
ShadingType: 2,
ColorSpace: this._colorSpace,
Coords: [this.x1, this.y1, this.x2, this.y2],
...
function PNGImage(data, label) { this.label = label; this.image = new PNG(data); this.width = this.image.width; this.height = this.image.height; this.imgData = this.image.imgData; this.obj = null; }
n/a
embed = function (document) { var k, len1, mask, palette, params, rgb, val, x; this.document = document; if (this.obj) { return; } this.obj = this.document.ref({ Type: 'XObject', Subtype: 'Image', BitsPerComponent: this.image.bits, Width: this.width, Height: this.height, Filter: 'FlateDecode' }); if (!this.image.hasAlphaChannel) { params = this.document.ref({ Predictor: 15, Colors: this.image.colors, BitsPerComponent: this.image.bits, Columns: this.width }); this.obj.data['DecodeParms'] = params; params.end(); } if (this.image.palette.length === 0) { this.obj.data['ColorSpace'] = this.image.colorSpace; } else { palette = this.document.ref(); palette.end(new Buffer(this.image.palette)); this.obj.data['ColorSpace'] = ['Indexed', 'DeviceRGB', (this.image.palette.length / 3) - 1, palette]; } if (this.image.transparency.grayscale) { val = this.image.transparency.greyscale; return this.obj.data['Mask'] = [val, val]; } else if (this.image.transparency.rgb) { rgb = this.image.transparency.rgb; mask = []; for (k = 0, len1 = rgb.length; k < len1; k++) { x = rgb[k]; mask.push(x, x); } return this.obj.data['Mask'] = mask; } else if (this.image.transparency.indexed) { return this.loadIndexedAlphaChannel(); } else if (this.image.hasAlphaChannel) { return this.splitAlphaChannel(); } else { return this.finalize(); } }
...
return this.dictionary != null ? this.dictionary : this.dictionary = this.document.ref();
};
PDFFont.prototype.finalize = function() {
if (this.embedded || (this.dictionary == null)) {
return;
}
this.embed();
return this.embedded = true;
};
PDFFont.prototype.embed = function() {
throw new Error('Must be implemented by subclasses');
};
...
finalize = function () { var sMask; if (this.alphaChannel) { sMask = this.document.ref({ Type: 'XObject', Subtype: 'Image', Height: this.height, Width: this.width, BitsPerComponent: 8, Filter: 'FlateDecode', ColorSpace: 'DeviceGray', Decode: [0, 1] }); sMask.end(this.alphaChannel); this.obj.data['SMask'] = sMask; } this.obj.end(this.imgData); this.image = null; return this.imgData = null; }
...
};
PDFReference.prototype.end = function(chunk) {
PDFReference.__super__.end.apply(this, arguments);
if (this.deflate) {
return this.deflate.end();
} else {
return this.finalize();
}
};
PDFReference.prototype.finalize = function() {
var chunk, i, len, ref;
this.offset = this.document._offset;
this.document._write(this.id + " " + this.gen + " obj");
...
loadIndexedAlphaChannel = function (fn) { var transparency; transparency = this.image.transparency.indexed; return this.image.decodePixels((function(_this) { return function(pixels) { var alphaChannel, i, j, k, ref; alphaChannel = new Buffer(_this.width * _this.height); i = 0; for (j = k = 0, ref = pixels.length; k < ref; j = k += 1) { alphaChannel[i++] = transparency[pixels[j]]; } return zlib.deflate(alphaChannel, function(err, alphaChannel1) { _this.alphaChannel = alphaChannel1; if (err) { throw err; } return _this.finalize(); }); }; })(this)); }
...
mask = [];
for (k = 0, len1 = rgb.length; k < len1; k++) {
x = rgb[k];
mask.push(x, x);
}
return this.obj.data['Mask'] = mask;
} else if (this.image.transparency.indexed) {
return this.loadIndexedAlphaChannel();
} else if (this.image.hasAlphaChannel) {
return this.splitAlphaChannel();
} else {
return this.finalize();
}
};
...
splitAlphaChannel = function () { return this.image.decodePixels((function(_this) { return function(pixels) { var a, alphaChannel, colorByteSize, done, i, imgData, len, p, pixelCount; colorByteSize = _this.image.colors * _this.image.bits / 8; pixelCount = _this.width * _this.height; imgData = new Buffer(pixelCount * colorByteSize); alphaChannel = new Buffer(pixelCount); i = p = a = 0; len = pixels.length; while (i < len) { imgData[p++] = pixels[i++]; imgData[p++] = pixels[i++]; imgData[p++] = pixels[i++]; alphaChannel[a++] = pixels[i++]; } done = 0; zlib.deflate(imgData, function(err, imgData1) { _this.imgData = imgData1; if (err) { throw err; } if (++done === 2) { return _this.finalize(); } }); return zlib.deflate(alphaChannel, function(err, alphaChannel1) { _this.alphaChannel = alphaChannel1; if (err) { throw err; } if (++done === 2) { return _this.finalize(); } }); }; })(this)); }
...
x = rgb[k];
mask.push(x, x);
}
return this.obj.data['Mask'] = mask;
} else if (this.image.transparency.indexed) {
return this.loadIndexedAlphaChannel();
} else if (this.image.hasAlphaChannel) {
return this.splitAlphaChannel();
} else {
return this.finalize();
}
};
PNGImage.prototype.finalize = function() {
var sMask;
...
function PDFReference(document, id, data) { this.document = document; this.id = id; this.data = data != null ? data : {}; this.finalize = bind(this.finalize, this); PDFReference.__super__.constructor.call(this, { decodeStrings: false }); this.gen = 0; this.deflate = null; this.compress = this.document.compress && !this.data.Filter; this.uncompressedLength = 0; this.chunks = []; }
n/a
function WritableState(options, stream) { options = options || {}; // object stream flag to indicate whether or not this stream // contains buffers or objects. this.objectMode = !!options.objectMode; if (stream instanceof Stream.Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode; // the point at which write() starts returning false // Note: 0 is a valid value, means that we always return false if // the entire buffer is not flushed immediately on write() var hwm = options.highWaterMark; var defaultHwm = this.objectMode ? 16 : 16 * 1024; this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm; // cast to ints. this.highWaterMark = ~~this.highWaterMark; // drain event flag. this.needDrain = false; // at the start of calling end() this.ending = false; // when end() has been called, and returned this.ended = false; // when 'finish' is emitted this.finished = false; // should we decode strings into buffers before passing to _write? // this is here so that some node-core streams can optimize string // handling at a lower level. var noDecode = options.decodeStrings === false; this.decodeStrings = !noDecode; // Crypto is kind of old and crusty. Historically, its default string // encoding is 'binary' so we have to make this configurable. // Everything else in the universe uses 'utf8', though. this.defaultEncoding = options.defaultEncoding || 'utf8'; // not an actual buffer we keep track of, but a measurement // of how much we're waiting to get pushed to some underlying // socket or file. this.length = 0; // a flag to see when we're in the middle of a write. this.writing = false; // when true all writes will be buffered until .uncork() call this.corked = 0; // a flag to be able to tell if the onwrite cb is called immediately, // or on a later tick. We set this to true at first, because any // actions that shouldn't happen until "later" should generally also // not happen before the first write call. this.sync = true; // a flag to know if we're processing previously buffered items, which // may call the _write() callback in the same tick, so that we don't // end up in an overlapped onwrite situation. this.bufferProcessing = false; // the callback that's passed to _write(chunk,cb) this.onwrite = function(er) { onwrite(stream, er); }; // the callback that the user supplies to write(chunk,encoding,cb) this.writecb = null; // the amount that is being written when _write is called. this.writelen = 0; this.bufferedRequest = null; this.lastBufferedRequest = null; // number of pending user-supplied write callbacks // this must be 0 before 'finish' can be emitted this.pendingcb = 0; // emit prefinish if the only thing we're waiting for is _write cbs // This is relevant for synchronous Transform streams this.prefinished = false; // True if the error was already emitted and should not be thrown again this.errorEmitted = false; // count buffered requests this.bufferedRequestCount = 0; // allocate the first CorkedRequest, there is always // one allocated and free to use, and we maintain at most two this.corkedRequestsFree = new CorkedRequest(this); }
n/a
function Stream() { EE.call(this); }
n/a
_write = function (chunk, encoding, callback) { var base; if (!Buffer.isBuffer(chunk)) { chunk = new Buffer(chunk + '\n', 'binary'); } this.uncompressedLength += chunk.length; if ((base = this.data).Length == null) { base.Length = 0; } if (this.compress) { if (!this.deflate) { this.initDeflate(); } this.deflate.write(chunk); } else { this.chunks.push(chunk); this.data.Length += chunk.length; } return callback(); }
...
return this.finalize();
}
};
PDFReference.prototype.finalize = function() {
var chunk, i, len, ref;
this.offset = this.document._offset;
this.document._write(this.id + " " + this.gen + " obj");
this.document._write(PDFObject.convert(this.data));
if (this.chunks.length) {
this.document._write('stream');
ref = this.chunks;
for (i = 0, len = ref.length; i < len; i++) {
chunk = ref[i];
this.document._write(chunk);
...
function PDFReference(document, id, data) { this.document = document; this.id = id; this.data = data != null ? data : {}; this.finalize = bind(this.finalize, this); PDFReference.__super__.constructor.call(this, { decodeStrings: false }); this.gen = 0; this.deflate = null; this.compress = this.document.compress && !this.data.Filter; this.uncompressedLength = 0; this.chunks = []; }
n/a
end = function (chunk) { PDFReference.__super__.end.apply(this, arguments); if (this.deflate) { return this.deflate.end(); } else { return this.finalize(); } }
...
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
...
finalize = function () { var chunk, i, len, ref; this.offset = this.document._offset; this.document._write(this.id + " " + this.gen + " obj"); this.document._write(PDFObject.convert(this.data)); if (this.chunks.length) { this.document._write('stream'); ref = this.chunks; for (i = 0, len = ref.length; i < len; i++) { chunk = ref[i]; this.document._write(chunk); } this.chunks.length = 0; this.document._write('\nendstream'); } this.document._write('endobj'); return this.document._refEnd(this); }
...
};
PDFReference.prototype.end = function(chunk) {
PDFReference.__super__.end.apply(this, arguments);
if (this.deflate) {
return this.deflate.end();
} else {
return this.finalize();
}
};
PDFReference.prototype.finalize = function() {
var chunk, i, len, ref;
this.offset = this.document._offset;
this.document._write(this.id + " " + this.gen + " obj");
...
initDeflate = function () { this.data.Filter = 'FlateDecode'; this.deflate = zlib.createDeflate(); this.deflate.on('data', (function(_this) { return function(chunk) { _this.chunks.push(chunk); return _this.data.Length += chunk.length; }; })(this)); return this.deflate.on('end', this.finalize); }
...
}
this.uncompressedLength += chunk.length;
if ((base = this.data).Length == null) {
base.Length = 0;
}
if (this.compress) {
if (!this.deflate) {
this.initDeflate();
}
this.deflate.write(chunk);
} else {
this.chunks.push(chunk);
this.data.Length += chunk.length;
}
return callback();
...
toString = function () { return this.id + " " + this.gen + " R"; }
...
if (!data) {
return;
}
}
}
if (data[0] === 0xff && data[1] === 0xd8) {
return new JPEG(data, label);
} else if (data[0] === 0x89 && data.toString('ascii', 1, 4) ===
x27;PNG') {
return new PNG(data, label);
} else {
throw new Error('Unknown image format.');
}
};
return PDFImage;
...
function StandardFont(document, name1, id) { var ref; this.document = document; this.name = name1; this.id = id; this.font = new AFMFont(STANDARD_FONTS[this.name]()); ref = this.font, this.ascender = ref.ascender, this.descender = ref.descender, this.bbox = ref.bbox, this.lineGap = ref.lineGap ; }
n/a
isStandardFont = function (name) { return name in STANDARD_FONTS; }
...
fontkit = require('fontkit');
PDFFont = (function() {
PDFFont.open = function(document, src, family, id) {
var font;
if (typeof src === 'string') {
if (StandardFont.isStandardFont(src)) {
return new StandardFont(document, src, id);
}
font = fontkit.openSync(src, family);
} else if (Buffer.isBuffer(src)) {
font = fontkit.create(src, family);
} else if (src instanceof Uint8Array) {
font = fontkit.create(new Buffer(src), family);
...
open = function (document, src, family, id) { var font; if (typeof src === 'string') { if (StandardFont.isStandardFont(src)) { return new StandardFont(document, src, id); } font = fontkit.openSync(src, family); } else if (Buffer.isBuffer(src)) { font = fontkit.create(src, family); } else if (src instanceof Uint8Array) { font = fontkit.create(new Buffer(src), family); } else if (src instanceof ArrayBuffer) { font = fontkit.create(new Buffer(new Uint8Array(src)), family); } if (font == null) { throw new Error('Not a supported font format or standard PDF font.'); } return new EmbeddedFont(document, font, id); }
...
this.fontSize(size);
}
if (font = this._fontFamilies[cacheKey]) {
this._font = font;
return this;
}
id = 'F' + (++this._fontCount);
this._font = PDFFont.open(this, src, family, id);
if (font = this._fontFamilies[this._font.name]) {
this._font = font;
return this;
}
if (cacheKey) {
this._fontFamilies[cacheKey] = this._font;
}
...
function StandardFont(document, name1, id) { var ref; this.document = document; this.name = name1; this.id = id; this.font = new AFMFont(STANDARD_FONTS[this.name]()); ref = this.font, this.ascender = ref.ascender, this.descender = ref.descender, this.bbox = ref.bbox, this.lineGap = ref.lineGap ; }
n/a
embed = function () { this.dictionary.data = { Type: 'Font', BaseFont: this.name, Subtype: 'Type1', Encoding: 'WinAnsiEncoding' }; return this.dictionary.end(); }
...
return this.dictionary != null ? this.dictionary : this.dictionary = this.document.ref();
};
PDFFont.prototype.finalize = function() {
if (this.embedded || (this.dictionary == null)) {
return;
}
this.embed();
return this.embedded = true;
};
PDFFont.prototype.embed = function() {
throw new Error('Must be implemented by subclasses');
};
...
encode = function (text) { var advances, encoded, glyph, glyphs, i, j, len, positions; encoded = this.font.encodeText(text); glyphs = this.font.glyphsForString('' + text); advances = this.font.advancesForGlyphs(glyphs); positions = []; for (i = j = 0, len = glyphs.length; j < len; i = ++j) { glyph = glyphs[i]; positions.push({ xAdvance: advances[i], yAdvance: 0, xOffset: 0, yOffset: 0, advanceWidth: this.font.widthOfGlyph(glyph) }); } return [encoded, positions]; }
...
words = text.trim().split(/\s+/);
wordSpacing += this.widthOfString(' ') + characterSpacing;
wordSpacing *= 1000 / this._fontSize;
encoded = [];
positions = [];
for (j = 0, len = words.length; j < len; j++) {
word = words[j];
ref = this._font.encode(word, options.features), encodedWord = ref[0], positionsWord
= ref[1];
encoded.push.apply(encoded, encodedWord);
positions.push.apply(positions, positionsWord);
positions[positions.length - 1].xAdvance += wordSpacing;
}
} else {
ref1 = this._font.encode(text, options.features), encoded = ref1[0], positions = ref1[1];
}
...
widthOfString = function (string, size) { var advance, advances, glyphs, j, len, scale, width; glyphs = this.font.glyphsForString('' + string); advances = this.font.advancesForGlyphs(glyphs); width = 0; for (j = 0, len = advances.length; j < len; j++) { advance = advances[j]; width += advance; } scale = size / 1000; return width * scale; }
...
return _this.lastLine = false;
});
};
})(this));
}
LineWrapper.prototype.wordWidth = function(word) {
return this.document.widthOfString(word, this) + this.characterSpacing + this.wordSpacing
;
};
LineWrapper.prototype.eachWord = function(text, fn) {
var bk, breaker, fbk, l, last, lbk, shouldContinue, w, word, wordWidths;
breaker = new LineBreaker(text);
last = null;
wordWidths = Object.create(null);
...
text = function (text, x, y, options) { return this._text(text, x, y, options, this._line.bind(this)); }
...
# Pipe its 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
...
_fragment = function (text, x, y, options) { var addSegment, align, base, characterSpacing, commands, d, encoded, encodedWord, flush, hadOffset, i, j, last, len, len1, lineWidth , lineY, m, mode, name, pos, positions, positionsWord, ref, ref1, renderedWidth, scale, spaceWidth, textWidth, word, wordSpacing , words; text = ('' + text).replace(/\n/g, ''); if (text.length === 0) { return; } align = options.align || 'left'; wordSpacing = options.wordSpacing || 0; characterSpacing = options.characterSpacing || 0; if (options.width) { switch (align) { case 'right': textWidth = this.widthOfString(text.replace(/\s+$/, ''), options); x += options.lineWidth - textWidth; break; case 'center': x += options.lineWidth / 2 - options.textWidth / 2; break; case 'justify': words = text.trim().split(/\s+/); textWidth = this.widthOfString(text.replace(/\s+/g, ''), options); spaceWidth = this.widthOfString(' ') + characterSpacing; wordSpacing = Math.max(0, (options.lineWidth - textWidth) / Math.max(1, words.length - 1) - spaceWidth); } } renderedWidth = options.textWidth + (wordSpacing * (options.wordCount - 1)) + (characterSpacing * (text.length - 1)); if (options.link) { this.link(x, y, renderedWidth, this.currentLineHeight(), options.link); } if (options.underline || options.strike) { this.save(); if (!options.stroke) { this.strokeColor.apply(this, this._fillColor); } lineWidth = this._fontSize < 10 ? 0.5 : Math.floor(this._fontSize / 10); this.lineWidth(lineWidth); d = options.underline ? 1 : 2; lineY = y + this.currentLineHeight() / d; if (options.underline) { lineY -= lineWidth; } this.moveTo(x, lineY); this.lineTo(x + renderedWidth, lineY); this.stroke(); this.restore(); } this.save(); this.transform(1, 0, 0, -1, 0, this.page.height); y = this.page.height - y - (this._font.ascender / 1000 * this._fontSize); if ((base = this.page.fonts)[name = this._font.id] == null) { base[name] = this._font.ref(); } this.addContent("BT"); this.addContent("1 0 0 1 " + x + " " + y + " Tm"); this.addContent("/" + this._font.id + " " + this._fontSize + " Tf"); mode = options.fill && options.stroke ? 2 : options.stroke ? 1 : 0; if (mode) { this.addContent(mode + " Tr"); } if (characterSpacing) { this.addContent(characterSpacing + " Tc"); } if (wordSpacing) { words = text.trim().split(/\s+/); wordSpacing += this.widthOfString(' ') + characterSpacing; wordSpacing *= 1000 / this._fontSize; encoded = []; positions = []; for (j = 0, len = words.length; j < len; j++) { word = words[j]; ref = this._font.encode(word, options.features), encodedWord = ref[0], positionsWord = ref[1]; encoded.push.apply(encoded, encodedWord); positions.push.apply(positions, positionsWord); positions[positions.length - 1].xAdvance += wordSpacing; } } else { ref1 = this._font.encode(text, options.features), encoded = ref1[0], positions = ref1[1]; } scale = this._fontSize / 1000; commands = []; last = 0; hadOffset = false; addSegment = (function(_this) { return function(cur) { var advance, hex; if (last < cur) { hex = encoded.slice(last, cur).join(''); advance = positions[cur - 1].xAdvance - positions[cur - 1].advanceWidth; commands.push("<" + hex + "> " + (-advance)); } return last = cur; }; })(this); flush = (function(_this) { return function(i) { addSegment(i); if (commands.length > 0) { _this.addContent("[" + (commands.join(' ')) + "] TJ"); return commands.length = 0; } }; })(this); for (i = m = 0, len1 = positions.length; m < len1; i = ++m) { pos = positions[i]; if (pos.xOffset || pos.yOffset) { flush(i); this.addContent("1 0 0 1 " + (x + pos.xOffset * scale) + " " + (y + pos.yOffset * scale) + " Tm"); flush(i + 1); hadOffset = true; } else { ...
...
return options;
},
_line: function(text, options, wrapper) {
var lineGap;
if (options == null) {
options = {};
}
this._fragment(text, this.x, this.y, options);
lineGap = options.lineGap || this._lineGap || 0;
if (!wrapper) {
return this.x += this.widthOfString(text);
} else {
return this.y += this.currentLineHeight(true) + lineGap;
}
},
...
_initOptions = function (x, y, options) { var key, margins, ref, val; if (x == null) { x = {}; } if (options == null) { options = {}; } if (typeof x === 'object') { options = x; x = null; } options = (function() { var k, opts, v; opts = {}; for (k in options) { v = options[k]; opts[k] = v; } return opts; })(); if (this._textOptions) { ref = this._textOptions; for (key in ref) { val = ref[key]; if (key !== 'continued') { if (options[key] == null) { options[key] = val; } } } } if (x != null) { this.x = x; } if (y != null) { this.y = y; } if (options.lineBreak !== false) { margins = this.page.margins; if (options.width == null) { options.width = this.page.width - this.x - margins.right; } } options.columns || (options.columns = 0); if (options.columnGap == null) { options.columnGap = 18; } return options; }
...
lines = 1;
}
this.y -= this.currentLineHeight(true) * lines + this._lineGap;
return this;
},
_text: function(text, x, y, options, lineCallback) {
var j, len, line, ref, wrapper;
options = this._initOptions(x, y, options);
text = '' + text;
if (options.wordSpacing) {
text = text.replace(/\s{2,}/g, ' ');
}
if (options.width) {
wrapper = this._wrapper;
if (!wrapper) {
...
_line = function (text, options, wrapper) { var lineGap; if (options == null) { options = {}; } this._fragment(text, this.x, this.y, options); lineGap = options.lineGap || this._lineGap || 0; if (!wrapper) { return this.x += this.widthOfString(text); } else { return this.y += this.currentLineHeight(true) + lineGap; } }
n/a
_text = function (text, x, y, options, lineCallback) { var j, len, line, ref, wrapper; options = this._initOptions(x, y, options); text = '' + text; if (options.wordSpacing) { text = text.replace(/\s{2,}/g, ' '); } if (options.width) { wrapper = this._wrapper; if (!wrapper) { wrapper = new LineWrapper(this, options); wrapper.on('line', lineCallback); } this._wrapper = options.continued ? wrapper : null; this._textOptions = options.continued ? options : null; wrapper.wrap(text, options); } else { ref = text.split('\n'); for (j = 0, len = ref.length; j < len; j++) { line = ref[j]; lineCallback(line, options); } } return this; }
...
line = ref[j];
lineCallback(line, options);
}
}
return this;
},
text: function(text, x, y, options) {
return this._text(text, x, y, options, this._line.bind(this));
},
widthOfString: function(string, options) {
if (options == null) {
options = {};
}
return this._font.widthOfString(string, this._fontSize, options.features) + (options.characterSpacing || 0) * (string.length -
1);
},
...
heightOfString = function (text, options) { var height, lineGap, x, y; if (options == null) { options = {}; } x = this.x, y = this.y; options = this._initOptions(options); options.height = Infinity; lineGap = options.lineGap || this._lineGap || 0; this._text(text, this.x, this.y, options, (function(_this) { return function(line, options) { return _this.y += _this.currentLineHeight(true) + lineGap; }; })(this)); height = this.y - y; this.x = x; this.y = y; return height; }
n/a
initText = function () { this.x = 0; this.y = 0; return this._lineGap = 0; }
n/a
lineGap = function (_lineGap) { this._lineGap = _lineGap; return this; }
n/a
list = function (list, x, y, options, wrapper) { var flatten, i, indent, itemIndent, items, level, levels, r; options = this._initOptions(x, y, options); r = Math.round((this._font.ascender / 1000 * this._fontSize) / 3); indent = options.textIndent || r * 5; itemIndent = options.bulletIndent || r * 8; level = 1; items = []; levels = []; flatten = function(list) { var i, item, j, len, results; results = []; for (i = j = 0, len = list.length; j < len; i = ++j) { item = list[i]; if (Array.isArray(item)) { level++; flatten(item); results.push(level--); } else { items.push(item); results.push(levels.push(level)); } } return results; }; flatten(list); wrapper = new LineWrapper(this, options); wrapper.on('line', this._line.bind(this)); level = 1; i = 0; wrapper.on('firstLine', (function(_this) { return function() { var diff, l; if ((l = levels[i++]) !== level) { diff = itemIndent * (l - level); _this.x += diff; wrapper.lineWidth -= diff; level = l; } _this.circle(_this.x - indent + r, _this.y + r + (r / 2), r); return _this.fill(); }; })(this)); wrapper.on('sectionStart', (function(_this) { return function() { var pos; pos = indent + itemIndent * (level - 1); _this.x += pos; return wrapper.lineWidth -= pos; }; })(this)); wrapper.on('sectionEnd', (function(_this) { return function() { var pos; pos = indent + itemIndent * (level - 1); _this.x -= pos; return wrapper.lineWidth += pos; }; })(this)); wrapper.wrap(items.join('\n'), options); return this; }
n/a
moveDown = function (lines) { if (lines == null) { lines = 1; } this.y += this.currentLineHeight(true) * lines + this._lineGap; return this; }
n/a
moveUp = function (lines) { if (lines == null) { lines = 1; } this.y -= this.currentLineHeight(true) * lines + this._lineGap; return this; }
n/a
widthOfString = function (string, options) { if (options == null) { options = {}; } return this._font.widthOfString(string, this._fontSize, options.features) + (options.characterSpacing || 0) * (string.length - 1); }
...
return _this.lastLine = false;
});
};
})(this));
}
LineWrapper.prototype.wordWidth = function(word) {
return this.document.widthOfString(word, this) + this.characterSpacing + this.wordSpacing
;
};
LineWrapper.prototype.eachWord = function(text, fn) {
var bk, breaker, fbk, l, last, lbk, shouldContinue, w, word, wordWidths;
breaker = new LineBreaker(text);
last = null;
wordWidths = Object.create(null);
...
_windingRule = function (rule) { if (/even-?odd/.test(rule)) { return '*'; } return ''; }
...
if (/(even-?odd)|(non-?zero)/.test(color)) {
rule = color;
color = null;
}
if (color) {
this.fillColor(color);
}
return this.addContent('f' + this._windingRule(rule));
},
stroke: function(color) {
if (color) {
this.strokeColor(color);
}
return this.addContent('S');
},
...
bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) { return this.addContent(cp1x + " " + cp1y + " " + cp2x + " " + cp2y + " " + x + " " + y + " c"); }
...
cx = a[4];
cy = a[5];
px = a[2];
py = a[3];
return doc.bezierCurveTo.apply(doc, a);
},
c: function(doc, a) {
doc.bezierCurveTo(a[0] + cx, a[1] + cy, a[2] + cx, a[3] + cy, a[4] + cx, a[5] + cy);
px = cx + a[2];
py = cy + a[3];
cx += a[4];
return cy += a[5];
},
S: function(doc, a) {
if (px === null) {
...
circle = function (x, y, radius) { return this.ellipse(x, y, radius); }
...
var diff, l;
if ((l = levels[i++]) !== level) {
diff = itemIndent * (l - level);
_this.x += diff;
wrapper.lineWidth -= diff;
level = l;
}
_this.circle(_this.x - indent + r, _this.y + r + (r / 2), r);
return _this.fill();
};
})(this));
wrapper.on('sectionStart', (function(_this) {
return function() {
var pos;
pos = indent + itemIndent * (level - 1);
...
clip = function (rule) { return this.addContent('W' + this._windingRule(rule) + ' n'); }
n/a
closePath = function () { return this.addContent('h'); }
...
},
v: function(doc, a) {
cy += a[0];
px = py = null;
return doc.lineTo(cx, cy);
},
Z: function(doc) {
doc.closePath();
cx = sx;
return cy = sy;
},
z: function(doc) {
doc.closePath();
cx = sx;
return cy = sy;
...
dash = function (length, options) { var phase, ref, space; if (options == null) { options = {}; } if (length == null) { return this; } space = (ref = options.space) != null ? ref : length; phase = options.phase || 0; return this.addContent("[" + length + " " + space + "] " + phase + " d"); }
n/a
ellipse = function (x, y, r1, r2) { var ox, oy, xe, xm, ye, ym; if (r2 == null) { r2 = r1; } x -= r1; y -= r2; ox = r1 * KAPPA; oy = r2 * KAPPA; xe = x + r1 * 2; ye = y + r2 * 2; xm = x + r1; ym = y + r2; this.moveTo(x, ym); this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); return this.closePath(); }
...
this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
return this.closePath();
},
circle: function(x, y, radius) {
return this.ellipse(x, y, radius);
},
polygon: function() {
var i, len, point, points;
points = 1 <= arguments.length ? slice.call(arguments, 0) : [];
this.moveTo.apply(this, points.shift());
for (i = 0, len = points.length; i < len; i++) {
point = points[i];
...
fill = function (color, rule) { if (/(even-?odd)|(non-?zero)/.test(color)) { rule = color; color = null; } if (color) { this.fillColor(color); } return this.addContent('f' + this._windingRule(rule)); }
...
.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()
...
fillAndStroke = function (fillColor, strokeColor, rule) { var isFillRule; if (strokeColor == null) { strokeColor = fillColor; } isFillRule = /(even-?odd)|(non-?zero)/; if (isFillRule.test(fillColor)) { rule = fillColor; fillColor = null; } if (isFillRule.test(strokeColor)) { rule = strokeColor; strokeColor = fillColor; } if (fillColor) { this.fillColor(fillColor); this.strokeColor(strokeColor); } return this.addContent('B' + this._windingRule(rule)); }
n/a
initVector = function () { this._ctm = [1, 0, 0, 1, 0, 0]; return this._ctmStack = []; }
n/a
lineCap = function (c) { if (typeof c === 'string') { c = this._CAP_STYLES[c.toUpperCase()]; } return this.addContent(c + " J"); }
n/a
lineJoin = function (j) { if (typeof j === 'string') { j = this._JOIN_STYLES[j.toUpperCase()]; } return this.addContent(j + " j"); }
n/a
lineTo = function (x, y) { return this.addContent(x + " " + y + " l"); }
...
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')
...
lineWidth = function (w) { return this.addContent(w + " w"); }
...
}
if (options.underline || options.strike) {
this.save();
if (!options.stroke) {
this.strokeColor.apply(this, this._fillColor);
}
lineWidth = this._fontSize < 10 ? 0.5 : Math.floor(this._fontSize / 10);
this.lineWidth(lineWidth);
d = options.underline ? 1 : 2;
lineY = y + this.currentLineHeight() / d;
if (options.underline) {
lineY -= lineWidth;
}
this.moveTo(x, lineY);
this.lineTo(x + renderedWidth, lineY);
...
miterLimit = function (m) { return this.addContent(m + " M"); }
n/a
moveTo = function (x, y) { return this.addContent(x + " " + y + " m"); }
...
# 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 = function (path) { SVGPath.apply(this, path); return this; }
...
.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)
...
polygon = function () { var i, len, point, points; points = 1 <= arguments.length ? slice.call(arguments, 0) : []; this.moveTo.apply(this, points.shift()); for (i = 0, len = points.length; i < len; i++) { point = points[i]; this.lineTo.apply(this, point); } return this.closePath(); }
n/a
quadraticCurveTo = function (cpx, cpy, x, y) { return this.addContent(cpx + " " + cpy + " " + x + " " + y + " v"); }
...
return cy += a[3];
},
Q: function(doc, a) {
px = a[0];
py = a[1];
cx = a[2];
cy = a[3];
return doc.quadraticCurveTo(a[0], a[1], cx, cy);
},
q: function(doc, a) {
doc.quadraticCurveTo(a[0] + cx, a[1] + cy, a[2] + cx, a[3] + cy);
px = cx + a[0];
py = cy + a[1];
cx += a[2];
return cy += a[3];
...
rect = function (x, y, w, h) { return this.addContent(x + " " + y + " " + w + " " + h + " re"); }
n/a
restore = function () { this._ctm = this._ctmStack.pop() || [1, 0, 0, 1, 0, 0]; return this.addContent('Q'); }
...
.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/')
...
rotate = function (angle, options) { var cos, rad, ref, sin, x, x1, y, y1; if (options == null) { options = {}; } rad = angle * Math.PI / 180; cos = Math.cos(rad); sin = Math.sin(rad); x = y = 0; if (options.origin != null) { ref = options.origin, x = ref[0], y = ref[1]; x1 = x * cos - y * sin; y1 = x * sin + y * cos; x -= x1; y -= y1; } return this.transform(cos, sin, -sin, cos, x, y); }
n/a
roundedRect = function (x, y, w, h, r) { if (r == null) { r = 0; } this.moveTo(x + r, y); this.lineTo(x + w - r, y); this.quadraticCurveTo(x + w, y, x + w, y + r); this.lineTo(x + w, y + h - r); this.quadraticCurveTo(x + w, y + h, x + w - r, y + h); this.lineTo(x + r, y + h); this.quadraticCurveTo(x, y + h, x, y + h - r); this.lineTo(x, y + r); return this.quadraticCurveTo(x, y, x + r, y); }
n/a
save = function () { this._ctmStack.push(this._ctm.slice()); return this.addContent('q'); }
...
# 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)
...
scale = function (xFactor, yFactor, options) { var ref, x, y; if (yFactor == null) { yFactor = xFactor; } if (options == null) { options = {}; } if (arguments.length === 2) { yFactor = xFactor; options = yFactor; } x = y = 0; if (options.origin != null) { ref = options.origin, x = ref[0], y = ref[1]; x -= xFactor * x; y -= yFactor * y; } return this.transform(xFactor, 0, 0, yFactor, x, y); }
...
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()
...
stroke = function (color) { if (color) { this.strokeColor(color); } return this.addContent('S'); }
...
d = options.underline ? 1 : 2;
lineY = y + this.currentLineHeight() / d;
if (options.underline) {
lineY -= lineWidth;
}
this.moveTo(x, lineY);
this.lineTo(x + renderedWidth, lineY);
this.stroke();
this.restore();
}
this.save();
this.transform(1, 0, 0, -1, 0, this.page.height);
y = this.page.height - y - (this._font.ascender / 1000 * this._fontSize);
if ((base = this.page.fonts)[name = this._font.id] == null) {
base[name] = this._font.ref();
...
transform = function (m11, m12, m21, m22, dx, dy) { var m, m0, m1, m2, m3, m4, m5, v, values; m = this._ctm; m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3], m4 = m[4], m5 = m[5]; m[0] = m0 * m11 + m2 * m12; m[1] = m1 * m11 + m3 * m12; m[2] = m0 * m21 + m2 * m22; m[3] = m1 * m21 + m3 * m22; m[4] = m0 * dx + m2 * dy + m4; m[5] = m1 * dx + m3 * dy + m5; values = ((function() { var i, len, ref, results; ref = [m11, m12, m21, m22, dx, dy]; results = []; for (i = 0, len = ref.length; i < len; i++) { v = ref[i]; results.push(+v.toFixed(5)); } return results; })()).join(' '); return this.addContent(values + " cm"); }
...
y = y + bh - h;
}
}
if (this.y === y) {
this.y += h;
}
this.save();
this.transform(w, 0, 0, -h, x, y + h);
this.addContent("/" + image.label + " Do");
this.restore();
return this;
}
};
}).call(this);
...
translate = function (x, y) { return this.transform(1, 0, 0, 1, x, y); }
...
.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")
...
undash = function () { return this.addContent("[] 0 d"); }
n/a