Matthew Butterick 7 years ago
parent 50c4c80817
commit 6a466cda42

@ -0,0 +1,192 @@
// Generated by CoffeeScript 1.12.5
(function() {
var Data;
Data = (function() {
function Data(data) {
this.data = data != null ? data : [];
this.pos = 0;
this.length = this.data.length;
}
Data.prototype.readByte = function() {
return this.data[this.pos++];
};
Data.prototype.writeByte = function(byte) {
return this.data[this.pos++] = byte;
};
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() {
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;
};
Data.prototype.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.readInt32 = function() {
var int;
int = this.readUInt32();
if (int >= 0x80000000) {
return int - 0x100000000;
} else {
return int;
}
};
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;
};
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;
}
};
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());
}
return ret.join('');
};
Data.prototype.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;
};
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() {
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;
};
Data.prototype.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);
};
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) {
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;
};
Data.prototype.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;
};
return Data;
})();
module.exports = Data;
}).call(this);

@ -0,0 +1,75 @@
// Generated by CoffeeScript 1.12.5
(function() {
var EmbeddedFont, PDFFont, StandardFont, fontkit;
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);
} 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);
};
function PDFFont() {
throw new Error('Cannot construct a PDFFont directly.');
}
PDFFont.prototype.encode = function(text) {
throw new Error('Must be implemented by subclasses');
};
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();
return this.embedded = true;
};
PDFFont.prototype.embed = function() {
throw new Error('Must be implemented by subclasses');
};
PDFFont.prototype.lineHeight = function(size, includeGap) {
var gap;
if (includeGap == null) {
includeGap = false;
}
gap = includeGap ? this.lineGap : 0;
return (this.ascender + gap - this.descender) / 1000 * size;
};
return PDFFont;
})();
module.exports = PDFFont;
StandardFont = require('./font/standard');
EmbeddedFont = require('./font/embedded');
}).call(this);

