1 |
|
2 |
|
3 |
|
4 |
|
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);
|