UNPKG

7.08 kBJavaScriptView Raw
1
2/*
3PDFDocument - represents an entire PDF document
4By Devon Govett
5 */
6
7(function() {
8 var PDFDocument, PDFObject, PDFPage, PDFReference, fs, stream,
9 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; },
10 hasProp = {}.hasOwnProperty;
11
12 stream = require('stream');
13
14 fs = require('fs');
15
16 PDFObject = require('./object');
17
18 PDFReference = require('./reference');
19
20 PDFPage = require('./page');
21
22 PDFDocument = (function(superClass) {
23 var mixin;
24
25 extend(PDFDocument, superClass);
26
27 function PDFDocument(options1) {
28 var key, ref1, ref2, val;
29 this.options = options1 != null ? options1 : {};
30 PDFDocument.__super__.constructor.apply(this, arguments);
31 this.version = 1.7;
32 this.compress = (ref1 = this.options.compress) != null ? ref1 : true;
33 this._pageBuffer = [];
34 this._pageBufferStart = 0;
35 this._offsets = [];
36 this._waiting = 0;
37 this._ended = false;
38 this._offset = 0;
39 this._root = this.ref({
40 Type: 'Catalog',
41 Pages: this.ref({
42 Type: 'Pages',
43 Count: 0,
44 Kids: []
45 })
46 });
47 this.page = null;
48 this.initColor();
49 this.initVector();
50 this.initFonts();
51 this.initText();
52 this.initImages();
53 this.initOutline();
54 this.info = {
55 Producer: 'PDFKit',
56 Creator: 'PDFKit',
57 CreationDate: new Date()
58 };
59 if (this.options.info) {
60 ref2 = this.options.info;
61 for (key in ref2) {
62 val = ref2[key];
63 this.info[key] = val;
64 }
65 }
66 this._write("%PDF-" + this.version);
67 this._write("%\xFF\xFF\xFF\xFF");
68 if (this.options.autoFirstPage !== false) {
69 this.addPage();
70 }
71 }
72
73 mixin = function(methods) {
74 var method, name, results;
75 results = [];
76 for (name in methods) {
77 method = methods[name];
78 results.push(PDFDocument.prototype[name] = method);
79 }
80 return results;
81 };
82
83 mixin(require('./mixins/color'));
84
85 mixin(require('./mixins/vector'));
86
87 mixin(require('./mixins/fonts'));
88
89 mixin(require('./mixins/text'));
90
91 mixin(require('./mixins/images'));
92
93 mixin(require('./mixins/annotations'));
94
95 mixin(require('./mixins/outline'));
96
97 mixin(require('./mixins/metadata'));
98
99 PDFDocument.prototype.addPage = function(options) {
100 var pages;
101 if (options == null) {
102 options = this.options;
103 }
104 if (!this.options.bufferPages) {
105 this.flushPages();
106 }
107 this.page = new PDFPage(this, options);
108 this._pageBuffer.push(this.page);
109 pages = this._root.data.Pages.data;
110 pages.Kids.push(this.page.dictionary);
111 pages.Count++;
112 this.x = this.page.margins.left;
113 this.y = this.page.margins.top;
114 this._ctm = [1, 0, 0, 1, 0, 0];
115 this.transform(1, 0, 0, -1, 0, this.page.height);
116 this.emit('pageAdded');
117 return this;
118 };
119
120 PDFDocument.prototype.bufferedPageRange = function() {
121 return {
122 start: this._pageBufferStart,
123 count: this._pageBuffer.length
124 };
125 };
126
127 PDFDocument.prototype.switchToPage = function(n) {
128 var page;
129 if (!(page = this._pageBuffer[n - this._pageBufferStart])) {
130 throw new Error("switchToPage(" + n + ") out of bounds, current buffer covers pages " + this._pageBufferStart + " to " + (this._pageBufferStart + this._pageBuffer.length - 1));
131 }
132 return this.page = page;
133 };
134
135 PDFDocument.prototype.flushPages = function() {
136 var i, len, page, pages;
137 pages = this._pageBuffer;
138 this._pageBuffer = [];
139 this._pageBufferStart += pages.length;
140 for (i = 0, len = pages.length; i < len; i++) {
141 page = pages[i];
142 page.end();
143 }
144 };
145
146 PDFDocument.prototype.ref = function(data) {
147 var ref;
148 ref = new PDFReference(this, this._offsets.length + 1, data);
149 this._offsets.push(null);
150 this._waiting++;
151 return ref;
152 };
153
154 PDFDocument.prototype._read = function() {};
155
156 PDFDocument.prototype._write = function(data) {
157 if (!Buffer.isBuffer(data)) {
158 data = new Buffer(data + '\n', 'binary');
159 }
160 this.push(data);
161 return this._offset += data.length;
162 };
163
164 PDFDocument.prototype.addContent = function(data) {
165 this.page.write(data);
166 return this;
167 };
168
169 PDFDocument.prototype._refEnd = function(ref) {
170 this._offsets[ref.id - 1] = ref.offset;
171 if (--this._waiting === 0 && this._ended) {
172 this._finalize();
173 return this._ended = false;
174 }
175 };
176
177 PDFDocument.prototype.write = function(filename, fn) {
178 var err;
179 err = new Error('PDFDocument#write is deprecated, and will be removed in a future version of PDFKit. Please pipe the document into a Node stream.');
180 console.warn(err.stack);
181 this.pipe(fs.createWriteStream(filename));
182 this.end();
183 return this.once('end', fn);
184 };
185
186 PDFDocument.prototype.output = function(fn) {
187 throw new Error('PDFDocument#output is deprecated, and has been removed from PDFKit. Please pipe the document into a Node stream.');
188 };
189
190 PDFDocument.prototype.end = function() {
191 var font, key, name, ref1, ref2, val;
192 this.flushPages();
193 this._info = this.ref();
194 ref1 = this.info;
195 for (key in ref1) {
196 val = ref1[key];
197 if (typeof val === 'string') {
198 val = new String(val);
199 }
200 this._info.data[key] = val;
201 }
202 this._info.end();
203 ref2 = this._fontFamilies;
204 for (name in ref2) {
205 font = ref2[name];
206 font.finalize();
207 }
208 this.endOutline();
209 this._root.end();
210 this._root.data.Pages.end();
211 if (this._waiting === 0) {
212 return this._finalize();
213 } else {
214 return this._ended = true;
215 }
216 };
217
218 PDFDocument.prototype._finalize = function(fn) {
219 var i, len, offset, ref1, xRefOffset;
220 xRefOffset = this._offset;
221 this._write("xref");
222 this._write("0 " + (this._offsets.length + 1));
223 this._write("0000000000 65535 f ");
224 ref1 = this._offsets;
225 for (i = 0, len = ref1.length; i < len; i++) {
226 offset = ref1[i];
227 offset = ('0000000000' + offset).slice(-10);
228 this._write(offset + ' 00000 n ');
229 }
230 this._write('trailer');
231 this._write(PDFObject.convert({
232 Size: this._offsets.length + 1,
233 Root: this._root,
234 Info: this._info
235 }));
236 this._write('startxref');
237 this._write("" + xRefOffset);
238 this._write('%%EOF');
239 return this.push(null);
240 };
241
242 PDFDocument.prototype.toString = function() {
243 return "[object PDFDocument]";
244 };
245
246 return PDFDocument;
247
248 })(stream.Readable);
249
250 module.exports = PDFDocument;
251
252}).call(this);