@ -0,0 +1,240 @@
// Generated by CoffeeScript 1.12.5
(function() {
var PDFGradient, PDFLinearGradient, PDFRadialGradient,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
PDFGradient = (function() {
function PDFGradient(doc) {
this.doc = doc;
this.stops = [];
this.embedded = false;
this.transform = [1, 0, 0, 1, 0, 0];
this._colorSpace = 'DeviceRGB';
}
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.setTransform = function(m11, m12, m21, m22, dx, dy) {
this.transform = [m11, m12, m21, m22, dx, dy];
return this;
};
PDFGradient.prototype.embed = function(m) {
var bounds, encode, fn, form, grad, gstate, i, j, k, last, len, opacityPattern, pageBBox, pattern, ref, ref1, shader, stop, stops, v;
if (this.stops.length === 0) {
return;
}
this.embedded = true;
this.matrix = m;
last = this.stops[this.stops.length - 1];
if (last[0] < 1) {
this.stops.push([1, last[1], last[2]]);
}
bounds = [];
encode = [];
stops = [];
for (i = j = 0, ref = this.stops.length - 1; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
encode.push(0, 1);
if (i + 2 !== this.stops.length) {
bounds.push(this.stops[i + 1][0]);
}
fn = this.doc.ref({
FunctionType: 2,
Domain: [0, 1],
C0: this.stops[i + 0][1],
C1: this.stops[i + 1][1],
N: 1
});
stops.push(fn);
fn.end();
}
if (stops.length === 1) {
fn = stops[0];
} else {
fn = this.doc.ref({
FunctionType: 3,
Domain: [0, 1],
Functions: stops,
Bounds: bounds,
Encode: encode
});
fn.end();
}
this.id = 'Sh' + (++this.doc._gradCount);
shader = this.shader(fn);
shader.end();
pattern = this.doc.ref({
Type: 'Pattern',
PatternType: 2,
Shading: shader,
Matrix: (function() {
var k, len, ref1, results;
ref1 = this.matrix;
results = [];
for (k = 0, len = ref1.length; k < len; k++) {
v = ref1[k];
results.push(+v.toFixed(5));
}
return results;
}).call(this)
});
pattern.end();
if (this.stops.some(function(stop) {
return stop[2] < 1;
})) {
grad = this.opacityGradient();
grad._colorSpace = 'DeviceGray';
ref1 = this.stops;
for (k = 0, len = ref1.length; k < len; k++) {
stop = ref1[k];
grad.stop(stop[0], [stop[2]]);
}
grad = grad.embed(this.matrix);
pageBBox = [0, 0, this.doc.page.width, this.doc.page.height];
form = this.doc.ref({
Type: 'XObject',
Subtype: 'Form',
FormType: 1,
BBox: pageBBox,
Group: {
Type: 'Group',
S: 'Transparency',
CS: 'DeviceGray'
},
Resources: {
ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'],
Pattern: {
Sh1: grad
}
}
});
form.write("/Pattern cs /Sh1 scn");
form.end((pageBBox.join(" ")) + " re f");
gstate = this.doc.ref({
Type: 'ExtGState',
SMask: {
Type: 'Mask',
S: 'Luminosity',
G: form
}
});
gstate.end();
opacityPattern = this.doc.ref({
Type: 'Pattern',
PatternType: 1,
PaintType: 1,
TilingType: 2,
BBox: pageBBox,
XStep: pageBBox[2],
YStep: pageBBox[3],
Resources: {
ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'],
Pattern: {
Sh1: pattern
},
ExtGState: {
Gs1: gstate
}
}
});
opacityPattern.write("/Gs1 gs /Pattern cs /Sh1 scn");
opacityPattern.end((pageBBox.join(" ")) + " re f");
this.doc.page.patterns[this.id] = opacityPattern;
} else {
this.doc.page.patterns[this.id] = pattern;
}
return pattern;
};
PDFGradient.prototype.apply = function(op) {
var dx, dy, m, m0, m1, m11, m12, m2, m21, m22, m3, m4, m5, ref, ref1;
ref = this.doc._ctm.slice(), m0 = ref[0], m1 = ref[1], m2 = ref[2], m3 = ref[3], m4 = ref[4], m5 = ref[5];
ref1 = this.transform, m11 = ref1[0], m12 = ref1[1], m21 = ref1[2], m22 = ref1[3], dx = ref1[4], dy = ref1[5];
m = [m0 * m11 + m2 * m12, m1 * m11 + m3 * m12, m0 * m21 + m2 * m22, m1 * m21 + m3 * m22, m0 * dx + m2 * dy + m4, m1 * dx + m3 * dy + m5];
if (!(this.embedded && m.join(" ") === this.matrix.join(" "))) {
this.embed(m);
}
return this.doc.addContent("/" + this.id + " " + op);
};
return PDFGradient;
})();
PDFLinearGradient = (function(superClass) {
extend(PDFLinearGradient, superClass);
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: fn,
Extend: [true, true]
});
};
PDFLinearGradient.prototype.opacityGradient = function() {
return new PDFLinearGradient(this.doc, this.x1, this.y1, this.x2, this.y2);
};
return PDFLinearGradient;
})(PDFGradient);
PDFRadialGradient = (function(superClass) {
extend(PDFRadialGradient, superClass);
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);
}
PDFRadialGradient.prototype.shader = function(fn) {
return this.doc.ref({
ShadingType: 3,
ColorSpace: this._colorSpace,
Coords: [this.x1, this.y1, this.r1, this.x2, this.y2, this.r2],
Function: fn,
Extend: [true, true]
});
};
PDFRadialGradient.prototype.opacityGradient = function() {
return new PDFRadialGradient(this.doc, this.x1, this.y1, this.r1, this.x2, this.y2, this.r2);
};
return PDFRadialGradient;
})(PDFGradient);
module.exports = {
PDFGradient: PDFGradient,
PDFLinearGradient: PDFLinearGradient,
PDFRadialGradient: PDFRadialGradient
};
}).call(this);

@ -0,0 +1,53 @@
// Generated by CoffeeScript 1.12.5
/*
PDFImage - embeds images in PDF documents
By Devon Govett
*/
(function() {
var Data, JPEG, PDFImage, PNG, fs;
fs = require('fs');
Data = require('./data');
JPEG = require('./image/jpeg');
PNG = require('./image/png');
PDFImage = (function() {
function PDFImage() {}
PDFImage.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.');
}
};
return PDFImage;
})();
module.exports = PDFImage;
}).call(this);

@ -0,0 +1,252 @@
// Generated by CoffeeScript 1.12.5
(function() {
var EventEmitter, LineBreaker, LineWrapper,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
EventEmitter = require('events').EventEmitter;
LineBreaker = require('linebreak');
LineWrapper = (function(superClass) {
extend(LineWrapper, superClass);
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));
}
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);
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;
}
};
LineWrapper.prototype.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;
}
if (bk.required && w > _this.spaceLeft) {
buffer = word;
textWidth = w;
wc = 1;
}
emitLine();
if (_this.document.y + lh > _this.maxY) {
shouldContinue = _this.nextSection();
if (!shouldContinue) {
wc = 0;
buffer = '';
return false;
}
}
if (bk.required) {
_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;
}
};
LineWrapper.prototype.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;
};
return LineWrapper;
})(EventEmitter);
module.exports = LineWrapper;
}).call(this);

@ -7,7 +7,11 @@ class PDFObject
pad = (str, length) ->
(Array(length + 1).join('0') + str).slice(-length)
@pad = pad
escapableRe = /[\n\r\t\b\f\(\)\\]/g
@escapableRe = escapableRe
escapable =
'\n': '\\n'
'\r': '\\r'
@ -18,6 +22,8 @@ class PDFObject
'(': '\\('
')': '\\)'
@escapable = escapable
# Convert little endian UTF-16 to big endian
swapBytes = (buff) ->
l = buff.length
@ -31,6 +37,8 @@ class PDFObject
return buff
@swapBytes = swapBytes
@convert: (object) ->
# String literals are converted to the PDF name type
if typeof object is 'string'

@ -0,0 +1,122 @@
// Generated by CoffeeScript 1.12.5
/*
PDFObject - converts JavaScript types into their corrisponding PDF types.
By Devon Govett
*/
(function() {
var PDFObject, PDFReference;
PDFObject = (function() {
var escapable, escapableRe, pad, swapBytes;
function PDFObject() {}
pad = function(str, length) {
return (Array(length + 1).join('0') + str).slice(-length);
};
PDFObject.pad = pad;
escapableRe = /[\n\r\t\b\f\(\)\\]/g;
PDFObject.escapableRe = escapableRe;
escapable = {
'\n': '\\n',
'\r': '\\r',
'\t': '\\t',
'\b': '\\b',
'\f': '\\f',
'\\': '\\\\',
'(': '\\(',
')': '\\)'
};
PDFObject.escapable = escapable;
swapBytes = function(buff) {
var a, i, j, l, ref;
l = buff.length;
if (l & 0x01) {
throw new Error("Buffer length must be even");
} else {
for (i = j = 0, ref = l - 1; j < ref; i = j += 2) {
a = buff[i];
buff[i] = buff[i + 1];
buff[i + 1] = a;
}
}
return buff;
};
PDFObject.swapBytes = swapBytes;
PDFObject.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 if (typeof object === 'number') {
return PDFObject.number(object);
} else {
return '' + object;
}
};
PDFObject.number = function(n) {
if (n > -1e21 && n < 1e21) {
return Math.round(n * 1e6) / 1e6;
}
throw new Error("unsupported number: " + n);
};
return PDFObject;
})();
module.exports = PDFObject;
PDFReference = require('./reference');
}).call(this);

@ -0,0 +1,170 @@
// Generated by CoffeeScript 1.12.5
/*
PDFPage - represents a single page in the PDF document
By Devon Govett
*/
(function() {
var PDFPage;
PDFPage = (function() {
var DEFAULT_MARGINS, SIZES;
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
});
}
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();
};
DEFAULT_MARGINS = {
top: 72,
left: 72,
bottom: 72,
right: 72
};
SIZES = {
'4A0': [4767.87, 6740.79],
'2A0': [3370.39, 4767.87],
A0: [2383.94, 3370.39],
A1: [1683.78, 2383.94],
A2: [1190.55, 1683.78],
A3: [841.89, 1190.55],
A4: [595.28, 841.89],
A5: [419.53, 595.28],
A6: [297.64, 419.53],
A7: [209.76, 297.64],
A8: [147.40, 209.76],
A9: [104.88, 147.40],
A10: [73.70, 104.88],
B0: [2834.65, 4008.19],
B1: [2004.09, 2834.65],
B2: [1417.32, 2004.09],
B3: [1000.63, 1417.32],
B4: [708.66, 1000.63],
B5: [498.90, 708.66],
B6: [354.33, 498.90],
B7: [249.45, 354.33],
B8: [175.75, 249.45],
B9: [124.72, 175.75],
B10: [87.87, 124.72],
C0: [2599.37, 3676.54],
C1: [1836.85, 2599.37],
C2: [1298.27, 1836.85],
C3: [918.43, 1298.27],
C4: [649.13, 918.43],
C5: [459.21, 649.13],
C6: [323.15, 459.21],
C7: [229.61, 323.15],
C8: [161.57, 229.61],
C9: [113.39, 161.57],
C10: [79.37, 113.39],
RA0: [2437.80, 3458.27],
RA1: [1729.13, 2437.80],
RA2: [1218.90, 1729.13],
RA3: [864.57, 1218.90],
RA4: [609.45, 864.57],
SRA0: [2551.18, 3628.35],
SRA1: [1814.17, 2551.18],
SRA2: [1275.59, 1814.17],
SRA3: [907.09, 1275.59],
SRA4: [637.80, 907.09],
EXECUTIVE: [521.86, 756.00],
FOLIO: [612.00, 936.00],
LEGAL: [612.00, 1008.00],
LETTER: [612.00, 792.00],
TABLOID: [792.00, 1224.00]
};
return PDFPage;
})();
module.exports = PDFPage;
}).call(this);

@ -0,0 +1,366 @@
// Generated by CoffeeScript 1.12.5
(function() {
var SVGPath;
SVGPath = (function() {
var apply, arcToSegments, cx, cy, parameters, parse, px, py, runners, segmentToBezier, solveArc, sx, sy;
function SVGPath() {}
SVGPath.apply = function(doc, path) {
var commands;
commands = parse(path);
return apply(commands, doc);
};
parameters = {
A: 7,
a: 7,
C: 6,
c: 6,
H: 1,
h: 1,
L: 2,
l: 2,
M: 2,
m: 2,
Q: 4,
q: 4,
S: 4,
s: 4,
T: 2,
t: 2,
V: 1,
v: 1,
Z: 0,
z: 0
};
parse = function(path) {
var args, c, cmd, curArg, foundDecimal, j, len, params, ret;
ret = [];
args = [];
curArg = "";
foundDecimal = false;
params = 0;
for (j = 0, len = path.length; j < len; j++) {
c = path[j];
if (parameters[c] != null) {
params = parameters[c];
if (cmd) {
if (curArg.length > 0) {
args[args.length] = +curArg;
}
ret[ret.length] = {
cmd: cmd,
args: args
};
args = [];
curArg = "";
foundDecimal = false;
}
cmd = c;
} else if ((c === " " || c === ",") || (c === "-" && curArg.length > 0 && curArg[curArg.length - 1] !== 'e') || (c === "." && foundDecimal)) {
if (curArg.length === 0) {
continue;
}
if (args.length === params) {
ret[ret.length] = {
cmd: cmd,
args: args
};
args = [+curArg];
if (cmd === "M") {
cmd = "L";
}
if (cmd === "m") {
cmd = "l";
}
} else {
args[args.length] = +curArg;
}
foundDecimal = c === ".";
curArg = c === '-' || c === '.' ? c : '';
} else {
curArg += c;
if (c === '.') {
foundDecimal = true;
}
}
}
if (curArg.length > 0) {
if (args.length === params) {
ret[ret.length] = {
cmd: cmd,
args: args
};
args = [+curArg];
if (cmd === "M") {
cmd = "L";
}
if (cmd === "m") {
cmd = "l";
}
} else {
args[args.length] = +curArg;
}
}
ret[ret.length] = {
cmd: cmd,
args: args
};
return ret;
};
cx = cy = px = py = sx = sy = 0;
apply = function(commands, doc) {
var c, i, j, len, name;
cx = cy = px = py = sx = sy = 0;
for (i = j = 0, len = commands.length; j < len; i = ++j) {
c = commands[i];
if (typeof runners[name = c.cmd] === "function") {
runners[name](doc, c.args);
}
}
return cx = cy = px = py = 0;
};
runners = {
M: function(doc, a) {
cx = a[0];
cy = a[1];
px = py = null;
sx = cx;
sy = cy;
return doc.moveTo(cx, cy);
},
m: function(doc, a) {
cx += a[0];
cy += a[1];
px = py = null;
sx = cx;
sy = cy;
return doc.moveTo(cx, cy);
},
C: function(doc, a) {
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) {
px = cx;
py = cy;
}
doc.bezierCurveTo(cx - (px - cx), cy - (py - cy), a[0], a[1], a[2], a[3]);
px = a[0];
py = a[1];
cx = a[2];
return cy = a[3];
},
s: function(doc, a) {
if (px === null) {
px = cx;
py = cy;
}
doc.bezierCurveTo(cx - (px - cx), cy - (py - cy), cx + a[0], cy + a[1], cx + a[2], cy + a[3]);
px = cx + a[0];
py = cy + a[1];
cx += a[2];
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];
},
T: function(doc, a) {
if (px === null) {
px = cx;
py = cy;
} else {
px = cx - (px - cx);
py = cy - (py - cy);
}
doc.quadraticCurveTo(px, py, a[0], a[1]);
px = cx - (px - cx);
py = cy - (py - cy);
cx = a[0];
return cy = a[1];
},
t: function(doc, a) {
if (px === null) {
px = cx;
py = cy;
} else {
px = cx - (px - cx);
py = cy - (py - cy);
}
doc.quadraticCurveTo(px, py, cx + a[0], cy + a[1]);
cx += a[0];
return cy += a[1];
},
A: function(doc, a) {
solveArc(doc, cx, cy, a);
cx = a[5];
return cy = a[6];
},
a: function(doc, a) {
a[5] += cx;
a[6] += cy;
solveArc(doc, cx, cy, a);
cx = a[5];
return cy = a[6];
},
L: function(doc, a) {
cx = a[0];
cy = a[1];
px = py = null;
return doc.lineTo(cx, cy);
},
l: function(doc, a) {
cx += a[0];
cy += a[1];
px = py = null;
return doc.lineTo(cx, cy);
},
H: function(doc, a) {
cx = a[0];
px = py = null;
return doc.lineTo(cx, cy);
},
h: function(doc, a) {
cx += a[0];
px = py = null;
return doc.lineTo(cx, cy);
},
V: function(doc, a) {
cy = a[0];
px = py = null;
return doc.lineTo(cx, cy);
},
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;
}
};
solveArc = function(doc, x, y, coords) {
var bez, ex, ey, j, large, len, results, rot, rx, ry, seg, segs, sweep;
rx = coords[0], ry = coords[1], rot = coords[2], large = coords[3], sweep = coords[4], ex = coords[5], ey = coords[6];
segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, x, y);
results = [];
for (j = 0, len = segs.length; j < len; j++) {
seg = segs[j];
bez = segmentToBezier.apply(null, seg);
results.push(doc.bezierCurveTo.apply(doc, bez));
}
return results;
};
arcToSegments = function(x, y, rx, ry, large, sweep, rotateX, ox, oy) {
var a00, a01, a10, a11, cos_th, d, i, j, pl, ref, result, segments, sfactor, sfactor_sq, sin_th, th, th0, th1, th2, th3, th_arc, x0, x1, xc, y0, y1, yc;
th = rotateX * (Math.PI / 180);
sin_th = Math.sin(th);
cos_th = Math.cos(th);
rx = Math.abs(rx);
ry = Math.abs(ry);
px = cos_th * (ox - x) * 0.5 + sin_th * (oy - y) * 0.5;
py = cos_th * (oy - y) * 0.5 - sin_th * (ox - x) * 0.5;
pl = (px * px) / (rx * rx) + (py * py) / (ry * ry);
if (pl > 1) {
pl = Math.sqrt(pl);
rx *= pl;
ry *= pl;
}
a00 = cos_th / rx;
a01 = sin_th / rx;
a10 = (-sin_th) / ry;
a11 = cos_th / ry;
x0 = a00 * ox + a01 * oy;
y0 = a10 * ox + a11 * oy;
x1 = a00 * x + a01 * y;
y1 = a10 * x + a11 * y;
d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
sfactor_sq = 1 / d - 0.25;
if (sfactor_sq < 0) {
sfactor_sq = 0;
}
sfactor = Math.sqrt(sfactor_sq);
if (sweep === large) {
sfactor = -sfactor;
}
xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
th0 = Math.atan2(y0 - yc, x0 - xc);
th1 = Math.atan2(y1 - yc, x1 - xc);
th_arc = th1 - th0;
if (th_arc < 0 && sweep === 1) {
th_arc += 2 * Math.PI;
} else if (th_arc > 0 && sweep === 0) {
th_arc -= 2 * Math.PI;
}
segments = Math.ceil(Math.abs(th_arc / (Math.PI * 0.5 + 0.001)));
result = [];
for (i = j = 0, ref = segments; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
th2 = th0 + i * th_arc / segments;
th3 = th0 + (i + 1) * th_arc / segments;
result[i] = [xc, yc, th2, th3, rx, ry, sin_th, cos_th];
}
return result;
};
segmentToBezier = function(cx, cy, th0, th1, rx, ry, sin_th, cos_th) {
var a00, a01, a10, a11, t, th_half, x1, x2, x3, y1, y2, y3;
a00 = cos_th * rx;
a01 = -sin_th * ry;
a10 = sin_th * rx;
a11 = cos_th * ry;
th_half = 0.5 * (th1 - th0);
t = (8 / 3) * Math.sin(th_half * 0.5) * Math.sin(th_half * 0.5) / Math.sin(th_half);
x1 = cx + Math.cos(th0) - t * Math.sin(th0);
y1 = cy + Math.sin(th0) + t * Math.cos(th0);
x3 = cx + Math.cos(th1);
y3 = cy + Math.sin(th1);
x2 = x3 + t * Math.sin(th1);
y2 = y3 - t * Math.cos(th1);
return [a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, a00 * x3 + a01 * y3, a10 * x3 + a11 * y3];
};
return SVGPath;
})();
module.exports = SVGPath;
}).call(this);

@ -0,0 +1,109 @@
// Generated by CoffeeScript 1.12.5
/*
PDFReference - represents a reference to another object in the PDF object heirarchy
By Devon Govett
*/
(function() {
var PDFObject, PDFReference, stream, zlib,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
zlib = require('zlib');
stream = require('stream');
PDFReference = (function(superClass) {
extend(PDFReference, superClass);
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 = [];
}
PDFReference.prototype.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);
};
PDFReference.prototype._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();
};
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");
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.toString = function() {
return this.id + " " + this.gen + " R";
};
return PDFReference;
})(stream.Writable);
module.exports = PDFReference;
PDFObject = require('./object');
}).call(this);

@ -2,6 +2,9 @@
(require racket/draw)
(provide PDFDocument)
(require "reference.rkt")
;(require "page.rkt")
(define PDFDocument
(class pdf-dc%
(init-field [options (hasheq)])
@ -20,21 +23,21 @@
;; Whether streams should be compressed
(field [compress (hash-ref options 'compress #t)])
(define _pageBuffer null)
(define _pageBufferStart 0)
(field [_pageBuffer null])
(field [_pageBufferStart 0])
;; The PDF object store
(define _offsets null)
(define _waiting 0)
(define _ended #f)
(define _offset 0)
(field [_offsets null])
(field [_waiting 0])
(field [_ended #f])
(field [_offset 0])
(define _root (ref
(field [_root (ref
(hasheq 'Type 'Catalog'
'Pages (ref
(hasheq 'Type 'Pages'
'Count 0
'Kids empty)))))
'Kids empty))))])
;; The current page
(field [page #f])
@ -59,7 +62,7 @@
;; Write the header
;; PDF version
(_write (format "%PDF-#{~a}" version))
(_write (format "%PDF-~a" version))
(_write (format "%~a~a~a~a" #xFF #xFF #xFF #xFF))
@ -83,7 +86,7 @@
(field [x 0])
(field [y 0])
(define _ctm null)
(field [_ctm null])
(define/public (addPage [options options])
;; end the current page if needed
(unless (hash-ref options 'bufferPages #f)
@ -114,9 +117,13 @@
(define/public (flushPages)
42) ; temp
(define/public (ref . xs)
42) ; temp
(define/public (ref data)
(define ref (make-object PDFReference this (add1 (length _offsets)) data))
(push! _offsets #f) ; placeholder for this object's offset once it is finalized
(set! _waiting (add1 _waiting))
ref
42)
(define/public (_write . xs)
42) ; temp

@ -0,0 +1,25 @@
#lang br
(define (string-slice str length)
(let loop ([length length])
(if (negative? length)
(loop (+ (string-length str) length))
(substring str length (string-length str)))))
(define PDFObject
(class object%
(super-new)
(define/public (pad str length)
(define newstr (string-append (string-join (make-list (add1 length) "") "0") str))
(string-slice newstr (- length)))))
(module+ test
(require rackunit)
(define o (new PDFObject))
(check-equal? (send o pad "foobar" -1) "oobar")
(check-equal? (send o pad "foobar" 0) "foobar")
(check-equal? (send o pad "foobar" 3) "bar")
(check-equal? (send o pad "foobar" 6) "foobar")
(check-equal? (send o pad "foobar" 10) "0000foobar"))

@ -0,0 +1,42 @@
#lang br
(provide PDFReference)
(define PDFReference
(class object%
(init-field document id [data (hasheq)])
(super-new)
(field [gen 0])
(field [deflate #f])
(field [compress (and (get-field compress document) (not (hash-ref data 'Filter #f)))])
(field [uncompressedLength 0])
(field [chunks empty])
(define/public (initDeflate)
;; todo
(void))
(define/public (_write chunk encoding callback)
;; assume chunk is a string
(set! uncompressedLength (+ uncompressedLength (string-length chunk)))
(hash-ref! data 'Length 0)
(cond
[compress (when (not deflate) (initDeflate))
(deflate chunk)]
[else (push! chunks chunk)
(hash-update! data 'Length (λ (len) (+ len (string-length chunk))))])
(callback))
(define/public (end chunk)
; (super) ; todo
(if deflate
(void) ; todo (deflate-end)
(finalize)))
(field [offset #f])
(define/public (finalize)
(set! offset (get-field _offset document))
(send document _write (format "~a ~a obj" id gen))
)
))

Binary file not shown.
Loading…
Cancel
Save