pdfkit 0.15.2 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.git-blame-ignore-revs +1 -0
- package/CHANGELOG.md +26 -0
- package/README.md +2 -2
- package/js/pdfkit.es.js +1105 -819
- package/js/pdfkit.es.js.map +1 -1
- package/js/pdfkit.es5.js +7493 -0
- package/js/pdfkit.es5.js.map +1 -0
- package/js/pdfkit.esnext.js +6782 -0
- package/js/pdfkit.esnext.js.map +1 -0
- package/js/pdfkit.js +1082 -818
- package/js/pdfkit.js.map +1 -1
- package/js/pdfkit.standalone.js +9853 -13090
- package/package.json +29 -28
package/js/pdfkit.es.js
CHANGED
|
@@ -2,30 +2,22 @@ import stream from 'stream';
|
|
|
2
2
|
import zlib from 'zlib';
|
|
3
3
|
import CryptoJS from 'crypto-js';
|
|
4
4
|
import fs from 'fs';
|
|
5
|
-
import fontkit from 'fontkit';
|
|
5
|
+
import * as fontkit from 'fontkit';
|
|
6
6
|
import { EventEmitter } from 'events';
|
|
7
7
|
import LineBreaker from 'linebreak';
|
|
8
8
|
import exif from 'jpeg-exif';
|
|
9
9
|
import PNG from 'png-js';
|
|
10
10
|
|
|
11
|
-
/*
|
|
12
|
-
PDFAbstractReference - abstract class for PDF reference
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
11
|
class PDFAbstractReference {
|
|
16
12
|
toString() {
|
|
17
13
|
throw new Error('Must be implemented by subclasses');
|
|
18
14
|
}
|
|
19
15
|
}
|
|
20
16
|
|
|
21
|
-
/*
|
|
22
|
-
PDFTree - abstract base class for name and number tree objects
|
|
23
|
-
*/
|
|
24
17
|
class PDFTree {
|
|
25
18
|
constructor() {
|
|
26
19
|
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
27
20
|
this._items = {};
|
|
28
|
-
// disable /Limits output for this tree
|
|
29
21
|
this.limits = typeof options.limits === 'boolean' ? options.limits : true;
|
|
30
22
|
}
|
|
31
23
|
add(key, val) {
|
|
@@ -35,7 +27,6 @@ class PDFTree {
|
|
|
35
27
|
return this._items[key];
|
|
36
28
|
}
|
|
37
29
|
toString() {
|
|
38
|
-
// Needs to be sorted by key
|
|
39
30
|
const sortedKeys = Object.keys(this._items).sort((a, b) => this._compareKeys(a, b));
|
|
40
31
|
const out = ['<<'];
|
|
41
32
|
if (this.limits && sortedKeys.length > 1) {
|
|
@@ -51,23 +42,37 @@ class PDFTree {
|
|
|
51
42
|
out.push('>>');
|
|
52
43
|
return out.join('\n');
|
|
53
44
|
}
|
|
54
|
-
_compareKeys(
|
|
55
|
-
) {
|
|
45
|
+
_compareKeys() {
|
|
56
46
|
throw new Error('Must be implemented by subclasses');
|
|
57
47
|
}
|
|
58
48
|
_keysName() {
|
|
59
49
|
throw new Error('Must be implemented by subclasses');
|
|
60
50
|
}
|
|
61
|
-
_dataForKey(
|
|
62
|
-
) {
|
|
51
|
+
_dataForKey() {
|
|
63
52
|
throw new Error('Must be implemented by subclasses');
|
|
64
53
|
}
|
|
65
54
|
}
|
|
66
55
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
56
|
+
class SpotColor {
|
|
57
|
+
constructor(doc, name, C, M, Y, K) {
|
|
58
|
+
this.id = 'CS' + Object.keys(doc.spotColors).length;
|
|
59
|
+
this.name = name;
|
|
60
|
+
this.values = [C, M, Y, K];
|
|
61
|
+
this.ref = doc.ref(['Separation', this.name, 'DeviceCMYK', {
|
|
62
|
+
Range: [0, 1, 0, 1, 0, 1, 0, 1],
|
|
63
|
+
C0: [0, 0, 0, 0],
|
|
64
|
+
C1: this.values.map(value => value / 100),
|
|
65
|
+
FunctionType: 2,
|
|
66
|
+
Domain: [0, 1],
|
|
67
|
+
N: 1
|
|
68
|
+
}]);
|
|
69
|
+
this.ref.end();
|
|
70
|
+
}
|
|
71
|
+
toString() {
|
|
72
|
+
return `${this.ref.id} 0 R`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
71
76
|
const pad = (str, length) => (Array(length + 1).join('0') + str).slice(-length);
|
|
72
77
|
const escapableRe = /[\n\r\t\b\f()\\]/g;
|
|
73
78
|
const escapable = {
|
|
@@ -80,8 +85,6 @@ const escapable = {
|
|
|
80
85
|
'(': '\\(',
|
|
81
86
|
')': '\\)'
|
|
82
87
|
};
|
|
83
|
-
|
|
84
|
-
// Convert little endian UTF-16 to big endian
|
|
85
88
|
const swapBytes = function (buff) {
|
|
86
89
|
const l = buff.length;
|
|
87
90
|
if (l & 0x01) {
|
|
@@ -98,14 +101,10 @@ const swapBytes = function (buff) {
|
|
|
98
101
|
class PDFObject {
|
|
99
102
|
static convert(object) {
|
|
100
103
|
let encryptFn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
101
|
-
// String literals are converted to the PDF name type
|
|
102
104
|
if (typeof object === 'string') {
|
|
103
105
|
return `/${object}`;
|
|
104
|
-
|
|
105
|
-
// String objects are converted to PDF strings (UTF-16)
|
|
106
106
|
} else if (object instanceof String) {
|
|
107
107
|
let string = object;
|
|
108
|
-
// Detect if this is a unicode string
|
|
109
108
|
let isUnicode = false;
|
|
110
109
|
for (let i = 0, end = string.length; i < end; i++) {
|
|
111
110
|
if (string.charCodeAt(i) > 0x7f) {
|
|
@@ -113,39 +112,27 @@ class PDFObject {
|
|
|
113
112
|
break;
|
|
114
113
|
}
|
|
115
114
|
}
|
|
116
|
-
|
|
117
|
-
// If so, encode it as big endian UTF-16
|
|
118
115
|
let stringBuffer;
|
|
119
116
|
if (isUnicode) {
|
|
120
117
|
stringBuffer = swapBytes(Buffer.from(`\ufeff${string}`, 'utf16le'));
|
|
121
118
|
} else {
|
|
122
119
|
stringBuffer = Buffer.from(string.valueOf(), 'ascii');
|
|
123
120
|
}
|
|
124
|
-
|
|
125
|
-
// Encrypt the string when necessary
|
|
126
121
|
if (encryptFn) {
|
|
127
122
|
string = encryptFn(stringBuffer).toString('binary');
|
|
128
123
|
} else {
|
|
129
124
|
string = stringBuffer.toString('binary');
|
|
130
125
|
}
|
|
131
|
-
|
|
132
|
-
// Escape characters as required by the spec
|
|
133
126
|
string = string.replace(escapableRe, c => escapable[c]);
|
|
134
127
|
return `(${string})`;
|
|
135
|
-
|
|
136
|
-
// Buffers are converted to PDF hex strings
|
|
137
128
|
} else if (Buffer.isBuffer(object)) {
|
|
138
129
|
return `<${object.toString('hex')}>`;
|
|
139
|
-
} else if (object instanceof PDFAbstractReference || object instanceof PDFTree) {
|
|
130
|
+
} else if (object instanceof PDFAbstractReference || object instanceof PDFTree || object instanceof SpotColor) {
|
|
140
131
|
return object.toString();
|
|
141
132
|
} else if (object instanceof Date) {
|
|
142
133
|
let string = `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';
|
|
143
|
-
|
|
144
|
-
// Encrypt the string when necessary
|
|
145
134
|
if (encryptFn) {
|
|
146
135
|
string = encryptFn(Buffer.from(string, 'ascii')).toString('binary');
|
|
147
|
-
|
|
148
|
-
// Escape characters as required by the spec
|
|
149
136
|
string = string.replace(escapableRe, c => escapable[c]);
|
|
150
137
|
}
|
|
151
138
|
return `(${string})`;
|
|
@@ -174,10 +161,6 @@ class PDFObject {
|
|
|
174
161
|
}
|
|
175
162
|
}
|
|
176
163
|
|
|
177
|
-
/*
|
|
178
|
-
PDFReference - represents a reference to another object in the PDF object heirarchy
|
|
179
|
-
By Devon Govett
|
|
180
|
-
*/
|
|
181
164
|
class PDFReference extends PDFAbstractReference {
|
|
182
165
|
constructor(document, id) {
|
|
183
166
|
let data = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
@@ -191,7 +174,7 @@ class PDFReference extends PDFAbstractReference {
|
|
|
191
174
|
this.buffer = [];
|
|
192
175
|
}
|
|
193
176
|
write(chunk) {
|
|
194
|
-
if (!
|
|
177
|
+
if (!(chunk instanceof Uint8Array)) {
|
|
195
178
|
chunk = Buffer.from(chunk + '\n', 'binary');
|
|
196
179
|
}
|
|
197
180
|
this.uncompressedLength += chunk.length;
|
|
@@ -201,14 +184,14 @@ class PDFReference extends PDFAbstractReference {
|
|
|
201
184
|
this.buffer.push(chunk);
|
|
202
185
|
this.data.Length += chunk.length;
|
|
203
186
|
if (this.compress) {
|
|
204
|
-
|
|
187
|
+
this.data.Filter = 'FlateDecode';
|
|
205
188
|
}
|
|
206
189
|
}
|
|
207
190
|
end(chunk) {
|
|
208
191
|
if (chunk) {
|
|
209
192
|
this.write(chunk);
|
|
210
193
|
}
|
|
211
|
-
|
|
194
|
+
this.finalize();
|
|
212
195
|
}
|
|
213
196
|
finalize() {
|
|
214
197
|
this.offset = this.document._offset;
|
|
@@ -228,7 +211,7 @@ class PDFReference extends PDFAbstractReference {
|
|
|
228
211
|
if (this.buffer.length) {
|
|
229
212
|
this.document._write('stream');
|
|
230
213
|
this.document._write(this.buffer);
|
|
231
|
-
this.buffer = [];
|
|
214
|
+
this.buffer = [];
|
|
232
215
|
this.document._write('\nendstream');
|
|
233
216
|
}
|
|
234
217
|
this.document._write('endobj');
|
|
@@ -239,10 +222,71 @@ class PDFReference extends PDFAbstractReference {
|
|
|
239
222
|
}
|
|
240
223
|
}
|
|
241
224
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
225
|
+
function PDFNumber(n) {
|
|
226
|
+
return Math.fround(n);
|
|
227
|
+
}
|
|
228
|
+
function normalizeSides(sides) {
|
|
229
|
+
let defaultDefinition = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
|
|
230
|
+
let transformer = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : v => v;
|
|
231
|
+
if (sides == null || typeof sides === 'object' && Object.keys(sides).length === 0) {
|
|
232
|
+
sides = defaultDefinition;
|
|
233
|
+
}
|
|
234
|
+
if (sides == null || typeof sides !== 'object') {
|
|
235
|
+
sides = {
|
|
236
|
+
top: sides,
|
|
237
|
+
right: sides,
|
|
238
|
+
bottom: sides,
|
|
239
|
+
left: sides
|
|
240
|
+
};
|
|
241
|
+
} else if (Array.isArray(sides)) {
|
|
242
|
+
if (sides.length === 2) {
|
|
243
|
+
sides = {
|
|
244
|
+
vertical: sides[0],
|
|
245
|
+
horizontal: sides[1]
|
|
246
|
+
};
|
|
247
|
+
} else {
|
|
248
|
+
sides = {
|
|
249
|
+
top: sides[0],
|
|
250
|
+
right: sides[1],
|
|
251
|
+
bottom: sides[2],
|
|
252
|
+
left: sides[3]
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if ('vertical' in sides || 'horizontal' in sides) {
|
|
257
|
+
sides = {
|
|
258
|
+
top: sides.vertical,
|
|
259
|
+
right: sides.horizontal,
|
|
260
|
+
bottom: sides.vertical,
|
|
261
|
+
left: sides.horizontal
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
top: transformer(sides.top),
|
|
266
|
+
right: transformer(sides.right),
|
|
267
|
+
bottom: transformer(sides.bottom),
|
|
268
|
+
left: transformer(sides.left)
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
const MM_TO_CM = 1 / 10;
|
|
272
|
+
const CM_TO_IN = 1 / 2.54;
|
|
273
|
+
const PX_TO_IN = 1 / 96;
|
|
274
|
+
const IN_TO_PT = 72;
|
|
275
|
+
const PC_TO_PT = 12;
|
|
276
|
+
function cosine(a) {
|
|
277
|
+
if (a === 0) return 1;
|
|
278
|
+
if (a === 90) return 0;
|
|
279
|
+
if (a === 180) return -1;
|
|
280
|
+
if (a === 270) return 0;
|
|
281
|
+
return Math.cos(a * Math.PI / 180);
|
|
282
|
+
}
|
|
283
|
+
function sine(a) {
|
|
284
|
+
if (a === 0) return 0;
|
|
285
|
+
if (a === 90) return 1;
|
|
286
|
+
if (a === 180) return 0;
|
|
287
|
+
if (a === 270) return -1;
|
|
288
|
+
return Math.sin(a * Math.PI / 180);
|
|
289
|
+
}
|
|
246
290
|
|
|
247
291
|
const DEFAULT_MARGINS = {
|
|
248
292
|
top: 72,
|
|
@@ -306,35 +350,19 @@ class PDFPage {
|
|
|
306
350
|
constructor(document) {
|
|
307
351
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
308
352
|
this.document = document;
|
|
353
|
+
this._options = options;
|
|
309
354
|
this.size = options.size || 'letter';
|
|
310
355
|
this.layout = options.layout || 'portrait';
|
|
311
|
-
|
|
312
|
-
// process margins
|
|
313
|
-
if (typeof options.margin === 'number') {
|
|
314
|
-
this.margins = {
|
|
315
|
-
top: options.margin,
|
|
316
|
-
left: options.margin,
|
|
317
|
-
bottom: options.margin,
|
|
318
|
-
right: options.margin
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
// default to 1 inch margins
|
|
322
|
-
} else {
|
|
323
|
-
this.margins = options.margins || DEFAULT_MARGINS;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// calculate page dimensions
|
|
327
356
|
const dimensions = Array.isArray(this.size) ? this.size : SIZES[this.size.toUpperCase()];
|
|
328
357
|
this.width = dimensions[this.layout === 'portrait' ? 0 : 1];
|
|
329
358
|
this.height = dimensions[this.layout === 'portrait' ? 1 : 0];
|
|
330
359
|
this.content = this.document.ref();
|
|
331
|
-
|
|
332
|
-
|
|
360
|
+
if (options.font) document.font(options.font, options.fontFamily);
|
|
361
|
+
if (options.fontSize) document.fontSize(options.fontSize);
|
|
362
|
+
this.margins = normalizeSides(options.margin ?? options.margins, DEFAULT_MARGINS, x => document.sizeToPoint(x, 0, this));
|
|
333
363
|
this.resources = this.document.ref({
|
|
334
364
|
ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI']
|
|
335
365
|
});
|
|
336
|
-
|
|
337
|
-
// The page dictionary
|
|
338
366
|
this.dictionary = this.document.ref({
|
|
339
367
|
Type: 'Page',
|
|
340
368
|
Parent: this.document._root.data.Pages,
|
|
@@ -344,8 +372,6 @@ class PDFPage {
|
|
|
344
372
|
});
|
|
345
373
|
this.markings = [];
|
|
346
374
|
}
|
|
347
|
-
|
|
348
|
-
// Lazily create these objects
|
|
349
375
|
get fonts() {
|
|
350
376
|
const data = this.resources.data;
|
|
351
377
|
return data.Font != null ? data.Font : data.Font = {};
|
|
@@ -374,204 +400,86 @@ class PDFPage {
|
|
|
374
400
|
const data = this.dictionary.data;
|
|
375
401
|
return data.StructParents != null ? data.StructParents : data.StructParents = this.document.createStructParentTreeNextKey();
|
|
376
402
|
}
|
|
403
|
+
get contentWidth() {
|
|
404
|
+
return this.width - this.margins.left - this.margins.right;
|
|
405
|
+
}
|
|
406
|
+
get contentHeight() {
|
|
407
|
+
return this.height - this.margins.top - this.margins.bottom;
|
|
408
|
+
}
|
|
377
409
|
maxY() {
|
|
378
410
|
return this.height - this.margins.bottom;
|
|
379
411
|
}
|
|
380
412
|
write(chunk) {
|
|
381
413
|
return this.content.write(chunk);
|
|
382
414
|
}
|
|
415
|
+
_setTabOrder() {
|
|
416
|
+
if (!this.dictionary.Tabs && this.document.hasMarkInfoDictionary()) {
|
|
417
|
+
this.dictionary.data.Tabs = 'S';
|
|
418
|
+
}
|
|
419
|
+
}
|
|
383
420
|
end() {
|
|
421
|
+
this._setTabOrder();
|
|
384
422
|
this.dictionary.end();
|
|
423
|
+
this.resources.data.ColorSpace = this.resources.data.ColorSpace || {};
|
|
424
|
+
for (let color of Object.values(this.document.spotColors)) {
|
|
425
|
+
this.resources.data.ColorSpace[color.id] = color;
|
|
426
|
+
}
|
|
385
427
|
this.resources.end();
|
|
386
428
|
return this.content.end();
|
|
387
429
|
}
|
|
388
430
|
}
|
|
389
431
|
|
|
390
|
-
/*
|
|
391
|
-
PDFNameTree - represents a name tree object
|
|
392
|
-
*/
|
|
393
432
|
class PDFNameTree extends PDFTree {
|
|
394
433
|
_compareKeys(a, b) {
|
|
395
434
|
return a.localeCompare(b);
|
|
396
435
|
}
|
|
397
436
|
_keysName() {
|
|
398
|
-
return
|
|
437
|
+
return 'Names';
|
|
399
438
|
}
|
|
400
439
|
_dataForKey(k) {
|
|
401
440
|
return new String(k);
|
|
402
441
|
}
|
|
403
442
|
}
|
|
404
443
|
|
|
405
|
-
/**
|
|
406
|
-
* Check if value is in a range group.
|
|
407
|
-
* @param {number} value
|
|
408
|
-
* @param {number[]} rangeGroup
|
|
409
|
-
* @returns {boolean}
|
|
410
|
-
*/
|
|
411
444
|
function inRange(value, rangeGroup) {
|
|
412
445
|
if (value < rangeGroup[0]) return false;
|
|
413
446
|
let startRange = 0;
|
|
414
447
|
let endRange = rangeGroup.length / 2;
|
|
415
448
|
while (startRange <= endRange) {
|
|
416
449
|
const middleRange = Math.floor((startRange + endRange) / 2);
|
|
417
|
-
|
|
418
|
-
// actual array index
|
|
419
450
|
const arrayIndex = middleRange * 2;
|
|
420
|
-
|
|
421
|
-
// Check if value is in range pointed by actual index
|
|
422
451
|
if (value >= rangeGroup[arrayIndex] && value <= rangeGroup[arrayIndex + 1]) {
|
|
423
452
|
return true;
|
|
424
453
|
}
|
|
425
454
|
if (value > rangeGroup[arrayIndex + 1]) {
|
|
426
|
-
// Search Right Side Of Array
|
|
427
455
|
startRange = middleRange + 1;
|
|
428
456
|
} else {
|
|
429
|
-
// Search Left Side Of Array
|
|
430
457
|
endRange = middleRange - 1;
|
|
431
458
|
}
|
|
432
459
|
}
|
|
433
460
|
return false;
|
|
434
461
|
}
|
|
435
462
|
|
|
436
|
-
// prettier-ignore-start
|
|
437
|
-
/**
|
|
438
|
-
* A.1 Unassigned code points in Unicode 3.2
|
|
439
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-A.1
|
|
440
|
-
*/
|
|
441
463
|
const unassigned_code_points = [0x0221, 0x0221, 0x0234, 0x024f, 0x02ae, 0x02af, 0x02ef, 0x02ff, 0x0350, 0x035f, 0x0370, 0x0373, 0x0376, 0x0379, 0x037b, 0x037d, 0x037f, 0x0383, 0x038b, 0x038b, 0x038d, 0x038d, 0x03a2, 0x03a2, 0x03cf, 0x03cf, 0x03f7, 0x03ff, 0x0487, 0x0487, 0x04cf, 0x04cf, 0x04f6, 0x04f7, 0x04fa, 0x04ff, 0x0510, 0x0530, 0x0557, 0x0558, 0x0560, 0x0560, 0x0588, 0x0588, 0x058b, 0x0590, 0x05a2, 0x05a2, 0x05ba, 0x05ba, 0x05c5, 0x05cf, 0x05eb, 0x05ef, 0x05f5, 0x060b, 0x060d, 0x061a, 0x061c, 0x061e, 0x0620, 0x0620, 0x063b, 0x063f, 0x0656, 0x065f, 0x06ee, 0x06ef, 0x06ff, 0x06ff, 0x070e, 0x070e, 0x072d, 0x072f, 0x074b, 0x077f, 0x07b2, 0x0900, 0x0904, 0x0904, 0x093a, 0x093b, 0x094e, 0x094f, 0x0955, 0x0957, 0x0971, 0x0980, 0x0984, 0x0984, 0x098d, 0x098e, 0x0991, 0x0992, 0x09a9, 0x09a9, 0x09b1, 0x09b1, 0x09b3, 0x09b5, 0x09ba, 0x09bb, 0x09bd, 0x09bd, 0x09c5, 0x09c6, 0x09c9, 0x09ca, 0x09ce, 0x09d6, 0x09d8, 0x09db, 0x09de, 0x09de, 0x09e4, 0x09e5, 0x09fb, 0x0a01, 0x0a03, 0x0a04, 0x0a0b, 0x0a0e, 0x0a11, 0x0a12, 0x0a29, 0x0a29, 0x0a31, 0x0a31, 0x0a34, 0x0a34, 0x0a37, 0x0a37, 0x0a3a, 0x0a3b, 0x0a3d, 0x0a3d, 0x0a43, 0x0a46, 0x0a49, 0x0a4a, 0x0a4e, 0x0a58, 0x0a5d, 0x0a5d, 0x0a5f, 0x0a65, 0x0a75, 0x0a80, 0x0a84, 0x0a84, 0x0a8c, 0x0a8c, 0x0a8e, 0x0a8e, 0x0a92, 0x0a92, 0x0aa9, 0x0aa9, 0x0ab1, 0x0ab1, 0x0ab4, 0x0ab4, 0x0aba, 0x0abb, 0x0ac6, 0x0ac6, 0x0aca, 0x0aca, 0x0ace, 0x0acf, 0x0ad1, 0x0adf, 0x0ae1, 0x0ae5, 0x0af0, 0x0b00, 0x0b04, 0x0b04, 0x0b0d, 0x0b0e, 0x0b11, 0x0b12, 0x0b29, 0x0b29, 0x0b31, 0x0b31, 0x0b34, 0x0b35, 0x0b3a, 0x0b3b, 0x0b44, 0x0b46, 0x0b49, 0x0b4a, 0x0b4e, 0x0b55, 0x0b58, 0x0b5b, 0x0b5e, 0x0b5e, 0x0b62, 0x0b65, 0x0b71, 0x0b81, 0x0b84, 0x0b84, 0x0b8b, 0x0b8d, 0x0b91, 0x0b91, 0x0b96, 0x0b98, 0x0b9b, 0x0b9b, 0x0b9d, 0x0b9d, 0x0ba0, 0x0ba2, 0x0ba5, 0x0ba7, 0x0bab, 0x0bad, 0x0bb6, 0x0bb6, 0x0bba, 0x0bbd, 0x0bc3, 0x0bc5, 0x0bc9, 0x0bc9, 0x0bce, 0x0bd6, 0x0bd8, 0x0be6, 0x0bf3, 0x0c00, 0x0c04, 0x0c04, 0x0c0d, 0x0c0d, 0x0c11, 0x0c11, 0x0c29, 0x0c29, 0x0c34, 0x0c34, 0x0c3a, 0x0c3d, 0x0c45, 0x0c45, 0x0c49, 0x0c49, 0x0c4e, 0x0c54, 0x0c57, 0x0c5f, 0x0c62, 0x0c65, 0x0c70, 0x0c81, 0x0c84, 0x0c84, 0x0c8d, 0x0c8d, 0x0c91, 0x0c91, 0x0ca9, 0x0ca9, 0x0cb4, 0x0cb4, 0x0cba, 0x0cbd, 0x0cc5, 0x0cc5, 0x0cc9, 0x0cc9, 0x0cce, 0x0cd4, 0x0cd7, 0x0cdd, 0x0cdf, 0x0cdf, 0x0ce2, 0x0ce5, 0x0cf0, 0x0d01, 0x0d04, 0x0d04, 0x0d0d, 0x0d0d, 0x0d11, 0x0d11, 0x0d29, 0x0d29, 0x0d3a, 0x0d3d, 0x0d44, 0x0d45, 0x0d49, 0x0d49, 0x0d4e, 0x0d56, 0x0d58, 0x0d5f, 0x0d62, 0x0d65, 0x0d70, 0x0d81, 0x0d84, 0x0d84, 0x0d97, 0x0d99, 0x0db2, 0x0db2, 0x0dbc, 0x0dbc, 0x0dbe, 0x0dbf, 0x0dc7, 0x0dc9, 0x0dcb, 0x0dce, 0x0dd5, 0x0dd5, 0x0dd7, 0x0dd7, 0x0de0, 0x0df1, 0x0df5, 0x0e00, 0x0e3b, 0x0e3e, 0x0e5c, 0x0e80, 0x0e83, 0x0e83, 0x0e85, 0x0e86, 0x0e89, 0x0e89, 0x0e8b, 0x0e8c, 0x0e8e, 0x0e93, 0x0e98, 0x0e98, 0x0ea0, 0x0ea0, 0x0ea4, 0x0ea4, 0x0ea6, 0x0ea6, 0x0ea8, 0x0ea9, 0x0eac, 0x0eac, 0x0eba, 0x0eba, 0x0ebe, 0x0ebf, 0x0ec5, 0x0ec5, 0x0ec7, 0x0ec7, 0x0ece, 0x0ecf, 0x0eda, 0x0edb, 0x0ede, 0x0eff, 0x0f48, 0x0f48, 0x0f6b, 0x0f70, 0x0f8c, 0x0f8f, 0x0f98, 0x0f98, 0x0fbd, 0x0fbd, 0x0fcd, 0x0fce, 0x0fd0, 0x0fff, 0x1022, 0x1022, 0x1028, 0x1028, 0x102b, 0x102b, 0x1033, 0x1035, 0x103a, 0x103f, 0x105a, 0x109f, 0x10c6, 0x10cf, 0x10f9, 0x10fa, 0x10fc, 0x10ff, 0x115a, 0x115e, 0x11a3, 0x11a7, 0x11fa, 0x11ff, 0x1207, 0x1207, 0x1247, 0x1247, 0x1249, 0x1249, 0x124e, 0x124f, 0x1257, 0x1257, 0x1259, 0x1259, 0x125e, 0x125f, 0x1287, 0x1287, 0x1289, 0x1289, 0x128e, 0x128f, 0x12af, 0x12af, 0x12b1, 0x12b1, 0x12b6, 0x12b7, 0x12bf, 0x12bf, 0x12c1, 0x12c1, 0x12c6, 0x12c7, 0x12cf, 0x12cf, 0x12d7, 0x12d7, 0x12ef, 0x12ef, 0x130f, 0x130f, 0x1311, 0x1311, 0x1316, 0x1317, 0x131f, 0x131f, 0x1347, 0x1347, 0x135b, 0x1360, 0x137d, 0x139f, 0x13f5, 0x1400, 0x1677, 0x167f, 0x169d, 0x169f, 0x16f1, 0x16ff, 0x170d, 0x170d, 0x1715, 0x171f, 0x1737, 0x173f, 0x1754, 0x175f, 0x176d, 0x176d, 0x1771, 0x1771, 0x1774, 0x177f, 0x17dd, 0x17df, 0x17ea, 0x17ff, 0x180f, 0x180f, 0x181a, 0x181f, 0x1878, 0x187f, 0x18aa, 0x1dff, 0x1e9c, 0x1e9f, 0x1efa, 0x1eff, 0x1f16, 0x1f17, 0x1f1e, 0x1f1f, 0x1f46, 0x1f47, 0x1f4e, 0x1f4f, 0x1f58, 0x1f58, 0x1f5a, 0x1f5a, 0x1f5c, 0x1f5c, 0x1f5e, 0x1f5e, 0x1f7e, 0x1f7f, 0x1fb5, 0x1fb5, 0x1fc5, 0x1fc5, 0x1fd4, 0x1fd5, 0x1fdc, 0x1fdc, 0x1ff0, 0x1ff1, 0x1ff5, 0x1ff5, 0x1fff, 0x1fff, 0x2053, 0x2056, 0x2058, 0x205e, 0x2064, 0x2069, 0x2072, 0x2073, 0x208f, 0x209f, 0x20b2, 0x20cf, 0x20eb, 0x20ff, 0x213b, 0x213c, 0x214c, 0x2152, 0x2184, 0x218f, 0x23cf, 0x23ff, 0x2427, 0x243f, 0x244b, 0x245f, 0x24ff, 0x24ff, 0x2614, 0x2615, 0x2618, 0x2618, 0x267e, 0x267f, 0x268a, 0x2700, 0x2705, 0x2705, 0x270a, 0x270b, 0x2728, 0x2728, 0x274c, 0x274c, 0x274e, 0x274e, 0x2753, 0x2755, 0x2757, 0x2757, 0x275f, 0x2760, 0x2795, 0x2797, 0x27b0, 0x27b0, 0x27bf, 0x27cf, 0x27ec, 0x27ef, 0x2b00, 0x2e7f, 0x2e9a, 0x2e9a, 0x2ef4, 0x2eff, 0x2fd6, 0x2fef, 0x2ffc, 0x2fff, 0x3040, 0x3040, 0x3097, 0x3098, 0x3100, 0x3104, 0x312d, 0x3130, 0x318f, 0x318f, 0x31b8, 0x31ef, 0x321d, 0x321f, 0x3244, 0x3250, 0x327c, 0x327e, 0x32cc, 0x32cf, 0x32ff, 0x32ff, 0x3377, 0x337a, 0x33de, 0x33df, 0x33ff, 0x33ff, 0x4db6, 0x4dff, 0x9fa6, 0x9fff, 0xa48d, 0xa48f, 0xa4c7, 0xabff, 0xd7a4, 0xd7ff, 0xfa2e, 0xfa2f, 0xfa6b, 0xfaff, 0xfb07, 0xfb12, 0xfb18, 0xfb1c, 0xfb37, 0xfb37, 0xfb3d, 0xfb3d, 0xfb3f, 0xfb3f, 0xfb42, 0xfb42, 0xfb45, 0xfb45, 0xfbb2, 0xfbd2, 0xfd40, 0xfd4f, 0xfd90, 0xfd91, 0xfdc8, 0xfdcf, 0xfdfd, 0xfdff, 0xfe10, 0xfe1f, 0xfe24, 0xfe2f, 0xfe47, 0xfe48, 0xfe53, 0xfe53, 0xfe67, 0xfe67, 0xfe6c, 0xfe6f, 0xfe75, 0xfe75, 0xfefd, 0xfefe, 0xff00, 0xff00, 0xffbf, 0xffc1, 0xffc8, 0xffc9, 0xffd0, 0xffd1, 0xffd8, 0xffd9, 0xffdd, 0xffdf, 0xffe7, 0xffe7, 0xffef, 0xfff8, 0x10000, 0x102ff, 0x1031f, 0x1031f, 0x10324, 0x1032f, 0x1034b, 0x103ff, 0x10426, 0x10427, 0x1044e, 0x1cfff, 0x1d0f6, 0x1d0ff, 0x1d127, 0x1d129, 0x1d1de, 0x1d3ff, 0x1d455, 0x1d455, 0x1d49d, 0x1d49d, 0x1d4a0, 0x1d4a1, 0x1d4a3, 0x1d4a4, 0x1d4a7, 0x1d4a8, 0x1d4ad, 0x1d4ad, 0x1d4ba, 0x1d4ba, 0x1d4bc, 0x1d4bc, 0x1d4c1, 0x1d4c1, 0x1d4c4, 0x1d4c4, 0x1d506, 0x1d506, 0x1d50b, 0x1d50c, 0x1d515, 0x1d515, 0x1d51d, 0x1d51d, 0x1d53a, 0x1d53a, 0x1d53f, 0x1d53f, 0x1d545, 0x1d545, 0x1d547, 0x1d549, 0x1d551, 0x1d551, 0x1d6a4, 0x1d6a7, 0x1d7ca, 0x1d7cd, 0x1d800, 0x1fffd, 0x2a6d7, 0x2f7ff, 0x2fa1e, 0x2fffd, 0x30000, 0x3fffd, 0x40000, 0x4fffd, 0x50000, 0x5fffd, 0x60000, 0x6fffd, 0x70000, 0x7fffd, 0x80000, 0x8fffd, 0x90000, 0x9fffd, 0xa0000, 0xafffd, 0xb0000, 0xbfffd, 0xc0000, 0xcfffd, 0xd0000, 0xdfffd, 0xe0000, 0xe0000, 0xe0002, 0xe001f, 0xe0080, 0xefffd];
|
|
442
|
-
// prettier-ignore-end
|
|
443
|
-
|
|
444
464
|
const isUnassignedCodePoint = character => inRange(character, unassigned_code_points);
|
|
445
|
-
|
|
446
|
-
// prettier-ignore-start
|
|
447
|
-
/**
|
|
448
|
-
* B.1 Commonly mapped to nothing
|
|
449
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-B.1
|
|
450
|
-
*/
|
|
451
465
|
const commonly_mapped_to_nothing = [0x00ad, 0x00ad, 0x034f, 0x034f, 0x1806, 0x1806, 0x180b, 0x180b, 0x180c, 0x180c, 0x180d, 0x180d, 0x200b, 0x200b, 0x200c, 0x200c, 0x200d, 0x200d, 0x2060, 0x2060, 0xfe00, 0xfe00, 0xfe01, 0xfe01, 0xfe02, 0xfe02, 0xfe03, 0xfe03, 0xfe04, 0xfe04, 0xfe05, 0xfe05, 0xfe06, 0xfe06, 0xfe07, 0xfe07, 0xfe08, 0xfe08, 0xfe09, 0xfe09, 0xfe0a, 0xfe0a, 0xfe0b, 0xfe0b, 0xfe0c, 0xfe0c, 0xfe0d, 0xfe0d, 0xfe0e, 0xfe0e, 0xfe0f, 0xfe0f, 0xfeff, 0xfeff];
|
|
452
|
-
// prettier-ignore-end
|
|
453
|
-
|
|
454
466
|
const isCommonlyMappedToNothing = character => inRange(character, commonly_mapped_to_nothing);
|
|
455
|
-
|
|
456
|
-
// prettier-ignore-start
|
|
457
|
-
/**
|
|
458
|
-
* C.1.2 Non-ASCII space characters
|
|
459
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.1.2
|
|
460
|
-
*/
|
|
461
|
-
const non_ASCII_space_characters = [0x00a0, 0x00a0 /* NO-BREAK SPACE */, 0x1680, 0x1680 /* OGHAM SPACE MARK */, 0x2000, 0x2000 /* EN QUAD */, 0x2001, 0x2001 /* EM QUAD */, 0x2002, 0x2002 /* EN SPACE */, 0x2003, 0x2003 /* EM SPACE */, 0x2004, 0x2004 /* THREE-PER-EM SPACE */, 0x2005, 0x2005 /* FOUR-PER-EM SPACE */, 0x2006, 0x2006 /* SIX-PER-EM SPACE */, 0x2007, 0x2007 /* FIGURE SPACE */, 0x2008, 0x2008 /* PUNCTUATION SPACE */, 0x2009, 0x2009 /* THIN SPACE */, 0x200a, 0x200a /* HAIR SPACE */, 0x200b, 0x200b /* ZERO WIDTH SPACE */, 0x202f, 0x202f /* NARROW NO-BREAK SPACE */, 0x205f, 0x205f /* MEDIUM MATHEMATICAL SPACE */, 0x3000, 0x3000 /* IDEOGRAPHIC SPACE */];
|
|
462
|
-
// prettier-ignore-end
|
|
463
|
-
|
|
467
|
+
const non_ASCII_space_characters = [0x00a0, 0x00a0, 0x1680, 0x1680, 0x2000, 0x2000, 0x2001, 0x2001, 0x2002, 0x2002, 0x2003, 0x2003, 0x2004, 0x2004, 0x2005, 0x2005, 0x2006, 0x2006, 0x2007, 0x2007, 0x2008, 0x2008, 0x2009, 0x2009, 0x200a, 0x200a, 0x200b, 0x200b, 0x202f, 0x202f, 0x205f, 0x205f, 0x3000, 0x3000];
|
|
464
468
|
const isNonASCIISpaceCharacter = character => inRange(character, non_ASCII_space_characters);
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
const
|
|
468
|
-
/**
|
|
469
|
-
* C.2.2 Non-ASCII control characters
|
|
470
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.2.2
|
|
471
|
-
*/
|
|
472
|
-
0x0080, 0x009f /* [CONTROL CHARACTERS] */, 0x06dd, 0x06dd /* ARABIC END OF AYAH */, 0x070f, 0x070f /* SYRIAC ABBREVIATION MARK */, 0x180e, 0x180e /* MONGOLIAN VOWEL SEPARATOR */, 0x200c, 0x200c /* ZERO WIDTH NON-JOINER */, 0x200d, 0x200d /* ZERO WIDTH JOINER */, 0x2028, 0x2028 /* LINE SEPARATOR */, 0x2029, 0x2029 /* PARAGRAPH SEPARATOR */, 0x2060, 0x2060 /* WORD JOINER */, 0x2061, 0x2061 /* FUNCTION APPLICATION */, 0x2062, 0x2062 /* INVISIBLE TIMES */, 0x2063, 0x2063 /* INVISIBLE SEPARATOR */, 0x206a, 0x206f /* [CONTROL CHARACTERS] */, 0xfeff, 0xfeff /* ZERO WIDTH NO-BREAK SPACE */, 0xfff9, 0xfffc /* [CONTROL CHARACTERS] */, 0x1d173, 0x1d17a /* [MUSICAL CONTROL CHARACTERS] */];
|
|
473
|
-
const non_character_codepoints = [
|
|
474
|
-
/**
|
|
475
|
-
* C.4 Non-character code points
|
|
476
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.4
|
|
477
|
-
*/
|
|
478
|
-
0xfdd0, 0xfdef /* [NONCHARACTER CODE POINTS] */, 0xfffe, 0xffff /* [NONCHARACTER CODE POINTS] */, 0x1fffe, 0x1ffff /* [NONCHARACTER CODE POINTS] */, 0x2fffe, 0x2ffff /* [NONCHARACTER CODE POINTS] */, 0x3fffe, 0x3ffff /* [NONCHARACTER CODE POINTS] */, 0x4fffe, 0x4ffff /* [NONCHARACTER CODE POINTS] */, 0x5fffe, 0x5ffff /* [NONCHARACTER CODE POINTS] */, 0x6fffe, 0x6ffff /* [NONCHARACTER CODE POINTS] */, 0x7fffe, 0x7ffff /* [NONCHARACTER CODE POINTS] */, 0x8fffe, 0x8ffff /* [NONCHARACTER CODE POINTS] */, 0x9fffe, 0x9ffff /* [NONCHARACTER CODE POINTS] */, 0xafffe, 0xaffff /* [NONCHARACTER CODE POINTS] */, 0xbfffe, 0xbffff /* [NONCHARACTER CODE POINTS] */, 0xcfffe, 0xcffff /* [NONCHARACTER CODE POINTS] */, 0xdfffe, 0xdffff /* [NONCHARACTER CODE POINTS] */, 0xefffe, 0xeffff /* [NONCHARACTER CODE POINTS] */, 0x10fffe, 0x10ffff /* [NONCHARACTER CODE POINTS] */];
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* 2.3. Prohibited Output
|
|
482
|
-
*/
|
|
483
|
-
const prohibited_characters = [
|
|
484
|
-
/**
|
|
485
|
-
* C.2.1 ASCII control characters
|
|
486
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.2.1
|
|
487
|
-
*/
|
|
488
|
-
0, 0x001f /* [CONTROL CHARACTERS] */, 0x007f, 0x007f /* DELETE */,
|
|
489
|
-
/**
|
|
490
|
-
* C.8 Change display properties or are deprecated
|
|
491
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.8
|
|
492
|
-
*/
|
|
493
|
-
0x0340, 0x0340 /* COMBINING GRAVE TONE MARK */, 0x0341, 0x0341 /* COMBINING ACUTE TONE MARK */, 0x200e, 0x200e /* LEFT-TO-RIGHT MARK */, 0x200f, 0x200f /* RIGHT-TO-LEFT MARK */, 0x202a, 0x202a /* LEFT-TO-RIGHT EMBEDDING */, 0x202b, 0x202b /* RIGHT-TO-LEFT EMBEDDING */, 0x202c, 0x202c /* POP DIRECTIONAL FORMATTING */, 0x202d, 0x202d /* LEFT-TO-RIGHT OVERRIDE */, 0x202e, 0x202e /* RIGHT-TO-LEFT OVERRIDE */, 0x206a, 0x206a /* INHIBIT SYMMETRIC SWAPPING */, 0x206b, 0x206b /* ACTIVATE SYMMETRIC SWAPPING */, 0x206c, 0x206c /* INHIBIT ARABIC FORM SHAPING */, 0x206d, 0x206d /* ACTIVATE ARABIC FORM SHAPING */, 0x206e, 0x206e /* NATIONAL DIGIT SHAPES */, 0x206f, 0x206f /* NOMINAL DIGIT SHAPES */,
|
|
494
|
-
/**
|
|
495
|
-
* C.7 Inappropriate for canonical representation
|
|
496
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.7
|
|
497
|
-
*/
|
|
498
|
-
0x2ff0, 0x2ffb /* [IDEOGRAPHIC DESCRIPTION CHARACTERS] */,
|
|
499
|
-
/**
|
|
500
|
-
* C.5 Surrogate codes
|
|
501
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.5
|
|
502
|
-
*/
|
|
503
|
-
0xd800, 0xdfff,
|
|
504
|
-
/**
|
|
505
|
-
* C.3 Private use
|
|
506
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.3
|
|
507
|
-
*/
|
|
508
|
-
0xe000, 0xf8ff /* [PRIVATE USE, PLANE 0] */,
|
|
509
|
-
/**
|
|
510
|
-
* C.6 Inappropriate for plain text
|
|
511
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.6
|
|
512
|
-
*/
|
|
513
|
-
0xfff9, 0xfff9 /* INTERLINEAR ANNOTATION ANCHOR */, 0xfffa, 0xfffa /* INTERLINEAR ANNOTATION SEPARATOR */, 0xfffb, 0xfffb /* INTERLINEAR ANNOTATION TERMINATOR */, 0xfffc, 0xfffc /* OBJECT REPLACEMENT CHARACTER */, 0xfffd, 0xfffd /* REPLACEMENT CHARACTER */,
|
|
514
|
-
/**
|
|
515
|
-
* C.9 Tagging characters
|
|
516
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.9
|
|
517
|
-
*/
|
|
518
|
-
0xe0001, 0xe0001 /* LANGUAGE TAG */, 0xe0020, 0xe007f /* [TAGGING CHARACTERS] */,
|
|
519
|
-
/**
|
|
520
|
-
* C.3 Private use
|
|
521
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.3
|
|
522
|
-
*/
|
|
523
|
-
|
|
524
|
-
0xf0000, 0xffffd /* [PRIVATE USE, PLANE 15] */, 0x100000, 0x10fffd /* [PRIVATE USE, PLANE 16] */];
|
|
525
|
-
// prettier-ignore-end
|
|
526
|
-
|
|
469
|
+
const non_ASCII_controls_characters = [0x0080, 0x009f, 0x06dd, 0x06dd, 0x070f, 0x070f, 0x180e, 0x180e, 0x200c, 0x200c, 0x200d, 0x200d, 0x2028, 0x2028, 0x2029, 0x2029, 0x2060, 0x2060, 0x2061, 0x2061, 0x2062, 0x2062, 0x2063, 0x2063, 0x206a, 0x206f, 0xfeff, 0xfeff, 0xfff9, 0xfffc, 0x1d173, 0x1d17a];
|
|
470
|
+
const non_character_codepoints = [0xfdd0, 0xfdef, 0xfffe, 0xffff, 0x1fffe, 0x1ffff, 0x2fffe, 0x2ffff, 0x3fffe, 0x3ffff, 0x4fffe, 0x4ffff, 0x5fffe, 0x5ffff, 0x6fffe, 0x6ffff, 0x7fffe, 0x7ffff, 0x8fffe, 0x8ffff, 0x9fffe, 0x9ffff, 0xafffe, 0xaffff, 0xbfffe, 0xbffff, 0xcfffe, 0xcffff, 0xdfffe, 0xdffff, 0xefffe, 0xeffff, 0x10fffe, 0x10ffff];
|
|
471
|
+
const prohibited_characters = [0, 0x001f, 0x007f, 0x007f, 0x0340, 0x0340, 0x0341, 0x0341, 0x200e, 0x200e, 0x200f, 0x200f, 0x202a, 0x202a, 0x202b, 0x202b, 0x202c, 0x202c, 0x202d, 0x202d, 0x202e, 0x202e, 0x206a, 0x206a, 0x206b, 0x206b, 0x206c, 0x206c, 0x206d, 0x206d, 0x206e, 0x206e, 0x206f, 0x206f, 0x2ff0, 0x2ffb, 0xd800, 0xdfff, 0xe000, 0xf8ff, 0xfff9, 0xfff9, 0xfffa, 0xfffa, 0xfffb, 0xfffb, 0xfffc, 0xfffc, 0xfffd, 0xfffd, 0xe0001, 0xe0001, 0xe0020, 0xe007f, 0xf0000, 0xffffd, 0x100000, 0x10fffd];
|
|
527
472
|
const isProhibitedCharacter = character => inRange(character, non_ASCII_space_characters) || inRange(character, prohibited_characters) || inRange(character, non_ASCII_controls_characters) || inRange(character, non_character_codepoints);
|
|
528
|
-
|
|
529
|
-
// prettier-ignore-start
|
|
530
|
-
/**
|
|
531
|
-
* D.1 Characters with bidirectional property "R" or "AL"
|
|
532
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-D.1
|
|
533
|
-
*/
|
|
534
473
|
const bidirectional_r_al = [0x05be, 0x05be, 0x05c0, 0x05c0, 0x05c3, 0x05c3, 0x05d0, 0x05ea, 0x05f0, 0x05f4, 0x061b, 0x061b, 0x061f, 0x061f, 0x0621, 0x063a, 0x0640, 0x064a, 0x066d, 0x066f, 0x0671, 0x06d5, 0x06dd, 0x06dd, 0x06e5, 0x06e6, 0x06fa, 0x06fe, 0x0700, 0x070d, 0x0710, 0x0710, 0x0712, 0x072c, 0x0780, 0x07a5, 0x07b1, 0x07b1, 0x200f, 0x200f, 0xfb1d, 0xfb1d, 0xfb1f, 0xfb28, 0xfb2a, 0xfb36, 0xfb38, 0xfb3c, 0xfb3e, 0xfb3e, 0xfb40, 0xfb41, 0xfb43, 0xfb44, 0xfb46, 0xfbb1, 0xfbd3, 0xfd3d, 0xfd50, 0xfd8f, 0xfd92, 0xfdc7, 0xfdf0, 0xfdfc, 0xfe70, 0xfe74, 0xfe76, 0xfefc];
|
|
535
|
-
// prettier-ignore-end
|
|
536
|
-
|
|
537
474
|
const isBidirectionalRAL = character => inRange(character, bidirectional_r_al);
|
|
538
|
-
|
|
539
|
-
// prettier-ignore-start
|
|
540
|
-
/**
|
|
541
|
-
* D.2 Characters with bidirectional property "L"
|
|
542
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-D.2
|
|
543
|
-
*/
|
|
544
475
|
const bidirectional_l = [0x0041, 0x005a, 0x0061, 0x007a, 0x00aa, 0x00aa, 0x00b5, 0x00b5, 0x00ba, 0x00ba, 0x00c0, 0x00d6, 0x00d8, 0x00f6, 0x00f8, 0x0220, 0x0222, 0x0233, 0x0250, 0x02ad, 0x02b0, 0x02b8, 0x02bb, 0x02c1, 0x02d0, 0x02d1, 0x02e0, 0x02e4, 0x02ee, 0x02ee, 0x037a, 0x037a, 0x0386, 0x0386, 0x0388, 0x038a, 0x038c, 0x038c, 0x038e, 0x03a1, 0x03a3, 0x03ce, 0x03d0, 0x03f5, 0x0400, 0x0482, 0x048a, 0x04ce, 0x04d0, 0x04f5, 0x04f8, 0x04f9, 0x0500, 0x050f, 0x0531, 0x0556, 0x0559, 0x055f, 0x0561, 0x0587, 0x0589, 0x0589, 0x0903, 0x0903, 0x0905, 0x0939, 0x093d, 0x0940, 0x0949, 0x094c, 0x0950, 0x0950, 0x0958, 0x0961, 0x0964, 0x0970, 0x0982, 0x0983, 0x0985, 0x098c, 0x098f, 0x0990, 0x0993, 0x09a8, 0x09aa, 0x09b0, 0x09b2, 0x09b2, 0x09b6, 0x09b9, 0x09be, 0x09c0, 0x09c7, 0x09c8, 0x09cb, 0x09cc, 0x09d7, 0x09d7, 0x09dc, 0x09dd, 0x09df, 0x09e1, 0x09e6, 0x09f1, 0x09f4, 0x09fa, 0x0a05, 0x0a0a, 0x0a0f, 0x0a10, 0x0a13, 0x0a28, 0x0a2a, 0x0a30, 0x0a32, 0x0a33, 0x0a35, 0x0a36, 0x0a38, 0x0a39, 0x0a3e, 0x0a40, 0x0a59, 0x0a5c, 0x0a5e, 0x0a5e, 0x0a66, 0x0a6f, 0x0a72, 0x0a74, 0x0a83, 0x0a83, 0x0a85, 0x0a8b, 0x0a8d, 0x0a8d, 0x0a8f, 0x0a91, 0x0a93, 0x0aa8, 0x0aaa, 0x0ab0, 0x0ab2, 0x0ab3, 0x0ab5, 0x0ab9, 0x0abd, 0x0ac0, 0x0ac9, 0x0ac9, 0x0acb, 0x0acc, 0x0ad0, 0x0ad0, 0x0ae0, 0x0ae0, 0x0ae6, 0x0aef, 0x0b02, 0x0b03, 0x0b05, 0x0b0c, 0x0b0f, 0x0b10, 0x0b13, 0x0b28, 0x0b2a, 0x0b30, 0x0b32, 0x0b33, 0x0b36, 0x0b39, 0x0b3d, 0x0b3e, 0x0b40, 0x0b40, 0x0b47, 0x0b48, 0x0b4b, 0x0b4c, 0x0b57, 0x0b57, 0x0b5c, 0x0b5d, 0x0b5f, 0x0b61, 0x0b66, 0x0b70, 0x0b83, 0x0b83, 0x0b85, 0x0b8a, 0x0b8e, 0x0b90, 0x0b92, 0x0b95, 0x0b99, 0x0b9a, 0x0b9c, 0x0b9c, 0x0b9e, 0x0b9f, 0x0ba3, 0x0ba4, 0x0ba8, 0x0baa, 0x0bae, 0x0bb5, 0x0bb7, 0x0bb9, 0x0bbe, 0x0bbf, 0x0bc1, 0x0bc2, 0x0bc6, 0x0bc8, 0x0bca, 0x0bcc, 0x0bd7, 0x0bd7, 0x0be7, 0x0bf2, 0x0c01, 0x0c03, 0x0c05, 0x0c0c, 0x0c0e, 0x0c10, 0x0c12, 0x0c28, 0x0c2a, 0x0c33, 0x0c35, 0x0c39, 0x0c41, 0x0c44, 0x0c60, 0x0c61, 0x0c66, 0x0c6f, 0x0c82, 0x0c83, 0x0c85, 0x0c8c, 0x0c8e, 0x0c90, 0x0c92, 0x0ca8, 0x0caa, 0x0cb3, 0x0cb5, 0x0cb9, 0x0cbe, 0x0cbe, 0x0cc0, 0x0cc4, 0x0cc7, 0x0cc8, 0x0cca, 0x0ccb, 0x0cd5, 0x0cd6, 0x0cde, 0x0cde, 0x0ce0, 0x0ce1, 0x0ce6, 0x0cef, 0x0d02, 0x0d03, 0x0d05, 0x0d0c, 0x0d0e, 0x0d10, 0x0d12, 0x0d28, 0x0d2a, 0x0d39, 0x0d3e, 0x0d40, 0x0d46, 0x0d48, 0x0d4a, 0x0d4c, 0x0d57, 0x0d57, 0x0d60, 0x0d61, 0x0d66, 0x0d6f, 0x0d82, 0x0d83, 0x0d85, 0x0d96, 0x0d9a, 0x0db1, 0x0db3, 0x0dbb, 0x0dbd, 0x0dbd, 0x0dc0, 0x0dc6, 0x0dcf, 0x0dd1, 0x0dd8, 0x0ddf, 0x0df2, 0x0df4, 0x0e01, 0x0e30, 0x0e32, 0x0e33, 0x0e40, 0x0e46, 0x0e4f, 0x0e5b, 0x0e81, 0x0e82, 0x0e84, 0x0e84, 0x0e87, 0x0e88, 0x0e8a, 0x0e8a, 0x0e8d, 0x0e8d, 0x0e94, 0x0e97, 0x0e99, 0x0e9f, 0x0ea1, 0x0ea3, 0x0ea5, 0x0ea5, 0x0ea7, 0x0ea7, 0x0eaa, 0x0eab, 0x0ead, 0x0eb0, 0x0eb2, 0x0eb3, 0x0ebd, 0x0ebd, 0x0ec0, 0x0ec4, 0x0ec6, 0x0ec6, 0x0ed0, 0x0ed9, 0x0edc, 0x0edd, 0x0f00, 0x0f17, 0x0f1a, 0x0f34, 0x0f36, 0x0f36, 0x0f38, 0x0f38, 0x0f3e, 0x0f47, 0x0f49, 0x0f6a, 0x0f7f, 0x0f7f, 0x0f85, 0x0f85, 0x0f88, 0x0f8b, 0x0fbe, 0x0fc5, 0x0fc7, 0x0fcc, 0x0fcf, 0x0fcf, 0x1000, 0x1021, 0x1023, 0x1027, 0x1029, 0x102a, 0x102c, 0x102c, 0x1031, 0x1031, 0x1038, 0x1038, 0x1040, 0x1057, 0x10a0, 0x10c5, 0x10d0, 0x10f8, 0x10fb, 0x10fb, 0x1100, 0x1159, 0x115f, 0x11a2, 0x11a8, 0x11f9, 0x1200, 0x1206, 0x1208, 0x1246, 0x1248, 0x1248, 0x124a, 0x124d, 0x1250, 0x1256, 0x1258, 0x1258, 0x125a, 0x125d, 0x1260, 0x1286, 0x1288, 0x1288, 0x128a, 0x128d, 0x1290, 0x12ae, 0x12b0, 0x12b0, 0x12b2, 0x12b5, 0x12b8, 0x12be, 0x12c0, 0x12c0, 0x12c2, 0x12c5, 0x12c8, 0x12ce, 0x12d0, 0x12d6, 0x12d8, 0x12ee, 0x12f0, 0x130e, 0x1310, 0x1310, 0x1312, 0x1315, 0x1318, 0x131e, 0x1320, 0x1346, 0x1348, 0x135a, 0x1361, 0x137c, 0x13a0, 0x13f4, 0x1401, 0x1676, 0x1681, 0x169a, 0x16a0, 0x16f0, 0x1700, 0x170c, 0x170e, 0x1711, 0x1720, 0x1731, 0x1735, 0x1736, 0x1740, 0x1751, 0x1760, 0x176c, 0x176e, 0x1770, 0x1780, 0x17b6, 0x17be, 0x17c5, 0x17c7, 0x17c8, 0x17d4, 0x17da, 0x17dc, 0x17dc, 0x17e0, 0x17e9, 0x1810, 0x1819, 0x1820, 0x1877, 0x1880, 0x18a8, 0x1e00, 0x1e9b, 0x1ea0, 0x1ef9, 0x1f00, 0x1f15, 0x1f18, 0x1f1d, 0x1f20, 0x1f45, 0x1f48, 0x1f4d, 0x1f50, 0x1f57, 0x1f59, 0x1f59, 0x1f5b, 0x1f5b, 0x1f5d, 0x1f5d, 0x1f5f, 0x1f7d, 0x1f80, 0x1fb4, 0x1fb6, 0x1fbc, 0x1fbe, 0x1fbe, 0x1fc2, 0x1fc4, 0x1fc6, 0x1fcc, 0x1fd0, 0x1fd3, 0x1fd6, 0x1fdb, 0x1fe0, 0x1fec, 0x1ff2, 0x1ff4, 0x1ff6, 0x1ffc, 0x200e, 0x200e, 0x2071, 0x2071, 0x207f, 0x207f, 0x2102, 0x2102, 0x2107, 0x2107, 0x210a, 0x2113, 0x2115, 0x2115, 0x2119, 0x211d, 0x2124, 0x2124, 0x2126, 0x2126, 0x2128, 0x2128, 0x212a, 0x212d, 0x212f, 0x2131, 0x2133, 0x2139, 0x213d, 0x213f, 0x2145, 0x2149, 0x2160, 0x2183, 0x2336, 0x237a, 0x2395, 0x2395, 0x249c, 0x24e9, 0x3005, 0x3007, 0x3021, 0x3029, 0x3031, 0x3035, 0x3038, 0x303c, 0x3041, 0x3096, 0x309d, 0x309f, 0x30a1, 0x30fa, 0x30fc, 0x30ff, 0x3105, 0x312c, 0x3131, 0x318e, 0x3190, 0x31b7, 0x31f0, 0x321c, 0x3220, 0x3243, 0x3260, 0x327b, 0x327f, 0x32b0, 0x32c0, 0x32cb, 0x32d0, 0x32fe, 0x3300, 0x3376, 0x337b, 0x33dd, 0x33e0, 0x33fe, 0x3400, 0x4db5, 0x4e00, 0x9fa5, 0xa000, 0xa48c, 0xac00, 0xd7a3, 0xd800, 0xfa2d, 0xfa30, 0xfa6a, 0xfb00, 0xfb06, 0xfb13, 0xfb17, 0xff21, 0xff3a, 0xff41, 0xff5a, 0xff66, 0xffbe, 0xffc2, 0xffc7, 0xffca, 0xffcf, 0xffd2, 0xffd7, 0xffda, 0xffdc, 0x10300, 0x1031e, 0x10320, 0x10323, 0x10330, 0x1034a, 0x10400, 0x10425, 0x10428, 0x1044d, 0x1d000, 0x1d0f5, 0x1d100, 0x1d126, 0x1d12a, 0x1d166, 0x1d16a, 0x1d172, 0x1d183, 0x1d184, 0x1d18c, 0x1d1a9, 0x1d1ae, 0x1d1dd, 0x1d400, 0x1d454, 0x1d456, 0x1d49c, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a2, 0x1d4a5, 0x1d4a6, 0x1d4a9, 0x1d4ac, 0x1d4ae, 0x1d4b9, 0x1d4bb, 0x1d4bb, 0x1d4bd, 0x1d4c0, 0x1d4c2, 0x1d4c3, 0x1d4c5, 0x1d505, 0x1d507, 0x1d50a, 0x1d50d, 0x1d514, 0x1d516, 0x1d51c, 0x1d51e, 0x1d539, 0x1d53b, 0x1d53e, 0x1d540, 0x1d544, 0x1d546, 0x1d546, 0x1d54a, 0x1d550, 0x1d552, 0x1d6a3, 0x1d6a8, 0x1d7c9, 0x20000, 0x2a6d6, 0x2f800, 0x2fa1d, 0xf0000, 0xffffd, 0x100000, 0x10fffd];
|
|
545
|
-
// prettier-ignore-end
|
|
546
|
-
|
|
547
476
|
const isBidirectionalL = character => inRange(character, bidirectional_l);
|
|
548
477
|
|
|
549
|
-
// 2.1. Mapping
|
|
550
|
-
|
|
551
|
-
/**
|
|
552
|
-
* non-ASCII space characters [StringPrep, C.1.2] that can be
|
|
553
|
-
* mapped to SPACE (U+0020)
|
|
554
|
-
*/
|
|
555
478
|
const mapping2space = isNonASCIISpaceCharacter;
|
|
556
|
-
|
|
557
|
-
/**
|
|
558
|
-
* the "commonly mapped to nothing" characters [StringPrep, B.1]
|
|
559
|
-
* that can be mapped to nothing.
|
|
560
|
-
*/
|
|
561
479
|
const mapping2nothing = isCommonlyMappedToNothing;
|
|
562
|
-
|
|
563
|
-
// utils
|
|
564
480
|
const getCodePoint = character => character.codePointAt(0);
|
|
565
481
|
const first = x => x[0];
|
|
566
482
|
const last = x => x[x.length - 1];
|
|
567
|
-
|
|
568
|
-
/**
|
|
569
|
-
* Convert provided string into an array of Unicode Code Points.
|
|
570
|
-
* Based on https://stackoverflow.com/a/21409165/1556249
|
|
571
|
-
* and https://www.npmjs.com/package/code-point-at.
|
|
572
|
-
* @param {string} input
|
|
573
|
-
* @returns {number[]}
|
|
574
|
-
*/
|
|
575
483
|
function toCodePoints(input) {
|
|
576
484
|
const codepoints = [];
|
|
577
485
|
const size = input.length;
|
|
@@ -589,14 +497,6 @@ function toCodePoints(input) {
|
|
|
589
497
|
}
|
|
590
498
|
return codepoints;
|
|
591
499
|
}
|
|
592
|
-
|
|
593
|
-
/**
|
|
594
|
-
* SASLprep.
|
|
595
|
-
* @param {string} input
|
|
596
|
-
* @param {Object} opts
|
|
597
|
-
* @param {boolean} opts.allowUnassigned
|
|
598
|
-
* @returns {string}
|
|
599
|
-
*/
|
|
600
500
|
function saslprep(input) {
|
|
601
501
|
let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
602
502
|
if (typeof input !== 'string') {
|
|
@@ -605,49 +505,24 @@ function saslprep(input) {
|
|
|
605
505
|
if (input.length === 0) {
|
|
606
506
|
return '';
|
|
607
507
|
}
|
|
608
|
-
|
|
609
|
-
// 1. Map
|
|
610
|
-
const mapped_input = toCodePoints(input)
|
|
611
|
-
// 1.1 mapping to space
|
|
612
|
-
.map(character => mapping2space(character) ? 0x20 : character)
|
|
613
|
-
// 1.2 mapping to nothing
|
|
614
|
-
.filter(character => !mapping2nothing(character));
|
|
615
|
-
|
|
616
|
-
// 2. Normalize
|
|
508
|
+
const mapped_input = toCodePoints(input).map(character => mapping2space(character) ? 0x20 : character).filter(character => !mapping2nothing(character));
|
|
617
509
|
const normalized_input = String.fromCodePoint.apply(null, mapped_input).normalize('NFKC');
|
|
618
510
|
const normalized_map = toCodePoints(normalized_input);
|
|
619
|
-
|
|
620
|
-
// 3. Prohibit
|
|
621
511
|
const hasProhibited = normalized_map.some(isProhibitedCharacter);
|
|
622
512
|
if (hasProhibited) {
|
|
623
513
|
throw new Error('Prohibited character, see https://tools.ietf.org/html/rfc4013#section-2.3');
|
|
624
514
|
}
|
|
625
|
-
|
|
626
|
-
// Unassigned Code Points
|
|
627
515
|
if (opts.allowUnassigned !== true) {
|
|
628
516
|
const hasUnassigned = normalized_map.some(isUnassignedCodePoint);
|
|
629
517
|
if (hasUnassigned) {
|
|
630
518
|
throw new Error('Unassigned code point, see https://tools.ietf.org/html/rfc4013#section-2.5');
|
|
631
519
|
}
|
|
632
520
|
}
|
|
633
|
-
|
|
634
|
-
// 4. check bidi
|
|
635
|
-
|
|
636
521
|
const hasBidiRAL = normalized_map.some(isBidirectionalRAL);
|
|
637
522
|
const hasBidiL = normalized_map.some(isBidirectionalL);
|
|
638
|
-
|
|
639
|
-
// 4.1 If a string contains any RandALCat character, the string MUST NOT
|
|
640
|
-
// contain any LCat character.
|
|
641
523
|
if (hasBidiRAL && hasBidiL) {
|
|
642
524
|
throw new Error('String must not contain RandALCat and LCat at the same time,' + ' see https://tools.ietf.org/html/rfc3454#section-6');
|
|
643
525
|
}
|
|
644
|
-
|
|
645
|
-
/**
|
|
646
|
-
* 4.2 If a string contains any RandALCat character, a RandALCat
|
|
647
|
-
* character MUST be the first character of the string, and a
|
|
648
|
-
* RandALCat character MUST be the last character of the string.
|
|
649
|
-
*/
|
|
650
|
-
|
|
651
526
|
const isFirstBidiRAL = isBidirectionalRAL(getCodePoint(first(normalized_input)));
|
|
652
527
|
const isLastBidiRAL = isBidirectionalRAL(getCodePoint(last(normalized_input)));
|
|
653
528
|
if (hasBidiRAL && !(isFirstBidiRAL && isLastBidiRAL)) {
|
|
@@ -656,16 +531,11 @@ function saslprep(input) {
|
|
|
656
531
|
return normalized_input;
|
|
657
532
|
}
|
|
658
533
|
|
|
659
|
-
/*
|
|
660
|
-
PDFSecurity - represents PDF security settings
|
|
661
|
-
By Yang Liu <hi@zesik.com>
|
|
662
|
-
*/
|
|
663
534
|
class PDFSecurity {
|
|
664
535
|
static generateFileID() {
|
|
665
536
|
let info = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
666
537
|
let infoStr = `${info.CreationDate.getTime()}\n`;
|
|
667
538
|
for (let key in info) {
|
|
668
|
-
// eslint-disable-next-line no-prototype-builtins
|
|
669
539
|
if (!info.hasOwnProperty(key)) {
|
|
670
540
|
continue;
|
|
671
541
|
}
|
|
@@ -1002,9 +872,9 @@ function wordArrayToBuffer(wordArray) {
|
|
|
1002
872
|
const PASSWORD_PADDING = [0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a];
|
|
1003
873
|
|
|
1004
874
|
const {
|
|
1005
|
-
number
|
|
875
|
+
number: number$2
|
|
1006
876
|
} = PDFObject;
|
|
1007
|
-
class PDFGradient {
|
|
877
|
+
class PDFGradient$1 {
|
|
1008
878
|
constructor(doc) {
|
|
1009
879
|
this.doc = doc;
|
|
1010
880
|
this.stops = [];
|
|
@@ -1045,8 +915,6 @@ class PDFGradient {
|
|
|
1045
915
|
}
|
|
1046
916
|
this.embedded = true;
|
|
1047
917
|
this.matrix = m;
|
|
1048
|
-
|
|
1049
|
-
// if the last stop comes before 100%, add a copy at 100%
|
|
1050
918
|
const last = this.stops[stopsLength - 1];
|
|
1051
919
|
if (last[0] < 1) {
|
|
1052
920
|
this.stops.push([1, last[1], last[2]]);
|
|
@@ -1069,14 +937,11 @@ class PDFGradient {
|
|
|
1069
937
|
stops.push(fn);
|
|
1070
938
|
fn.end();
|
|
1071
939
|
}
|
|
1072
|
-
|
|
1073
|
-
// if there are only two stops, we don't need a stitching function
|
|
1074
940
|
if (stopsLength === 1) {
|
|
1075
941
|
fn = stops[0];
|
|
1076
942
|
} else {
|
|
1077
943
|
fn = this.doc.ref({
|
|
1078
944
|
FunctionType: 3,
|
|
1079
|
-
// stitching function
|
|
1080
945
|
Domain: [0, 1],
|
|
1081
946
|
Functions: stops,
|
|
1082
947
|
Bounds: bounds,
|
|
@@ -1091,7 +956,7 @@ class PDFGradient {
|
|
|
1091
956
|
Type: 'Pattern',
|
|
1092
957
|
PatternType: 2,
|
|
1093
958
|
Shading: shader,
|
|
1094
|
-
Matrix: this.matrix.map(number)
|
|
959
|
+
Matrix: this.matrix.map(number$2)
|
|
1095
960
|
});
|
|
1096
961
|
pattern.end();
|
|
1097
962
|
if (this.stops.some(stop => stop[2] < 1)) {
|
|
@@ -1157,7 +1022,6 @@ class PDFGradient {
|
|
|
1157
1022
|
return pattern;
|
|
1158
1023
|
}
|
|
1159
1024
|
apply(stroke) {
|
|
1160
|
-
// apply gradient transform to existing document ctm
|
|
1161
1025
|
const [m0, m1, m2, m3, m4, m5] = this.doc._ctm;
|
|
1162
1026
|
const [m11, m12, m21, m22, dx, dy] = this.transform;
|
|
1163
1027
|
const 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];
|
|
@@ -1169,7 +1033,7 @@ class PDFGradient {
|
|
|
1169
1033
|
return this.doc.addContent(`/${this.id} ${op}`);
|
|
1170
1034
|
}
|
|
1171
1035
|
}
|
|
1172
|
-
class PDFLinearGradient extends PDFGradient {
|
|
1036
|
+
class PDFLinearGradient$1 extends PDFGradient$1 {
|
|
1173
1037
|
constructor(doc, x1, y1, x2, y2) {
|
|
1174
1038
|
super(doc);
|
|
1175
1039
|
this.x1 = x1;
|
|
@@ -1187,10 +1051,10 @@ class PDFLinearGradient extends PDFGradient {
|
|
|
1187
1051
|
});
|
|
1188
1052
|
}
|
|
1189
1053
|
opacityGradient() {
|
|
1190
|
-
return new PDFLinearGradient(this.doc, this.x1, this.y1, this.x2, this.y2);
|
|
1054
|
+
return new PDFLinearGradient$1(this.doc, this.x1, this.y1, this.x2, this.y2);
|
|
1191
1055
|
}
|
|
1192
1056
|
}
|
|
1193
|
-
class PDFRadialGradient extends PDFGradient {
|
|
1057
|
+
class PDFRadialGradient$1 extends PDFGradient$1 {
|
|
1194
1058
|
constructor(doc, x1, y1, r1, x2, y2, r2) {
|
|
1195
1059
|
super(doc);
|
|
1196
1060
|
this.doc = doc;
|
|
@@ -1211,21 +1075,17 @@ class PDFRadialGradient extends PDFGradient {
|
|
|
1211
1075
|
});
|
|
1212
1076
|
}
|
|
1213
1077
|
opacityGradient() {
|
|
1214
|
-
return new PDFRadialGradient(this.doc, this.x1, this.y1, this.r1, this.x2, this.y2, this.r2);
|
|
1078
|
+
return new PDFRadialGradient$1(this.doc, this.x1, this.y1, this.r1, this.x2, this.y2, this.r2);
|
|
1215
1079
|
}
|
|
1216
1080
|
}
|
|
1217
1081
|
var Gradient = {
|
|
1218
|
-
PDFGradient,
|
|
1219
|
-
PDFLinearGradient,
|
|
1220
|
-
PDFRadialGradient
|
|
1082
|
+
PDFGradient: PDFGradient$1,
|
|
1083
|
+
PDFLinearGradient: PDFLinearGradient$1,
|
|
1084
|
+
PDFRadialGradient: PDFRadialGradient$1
|
|
1221
1085
|
};
|
|
1222
1086
|
|
|
1223
|
-
/*
|
|
1224
|
-
PDF tiling pattern support. Uncolored only.
|
|
1225
|
-
*/
|
|
1226
|
-
|
|
1227
1087
|
const underlyingColorSpaces = ['DeviceCMYK', 'DeviceRGB'];
|
|
1228
|
-
class PDFTilingPattern {
|
|
1088
|
+
class PDFTilingPattern$1 {
|
|
1229
1089
|
constructor(doc, bBox, xStep, yStep, stream) {
|
|
1230
1090
|
this.doc = doc;
|
|
1231
1091
|
this.bBox = bBox;
|
|
@@ -1234,23 +1094,16 @@ class PDFTilingPattern {
|
|
|
1234
1094
|
this.stream = stream;
|
|
1235
1095
|
}
|
|
1236
1096
|
createPattern() {
|
|
1237
|
-
// no resources needed for our current usage
|
|
1238
|
-
// required entry
|
|
1239
1097
|
const resources = this.doc.ref();
|
|
1240
1098
|
resources.end();
|
|
1241
|
-
// apply default transform matrix (flipped in the default doc._ctm)
|
|
1242
|
-
// see document.js & gradient.js
|
|
1243
1099
|
const [m0, m1, m2, m3, m4, m5] = this.doc._ctm;
|
|
1244
1100
|
const [m11, m12, m21, m22, dx, dy] = [1, 0, 0, 1, 0, 0];
|
|
1245
1101
|
const 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];
|
|
1246
1102
|
const pattern = this.doc.ref({
|
|
1247
1103
|
Type: 'Pattern',
|
|
1248
1104
|
PatternType: 1,
|
|
1249
|
-
// tiling
|
|
1250
1105
|
PaintType: 2,
|
|
1251
|
-
// 1-colored, 2-uncolored
|
|
1252
1106
|
TilingType: 2,
|
|
1253
|
-
// 2-no distortion
|
|
1254
1107
|
BBox: this.bBox,
|
|
1255
1108
|
XStep: this.xStep,
|
|
1256
1109
|
YStep: this.yStep,
|
|
@@ -1261,8 +1114,6 @@ class PDFTilingPattern {
|
|
|
1261
1114
|
return pattern;
|
|
1262
1115
|
}
|
|
1263
1116
|
embedPatternColorSpaces() {
|
|
1264
|
-
// map each pattern to an underlying color space
|
|
1265
|
-
// and embed on each page
|
|
1266
1117
|
underlyingColorSpaces.forEach(csName => {
|
|
1267
1118
|
const csId = this.getPatternColorSpaceId(csName);
|
|
1268
1119
|
if (this.doc.page.colorSpaces[csId]) return;
|
|
@@ -1280,47 +1131,40 @@ class PDFTilingPattern {
|
|
|
1280
1131
|
this.id = 'P' + this.doc._patternCount;
|
|
1281
1132
|
this.pattern = this.createPattern();
|
|
1282
1133
|
}
|
|
1283
|
-
|
|
1284
|
-
// patterns are embedded in each page
|
|
1285
1134
|
if (!this.doc.page.patterns[this.id]) {
|
|
1286
1135
|
this.doc.page.patterns[this.id] = this.pattern;
|
|
1287
1136
|
}
|
|
1288
1137
|
}
|
|
1289
1138
|
apply(stroke, patternColor) {
|
|
1290
|
-
// do any embedding/creating that might be needed
|
|
1291
1139
|
this.embedPatternColorSpaces();
|
|
1292
1140
|
this.embed();
|
|
1293
1141
|
const normalizedColor = this.doc._normalizeColor(patternColor);
|
|
1294
1142
|
if (!normalizedColor) throw Error(`invalid pattern color. (value: ${patternColor})`);
|
|
1295
|
-
|
|
1296
|
-
// select one of the pattern color spaces
|
|
1297
1143
|
const csId = this.getPatternColorSpaceId(this.doc._getColorSpace(normalizedColor));
|
|
1298
1144
|
this.doc._setColorSpace(csId, stroke);
|
|
1299
|
-
|
|
1300
|
-
// stroke/fill using the pattern and color (in the above underlying color space)
|
|
1301
1145
|
const op = stroke ? 'SCN' : 'scn';
|
|
1302
1146
|
return this.doc.addContent(`${normalizedColor.join(' ')} /${this.id} ${op}`);
|
|
1303
1147
|
}
|
|
1304
1148
|
}
|
|
1305
1149
|
var pattern = {
|
|
1306
|
-
PDFTilingPattern
|
|
1150
|
+
PDFTilingPattern: PDFTilingPattern$1
|
|
1307
1151
|
};
|
|
1308
1152
|
|
|
1309
1153
|
const {
|
|
1310
|
-
PDFGradient
|
|
1311
|
-
PDFLinearGradient
|
|
1312
|
-
PDFRadialGradient
|
|
1154
|
+
PDFGradient,
|
|
1155
|
+
PDFLinearGradient,
|
|
1156
|
+
PDFRadialGradient
|
|
1313
1157
|
} = Gradient;
|
|
1314
1158
|
const {
|
|
1315
|
-
PDFTilingPattern
|
|
1159
|
+
PDFTilingPattern
|
|
1316
1160
|
} = pattern;
|
|
1317
1161
|
var ColorMixin = {
|
|
1318
1162
|
initColor() {
|
|
1319
|
-
|
|
1163
|
+
this.spotColors = {};
|
|
1320
1164
|
this._opacityRegistry = {};
|
|
1321
1165
|
this._opacityCount = 0;
|
|
1322
1166
|
this._patternCount = 0;
|
|
1323
|
-
|
|
1167
|
+
this._gradCount = 0;
|
|
1324
1168
|
},
|
|
1325
1169
|
_normalizeColor(color) {
|
|
1326
1170
|
if (typeof color === 'string') {
|
|
@@ -1332,13 +1176,13 @@ var ColorMixin = {
|
|
|
1332
1176
|
color = [hex >> 16, hex >> 8 & 0xff, hex & 0xff];
|
|
1333
1177
|
} else if (namedColors[color]) {
|
|
1334
1178
|
color = namedColors[color];
|
|
1179
|
+
} else if (this.spotColors[color]) {
|
|
1180
|
+
return this.spotColors[color];
|
|
1335
1181
|
}
|
|
1336
1182
|
}
|
|
1337
1183
|
if (Array.isArray(color)) {
|
|
1338
|
-
// RGB
|
|
1339
1184
|
if (color.length === 3) {
|
|
1340
1185
|
color = color.map(part => part / 255);
|
|
1341
|
-
// CMYK
|
|
1342
1186
|
} else if (color.length === 4) {
|
|
1343
1187
|
color = color.map(part => part / 100);
|
|
1344
1188
|
}
|
|
@@ -1347,15 +1191,13 @@ var ColorMixin = {
|
|
|
1347
1191
|
return null;
|
|
1348
1192
|
},
|
|
1349
1193
|
_setColor(color, stroke) {
|
|
1350
|
-
if (color instanceof PDFGradient
|
|
1194
|
+
if (color instanceof PDFGradient) {
|
|
1351
1195
|
color.apply(stroke);
|
|
1352
1196
|
return true;
|
|
1353
|
-
|
|
1354
|
-
} else if (Array.isArray(color) && color[0] instanceof PDFTilingPattern$1) {
|
|
1197
|
+
} else if (Array.isArray(color) && color[0] instanceof PDFTilingPattern) {
|
|
1355
1198
|
color[0].apply(stroke, color[1]);
|
|
1356
1199
|
return true;
|
|
1357
1200
|
}
|
|
1358
|
-
// any other case should be a normal color and not a pattern
|
|
1359
1201
|
return this._setColorCore(color, stroke);
|
|
1360
1202
|
},
|
|
1361
1203
|
_setColorCore(color, stroke) {
|
|
@@ -1366,8 +1208,12 @@ var ColorMixin = {
|
|
|
1366
1208
|
const op = stroke ? 'SCN' : 'scn';
|
|
1367
1209
|
const space = this._getColorSpace(color);
|
|
1368
1210
|
this._setColorSpace(space, stroke);
|
|
1369
|
-
color
|
|
1370
|
-
|
|
1211
|
+
if (color instanceof SpotColor) {
|
|
1212
|
+
this.page.colorSpaces[color.id] = color.ref;
|
|
1213
|
+
this.addContent(`1 ${op}`);
|
|
1214
|
+
} else {
|
|
1215
|
+
this.addContent(`${color.join(' ')} ${op}`);
|
|
1216
|
+
}
|
|
1371
1217
|
return true;
|
|
1372
1218
|
},
|
|
1373
1219
|
_setColorSpace(space, stroke) {
|
|
@@ -1375,6 +1221,9 @@ var ColorMixin = {
|
|
|
1375
1221
|
return this.addContent(`/${space} ${op}`);
|
|
1376
1222
|
},
|
|
1377
1223
|
_getColorSpace(color) {
|
|
1224
|
+
if (color instanceof SpotColor) {
|
|
1225
|
+
return color.id;
|
|
1226
|
+
}
|
|
1378
1227
|
return color.length === 4 ? 'DeviceCMYK' : 'DeviceRGB';
|
|
1379
1228
|
},
|
|
1380
1229
|
fillColor(color, opacity) {
|
|
@@ -1382,9 +1231,6 @@ var ColorMixin = {
|
|
|
1382
1231
|
if (set) {
|
|
1383
1232
|
this.fillOpacity(opacity);
|
|
1384
1233
|
}
|
|
1385
|
-
|
|
1386
|
-
// save this for text wrapper, which needs to reset
|
|
1387
|
-
// the fill color on new pages
|
|
1388
1234
|
this._fillColor = [color, opacity];
|
|
1389
1235
|
return this;
|
|
1390
1236
|
},
|
|
@@ -1441,13 +1287,18 @@ var ColorMixin = {
|
|
|
1441
1287
|
return this.addContent(`/${name} gs`);
|
|
1442
1288
|
},
|
|
1443
1289
|
linearGradient(x1, y1, x2, y2) {
|
|
1444
|
-
return new PDFLinearGradient
|
|
1290
|
+
return new PDFLinearGradient(this, x1, y1, x2, y2);
|
|
1445
1291
|
},
|
|
1446
1292
|
radialGradient(x1, y1, r1, x2, y2, r2) {
|
|
1447
|
-
return new PDFRadialGradient
|
|
1293
|
+
return new PDFRadialGradient(this, x1, y1, r1, x2, y2, r2);
|
|
1448
1294
|
},
|
|
1449
1295
|
pattern(bbox, xStep, yStep, stream) {
|
|
1450
|
-
return new PDFTilingPattern
|
|
1296
|
+
return new PDFTilingPattern(this, bbox, xStep, yStep, stream);
|
|
1297
|
+
},
|
|
1298
|
+
addSpotColor(name, C, M, Y, K) {
|
|
1299
|
+
const color = new SpotColor(this, name, C, M, Y, K);
|
|
1300
|
+
this.spotColors[name] = color;
|
|
1301
|
+
return this;
|
|
1451
1302
|
}
|
|
1452
1303
|
};
|
|
1453
1304
|
var namedColors = {
|
|
@@ -1635,7 +1486,6 @@ const parse = function (path) {
|
|
|
1635
1486
|
if (parameters[c] != null) {
|
|
1636
1487
|
params = parameters[c];
|
|
1637
1488
|
if (cmd) {
|
|
1638
|
-
// save existing command
|
|
1639
1489
|
if (curArg.length > 0) {
|
|
1640
1490
|
args[args.length] = +curArg;
|
|
1641
1491
|
}
|
|
@@ -1653,14 +1503,11 @@ const parse = function (path) {
|
|
|
1653
1503
|
continue;
|
|
1654
1504
|
}
|
|
1655
1505
|
if (args.length === params) {
|
|
1656
|
-
// handle reused commands
|
|
1657
1506
|
ret[ret.length] = {
|
|
1658
1507
|
cmd,
|
|
1659
1508
|
args
|
|
1660
1509
|
};
|
|
1661
1510
|
args = [+curArg];
|
|
1662
|
-
|
|
1663
|
-
// handle assumed commands
|
|
1664
1511
|
if (cmd === 'M') {
|
|
1665
1512
|
cmd = 'L';
|
|
1666
1513
|
}
|
|
@@ -1671,8 +1518,6 @@ const parse = function (path) {
|
|
|
1671
1518
|
args[args.length] = +curArg;
|
|
1672
1519
|
}
|
|
1673
1520
|
foundDecimal = c === '.';
|
|
1674
|
-
|
|
1675
|
-
// fix for negative numbers or repeated decimals with no delimeter between commands
|
|
1676
1521
|
curArg = ['-', '.'].includes(c) ? c : '';
|
|
1677
1522
|
} else {
|
|
1678
1523
|
curArg += c;
|
|
@@ -1681,18 +1526,13 @@ const parse = function (path) {
|
|
|
1681
1526
|
}
|
|
1682
1527
|
}
|
|
1683
1528
|
}
|
|
1684
|
-
|
|
1685
|
-
// add the last command
|
|
1686
1529
|
if (curArg.length > 0) {
|
|
1687
1530
|
if (args.length === params) {
|
|
1688
|
-
// handle reused commands
|
|
1689
1531
|
ret[ret.length] = {
|
|
1690
1532
|
cmd,
|
|
1691
1533
|
args
|
|
1692
1534
|
};
|
|
1693
1535
|
args = [+curArg];
|
|
1694
|
-
|
|
1695
|
-
// handle assumed commands
|
|
1696
1536
|
if (cmd === 'M') {
|
|
1697
1537
|
cmd = 'L';
|
|
1698
1538
|
}
|
|
@@ -1710,10 +1550,7 @@ const parse = function (path) {
|
|
|
1710
1550
|
return ret;
|
|
1711
1551
|
};
|
|
1712
1552
|
const apply = function (commands, doc) {
|
|
1713
|
-
// current point, control point, and subpath starting point
|
|
1714
1553
|
cx = cy = px = py = sx = sy = 0;
|
|
1715
|
-
|
|
1716
|
-
// run the commands
|
|
1717
1554
|
for (let i = 0; i < commands.length; i++) {
|
|
1718
1555
|
const c = commands[i];
|
|
1719
1556
|
if (typeof runners[c.cmd] === 'function') {
|
|
@@ -1877,8 +1714,6 @@ const solveArc = function (doc, x, y, coords) {
|
|
|
1877
1714
|
doc.bezierCurveTo(...bez);
|
|
1878
1715
|
}
|
|
1879
1716
|
};
|
|
1880
|
-
|
|
1881
|
-
// from Inkscape svgtopdf, thanks!
|
|
1882
1717
|
const arcToSegments = function (x, y, rx, ry, large, sweep, rotateX, ox, oy) {
|
|
1883
1718
|
const th = rotateX * (Math.PI / 180);
|
|
1884
1719
|
const sin_th = Math.sin(th);
|
|
@@ -1954,18 +1789,14 @@ class SVGPath {
|
|
|
1954
1789
|
const {
|
|
1955
1790
|
number: number$1
|
|
1956
1791
|
} = PDFObject;
|
|
1957
|
-
|
|
1958
|
-
// This constant is used to approximate a symmetrical arc using a cubic
|
|
1959
|
-
// Bezier curve.
|
|
1960
1792
|
const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);
|
|
1961
1793
|
var VectorMixin = {
|
|
1962
1794
|
initVector() {
|
|
1963
|
-
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
1964
|
-
|
|
1795
|
+
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
1796
|
+
this._ctmStack = [];
|
|
1965
1797
|
},
|
|
1966
1798
|
save() {
|
|
1967
1799
|
this._ctmStack.push(this._ctm.slice());
|
|
1968
|
-
// TODO: save/restore colorspace and styles so not setting it unnessesarily all the time?
|
|
1969
1800
|
return this.addContent('q');
|
|
1970
1801
|
},
|
|
1971
1802
|
restore() {
|
|
@@ -2039,8 +1870,6 @@ var VectorMixin = {
|
|
|
2039
1870
|
r = 0;
|
|
2040
1871
|
}
|
|
2041
1872
|
r = Math.min(r, 0.5 * w, 0.5 * h);
|
|
2042
|
-
|
|
2043
|
-
// amount to inset control points from corners (see `ellipse`)
|
|
2044
1873
|
const c = r * (1.0 - KAPPA);
|
|
2045
1874
|
this.moveTo(x + r, y);
|
|
2046
1875
|
this.lineTo(x + w - r, y);
|
|
@@ -2054,7 +1883,6 @@ var VectorMixin = {
|
|
|
2054
1883
|
return this.closePath();
|
|
2055
1884
|
},
|
|
2056
1885
|
ellipse(x, y, r1, r2) {
|
|
2057
|
-
// based on http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas/2173084#2173084
|
|
2058
1886
|
if (r2 == null) {
|
|
2059
1887
|
r2 = r1;
|
|
2060
1888
|
}
|
|
@@ -2084,10 +1912,8 @@ var VectorMixin = {
|
|
|
2084
1912
|
const HALF_PI = 0.5 * Math.PI;
|
|
2085
1913
|
let deltaAng = endAngle - startAngle;
|
|
2086
1914
|
if (Math.abs(deltaAng) > TWO_PI) {
|
|
2087
|
-
// draw only full circle if more than that is specified
|
|
2088
1915
|
deltaAng = TWO_PI;
|
|
2089
1916
|
} else if (deltaAng !== 0 && anticlockwise !== deltaAng < 0) {
|
|
2090
|
-
// necessary to flip direction of rendering
|
|
2091
1917
|
const dir = anticlockwise ? -1 : 1;
|
|
2092
1918
|
deltaAng = dir * TWO_PI + deltaAng;
|
|
2093
1919
|
}
|
|
@@ -2095,38 +1921,21 @@ var VectorMixin = {
|
|
|
2095
1921
|
const segAng = deltaAng / numSegs;
|
|
2096
1922
|
const handleLen = segAng / HALF_PI * KAPPA * radius;
|
|
2097
1923
|
let curAng = startAngle;
|
|
2098
|
-
|
|
2099
|
-
// component distances between anchor point and control point
|
|
2100
1924
|
let deltaCx = -Math.sin(curAng) * handleLen;
|
|
2101
1925
|
let deltaCy = Math.cos(curAng) * handleLen;
|
|
2102
|
-
|
|
2103
|
-
// anchor point
|
|
2104
1926
|
let ax = x + Math.cos(curAng) * radius;
|
|
2105
1927
|
let ay = y + Math.sin(curAng) * radius;
|
|
2106
|
-
|
|
2107
|
-
// calculate and render segments
|
|
2108
1928
|
this.moveTo(ax, ay);
|
|
2109
1929
|
for (let segIdx = 0; segIdx < numSegs; segIdx++) {
|
|
2110
|
-
// starting control point
|
|
2111
1930
|
const cp1x = ax + deltaCx;
|
|
2112
1931
|
const cp1y = ay + deltaCy;
|
|
2113
|
-
|
|
2114
|
-
// step angle
|
|
2115
1932
|
curAng += segAng;
|
|
2116
|
-
|
|
2117
|
-
// next anchor point
|
|
2118
1933
|
ax = x + Math.cos(curAng) * radius;
|
|
2119
1934
|
ay = y + Math.sin(curAng) * radius;
|
|
2120
|
-
|
|
2121
|
-
// next control point delta
|
|
2122
1935
|
deltaCx = -Math.sin(curAng) * handleLen;
|
|
2123
1936
|
deltaCy = Math.cos(curAng) * handleLen;
|
|
2124
|
-
|
|
2125
|
-
// ending control point
|
|
2126
1937
|
const cp2x = ax - deltaCx;
|
|
2127
1938
|
const cp2y = ay - deltaCy;
|
|
2128
|
-
|
|
2129
|
-
// render segment
|
|
2130
1939
|
this.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, ax, ay);
|
|
2131
1940
|
}
|
|
2132
1941
|
return this;
|
|
@@ -2190,9 +1999,7 @@ var VectorMixin = {
|
|
|
2190
1999
|
return this.addContent(`W${this._windingRule(rule)} n`);
|
|
2191
2000
|
},
|
|
2192
2001
|
transform(m11, m12, m21, m22, dx, dy) {
|
|
2193
|
-
// keep track of the current transformation matrix
|
|
2194
2002
|
if (m11 === 1 && m12 === 0 && m21 === 0 && m22 === 1 && dx === 0 && dy === 0) {
|
|
2195
|
-
// Ignore identity transforms
|
|
2196
2003
|
return this;
|
|
2197
2004
|
}
|
|
2198
2005
|
const m = this._ctm;
|
|
@@ -2358,7 +2165,6 @@ class AFMFont {
|
|
|
2358
2165
|
this.boundingBoxes = {};
|
|
2359
2166
|
this.kernPairs = {};
|
|
2360
2167
|
this.parse();
|
|
2361
|
-
// todo: remove charWidths since appears to not be used
|
|
2362
2168
|
this.charWidths = new Array(256);
|
|
2363
2169
|
for (let char = 0; char <= 255; char++) {
|
|
2364
2170
|
this.charWidths[char] = this.glyphWidths[characters[char]];
|
|
@@ -2465,21 +2271,18 @@ class PDFFont {
|
|
|
2465
2271
|
return;
|
|
2466
2272
|
}
|
|
2467
2273
|
this.embed();
|
|
2468
|
-
|
|
2274
|
+
this.embedded = true;
|
|
2469
2275
|
}
|
|
2470
2276
|
embed() {
|
|
2471
2277
|
throw new Error('Must be implemented by subclasses');
|
|
2472
2278
|
}
|
|
2473
|
-
lineHeight(size
|
|
2474
|
-
|
|
2475
|
-
includeGap = false;
|
|
2476
|
-
}
|
|
2279
|
+
lineHeight(size) {
|
|
2280
|
+
let includeGap = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
2477
2281
|
const gap = includeGap ? this.lineGap : 0;
|
|
2478
2282
|
return (this.ascender + gap - this.descender) / 1000 * size;
|
|
2479
2283
|
}
|
|
2480
2284
|
}
|
|
2481
2285
|
|
|
2482
|
-
// This insanity is so bundlers can inline the font files
|
|
2483
2286
|
const STANDARD_FONTS = {
|
|
2484
2287
|
Courier() {
|
|
2485
2288
|
return fs.readFileSync(__dirname + '/data/Courier.afm', 'utf8');
|
|
@@ -2607,8 +2410,6 @@ class EmbeddedFont extends PDFFont {
|
|
|
2607
2410
|
}
|
|
2608
2411
|
layoutRun(text, features) {
|
|
2609
2412
|
const run = this.font.layout(text, features);
|
|
2610
|
-
|
|
2611
|
-
// Normalize position values
|
|
2612
2413
|
for (let i = 0; i < run.positions.length; i++) {
|
|
2613
2414
|
const position = run.positions[i];
|
|
2614
2415
|
for (let key in position) {
|
|
@@ -2631,16 +2432,12 @@ class EmbeddedFont extends PDFFont {
|
|
|
2631
2432
|
return run;
|
|
2632
2433
|
}
|
|
2633
2434
|
layout(text, features, onlyWidth) {
|
|
2634
|
-
// Skip the cache if any user defined features are applied
|
|
2635
2435
|
if (features) {
|
|
2636
2436
|
return this.layoutRun(text, features);
|
|
2637
2437
|
}
|
|
2638
2438
|
let glyphs = onlyWidth ? null : [];
|
|
2639
2439
|
let positions = onlyWidth ? null : [];
|
|
2640
2440
|
let advanceWidth = 0;
|
|
2641
|
-
|
|
2642
|
-
// Split the string by words to increase cache efficiency.
|
|
2643
|
-
// For this purpose, spaces and tabs are a good enough delimeter.
|
|
2644
2441
|
let last = 0;
|
|
2645
2442
|
let index = 0;
|
|
2646
2443
|
while (index <= text.length) {
|
|
@@ -2693,7 +2490,7 @@ class EmbeddedFont extends PDFFont {
|
|
|
2693
2490
|
if (isCFF) {
|
|
2694
2491
|
fontFile.data.Subtype = 'CIDFontType0C';
|
|
2695
2492
|
}
|
|
2696
|
-
|
|
2493
|
+
fontFile.end(this.subset.encode());
|
|
2697
2494
|
const familyClass = ((this.font['OS/2'] != null ? this.font['OS/2'].sFamilyClass : undefined) || 0) >> 8;
|
|
2698
2495
|
let flags = 0;
|
|
2699
2496
|
if (this.font.post.isFixedPitch) {
|
|
@@ -2702,17 +2499,15 @@ class EmbeddedFont extends PDFFont {
|
|
|
2702
2499
|
if (1 <= familyClass && familyClass <= 7) {
|
|
2703
2500
|
flags |= 1 << 1;
|
|
2704
2501
|
}
|
|
2705
|
-
flags |= 1 << 2;
|
|
2502
|
+
flags |= 1 << 2;
|
|
2706
2503
|
if (familyClass === 10) {
|
|
2707
2504
|
flags |= 1 << 3;
|
|
2708
2505
|
}
|
|
2709
2506
|
if (this.font.head.macStyle.italic) {
|
|
2710
2507
|
flags |= 1 << 6;
|
|
2711
2508
|
}
|
|
2712
|
-
|
|
2713
|
-
// generate a tag (6 uppercase letters. 17 is the char code offset from '0' to 'A'. 73 will map to 'Z')
|
|
2714
2509
|
const tag = [1, 2, 3, 4, 5, 6].map(i => String.fromCharCode((this.id.charCodeAt(i) || 73) + 17)).join('');
|
|
2715
|
-
const name = tag + '+' + this.font.postscriptName;
|
|
2510
|
+
const name = tag + '+' + this.font.postscriptName?.replaceAll(' ', '_');
|
|
2716
2511
|
const {
|
|
2717
2512
|
bbox
|
|
2718
2513
|
} = this.font;
|
|
@@ -2727,8 +2522,7 @@ class EmbeddedFont extends PDFFont {
|
|
|
2727
2522
|
CapHeight: (this.font.capHeight || this.font.ascent) * this.scale,
|
|
2728
2523
|
XHeight: (this.font.xHeight || 0) * this.scale,
|
|
2729
2524
|
StemV: 0
|
|
2730
|
-
});
|
|
2731
|
-
|
|
2525
|
+
});
|
|
2732
2526
|
if (isCFF) {
|
|
2733
2527
|
descriptor.data.FontFile3 = fontFile;
|
|
2734
2528
|
} else {
|
|
@@ -2770,17 +2564,11 @@ class EmbeddedFont extends PDFFont {
|
|
|
2770
2564
|
};
|
|
2771
2565
|
return this.dictionary.end();
|
|
2772
2566
|
}
|
|
2773
|
-
|
|
2774
|
-
// Maps the glyph ids encoded in the PDF back to unicode strings
|
|
2775
|
-
// Because of ligature substitutions and the like, there may be one or more
|
|
2776
|
-
// unicode characters represented by each glyph.
|
|
2777
2567
|
toUnicodeCmap() {
|
|
2778
2568
|
const cmap = this.document.ref();
|
|
2779
2569
|
const entries = [];
|
|
2780
2570
|
for (let codePoints of this.unicode) {
|
|
2781
2571
|
const encoded = [];
|
|
2782
|
-
|
|
2783
|
-
// encode codePoints to utf16
|
|
2784
2572
|
for (let value of codePoints) {
|
|
2785
2573
|
if (value > 0xffff) {
|
|
2786
2574
|
value -= 0x10000;
|
|
@@ -2834,12 +2622,10 @@ class PDFFontFactory {
|
|
|
2834
2622
|
}
|
|
2835
2623
|
src = fs.readFileSync(src);
|
|
2836
2624
|
}
|
|
2837
|
-
if (
|
|
2625
|
+
if (src instanceof Uint8Array) {
|
|
2838
2626
|
font = fontkit.create(src, family);
|
|
2839
|
-
} else if (src instanceof Uint8Array) {
|
|
2840
|
-
font = fontkit.create(Buffer.from(src), family);
|
|
2841
2627
|
} else if (src instanceof ArrayBuffer) {
|
|
2842
|
-
font = fontkit.create(
|
|
2628
|
+
font = fontkit.create(new Uint8Array(src), family);
|
|
2843
2629
|
}
|
|
2844
2630
|
if (font == null) {
|
|
2845
2631
|
throw new Error('Not a supported font format or standard PDF font.');
|
|
@@ -2848,21 +2634,30 @@ class PDFFontFactory {
|
|
|
2848
2634
|
}
|
|
2849
2635
|
}
|
|
2850
2636
|
|
|
2637
|
+
const isEqualFont = (font1, font2) => {
|
|
2638
|
+
if (font1.font._tables?.head?.checkSumAdjustment !== font2.font._tables?.head?.checkSumAdjustment) {
|
|
2639
|
+
return false;
|
|
2640
|
+
}
|
|
2641
|
+
if (JSON.stringify(font1.font._tables?.name?.records) !== JSON.stringify(font2.font._tables?.name?.records)) {
|
|
2642
|
+
return false;
|
|
2643
|
+
}
|
|
2644
|
+
return true;
|
|
2645
|
+
};
|
|
2851
2646
|
var FontsMixin = {
|
|
2852
2647
|
initFonts() {
|
|
2853
2648
|
let defaultFont = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'Helvetica';
|
|
2854
|
-
|
|
2649
|
+
let defaultFontFamily = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
2650
|
+
let defaultFontSize = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 12;
|
|
2855
2651
|
this._fontFamilies = {};
|
|
2856
2652
|
this._fontCount = 0;
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
this._fontSize =
|
|
2653
|
+
this._fontSource = defaultFont;
|
|
2654
|
+
this._fontFamily = defaultFontFamily;
|
|
2655
|
+
this._fontSize = defaultFontSize;
|
|
2860
2656
|
this._font = null;
|
|
2657
|
+
this._remSize = defaultFontSize;
|
|
2861
2658
|
this._registeredFonts = {};
|
|
2862
|
-
|
|
2863
|
-
// Set the default font
|
|
2864
2659
|
if (defaultFont) {
|
|
2865
|
-
this.font(defaultFont);
|
|
2660
|
+
this.font(defaultFont, defaultFontFamily);
|
|
2866
2661
|
}
|
|
2867
2662
|
},
|
|
2868
2663
|
font(src, family, size) {
|
|
@@ -2871,8 +2666,6 @@ var FontsMixin = {
|
|
|
2871
2666
|
size = family;
|
|
2872
2667
|
family = null;
|
|
2873
2668
|
}
|
|
2874
|
-
|
|
2875
|
-
// check registered fonts if src is a string
|
|
2876
2669
|
if (typeof src === 'string' && this._registeredFonts[src]) {
|
|
2877
2670
|
cacheKey = src;
|
|
2878
2671
|
({
|
|
@@ -2885,28 +2678,21 @@ var FontsMixin = {
|
|
|
2885
2678
|
cacheKey = null;
|
|
2886
2679
|
}
|
|
2887
2680
|
}
|
|
2681
|
+
this._fontSource = src;
|
|
2682
|
+
this._fontFamily = family;
|
|
2888
2683
|
if (size != null) {
|
|
2889
2684
|
this.fontSize(size);
|
|
2890
2685
|
}
|
|
2891
|
-
|
|
2892
|
-
// fast path: check if the font is already in the PDF
|
|
2893
2686
|
if (font = this._fontFamilies[cacheKey]) {
|
|
2894
2687
|
this._font = font;
|
|
2895
2688
|
return this;
|
|
2896
2689
|
}
|
|
2897
|
-
|
|
2898
|
-
// load the font
|
|
2899
2690
|
const id = `F${++this._fontCount}`;
|
|
2900
2691
|
this._font = PDFFontFactory.open(this, src, family, id);
|
|
2901
|
-
|
|
2902
|
-
// check for existing font familes with the same name already in the PDF
|
|
2903
|
-
// useful if the font was passed as a buffer
|
|
2904
|
-
if (font = this._fontFamilies[this._font.name]) {
|
|
2692
|
+
if ((font = this._fontFamilies[this._font.name]) && isEqualFont(this._font, font)) {
|
|
2905
2693
|
this._font = font;
|
|
2906
2694
|
return this;
|
|
2907
2695
|
}
|
|
2908
|
-
|
|
2909
|
-
// save the font for reuse later
|
|
2910
2696
|
if (cacheKey) {
|
|
2911
2697
|
this._fontFamilies[cacheKey] = this._font;
|
|
2912
2698
|
}
|
|
@@ -2916,13 +2702,10 @@ var FontsMixin = {
|
|
|
2916
2702
|
return this;
|
|
2917
2703
|
},
|
|
2918
2704
|
fontSize(_fontSize) {
|
|
2919
|
-
this._fontSize = _fontSize;
|
|
2705
|
+
this._fontSize = this.sizeToPoint(_fontSize);
|
|
2920
2706
|
return this;
|
|
2921
2707
|
},
|
|
2922
2708
|
currentLineHeight(includeGap) {
|
|
2923
|
-
if (includeGap == null) {
|
|
2924
|
-
includeGap = false;
|
|
2925
|
-
}
|
|
2926
2709
|
return this._font.lineHeight(this._fontSize, includeGap);
|
|
2927
2710
|
},
|
|
2928
2711
|
registerFont(name, src, family) {
|
|
@@ -2931,6 +2714,67 @@ var FontsMixin = {
|
|
|
2931
2714
|
family
|
|
2932
2715
|
};
|
|
2933
2716
|
return this;
|
|
2717
|
+
},
|
|
2718
|
+
sizeToPoint(size) {
|
|
2719
|
+
let defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
2720
|
+
let page = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.page;
|
|
2721
|
+
let percentageWidth = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : undefined;
|
|
2722
|
+
if (!percentageWidth) percentageWidth = this._fontSize;
|
|
2723
|
+
if (typeof defaultValue !== 'number') defaultValue = this.sizeToPoint(defaultValue);
|
|
2724
|
+
if (size === undefined) return defaultValue;
|
|
2725
|
+
if (typeof size === 'number') return size;
|
|
2726
|
+
if (typeof size === 'boolean') return Number(size);
|
|
2727
|
+
const match = String(size).match(/((\d+)?(\.\d+)?)(em|in|px|cm|mm|pc|ex|ch|rem|vw|vh|vmin|vmax|%|pt)?/);
|
|
2728
|
+
if (!match) throw new Error(`Unsupported size '${size}'`);
|
|
2729
|
+
let multiplier;
|
|
2730
|
+
switch (match[4]) {
|
|
2731
|
+
case 'em':
|
|
2732
|
+
multiplier = this._fontSize;
|
|
2733
|
+
break;
|
|
2734
|
+
case 'in':
|
|
2735
|
+
multiplier = IN_TO_PT;
|
|
2736
|
+
break;
|
|
2737
|
+
case 'px':
|
|
2738
|
+
multiplier = PX_TO_IN * IN_TO_PT;
|
|
2739
|
+
break;
|
|
2740
|
+
case 'cm':
|
|
2741
|
+
multiplier = CM_TO_IN * IN_TO_PT;
|
|
2742
|
+
break;
|
|
2743
|
+
case 'mm':
|
|
2744
|
+
multiplier = MM_TO_CM * CM_TO_IN * IN_TO_PT;
|
|
2745
|
+
break;
|
|
2746
|
+
case 'pc':
|
|
2747
|
+
multiplier = PC_TO_PT;
|
|
2748
|
+
break;
|
|
2749
|
+
case 'ex':
|
|
2750
|
+
multiplier = this.currentLineHeight();
|
|
2751
|
+
break;
|
|
2752
|
+
case 'ch':
|
|
2753
|
+
multiplier = this.widthOfString('0');
|
|
2754
|
+
break;
|
|
2755
|
+
case 'rem':
|
|
2756
|
+
multiplier = this._remSize;
|
|
2757
|
+
break;
|
|
2758
|
+
case 'vw':
|
|
2759
|
+
multiplier = page.width / 100;
|
|
2760
|
+
break;
|
|
2761
|
+
case 'vh':
|
|
2762
|
+
multiplier = page.height / 100;
|
|
2763
|
+
break;
|
|
2764
|
+
case 'vmin':
|
|
2765
|
+
multiplier = Math.min(page.width, page.height) / 100;
|
|
2766
|
+
break;
|
|
2767
|
+
case 'vmax':
|
|
2768
|
+
multiplier = Math.max(page.width, page.height) / 100;
|
|
2769
|
+
break;
|
|
2770
|
+
case '%':
|
|
2771
|
+
multiplier = percentageWidth / 100;
|
|
2772
|
+
break;
|
|
2773
|
+
case 'pt':
|
|
2774
|
+
default:
|
|
2775
|
+
multiplier = 1;
|
|
2776
|
+
}
|
|
2777
|
+
return multiplier * Number(match[1]);
|
|
2934
2778
|
}
|
|
2935
2779
|
};
|
|
2936
2780
|
|
|
@@ -2940,12 +2784,13 @@ class LineWrapper extends EventEmitter {
|
|
|
2940
2784
|
constructor(document, options) {
|
|
2941
2785
|
super();
|
|
2942
2786
|
this.document = document;
|
|
2943
|
-
this.
|
|
2944
|
-
this.
|
|
2945
|
-
this.
|
|
2787
|
+
this.horizontalScaling = options.horizontalScaling || 100;
|
|
2788
|
+
this.indent = (options.indent || 0) * this.horizontalScaling / 100;
|
|
2789
|
+
this.characterSpacing = (options.characterSpacing || 0) * this.horizontalScaling / 100;
|
|
2790
|
+
this.wordSpacing = (options.wordSpacing === 0) * this.horizontalScaling / 100;
|
|
2946
2791
|
this.columns = options.columns || 1;
|
|
2947
|
-
this.columnGap = options.columnGap != null ? options.columnGap : 18
|
|
2948
|
-
this.lineWidth = (options.width - this.columnGap * (this.columns - 1)) / this.columns;
|
|
2792
|
+
this.columnGap = (options.columnGap != null ? options.columnGap : 18) * this.horizontalScaling / 100;
|
|
2793
|
+
this.lineWidth = (options.width * this.horizontalScaling / 100 - this.columnGap * (this.columns - 1)) / this.columns;
|
|
2949
2794
|
this.spaceLeft = this.lineWidth;
|
|
2950
2795
|
this.startX = this.document.x;
|
|
2951
2796
|
this.startY = this.document.y;
|
|
@@ -2953,36 +2798,30 @@ class LineWrapper extends EventEmitter {
|
|
|
2953
2798
|
this.ellipsis = options.ellipsis;
|
|
2954
2799
|
this.continuedX = 0;
|
|
2955
2800
|
this.features = options.features;
|
|
2956
|
-
|
|
2957
|
-
// calculate the maximum Y position the text can appear at
|
|
2958
2801
|
if (options.height != null) {
|
|
2959
2802
|
this.height = options.height;
|
|
2960
|
-
this.maxY = this.startY + options.height;
|
|
2803
|
+
this.maxY = PDFNumber(this.startY + options.height);
|
|
2961
2804
|
} else {
|
|
2962
|
-
this.maxY = this.document.page.maxY();
|
|
2805
|
+
this.maxY = PDFNumber(this.document.page.maxY());
|
|
2963
2806
|
}
|
|
2964
|
-
|
|
2965
|
-
// handle paragraph indents
|
|
2966
2807
|
this.on('firstLine', options => {
|
|
2967
|
-
// if this is the first line of the text segment, and
|
|
2968
|
-
// we're continuing where we left off, indent that much
|
|
2969
|
-
// otherwise use the user specified indent option
|
|
2970
2808
|
const indent = this.continuedX || this.indent;
|
|
2971
2809
|
this.document.x += indent;
|
|
2972
2810
|
this.lineWidth -= indent;
|
|
2973
|
-
|
|
2811
|
+
if (options.indentAllLines) {
|
|
2812
|
+
return;
|
|
2813
|
+
}
|
|
2814
|
+
this.once('line', () => {
|
|
2974
2815
|
this.document.x -= indent;
|
|
2975
2816
|
this.lineWidth += indent;
|
|
2976
2817
|
if (options.continued && !this.continuedX) {
|
|
2977
2818
|
this.continuedX = this.indent;
|
|
2978
2819
|
}
|
|
2979
2820
|
if (!options.continued) {
|
|
2980
|
-
|
|
2821
|
+
this.continuedX = 0;
|
|
2981
2822
|
}
|
|
2982
2823
|
});
|
|
2983
2824
|
});
|
|
2984
|
-
|
|
2985
|
-
// handle left aligning last lines of paragraphs
|
|
2986
2825
|
this.on('lastLine', options => {
|
|
2987
2826
|
const {
|
|
2988
2827
|
align
|
|
@@ -2991,7 +2830,7 @@ class LineWrapper extends EventEmitter {
|
|
|
2991
2830
|
options.align = 'left';
|
|
2992
2831
|
}
|
|
2993
2832
|
this.lastLine = true;
|
|
2994
|
-
|
|
2833
|
+
this.once('line', () => {
|
|
2995
2834
|
this.document.y += options.paragraphGap || 0;
|
|
2996
2835
|
options.align = align;
|
|
2997
2836
|
return this.lastLine = false;
|
|
@@ -3008,7 +2847,6 @@ class LineWrapper extends EventEmitter {
|
|
|
3008
2847
|
return w + this.wordWidth(HYPHEN) <= this.spaceLeft;
|
|
3009
2848
|
}
|
|
3010
2849
|
eachWord(text, fn) {
|
|
3011
|
-
// setup a unicode line breaker
|
|
3012
2850
|
let bk;
|
|
3013
2851
|
const breaker = new LineBreaker(text);
|
|
3014
2852
|
let last = null;
|
|
@@ -3017,19 +2855,12 @@ class LineWrapper extends EventEmitter {
|
|
|
3017
2855
|
var shouldContinue;
|
|
3018
2856
|
let word = text.slice((last != null ? last.position : undefined) || 0, bk.position);
|
|
3019
2857
|
let w = wordWidths[word] != null ? wordWidths[word] : wordWidths[word] = this.wordWidth(word);
|
|
3020
|
-
|
|
3021
|
-
// if the word is longer than the whole line, chop it up
|
|
3022
|
-
// TODO: break by grapheme clusters, not JS string characters
|
|
3023
2858
|
if (w > this.lineWidth + this.continuedX) {
|
|
3024
|
-
// make some fake break objects
|
|
3025
2859
|
let lbk = last;
|
|
3026
2860
|
const fbk = {};
|
|
3027
2861
|
while (word.length) {
|
|
3028
|
-
// fit as much of the word as possible into the space we have
|
|
3029
2862
|
var l, mightGrow;
|
|
3030
2863
|
if (w > this.spaceLeft) {
|
|
3031
|
-
// start our check at the end of our available space - this method is faster than a loop of each character and it resolves
|
|
3032
|
-
// an issue with long loops when processing massive words, such as a huge number of spaces
|
|
3033
2864
|
l = Math.ceil(this.spaceLeft / (w / word.length));
|
|
3034
2865
|
w = this.wordWidth(word.slice(0, l));
|
|
3035
2866
|
mightGrow = w <= this.spaceLeft && l < word.length;
|
|
@@ -3037,7 +2868,6 @@ class LineWrapper extends EventEmitter {
|
|
|
3037
2868
|
l = word.length;
|
|
3038
2869
|
}
|
|
3039
2870
|
let mustShrink = w > this.spaceLeft && l > 0;
|
|
3040
|
-
// shrink or grow word as necessary after our near-guess above
|
|
3041
2871
|
while (mustShrink || mightGrow) {
|
|
3042
2872
|
if (mustShrink) {
|
|
3043
2873
|
w = this.wordWidth(word.slice(0, --l));
|
|
@@ -3048,20 +2878,14 @@ class LineWrapper extends EventEmitter {
|
|
|
3048
2878
|
mightGrow = w <= this.spaceLeft && l < word.length;
|
|
3049
2879
|
}
|
|
3050
2880
|
}
|
|
3051
|
-
|
|
3052
|
-
// check for the edge case where a single character cannot fit into a line.
|
|
3053
2881
|
if (l === 0 && this.spaceLeft === this.lineWidth) {
|
|
3054
2882
|
l = 1;
|
|
3055
2883
|
}
|
|
3056
|
-
|
|
3057
|
-
// send a required break unless this is the last piece and a linebreak is not specified
|
|
3058
2884
|
fbk.required = bk.required || l < word.length;
|
|
3059
2885
|
shouldContinue = fn(word.slice(0, l), w, fbk, lbk);
|
|
3060
2886
|
lbk = {
|
|
3061
2887
|
required: false
|
|
3062
2888
|
};
|
|
3063
|
-
|
|
3064
|
-
// get the remaining piece of the word
|
|
3065
2889
|
word = word.slice(l);
|
|
3066
2890
|
w = this.wordWidth(word);
|
|
3067
2891
|
if (shouldContinue === false) {
|
|
@@ -3069,7 +2893,6 @@ class LineWrapper extends EventEmitter {
|
|
|
3069
2893
|
}
|
|
3070
2894
|
}
|
|
3071
2895
|
} else {
|
|
3072
|
-
// otherwise just emit the break as it was given to us
|
|
3073
2896
|
shouldContinue = fn(word, w, bk, last);
|
|
3074
2897
|
}
|
|
3075
2898
|
if (shouldContinue === false) {
|
|
@@ -3079,23 +2902,19 @@ class LineWrapper extends EventEmitter {
|
|
|
3079
2902
|
}
|
|
3080
2903
|
}
|
|
3081
2904
|
wrap(text, options) {
|
|
3082
|
-
|
|
2905
|
+
this.horizontalScaling = options.horizontalScaling || 100;
|
|
3083
2906
|
if (options.indent != null) {
|
|
3084
|
-
this.indent = options.indent;
|
|
2907
|
+
this.indent = options.indent * this.horizontalScaling / 100;
|
|
3085
2908
|
}
|
|
3086
2909
|
if (options.characterSpacing != null) {
|
|
3087
|
-
this.characterSpacing = options.characterSpacing;
|
|
2910
|
+
this.characterSpacing = options.characterSpacing * this.horizontalScaling / 100;
|
|
3088
2911
|
}
|
|
3089
2912
|
if (options.wordSpacing != null) {
|
|
3090
|
-
this.wordSpacing = options.wordSpacing;
|
|
2913
|
+
this.wordSpacing = options.wordSpacing * this.horizontalScaling / 100;
|
|
3091
2914
|
}
|
|
3092
2915
|
if (options.ellipsis != null) {
|
|
3093
2916
|
this.ellipsis = options.ellipsis;
|
|
3094
2917
|
}
|
|
3095
|
-
|
|
3096
|
-
// make sure we're actually on the page
|
|
3097
|
-
// and that the first line of is never by
|
|
3098
|
-
// itself at the bottom of a page (orphans)
|
|
3099
2918
|
const nextY = this.document.y + this.document.currentLineHeight(true);
|
|
3100
2919
|
if (this.document.y > this.maxY || nextY > this.maxY) {
|
|
3101
2920
|
this.nextSection();
|
|
@@ -3106,7 +2925,7 @@ class LineWrapper extends EventEmitter {
|
|
|
3106
2925
|
let lc = 0;
|
|
3107
2926
|
let {
|
|
3108
2927
|
y
|
|
3109
|
-
} = this.document;
|
|
2928
|
+
} = this.document;
|
|
3110
2929
|
const emitLine = () => {
|
|
3111
2930
|
options.textWidth = textWidth + this.wordSpacing * (wc - 1);
|
|
3112
2931
|
options.wordCount = wc;
|
|
@@ -3129,23 +2948,17 @@ class LineWrapper extends EventEmitter {
|
|
|
3129
2948
|
wc++;
|
|
3130
2949
|
}
|
|
3131
2950
|
if (bk.required || !this.canFit(word, w)) {
|
|
3132
|
-
// if the user specified a max height and an ellipsis, and is about to pass the
|
|
3133
|
-
// max height and max columns after the next line, append the ellipsis
|
|
3134
2951
|
const lh = this.document.currentLineHeight(true);
|
|
3135
|
-
if (this.height != null && this.ellipsis && this.document.y + lh * 2 > this.maxY && this.column >= this.columns) {
|
|
2952
|
+
if (this.height != null && this.ellipsis && PDFNumber(this.document.y + lh * 2) > this.maxY && this.column >= this.columns) {
|
|
3136
2953
|
if (this.ellipsis === true) {
|
|
3137
2954
|
this.ellipsis = '…';
|
|
3138
|
-
}
|
|
2955
|
+
}
|
|
3139
2956
|
buffer = buffer.replace(/\s+$/, '');
|
|
3140
2957
|
textWidth = this.wordWidth(buffer + this.ellipsis);
|
|
3141
|
-
|
|
3142
|
-
// remove characters from the buffer until the ellipsis fits
|
|
3143
|
-
// to avoid infinite loop need to stop while-loop if buffer is empty string
|
|
3144
2958
|
while (buffer && textWidth > this.lineWidth) {
|
|
3145
2959
|
buffer = buffer.slice(0, -1).replace(/\s+$/, '');
|
|
3146
2960
|
textWidth = this.wordWidth(buffer + this.ellipsis);
|
|
3147
2961
|
}
|
|
3148
|
-
// need to add ellipsis only if there is enough space for it
|
|
3149
2962
|
if (textWidth <= this.lineWidth) {
|
|
3150
2963
|
buffer = buffer + this.ellipsis;
|
|
3151
2964
|
}
|
|
@@ -3160,35 +2973,25 @@ class LineWrapper extends EventEmitter {
|
|
|
3160
2973
|
}
|
|
3161
2974
|
this.emit('lastLine', options, this);
|
|
3162
2975
|
}
|
|
3163
|
-
|
|
3164
|
-
// Previous entry is a soft hyphen - add visible hyphen.
|
|
3165
2976
|
if (buffer[buffer.length - 1] == SOFT_HYPHEN) {
|
|
3166
2977
|
buffer = buffer.slice(0, -1) + HYPHEN;
|
|
3167
2978
|
this.spaceLeft -= this.wordWidth(HYPHEN);
|
|
3168
2979
|
}
|
|
3169
2980
|
emitLine();
|
|
3170
|
-
|
|
3171
|
-
// if we've reached the edge of the page,
|
|
3172
|
-
// continue on a new page or column
|
|
3173
|
-
if (this.document.y + lh > this.maxY) {
|
|
2981
|
+
if (PDFNumber(this.document.y + lh) > this.maxY) {
|
|
3174
2982
|
const shouldContinue = this.nextSection();
|
|
3175
|
-
|
|
3176
|
-
// stop if we reached the maximum height
|
|
3177
2983
|
if (!shouldContinue) {
|
|
3178
2984
|
wc = 0;
|
|
3179
2985
|
buffer = '';
|
|
3180
2986
|
return false;
|
|
3181
2987
|
}
|
|
3182
2988
|
}
|
|
3183
|
-
|
|
3184
|
-
// reset the space left and buffer
|
|
3185
2989
|
if (bk.required) {
|
|
3186
2990
|
this.spaceLeft = this.lineWidth;
|
|
3187
2991
|
buffer = '';
|
|
3188
2992
|
textWidth = 0;
|
|
3189
2993
|
return wc = 0;
|
|
3190
2994
|
} else {
|
|
3191
|
-
// reset the space left and buffer
|
|
3192
2995
|
this.spaceLeft = this.lineWidth - w;
|
|
3193
2996
|
buffer = word;
|
|
3194
2997
|
textWidth = w;
|
|
@@ -3203,25 +3006,19 @@ class LineWrapper extends EventEmitter {
|
|
|
3203
3006
|
emitLine();
|
|
3204
3007
|
}
|
|
3205
3008
|
this.emit('sectionEnd', options, this);
|
|
3206
|
-
|
|
3207
|
-
// if the wrap is set to be continued, save the X position
|
|
3208
|
-
// to start the first line of the next segment at, and reset
|
|
3209
|
-
// the y position
|
|
3210
3009
|
if (options.continued === true) {
|
|
3211
3010
|
if (lc > 1) {
|
|
3212
3011
|
this.continuedX = 0;
|
|
3213
3012
|
}
|
|
3214
3013
|
this.continuedX += options.textWidth || 0;
|
|
3215
|
-
|
|
3014
|
+
this.document.y = y;
|
|
3216
3015
|
} else {
|
|
3217
|
-
|
|
3016
|
+
this.document.x = this.startX;
|
|
3218
3017
|
}
|
|
3219
3018
|
}
|
|
3220
3019
|
nextSection(options) {
|
|
3221
3020
|
this.emit('sectionEnd', options, this);
|
|
3222
3021
|
if (++this.column > this.columns) {
|
|
3223
|
-
// if a max height was specified by the user, we're done.
|
|
3224
|
-
// otherwise, the default is to make a new page at the bottom.
|
|
3225
3022
|
if (this.height != null) {
|
|
3226
3023
|
return false;
|
|
3227
3024
|
}
|
|
@@ -3245,15 +3042,14 @@ class LineWrapper extends EventEmitter {
|
|
|
3245
3042
|
}
|
|
3246
3043
|
|
|
3247
3044
|
const {
|
|
3248
|
-
number
|
|
3045
|
+
number
|
|
3249
3046
|
} = PDFObject;
|
|
3250
3047
|
var TextMixin = {
|
|
3251
3048
|
initText() {
|
|
3252
3049
|
this._line = this._line.bind(this);
|
|
3253
|
-
// Current coordinates
|
|
3254
3050
|
this.x = 0;
|
|
3255
3051
|
this.y = 0;
|
|
3256
|
-
|
|
3052
|
+
this._lineGap = 0;
|
|
3257
3053
|
},
|
|
3258
3054
|
lineGap(_lineGap) {
|
|
3259
3055
|
this._lineGap = _lineGap;
|
|
@@ -3275,11 +3071,7 @@ var TextMixin = {
|
|
|
3275
3071
|
},
|
|
3276
3072
|
_text(text, x, y, options, lineCallback) {
|
|
3277
3073
|
options = this._initOptions(x, y, options);
|
|
3278
|
-
|
|
3279
|
-
// Convert text to a string
|
|
3280
3074
|
text = text == null ? '' : `${text}`;
|
|
3281
|
-
|
|
3282
|
-
// if the wordSpacing option is specified, remove multiple consecutive spaces
|
|
3283
3075
|
if (options.wordSpacing) {
|
|
3284
3076
|
text = text.replace(/\s{2,}/g, ' ');
|
|
3285
3077
|
}
|
|
@@ -3288,8 +3080,12 @@ var TextMixin = {
|
|
|
3288
3080
|
options.structParent.add(this.struct(options.structType || 'P', [this.markStructureContent(options.structType || 'P')]));
|
|
3289
3081
|
}
|
|
3290
3082
|
};
|
|
3291
|
-
|
|
3292
|
-
|
|
3083
|
+
if (options.rotation !== 0) {
|
|
3084
|
+
this.save();
|
|
3085
|
+
this.rotate(-options.rotation, {
|
|
3086
|
+
origin: [this.x, this.y]
|
|
3087
|
+
});
|
|
3088
|
+
}
|
|
3293
3089
|
if (options.width) {
|
|
3294
3090
|
let wrapper = this._wrapper;
|
|
3295
3091
|
if (!wrapper) {
|
|
@@ -3300,14 +3096,13 @@ var TextMixin = {
|
|
|
3300
3096
|
this._wrapper = options.continued ? wrapper : null;
|
|
3301
3097
|
this._textOptions = options.continued ? options : null;
|
|
3302
3098
|
wrapper.wrap(text, options);
|
|
3303
|
-
|
|
3304
|
-
// render paragraphs as single lines
|
|
3305
3099
|
} else {
|
|
3306
3100
|
for (let line of text.split('\n')) {
|
|
3307
3101
|
addStructure();
|
|
3308
3102
|
lineCallback(line, options);
|
|
3309
3103
|
}
|
|
3310
3104
|
}
|
|
3105
|
+
if (options.rotation !== 0) this.restore();
|
|
3311
3106
|
return this;
|
|
3312
3107
|
},
|
|
3313
3108
|
text(text, x, y, options) {
|
|
@@ -3315,7 +3110,100 @@ var TextMixin = {
|
|
|
3315
3110
|
},
|
|
3316
3111
|
widthOfString(string) {
|
|
3317
3112
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
3318
|
-
|
|
3113
|
+
const horizontalScaling = options.horizontalScaling || 100;
|
|
3114
|
+
return (this._font.widthOfString(string, this._fontSize, options.features) + (options.characterSpacing || 0) * (string.length - 1)) * horizontalScaling / 100;
|
|
3115
|
+
},
|
|
3116
|
+
boundsOfString(string, x, y, options) {
|
|
3117
|
+
options = this._initOptions(x, y, options);
|
|
3118
|
+
({
|
|
3119
|
+
x,
|
|
3120
|
+
y
|
|
3121
|
+
} = this);
|
|
3122
|
+
const lineGap = options.lineGap ?? this._lineGap ?? 0;
|
|
3123
|
+
const lineHeight = this.currentLineHeight(true) + lineGap;
|
|
3124
|
+
let contentWidth = 0;
|
|
3125
|
+
string = String(string ?? '');
|
|
3126
|
+
if (options.wordSpacing) {
|
|
3127
|
+
string = string.replace(/\s{2,}/g, ' ');
|
|
3128
|
+
}
|
|
3129
|
+
if (options.width) {
|
|
3130
|
+
let wrapper = new LineWrapper(this, options);
|
|
3131
|
+
wrapper.on('line', (text, options) => {
|
|
3132
|
+
this.y += lineHeight;
|
|
3133
|
+
text = text.replace(/\n/g, '');
|
|
3134
|
+
if (text.length) {
|
|
3135
|
+
let wordSpacing = options.wordSpacing ?? 0;
|
|
3136
|
+
const characterSpacing = options.characterSpacing ?? 0;
|
|
3137
|
+
if (options.width && options.align === 'justify') {
|
|
3138
|
+
const words = text.trim().split(/\s+/);
|
|
3139
|
+
const textWidth = this.widthOfString(text.replace(/\s+/g, ''), options);
|
|
3140
|
+
const spaceWidth = this.widthOfString(' ') + characterSpacing;
|
|
3141
|
+
wordSpacing = Math.max(0, (options.lineWidth - textWidth) / Math.max(1, words.length - 1) - spaceWidth);
|
|
3142
|
+
}
|
|
3143
|
+
contentWidth = Math.max(contentWidth, options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1));
|
|
3144
|
+
}
|
|
3145
|
+
});
|
|
3146
|
+
wrapper.wrap(string, options);
|
|
3147
|
+
} else {
|
|
3148
|
+
for (let line of string.split('\n')) {
|
|
3149
|
+
const lineWidth = this.widthOfString(line, options);
|
|
3150
|
+
this.y += lineHeight;
|
|
3151
|
+
contentWidth = Math.max(contentWidth, lineWidth);
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
let contentHeight = this.y - y;
|
|
3155
|
+
if (options.height) contentHeight = Math.min(contentHeight, options.height);
|
|
3156
|
+
this.x = x;
|
|
3157
|
+
this.y = y;
|
|
3158
|
+
if (options.rotation === 0) {
|
|
3159
|
+
return {
|
|
3160
|
+
x,
|
|
3161
|
+
y,
|
|
3162
|
+
width: contentWidth,
|
|
3163
|
+
height: contentHeight
|
|
3164
|
+
};
|
|
3165
|
+
} else if (options.rotation === 90) {
|
|
3166
|
+
return {
|
|
3167
|
+
x: x,
|
|
3168
|
+
y: y - contentWidth,
|
|
3169
|
+
width: contentHeight,
|
|
3170
|
+
height: contentWidth
|
|
3171
|
+
};
|
|
3172
|
+
} else if (options.rotation === 180) {
|
|
3173
|
+
return {
|
|
3174
|
+
x: x - contentWidth,
|
|
3175
|
+
y: y - contentHeight,
|
|
3176
|
+
width: contentWidth,
|
|
3177
|
+
height: contentHeight
|
|
3178
|
+
};
|
|
3179
|
+
} else if (options.rotation === 270) {
|
|
3180
|
+
return {
|
|
3181
|
+
x: x - contentHeight,
|
|
3182
|
+
y: y,
|
|
3183
|
+
width: contentHeight,
|
|
3184
|
+
height: contentWidth
|
|
3185
|
+
};
|
|
3186
|
+
}
|
|
3187
|
+
const cos = cosine(options.rotation);
|
|
3188
|
+
const sin = sine(options.rotation);
|
|
3189
|
+
const x1 = x;
|
|
3190
|
+
const y1 = y;
|
|
3191
|
+
const x2 = x + contentWidth * cos;
|
|
3192
|
+
const y2 = y - contentWidth * sin;
|
|
3193
|
+
const x3 = x + contentWidth * cos + contentHeight * sin;
|
|
3194
|
+
const y3 = y - contentWidth * sin + contentHeight * cos;
|
|
3195
|
+
const x4 = x + contentHeight * sin;
|
|
3196
|
+
const y4 = y + contentHeight * cos;
|
|
3197
|
+
const xMin = Math.min(x1, x2, x3, x4);
|
|
3198
|
+
const xMax = Math.max(x1, x2, x3, x4);
|
|
3199
|
+
const yMin = Math.min(y1, y2, y3, y4);
|
|
3200
|
+
const yMax = Math.max(y1, y2, y3, y4);
|
|
3201
|
+
return {
|
|
3202
|
+
x: xMin,
|
|
3203
|
+
y: yMin,
|
|
3204
|
+
width: xMax - xMin,
|
|
3205
|
+
height: yMax - yMin
|
|
3206
|
+
};
|
|
3319
3207
|
},
|
|
3320
3208
|
heightOfString(text, options) {
|
|
3321
3209
|
const {
|
|
@@ -3323,11 +3211,10 @@ var TextMixin = {
|
|
|
3323
3211
|
y
|
|
3324
3212
|
} = this;
|
|
3325
3213
|
options = this._initOptions(options);
|
|
3326
|
-
options.height = Infinity;
|
|
3327
|
-
|
|
3214
|
+
options.height = Infinity;
|
|
3328
3215
|
const lineGap = options.lineGap || this._lineGap || 0;
|
|
3329
3216
|
this._text(text, this.x, this.y, options, () => {
|
|
3330
|
-
|
|
3217
|
+
this.y += this.currentLineHeight(true) + lineGap;
|
|
3331
3218
|
});
|
|
3332
3219
|
const height = this.y - y;
|
|
3333
3220
|
this.x = x;
|
|
@@ -3425,12 +3312,12 @@ var TextMixin = {
|
|
|
3425
3312
|
wrapper.on('sectionStart', () => {
|
|
3426
3313
|
const pos = indent + itemIndent * (level - 1);
|
|
3427
3314
|
this.x += pos;
|
|
3428
|
-
|
|
3315
|
+
wrapper.lineWidth -= pos;
|
|
3429
3316
|
});
|
|
3430
3317
|
wrapper.on('sectionEnd', () => {
|
|
3431
3318
|
const pos = indent + itemIndent * (level - 1);
|
|
3432
3319
|
this.x -= pos;
|
|
3433
|
-
|
|
3320
|
+
wrapper.lineWidth += pos;
|
|
3434
3321
|
});
|
|
3435
3322
|
wrapper.wrap(listItem, options);
|
|
3436
3323
|
};
|
|
@@ -3447,11 +3334,7 @@ var TextMixin = {
|
|
|
3447
3334
|
options = x;
|
|
3448
3335
|
x = null;
|
|
3449
3336
|
}
|
|
3450
|
-
|
|
3451
|
-
// clone options object
|
|
3452
3337
|
const result = Object.assign({}, options);
|
|
3453
|
-
|
|
3454
|
-
// extend options with previous values for continued text
|
|
3455
3338
|
if (this._textOptions) {
|
|
3456
3339
|
for (let key in this._textOptions) {
|
|
3457
3340
|
const val = this._textOptions[key];
|
|
@@ -3462,16 +3345,12 @@ var TextMixin = {
|
|
|
3462
3345
|
}
|
|
3463
3346
|
}
|
|
3464
3347
|
}
|
|
3465
|
-
|
|
3466
|
-
// Update the current position
|
|
3467
3348
|
if (x != null) {
|
|
3468
3349
|
this.x = x;
|
|
3469
3350
|
}
|
|
3470
3351
|
if (y != null) {
|
|
3471
3352
|
this.y = y;
|
|
3472
3353
|
}
|
|
3473
|
-
|
|
3474
|
-
// wrap to margins if no x or y position passed
|
|
3475
3354
|
if (result.lineBreak !== false) {
|
|
3476
3355
|
if (result.width == null) {
|
|
3477
3356
|
result.width = this.page.width - this.x - this.page.margins.right;
|
|
@@ -3483,8 +3362,9 @@ var TextMixin = {
|
|
|
3483
3362
|
}
|
|
3484
3363
|
if (result.columnGap == null) {
|
|
3485
3364
|
result.columnGap = 18;
|
|
3486
|
-
}
|
|
3487
|
-
|
|
3365
|
+
}
|
|
3366
|
+
result.rotation = Number(options.rotation ?? 0) % 360;
|
|
3367
|
+
if (result.rotation < 0) result.rotation += 360;
|
|
3488
3368
|
return result;
|
|
3489
3369
|
},
|
|
3490
3370
|
_line(text) {
|
|
@@ -3493,9 +3373,9 @@ var TextMixin = {
|
|
|
3493
3373
|
this._fragment(text, this.x, this.y, options);
|
|
3494
3374
|
const lineGap = options.lineGap || this._lineGap || 0;
|
|
3495
3375
|
if (!wrapper) {
|
|
3496
|
-
|
|
3376
|
+
this.x += this.widthOfString(text, options);
|
|
3497
3377
|
} else {
|
|
3498
|
-
|
|
3378
|
+
this.y += this.currentLineHeight(true) + lineGap;
|
|
3499
3379
|
}
|
|
3500
3380
|
},
|
|
3501
3381
|
_fragment(text, x, y, options) {
|
|
@@ -3504,13 +3384,10 @@ var TextMixin = {
|
|
|
3504
3384
|
if (text.length === 0) {
|
|
3505
3385
|
return;
|
|
3506
3386
|
}
|
|
3507
|
-
|
|
3508
|
-
// handle options
|
|
3509
3387
|
const align = options.align || 'left';
|
|
3510
3388
|
let wordSpacing = options.wordSpacing || 0;
|
|
3511
3389
|
const characterSpacing = options.characterSpacing || 0;
|
|
3512
|
-
|
|
3513
|
-
// text alignments
|
|
3390
|
+
const horizontalScaling = options.horizontalScaling || 100;
|
|
3514
3391
|
if (options.width) {
|
|
3515
3392
|
switch (align) {
|
|
3516
3393
|
case 'right':
|
|
@@ -3521,7 +3398,6 @@ var TextMixin = {
|
|
|
3521
3398
|
x += options.lineWidth / 2 - options.textWidth / 2;
|
|
3522
3399
|
break;
|
|
3523
3400
|
case 'justify':
|
|
3524
|
-
// calculate the word spacing value
|
|
3525
3401
|
words = text.trim().split(/\s+/);
|
|
3526
3402
|
textWidth = this.widthOfString(text.replace(/\s+/g, ''), options);
|
|
3527
3403
|
var spaceWidth = this.widthOfString(' ') + characterSpacing;
|
|
@@ -3529,8 +3405,6 @@ var TextMixin = {
|
|
|
3529
3405
|
break;
|
|
3530
3406
|
}
|
|
3531
3407
|
}
|
|
3532
|
-
|
|
3533
|
-
// text baseline alignments based on http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
|
|
3534
3408
|
if (typeof options.baseline === 'number') {
|
|
3535
3409
|
dy = -options.baseline;
|
|
3536
3410
|
} else {
|
|
@@ -3563,11 +3437,7 @@ var TextMixin = {
|
|
|
3563
3437
|
}
|
|
3564
3438
|
dy = dy / 1000 * this._fontSize;
|
|
3565
3439
|
}
|
|
3566
|
-
|
|
3567
|
-
// calculate the actual rendered width of the string after word and character spacing
|
|
3568
3440
|
const renderedWidth = options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1);
|
|
3569
|
-
|
|
3570
|
-
// create link annotations if the link option is given
|
|
3571
3441
|
if (options.link != null) {
|
|
3572
3442
|
this.link(x, y, renderedWidth, this.currentLineHeight(), options.link);
|
|
3573
3443
|
}
|
|
@@ -3577,8 +3447,6 @@ var TextMixin = {
|
|
|
3577
3447
|
if (options.destination != null) {
|
|
3578
3448
|
this.addNamedDestination(options.destination, 'XYZ', x, y, null);
|
|
3579
3449
|
}
|
|
3580
|
-
|
|
3581
|
-
// create underline
|
|
3582
3450
|
if (options.underline) {
|
|
3583
3451
|
this.save();
|
|
3584
3452
|
if (!options.stroke) {
|
|
@@ -3592,8 +3460,6 @@ var TextMixin = {
|
|
|
3592
3460
|
this.stroke();
|
|
3593
3461
|
this.restore();
|
|
3594
3462
|
}
|
|
3595
|
-
|
|
3596
|
-
// create strikethrough line
|
|
3597
3463
|
if (options.strike) {
|
|
3598
3464
|
this.save();
|
|
3599
3465
|
if (!options.stroke) {
|
|
@@ -3608,8 +3474,6 @@ var TextMixin = {
|
|
|
3608
3474
|
this.restore();
|
|
3609
3475
|
}
|
|
3610
3476
|
this.save();
|
|
3611
|
-
|
|
3612
|
-
// oblique (angle in degrees or boolean)
|
|
3613
3477
|
if (options.oblique) {
|
|
3614
3478
|
let skew;
|
|
3615
3479
|
if (typeof options.oblique === 'number') {
|
|
@@ -3621,40 +3485,24 @@ var TextMixin = {
|
|
|
3621
3485
|
this.transform(1, 0, skew, 1, -skew * dy, 0);
|
|
3622
3486
|
this.transform(1, 0, 0, 1, -x, -y);
|
|
3623
3487
|
}
|
|
3624
|
-
|
|
3625
|
-
// flip coordinate system
|
|
3626
3488
|
this.transform(1, 0, 0, -1, 0, this.page.height);
|
|
3627
3489
|
y = this.page.height - y - dy;
|
|
3628
|
-
|
|
3629
|
-
// add current font to page if necessary
|
|
3630
3490
|
if (this.page.fonts[this._font.id] == null) {
|
|
3631
3491
|
this.page.fonts[this._font.id] = this._font.ref();
|
|
3632
3492
|
}
|
|
3633
|
-
|
|
3634
|
-
// begin the text object
|
|
3635
3493
|
this.addContent('BT');
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
this.addContent(`1 0 0 1 ${number$2(x)} ${number$2(y)} Tm`);
|
|
3639
|
-
|
|
3640
|
-
// font and font size
|
|
3641
|
-
this.addContent(`/${this._font.id} ${number$2(this._fontSize)} Tf`);
|
|
3642
|
-
|
|
3643
|
-
// rendering mode
|
|
3494
|
+
this.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
|
|
3495
|
+
this.addContent(`/${this._font.id} ${number(this._fontSize)} Tf`);
|
|
3644
3496
|
const mode = options.fill && options.stroke ? 2 : options.stroke ? 1 : 0;
|
|
3645
3497
|
if (mode) {
|
|
3646
3498
|
this.addContent(`${mode} Tr`);
|
|
3647
3499
|
}
|
|
3648
|
-
|
|
3649
|
-
// Character spacing
|
|
3650
3500
|
if (characterSpacing) {
|
|
3651
|
-
this.addContent(`${number
|
|
3501
|
+
this.addContent(`${number(characterSpacing)} Tc`);
|
|
3502
|
+
}
|
|
3503
|
+
if (horizontalScaling !== 100) {
|
|
3504
|
+
this.addContent(`${horizontalScaling} Tz`);
|
|
3652
3505
|
}
|
|
3653
|
-
|
|
3654
|
-
// Add the actual text
|
|
3655
|
-
// If we have a word spacing value, we need to encode each word separately
|
|
3656
|
-
// since the normal Tw operator only works on character code 32, which isn't
|
|
3657
|
-
// used for embedded fonts.
|
|
3658
3506
|
if (wordSpacing) {
|
|
3659
3507
|
words = text.trim().split(/\s+/);
|
|
3660
3508
|
wordSpacing += this.widthOfString(' ') + characterSpacing;
|
|
@@ -3665,9 +3513,6 @@ var TextMixin = {
|
|
|
3665
3513
|
const [encodedWord, positionsWord] = this._font.encode(word, options.features);
|
|
3666
3514
|
encoded = encoded.concat(encodedWord);
|
|
3667
3515
|
positions = positions.concat(positionsWord);
|
|
3668
|
-
|
|
3669
|
-
// add the word spacing to the end of the word
|
|
3670
|
-
// clone object because of cache
|
|
3671
3516
|
const space = {};
|
|
3672
3517
|
const object = positions[positions.length - 1];
|
|
3673
3518
|
for (let key in object) {
|
|
@@ -3684,60 +3529,42 @@ var TextMixin = {
|
|
|
3684
3529
|
const commands = [];
|
|
3685
3530
|
let last = 0;
|
|
3686
3531
|
let hadOffset = false;
|
|
3687
|
-
|
|
3688
|
-
// Adds a segment of text to the TJ command buffer
|
|
3689
3532
|
const addSegment = cur => {
|
|
3690
3533
|
if (last < cur) {
|
|
3691
3534
|
const hex = encoded.slice(last, cur).join('');
|
|
3692
3535
|
const advance = positions[cur - 1].xAdvance - positions[cur - 1].advanceWidth;
|
|
3693
|
-
commands.push(`<${hex}> ${number
|
|
3536
|
+
commands.push(`<${hex}> ${number(-advance)}`);
|
|
3694
3537
|
}
|
|
3695
|
-
|
|
3538
|
+
last = cur;
|
|
3696
3539
|
};
|
|
3697
|
-
|
|
3698
|
-
// Flushes the current TJ commands to the output stream
|
|
3699
3540
|
const flush = i => {
|
|
3700
3541
|
addSegment(i);
|
|
3701
3542
|
if (commands.length > 0) {
|
|
3702
3543
|
this.addContent(`[${commands.join(' ')}] TJ`);
|
|
3703
|
-
|
|
3544
|
+
commands.length = 0;
|
|
3704
3545
|
}
|
|
3705
3546
|
};
|
|
3706
3547
|
for (i = 0; i < positions.length; i++) {
|
|
3707
|
-
// If we have an x or y offset, we have to break out of the current TJ command
|
|
3708
|
-
// so we can move the text position.
|
|
3709
3548
|
const pos = positions[i];
|
|
3710
3549
|
if (pos.xOffset || pos.yOffset) {
|
|
3711
|
-
// Flush the current buffer
|
|
3712
3550
|
flush(i);
|
|
3713
|
-
|
|
3714
|
-
// Move the text position and flush just the current character
|
|
3715
|
-
this.addContent(`1 0 0 1 ${number$2(x + pos.xOffset * scale)} ${number$2(y + pos.yOffset * scale)} Tm`);
|
|
3551
|
+
this.addContent(`1 0 0 1 ${number(x + pos.xOffset * scale)} ${number(y + pos.yOffset * scale)} Tm`);
|
|
3716
3552
|
flush(i + 1);
|
|
3717
3553
|
hadOffset = true;
|
|
3718
3554
|
} else {
|
|
3719
|
-
// If the last character had an offset, reset the text position
|
|
3720
3555
|
if (hadOffset) {
|
|
3721
|
-
this.addContent(`1 0 0 1 ${number
|
|
3556
|
+
this.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
|
|
3722
3557
|
hadOffset = false;
|
|
3723
3558
|
}
|
|
3724
|
-
|
|
3725
|
-
// Group segments that don't have any advance adjustments
|
|
3726
3559
|
if (pos.xAdvance - pos.advanceWidth !== 0) {
|
|
3727
3560
|
addSegment(i + 1);
|
|
3728
3561
|
}
|
|
3729
3562
|
}
|
|
3730
3563
|
x += pos.xAdvance * scale;
|
|
3731
3564
|
}
|
|
3732
|
-
|
|
3733
|
-
// Flush any remaining commands
|
|
3734
3565
|
flush(i);
|
|
3735
|
-
|
|
3736
|
-
// end the text object
|
|
3737
3566
|
this.addContent('ET');
|
|
3738
|
-
|
|
3739
|
-
// restore flipped coordinate system
|
|
3740
|
-
return this.restore();
|
|
3567
|
+
this.restore();
|
|
3741
3568
|
}
|
|
3742
3569
|
};
|
|
3743
3570
|
|
|
@@ -3755,8 +3582,6 @@ class JPEG {
|
|
|
3755
3582
|
if (this.data.readUInt16BE(0) !== 0xffd8) {
|
|
3756
3583
|
throw 'SOI not found in JPEG';
|
|
3757
3584
|
}
|
|
3758
|
-
|
|
3759
|
-
// Parse the EXIF orientation
|
|
3760
3585
|
this.orientation = exif.fromBuffer(this.data).Orientation || 1;
|
|
3761
3586
|
let pos = 2;
|
|
3762
3587
|
while (pos < this.data.length) {
|
|
@@ -3793,16 +3618,10 @@ class JPEG {
|
|
|
3793
3618
|
ColorSpace: this.colorSpace,
|
|
3794
3619
|
Filter: 'DCTDecode'
|
|
3795
3620
|
});
|
|
3796
|
-
|
|
3797
|
-
// add extra decode params for CMYK images. By swapping the
|
|
3798
|
-
// min and max values from the default, we invert the colors. See
|
|
3799
|
-
// section 4.8.4 of the spec.
|
|
3800
3621
|
if (this.colorSpace === 'DeviceCMYK') {
|
|
3801
3622
|
this.obj.data['Decode'] = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0];
|
|
3802
3623
|
}
|
|
3803
3624
|
this.obj.end(this.data);
|
|
3804
|
-
|
|
3805
|
-
// free memory
|
|
3806
3625
|
return this.data = null;
|
|
3807
3626
|
}
|
|
3808
3627
|
}
|
|
@@ -3845,24 +3664,14 @@ class PNGImage {
|
|
|
3845
3664
|
if (this.image.palette.length === 0) {
|
|
3846
3665
|
this.obj.data['ColorSpace'] = this.image.colorSpace;
|
|
3847
3666
|
} else {
|
|
3848
|
-
// embed the color palette in the PDF as an object stream
|
|
3849
3667
|
const palette = this.document.ref();
|
|
3850
3668
|
palette.end(Buffer.from(this.image.palette));
|
|
3851
|
-
|
|
3852
|
-
// build the color space array for the image
|
|
3853
3669
|
this.obj.data['ColorSpace'] = ['Indexed', 'DeviceRGB', this.image.palette.length / 3 - 1, palette];
|
|
3854
3670
|
}
|
|
3855
|
-
|
|
3856
|
-
// For PNG color types 0, 2 and 3, the transparency data is stored in
|
|
3857
|
-
// a dedicated PNG chunk.
|
|
3858
3671
|
if (this.image.transparency.grayscale != null) {
|
|
3859
|
-
// Use Color Key Masking (spec section 4.8.5)
|
|
3860
|
-
// An array with N elements, where N is two times the number of color components.
|
|
3861
3672
|
const val = this.image.transparency.grayscale;
|
|
3862
3673
|
this.obj.data['Mask'] = [val, val];
|
|
3863
3674
|
} else if (this.image.transparency.rgb) {
|
|
3864
|
-
// Use Color Key Masking (spec section 4.8.5)
|
|
3865
|
-
// An array with N elements, where N is two times the number of color components.
|
|
3866
3675
|
const {
|
|
3867
3676
|
rgb
|
|
3868
3677
|
} = this.image.transparency;
|
|
@@ -3872,14 +3681,9 @@ class PNGImage {
|
|
|
3872
3681
|
}
|
|
3873
3682
|
this.obj.data['Mask'] = mask;
|
|
3874
3683
|
} else if (this.image.transparency.indexed) {
|
|
3875
|
-
// Create a transparency SMask for the image based on the data
|
|
3876
|
-
// in the PLTE and tRNS sections. See below for details on SMasks.
|
|
3877
3684
|
dataDecoded = true;
|
|
3878
3685
|
return this.loadIndexedAlphaChannel();
|
|
3879
3686
|
} else if (hasAlphaChannel) {
|
|
3880
|
-
// For PNG color types 4 and 6, the transparency data is stored as a alpha
|
|
3881
|
-
// channel mixed in with the main image data. Separate this data out into an
|
|
3882
|
-
// SMask object and store it separately in the PDF.
|
|
3883
3687
|
dataDecoded = true;
|
|
3884
3688
|
return this.splitAlphaChannel();
|
|
3885
3689
|
}
|
|
@@ -3903,11 +3707,7 @@ class PNGImage {
|
|
|
3903
3707
|
sMask.end(this.alphaChannel);
|
|
3904
3708
|
this.obj.data['SMask'] = sMask;
|
|
3905
3709
|
}
|
|
3906
|
-
|
|
3907
|
-
// add the actual image data
|
|
3908
3710
|
this.obj.end(this.imgData);
|
|
3909
|
-
|
|
3910
|
-
// free memory
|
|
3911
3711
|
this.image = null;
|
|
3912
3712
|
return this.imgData = null;
|
|
3913
3713
|
}
|
|
@@ -3920,7 +3720,6 @@ class PNGImage {
|
|
|
3920
3720
|
const alphaChannel = Buffer.alloc(pixelCount);
|
|
3921
3721
|
let i = p = a = 0;
|
|
3922
3722
|
const len = pixels.length;
|
|
3923
|
-
// For 16bit images copy only most significant byte (MSB) - PNG data is always stored in network byte order (MSB first)
|
|
3924
3723
|
const skipByteCount = this.image.bits === 16 ? 1 : 0;
|
|
3925
3724
|
while (i < len) {
|
|
3926
3725
|
for (let colorIndex = 0; colorIndex < colorCount; colorIndex++) {
|
|
@@ -3955,10 +3754,6 @@ class PNGImage {
|
|
|
3955
3754
|
}
|
|
3956
3755
|
}
|
|
3957
3756
|
|
|
3958
|
-
/*
|
|
3959
|
-
PDFImage - embeds images in PDF documents
|
|
3960
|
-
By Devon Govett
|
|
3961
|
-
*/
|
|
3962
3757
|
class PDFImage {
|
|
3963
3758
|
static open(src, label) {
|
|
3964
3759
|
let data;
|
|
@@ -3990,18 +3785,17 @@ class PDFImage {
|
|
|
3990
3785
|
var ImagesMixin = {
|
|
3991
3786
|
initImages() {
|
|
3992
3787
|
this._imageRegistry = {};
|
|
3993
|
-
|
|
3788
|
+
this._imageCount = 0;
|
|
3994
3789
|
},
|
|
3995
3790
|
image(src, x, y) {
|
|
3996
3791
|
let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
3997
|
-
let bh, bp, bw, image, ip, left, left1,
|
|
3792
|
+
let bh, bp, bw, image, ip, left, left1, originX, originY;
|
|
3998
3793
|
if (typeof x === 'object') {
|
|
3999
3794
|
options = x;
|
|
4000
3795
|
x = null;
|
|
4001
3796
|
}
|
|
4002
|
-
|
|
4003
|
-
// Ignore orientation based on document options or image options
|
|
4004
3797
|
const ignoreOrientation = options.ignoreOrientation || options.ignoreOrientation !== false && this.options.ignoreOrientation;
|
|
3798
|
+
const inDocumentFlow = typeof y !== 'number';
|
|
4005
3799
|
x = (left = x != null ? x : options.x) != null ? left : this.x;
|
|
4006
3800
|
y = (left1 = y != null ? y : options.y) != null ? left1 : this.y;
|
|
4007
3801
|
if (typeof src === 'string') {
|
|
@@ -4024,8 +3818,6 @@ var ImagesMixin = {
|
|
|
4024
3818
|
width,
|
|
4025
3819
|
height
|
|
4026
3820
|
} = image;
|
|
4027
|
-
|
|
4028
|
-
// If EXIF orientation calls for it, swap width and height
|
|
4029
3821
|
if (!ignoreOrientation && image.orientation > 4) {
|
|
4030
3822
|
[width, height] = [height, width];
|
|
4031
3823
|
}
|
|
@@ -4077,80 +3869,70 @@ var ImagesMixin = {
|
|
|
4077
3869
|
y = y + bh - h;
|
|
4078
3870
|
}
|
|
4079
3871
|
}
|
|
3872
|
+
let rotateAngle = 0;
|
|
3873
|
+
let xTransform = x;
|
|
3874
|
+
let yTransform = y;
|
|
3875
|
+
let hTransform = h;
|
|
3876
|
+
let wTransform = w;
|
|
4080
3877
|
if (!ignoreOrientation) {
|
|
4081
3878
|
switch (image.orientation) {
|
|
4082
|
-
// No orientation (need to flip image, though, because of the default transform matrix on the document)
|
|
4083
3879
|
default:
|
|
4084
3880
|
case 1:
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
rotateAngle = 0;
|
|
3881
|
+
hTransform = -h;
|
|
3882
|
+
yTransform += h;
|
|
4088
3883
|
break;
|
|
4089
|
-
// Flip Horizontal
|
|
4090
3884
|
case 2:
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
rotateAngle = 0;
|
|
3885
|
+
wTransform = -w;
|
|
3886
|
+
hTransform = -h;
|
|
3887
|
+
xTransform += w;
|
|
3888
|
+
yTransform += h;
|
|
4096
3889
|
break;
|
|
4097
|
-
// Rotate 180 degrees
|
|
4098
3890
|
case 3:
|
|
4099
3891
|
originX = x;
|
|
4100
3892
|
originY = y;
|
|
4101
|
-
|
|
4102
|
-
|
|
3893
|
+
hTransform = -h;
|
|
3894
|
+
xTransform -= w;
|
|
4103
3895
|
rotateAngle = 180;
|
|
4104
3896
|
break;
|
|
4105
|
-
// Flip vertical
|
|
4106
3897
|
case 4:
|
|
4107
|
-
// Do nothing, image will be flipped
|
|
4108
|
-
|
|
4109
3898
|
break;
|
|
4110
|
-
// Flip horizontally and rotate 270 degrees CW
|
|
4111
3899
|
case 5:
|
|
4112
3900
|
originX = x;
|
|
4113
3901
|
originY = y;
|
|
4114
|
-
|
|
4115
|
-
|
|
3902
|
+
wTransform = h;
|
|
3903
|
+
hTransform = w;
|
|
3904
|
+
yTransform -= hTransform;
|
|
4116
3905
|
rotateAngle = 90;
|
|
4117
3906
|
break;
|
|
4118
|
-
// Rotate 90 degrees CW
|
|
4119
3907
|
case 6:
|
|
4120
3908
|
originX = x;
|
|
4121
3909
|
originY = y;
|
|
4122
|
-
|
|
4123
|
-
|
|
3910
|
+
wTransform = h;
|
|
3911
|
+
hTransform = -w;
|
|
4124
3912
|
rotateAngle = 90;
|
|
4125
3913
|
break;
|
|
4126
|
-
// Flip horizontally and rotate 90 degrees CW
|
|
4127
3914
|
case 7:
|
|
4128
3915
|
originX = x;
|
|
4129
3916
|
originY = y;
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
x -= w;
|
|
3917
|
+
hTransform = -w;
|
|
3918
|
+
wTransform = -h;
|
|
3919
|
+
xTransform += h;
|
|
4134
3920
|
rotateAngle = 90;
|
|
4135
3921
|
break;
|
|
4136
|
-
// Rotate 270 degrees CW
|
|
4137
3922
|
case 8:
|
|
4138
3923
|
originX = x;
|
|
4139
3924
|
originY = y;
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
3925
|
+
wTransform = h;
|
|
3926
|
+
hTransform = -w;
|
|
3927
|
+
xTransform -= h;
|
|
3928
|
+
yTransform += w;
|
|
4144
3929
|
rotateAngle = -90;
|
|
4145
3930
|
break;
|
|
4146
3931
|
}
|
|
4147
3932
|
} else {
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
rotateAngle = 0;
|
|
3933
|
+
hTransform = -h;
|
|
3934
|
+
yTransform += h;
|
|
4151
3935
|
}
|
|
4152
|
-
|
|
4153
|
-
// create link annotations if the link option is given
|
|
4154
3936
|
if (options.link != null) {
|
|
4155
3937
|
this.link(x, y, w, h, options.link);
|
|
4156
3938
|
}
|
|
@@ -4160,9 +3942,7 @@ var ImagesMixin = {
|
|
|
4160
3942
|
if (options.destination != null) {
|
|
4161
3943
|
this.addNamedDestination(options.destination, 'XYZ', x, y, null);
|
|
4162
3944
|
}
|
|
4163
|
-
|
|
4164
|
-
// Set the current y position to below the image if it is in the document flow
|
|
4165
|
-
if (this.y === y) {
|
|
3945
|
+
if (inDocumentFlow) {
|
|
4166
3946
|
this.y += h;
|
|
4167
3947
|
}
|
|
4168
3948
|
this.save();
|
|
@@ -4171,7 +3951,7 @@ var ImagesMixin = {
|
|
|
4171
3951
|
origin: [originX, originY]
|
|
4172
3952
|
});
|
|
4173
3953
|
}
|
|
4174
|
-
this.transform(
|
|
3954
|
+
this.transform(wTransform, 0, 0, hTransform, xTransform, yTransform);
|
|
4175
3955
|
this.addContent(`/${image.label} Do`);
|
|
4176
3956
|
this.restore();
|
|
4177
3957
|
return this;
|
|
@@ -4197,19 +3977,17 @@ var AnnotationsMixin = {
|
|
|
4197
3977
|
options.Rect = this._convertRect(x, y, w, h);
|
|
4198
3978
|
options.Border = [0, 0, 0];
|
|
4199
3979
|
if (options.Subtype === 'Link' && typeof options.F === 'undefined') {
|
|
4200
|
-
options.F = 1 << 2;
|
|
3980
|
+
options.F = 1 << 2;
|
|
4201
3981
|
}
|
|
4202
3982
|
if (options.Subtype !== 'Link') {
|
|
4203
3983
|
if (options.C == null) {
|
|
4204
3984
|
options.C = this._normalizeColor(options.color || [0, 0, 0]);
|
|
4205
3985
|
}
|
|
4206
|
-
}
|
|
3986
|
+
}
|
|
4207
3987
|
delete options.color;
|
|
4208
3988
|
if (typeof options.Dest === 'string') {
|
|
4209
3989
|
options.Dest = new String(options.Dest);
|
|
4210
3990
|
}
|
|
4211
|
-
|
|
4212
|
-
// Capitalize keys
|
|
4213
3991
|
for (let key in options) {
|
|
4214
3992
|
const val = options[key];
|
|
4215
3993
|
options[key[0].toUpperCase() + key.slice(1)] = val;
|
|
@@ -4223,7 +4001,9 @@ var AnnotationsMixin = {
|
|
|
4223
4001
|
let options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
|
|
4224
4002
|
options.Subtype = 'Text';
|
|
4225
4003
|
options.Contents = new String(contents);
|
|
4226
|
-
options.Name
|
|
4004
|
+
if (options.Name == null) {
|
|
4005
|
+
options.Name = 'Comment';
|
|
4006
|
+
}
|
|
4227
4007
|
if (options.color == null) {
|
|
4228
4008
|
options.color = [243, 223, 92];
|
|
4229
4009
|
}
|
|
@@ -4243,7 +4023,6 @@ var AnnotationsMixin = {
|
|
|
4243
4023
|
let options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
|
|
4244
4024
|
options.Subtype = 'Link';
|
|
4245
4025
|
if (typeof url === 'number') {
|
|
4246
|
-
// Link to a page in the document (the page must already exist)
|
|
4247
4026
|
const pages = this._root.data.Pages.data;
|
|
4248
4027
|
if (url >= 0 && url < pages.Kids.length) {
|
|
4249
4028
|
options.A = this.ref({
|
|
@@ -4255,7 +4034,6 @@ var AnnotationsMixin = {
|
|
|
4255
4034
|
throw new Error(`The document has no page ${url}`);
|
|
4256
4035
|
}
|
|
4257
4036
|
} else {
|
|
4258
|
-
// Link to an external url
|
|
4259
4037
|
options.A = this.ref({
|
|
4260
4038
|
S: 'URI',
|
|
4261
4039
|
URI: new String(url)
|
|
@@ -4318,14 +4096,11 @@ var AnnotationsMixin = {
|
|
|
4318
4096
|
fileAnnotation(x, y, w, h) {
|
|
4319
4097
|
let file = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
|
|
4320
4098
|
let options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
|
|
4321
|
-
// create hidden file
|
|
4322
4099
|
const filespec = this.file(file.src, Object.assign({
|
|
4323
4100
|
hidden: true
|
|
4324
4101
|
}, file));
|
|
4325
4102
|
options.Subtype = 'FileAttachment';
|
|
4326
4103
|
options.FS = filespec;
|
|
4327
|
-
|
|
4328
|
-
// add description from filespec unless description (Contents) has already been set
|
|
4329
4104
|
if (options.Contents) {
|
|
4330
4105
|
options.Contents = new String(options.Contents);
|
|
4331
4106
|
} else if (filespec.data.Desc) {
|
|
@@ -4334,14 +4109,9 @@ var AnnotationsMixin = {
|
|
|
4334
4109
|
return this.annotate(x, y, w, h, options);
|
|
4335
4110
|
},
|
|
4336
4111
|
_convertRect(x1, y1, w, h) {
|
|
4337
|
-
// flip y1 and y2
|
|
4338
4112
|
let y2 = y1;
|
|
4339
4113
|
y1 += h;
|
|
4340
|
-
|
|
4341
|
-
// make x2
|
|
4342
4114
|
let x2 = x1 + w;
|
|
4343
|
-
|
|
4344
|
-
// apply current transformation matrix to points
|
|
4345
4115
|
const [m0, m1, m2, m3, m4, m5] = this._ctm;
|
|
4346
4116
|
x1 = m0 * x1 + m2 * y1 + m4;
|
|
4347
4117
|
y1 = m1 * x1 + m3 * y1 + m5;
|
|
@@ -4405,7 +4175,7 @@ class PDFOutline {
|
|
|
4405
4175
|
|
|
4406
4176
|
var OutlineMixin = {
|
|
4407
4177
|
initOutline() {
|
|
4408
|
-
|
|
4178
|
+
this.outline = new PDFOutline(this, null, null, null);
|
|
4409
4179
|
},
|
|
4410
4180
|
endOutline() {
|
|
4411
4181
|
this.outline.endOutline();
|
|
@@ -4416,11 +4186,6 @@ var OutlineMixin = {
|
|
|
4416
4186
|
}
|
|
4417
4187
|
};
|
|
4418
4188
|
|
|
4419
|
-
/*
|
|
4420
|
-
PDFStructureContent - a reference to a marked structure content
|
|
4421
|
-
By Ben Schmidt
|
|
4422
|
-
*/
|
|
4423
|
-
|
|
4424
4189
|
class PDFStructureContent {
|
|
4425
4190
|
constructor(pageRef, mcid) {
|
|
4426
4191
|
this.refs = [{
|
|
@@ -4433,10 +4198,6 @@ class PDFStructureContent {
|
|
|
4433
4198
|
}
|
|
4434
4199
|
}
|
|
4435
4200
|
|
|
4436
|
-
/*
|
|
4437
|
-
PDFStructureElement - represents an element in the PDF logical structure tree
|
|
4438
|
-
By Ben Schmidt
|
|
4439
|
-
*/
|
|
4440
4201
|
class PDFStructureElement {
|
|
4441
4202
|
constructor(document, type) {
|
|
4442
4203
|
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
@@ -4446,7 +4207,6 @@ class PDFStructureElement {
|
|
|
4446
4207
|
this._ended = false;
|
|
4447
4208
|
this._flushed = false;
|
|
4448
4209
|
this.dictionary = document.ref({
|
|
4449
|
-
// Type: "StructElem",
|
|
4450
4210
|
S: type
|
|
4451
4211
|
});
|
|
4452
4212
|
const data = this.dictionary.data;
|
|
@@ -4495,7 +4255,6 @@ class PDFStructureElement {
|
|
|
4495
4255
|
this._addContentToParentTree(child);
|
|
4496
4256
|
}
|
|
4497
4257
|
if (typeof child === 'function' && this._attached) {
|
|
4498
|
-
// _contentForClosure() adds the content to the parent tree
|
|
4499
4258
|
child = this._contentForClosure(child);
|
|
4500
4259
|
}
|
|
4501
4260
|
this._children.push(child);
|
|
@@ -4572,10 +4331,6 @@ class PDFStructureElement {
|
|
|
4572
4331
|
this.dictionary.data.K = [];
|
|
4573
4332
|
this._children.forEach(child => this._flushChild(child));
|
|
4574
4333
|
this.dictionary.end();
|
|
4575
|
-
|
|
4576
|
-
// free memory used by children; the dictionary itself may still be
|
|
4577
|
-
// referenced by a parent structure element or root, but we can
|
|
4578
|
-
// at least trim the tree here
|
|
4579
4334
|
this._children = [];
|
|
4580
4335
|
this.dictionary.data.K = null;
|
|
4581
4336
|
this._flushed = true;
|
|
@@ -4597,7 +4352,7 @@ class PDFStructureElement {
|
|
|
4597
4352
|
this.dictionary.data.K.push(mcid);
|
|
4598
4353
|
} else {
|
|
4599
4354
|
this.dictionary.data.K.push({
|
|
4600
|
-
Type:
|
|
4355
|
+
Type: 'MCR',
|
|
4601
4356
|
Pg: pageRef,
|
|
4602
4357
|
MCID: mcid
|
|
4603
4358
|
});
|
|
@@ -4607,25 +4362,18 @@ class PDFStructureElement {
|
|
|
4607
4362
|
}
|
|
4608
4363
|
}
|
|
4609
4364
|
|
|
4610
|
-
/*
|
|
4611
|
-
PDFNumberTree - represents a number tree object
|
|
4612
|
-
*/
|
|
4613
4365
|
class PDFNumberTree extends PDFTree {
|
|
4614
4366
|
_compareKeys(a, b) {
|
|
4615
4367
|
return parseInt(a) - parseInt(b);
|
|
4616
4368
|
}
|
|
4617
4369
|
_keysName() {
|
|
4618
|
-
return
|
|
4370
|
+
return 'Nums';
|
|
4619
4371
|
}
|
|
4620
4372
|
_dataForKey(k) {
|
|
4621
4373
|
return parseInt(k);
|
|
4622
4374
|
}
|
|
4623
4375
|
}
|
|
4624
4376
|
|
|
4625
|
-
/*
|
|
4626
|
-
Markings mixin - support marked content sequences in content streams
|
|
4627
|
-
By Ben Schmidt
|
|
4628
|
-
*/
|
|
4629
4377
|
var MarkingsMixin = {
|
|
4630
4378
|
initMarkings(options) {
|
|
4631
4379
|
this.structChildren = [];
|
|
@@ -4748,6 +4496,9 @@ var MarkingsMixin = {
|
|
|
4748
4496
|
}
|
|
4749
4497
|
return this._root.data.MarkInfo;
|
|
4750
4498
|
},
|
|
4499
|
+
hasMarkInfoDictionary() {
|
|
4500
|
+
return !!this._root.data.MarkInfo;
|
|
4501
|
+
},
|
|
4751
4502
|
getStructTreeRoot() {
|
|
4752
4503
|
if (!this._root.data.StructTreeRoot) {
|
|
4753
4504
|
this._root.data.StructTreeRoot = this.ref({
|
|
@@ -4762,7 +4513,6 @@ var MarkingsMixin = {
|
|
|
4762
4513
|
return this.getStructTreeRoot().data.ParentTree;
|
|
4763
4514
|
},
|
|
4764
4515
|
createStructParentTreeNextKey() {
|
|
4765
|
-
// initialise the MarkInfo dictionary
|
|
4766
4516
|
this.getMarkInfoDictionary();
|
|
4767
4517
|
const structTreeRoot = this.getStructTreeRoot();
|
|
4768
4518
|
const key = structTreeRoot.data.ParentTreeNextKey++;
|
|
@@ -4826,10 +4576,6 @@ const FORMAT_DEFAULT = {
|
|
|
4826
4576
|
}
|
|
4827
4577
|
};
|
|
4828
4578
|
var AcroFormMixin = {
|
|
4829
|
-
/**
|
|
4830
|
-
* Must call if adding AcroForms to a document. Must also call font() before
|
|
4831
|
-
* this method to set the default font.
|
|
4832
|
-
*/
|
|
4833
4579
|
initForm() {
|
|
4834
4580
|
if (!this._font) {
|
|
4835
4581
|
throw new Error('Must set a font before calling initForm method');
|
|
@@ -4852,9 +4598,6 @@ var AcroFormMixin = {
|
|
|
4852
4598
|
this._root.data.AcroForm = AcroForm;
|
|
4853
4599
|
return this;
|
|
4854
4600
|
},
|
|
4855
|
-
/**
|
|
4856
|
-
* Called automatically by document.js
|
|
4857
|
-
*/
|
|
4858
4601
|
endAcroForm() {
|
|
4859
4602
|
if (this._root.data.AcroForm) {
|
|
4860
4603
|
if (!Object.keys(this._acroform.fonts).length && !this._acroform.defaultFont) {
|
|
@@ -4880,13 +4623,6 @@ var AcroFormMixin = {
|
|
|
4880
4623
|
}
|
|
4881
4624
|
return this;
|
|
4882
4625
|
},
|
|
4883
|
-
/**
|
|
4884
|
-
* Creates and adds a form field to the document. Form fields are intermediate
|
|
4885
|
-
* nodes in a PDF form that are used to specify form name heirarchy and form
|
|
4886
|
-
* value defaults.
|
|
4887
|
-
* @param {string} name - field name (T attribute in field dictionary)
|
|
4888
|
-
* @param {object} options - other attributes to include in field dictionary
|
|
4889
|
-
*/
|
|
4890
4626
|
formField(name) {
|
|
4891
4627
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
4892
4628
|
let fieldDict = this._fieldDict(name, null, options);
|
|
@@ -4894,26 +4630,13 @@ var AcroFormMixin = {
|
|
|
4894
4630
|
this._addToParent(fieldRef);
|
|
4895
4631
|
return fieldRef;
|
|
4896
4632
|
},
|
|
4897
|
-
/**
|
|
4898
|
-
* Creates and adds a Form Annotation to the document. Form annotations are
|
|
4899
|
-
* called Widget annotations internally within a PDF file.
|
|
4900
|
-
* @param {string} name - form field name (T attribute of widget annotation
|
|
4901
|
-
* dictionary)
|
|
4902
|
-
* @param {number} x
|
|
4903
|
-
* @param {number} y
|
|
4904
|
-
* @param {number} w
|
|
4905
|
-
* @param {number} h
|
|
4906
|
-
* @param {object} options
|
|
4907
|
-
*/
|
|
4908
4633
|
formAnnotation(name, type, x, y, w, h) {
|
|
4909
4634
|
let options = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {};
|
|
4910
4635
|
let fieldDict = this._fieldDict(name, type, options);
|
|
4911
4636
|
fieldDict.Subtype = 'Widget';
|
|
4912
4637
|
if (fieldDict.F === undefined) {
|
|
4913
|
-
fieldDict.F = 4;
|
|
4638
|
+
fieldDict.F = 4;
|
|
4914
4639
|
}
|
|
4915
|
-
|
|
4916
|
-
// Add Field annot to page, and get it's ref
|
|
4917
4640
|
this.annotate(x, y, w, h, fieldDict);
|
|
4918
4641
|
let annotRef = this.page.annotations[this.page.annotations.length - 1];
|
|
4919
4642
|
return this._addToParent(annotRef);
|
|
@@ -5081,23 +4804,18 @@ var AcroFormMixin = {
|
|
|
5081
4804
|
delete options.align;
|
|
5082
4805
|
}
|
|
5083
4806
|
if (result !== 0) {
|
|
5084
|
-
options.Q = result;
|
|
4807
|
+
options.Q = result;
|
|
5085
4808
|
}
|
|
5086
4809
|
return options;
|
|
5087
4810
|
},
|
|
5088
4811
|
_resolveFont(options) {
|
|
5089
|
-
// add current font to document-level AcroForm dict if necessary
|
|
5090
4812
|
if (this._acroform.fonts[this._font.id] == null) {
|
|
5091
4813
|
this._acroform.fonts[this._font.id] = this._font.ref();
|
|
5092
4814
|
}
|
|
5093
|
-
|
|
5094
|
-
// add current font to field's resource dict (RD) if not the default acroform font
|
|
5095
4815
|
if (this._acroform.defaultFont !== this._font.name) {
|
|
5096
4816
|
options.DR = {
|
|
5097
4817
|
Font: {}
|
|
5098
4818
|
};
|
|
5099
|
-
|
|
5100
|
-
// Get the fontSize option. If not set use auto sizing
|
|
5101
4819
|
const fontSize = options.fontSize || 0;
|
|
5102
4820
|
options.DR.Font[this._font.id] = this._font.ref();
|
|
5103
4821
|
options.DA = new String(`/${this._font.id} ${fontSize} Tf 0 g`);
|
|
@@ -5149,19 +4867,6 @@ var AcroFormMixin = {
|
|
|
5149
4867
|
};
|
|
5150
4868
|
|
|
5151
4869
|
var AttachmentsMixin = {
|
|
5152
|
-
/**
|
|
5153
|
-
* Embed contents of `src` in PDF
|
|
5154
|
-
* @param {Buffer | ArrayBuffer | string} src input Buffer, ArrayBuffer, base64 encoded string or path to file
|
|
5155
|
-
* @param {object} options
|
|
5156
|
-
* * options.name: filename to be shown in PDF, will use `src` if none set
|
|
5157
|
-
* * options.type: filetype to be shown in PDF
|
|
5158
|
-
* * options.description: description to be shown in PDF
|
|
5159
|
-
* * options.hidden: if true, do not add attachment to EmbeddedFiles dictionary. Useful for file attachment annotations
|
|
5160
|
-
* * options.creationDate: override creation date
|
|
5161
|
-
* * options.modifiedDate: override modified date
|
|
5162
|
-
* * options.relationship: Relationship between the PDF document and its attached file. Can be 'Alternative', 'Data', 'Source', 'Supplement' or 'Unspecified'.
|
|
5163
|
-
* @returns filespec reference
|
|
5164
|
-
*/
|
|
5165
4870
|
file(src) {
|
|
5166
4871
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
5167
4872
|
options.name = options.name || src;
|
|
@@ -5190,8 +4895,6 @@ var AttachmentsMixin = {
|
|
|
5190
4895
|
if (!data) {
|
|
5191
4896
|
throw new Error(`Could not read contents of file at filepath ${src}`);
|
|
5192
4897
|
}
|
|
5193
|
-
|
|
5194
|
-
// update CreationDate and ModDate
|
|
5195
4898
|
const {
|
|
5196
4899
|
birthtime,
|
|
5197
4900
|
ctime
|
|
@@ -5200,26 +4903,18 @@ var AttachmentsMixin = {
|
|
|
5200
4903
|
refBody.Params.ModDate = ctime;
|
|
5201
4904
|
}
|
|
5202
4905
|
}
|
|
5203
|
-
|
|
5204
|
-
// override creation date and modified date
|
|
5205
4906
|
if (options.creationDate instanceof Date) {
|
|
5206
4907
|
refBody.Params.CreationDate = options.creationDate;
|
|
5207
4908
|
}
|
|
5208
4909
|
if (options.modifiedDate instanceof Date) {
|
|
5209
4910
|
refBody.Params.ModDate = options.modifiedDate;
|
|
5210
4911
|
}
|
|
5211
|
-
// add optional subtype
|
|
5212
4912
|
if (options.type) {
|
|
5213
4913
|
refBody.Subtype = options.type.replace('/', '#2F');
|
|
5214
4914
|
}
|
|
5215
|
-
|
|
5216
|
-
// add checksum and size information
|
|
5217
4915
|
const checksum = CryptoJS.MD5(CryptoJS.lib.WordArray.create(new Uint8Array(data)));
|
|
5218
4916
|
refBody.Params.CheckSum = new String(checksum);
|
|
5219
4917
|
refBody.Params.Size = data.byteLength;
|
|
5220
|
-
|
|
5221
|
-
// save some space when embedding the same file again
|
|
5222
|
-
// if a file with the same name and metadata exists, reuse its reference
|
|
5223
4918
|
let ref;
|
|
5224
4919
|
if (!this._fileRegistry) this._fileRegistry = {};
|
|
5225
4920
|
let file = this._fileRegistry[options.name];
|
|
@@ -5233,7 +4928,6 @@ var AttachmentsMixin = {
|
|
|
5233
4928
|
ref
|
|
5234
4929
|
};
|
|
5235
4930
|
}
|
|
5236
|
-
// add filespec for embedded file
|
|
5237
4931
|
const fileSpecBody = {
|
|
5238
4932
|
Type: 'Filespec',
|
|
5239
4933
|
AFRelationship: options.relationship,
|
|
@@ -5251,8 +4945,6 @@ var AttachmentsMixin = {
|
|
|
5251
4945
|
if (!options.hidden) {
|
|
5252
4946
|
this.addNamedEmbeddedFile(options.name, filespec);
|
|
5253
4947
|
}
|
|
5254
|
-
|
|
5255
|
-
// Add file to the catalogue to be PDF/A3 compliant
|
|
5256
4948
|
if (this._root.data.AF) {
|
|
5257
4949
|
this._root.data.AF.push(filespec);
|
|
5258
4950
|
} else {
|
|
@@ -5261,8 +4953,6 @@ var AttachmentsMixin = {
|
|
|
5261
4953
|
return filespec;
|
|
5262
4954
|
}
|
|
5263
4955
|
};
|
|
5264
|
-
|
|
5265
|
-
/** check two embedded file metadata objects for equality */
|
|
5266
4956
|
function isEqual(a, b) {
|
|
5267
4957
|
return a.Subtype === b.Subtype && a.Params.CheckSum.toString() === b.Params.CheckSum.toString() && a.Params.Size === b.Params.Size && a.Params.CreationDate.getTime() === b.Params.CreationDate.getTime() && (a.Params.ModDate === undefined && b.Params.ModDate === undefined || a.Params.ModDate.getTime() === b.Params.ModDate.getTime());
|
|
5268
4958
|
}
|
|
@@ -5273,7 +4963,6 @@ var PDFA = {
|
|
|
5273
4963
|
this.subset_conformance = pSubset.charAt(pSubset.length - 1).toUpperCase();
|
|
5274
4964
|
this.subset = parseInt(pSubset.charAt(pSubset.length - 2));
|
|
5275
4965
|
} else {
|
|
5276
|
-
// Default to Basic conformance when user doesn't specify
|
|
5277
4966
|
this.subset_conformance = 'B';
|
|
5278
4967
|
this.subset = parseInt(pSubset.charAt(pSubset.length - 1));
|
|
5279
4968
|
}
|
|
@@ -5358,6 +5047,656 @@ var SubsetMixin = {
|
|
|
5358
5047
|
}
|
|
5359
5048
|
};
|
|
5360
5049
|
|
|
5050
|
+
const ROW_FIELDS = ['height', 'minHeight', 'maxHeight'];
|
|
5051
|
+
const COLUMN_FIELDS = ['width', 'minWidth', 'maxWidth'];
|
|
5052
|
+
function memoize(fn, maxSize) {
|
|
5053
|
+
const cache = new Map();
|
|
5054
|
+
return function () {
|
|
5055
|
+
const key = arguments.length <= 0 ? undefined : arguments[0];
|
|
5056
|
+
if (!cache.has(key)) {
|
|
5057
|
+
cache.set(key, fn(...arguments));
|
|
5058
|
+
if (cache.size > maxSize) cache.delete(cache.keys().next());
|
|
5059
|
+
}
|
|
5060
|
+
return cache.get(key);
|
|
5061
|
+
};
|
|
5062
|
+
}
|
|
5063
|
+
function isObject(item) {
|
|
5064
|
+
return item && typeof item === 'object' && !Array.isArray(item);
|
|
5065
|
+
}
|
|
5066
|
+
function deepMerge(target) {
|
|
5067
|
+
if (!isObject(target)) return target;
|
|
5068
|
+
target = deepClone(target);
|
|
5069
|
+
for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
5070
|
+
sources[_key - 1] = arguments[_key];
|
|
5071
|
+
}
|
|
5072
|
+
for (const source of sources) {
|
|
5073
|
+
if (isObject(source)) {
|
|
5074
|
+
for (const key in source) {
|
|
5075
|
+
if (isObject(source[key])) {
|
|
5076
|
+
if (!(key in target)) target[key] = {};
|
|
5077
|
+
target[key] = deepMerge(target[key], source[key]);
|
|
5078
|
+
} else if (source[key] !== undefined) {
|
|
5079
|
+
target[key] = deepClone(source[key]);
|
|
5080
|
+
}
|
|
5081
|
+
}
|
|
5082
|
+
}
|
|
5083
|
+
}
|
|
5084
|
+
return target;
|
|
5085
|
+
}
|
|
5086
|
+
function deepClone(obj) {
|
|
5087
|
+
let result = obj;
|
|
5088
|
+
if (typeof obj == 'object') {
|
|
5089
|
+
result = Array.isArray(obj) ? [] : {};
|
|
5090
|
+
for (const key in obj) result[key] = deepClone(obj[key]);
|
|
5091
|
+
}
|
|
5092
|
+
return result;
|
|
5093
|
+
}
|
|
5094
|
+
|
|
5095
|
+
function normalizedDefaultStyle(defaultStyleInternal) {
|
|
5096
|
+
let defaultStyle = defaultStyleInternal;
|
|
5097
|
+
if (typeof defaultStyle !== 'object') defaultStyle = {
|
|
5098
|
+
text: defaultStyle
|
|
5099
|
+
};
|
|
5100
|
+
const defaultRowStyle = Object.fromEntries(Object.entries(defaultStyle).filter(_ref => {
|
|
5101
|
+
let [k] = _ref;
|
|
5102
|
+
return ROW_FIELDS.includes(k);
|
|
5103
|
+
}));
|
|
5104
|
+
const defaultColStyle = Object.fromEntries(Object.entries(defaultStyle).filter(_ref2 => {
|
|
5105
|
+
let [k] = _ref2;
|
|
5106
|
+
return COLUMN_FIELDS.includes(k);
|
|
5107
|
+
}));
|
|
5108
|
+
defaultStyle.padding = normalizeSides(defaultStyle.padding);
|
|
5109
|
+
defaultStyle.border = normalizeSides(defaultStyle.border);
|
|
5110
|
+
defaultStyle.borderColor = normalizeSides(defaultStyle.borderColor);
|
|
5111
|
+
defaultStyle.align = normalizeAlignment(defaultStyle.align);
|
|
5112
|
+
return {
|
|
5113
|
+
defaultStyle,
|
|
5114
|
+
defaultRowStyle,
|
|
5115
|
+
defaultColStyle
|
|
5116
|
+
};
|
|
5117
|
+
}
|
|
5118
|
+
function normalizedRowStyle(defaultRowStyle, rowStyleInternal, i) {
|
|
5119
|
+
let rowStyle = rowStyleInternal(i);
|
|
5120
|
+
if (rowStyle == null || typeof rowStyle !== 'object') {
|
|
5121
|
+
rowStyle = {
|
|
5122
|
+
height: rowStyle
|
|
5123
|
+
};
|
|
5124
|
+
}
|
|
5125
|
+
rowStyle.padding = normalizeSides(rowStyle.padding);
|
|
5126
|
+
rowStyle.border = normalizeSides(rowStyle.border);
|
|
5127
|
+
rowStyle.borderColor = normalizeSides(rowStyle.borderColor);
|
|
5128
|
+
rowStyle.align = normalizeAlignment(rowStyle.align);
|
|
5129
|
+
rowStyle = deepMerge(defaultRowStyle, rowStyle);
|
|
5130
|
+
const document = this.document;
|
|
5131
|
+
const page = document.page;
|
|
5132
|
+
const contentHeight = page.contentHeight;
|
|
5133
|
+
if (rowStyle.height == null || rowStyle.height === 'auto') {
|
|
5134
|
+
rowStyle.height = 'auto';
|
|
5135
|
+
} else {
|
|
5136
|
+
rowStyle.height = document.sizeToPoint(rowStyle.height, 0, page, contentHeight);
|
|
5137
|
+
}
|
|
5138
|
+
rowStyle.minHeight = document.sizeToPoint(rowStyle.minHeight, 0, page, contentHeight);
|
|
5139
|
+
rowStyle.maxHeight = document.sizeToPoint(rowStyle.maxHeight, 0, page, contentHeight);
|
|
5140
|
+
return rowStyle;
|
|
5141
|
+
}
|
|
5142
|
+
function normalizedColumnStyle(defaultColStyle, colStyleInternal, i) {
|
|
5143
|
+
let colStyle = colStyleInternal(i);
|
|
5144
|
+
if (colStyle == null || typeof colStyle !== 'object') {
|
|
5145
|
+
colStyle = {
|
|
5146
|
+
width: colStyle
|
|
5147
|
+
};
|
|
5148
|
+
}
|
|
5149
|
+
colStyle.padding = normalizeSides(colStyle.padding);
|
|
5150
|
+
colStyle.border = normalizeSides(colStyle.border);
|
|
5151
|
+
colStyle.borderColor = normalizeSides(colStyle.borderColor);
|
|
5152
|
+
colStyle.align = normalizeAlignment(colStyle.align);
|
|
5153
|
+
colStyle = deepMerge(defaultColStyle, colStyle);
|
|
5154
|
+
if (colStyle.width == null || colStyle.width === '*') {
|
|
5155
|
+
colStyle.width = '*';
|
|
5156
|
+
} else {
|
|
5157
|
+
colStyle.width = this.document.sizeToPoint(colStyle.width, 0, this.document.page, this._maxWidth);
|
|
5158
|
+
}
|
|
5159
|
+
colStyle.minWidth = this.document.sizeToPoint(colStyle.minWidth, 0, this.document.page, this._maxWidth);
|
|
5160
|
+
colStyle.maxWidth = this.document.sizeToPoint(colStyle.maxWidth, 0, this.document.page, this._maxWidth);
|
|
5161
|
+
return colStyle;
|
|
5162
|
+
}
|
|
5163
|
+
function normalizeAlignment(align) {
|
|
5164
|
+
return align == null || typeof align === 'string' ? {
|
|
5165
|
+
x: align,
|
|
5166
|
+
y: align
|
|
5167
|
+
} : align;
|
|
5168
|
+
}
|
|
5169
|
+
|
|
5170
|
+
function normalizeTable() {
|
|
5171
|
+
const doc = this.document;
|
|
5172
|
+
const opts = this.opts;
|
|
5173
|
+
let index = doc._tableIndex++;
|
|
5174
|
+
this._id = new String(opts.id ?? `table-${index}`);
|
|
5175
|
+
this._position = {
|
|
5176
|
+
x: doc.sizeToPoint(opts.position?.x, doc.x),
|
|
5177
|
+
y: doc.sizeToPoint(opts.position?.y, doc.y)
|
|
5178
|
+
};
|
|
5179
|
+
this._maxWidth = doc.sizeToPoint(opts.maxWidth, doc.page.width - doc.page.margins.right - this._position.x);
|
|
5180
|
+
const {
|
|
5181
|
+
defaultStyle,
|
|
5182
|
+
defaultColStyle,
|
|
5183
|
+
defaultRowStyle
|
|
5184
|
+
} = normalizedDefaultStyle(opts.defaultStyle);
|
|
5185
|
+
this._defaultStyle = defaultStyle;
|
|
5186
|
+
let colStyle;
|
|
5187
|
+
if (opts.columnStyles) {
|
|
5188
|
+
if (Array.isArray(opts.columnStyles)) {
|
|
5189
|
+
colStyle = i => opts.columnStyles[i];
|
|
5190
|
+
} else if (typeof opts.columnStyles === 'function') {
|
|
5191
|
+
colStyle = memoize(i => opts.columnStyles(i), Infinity);
|
|
5192
|
+
} else if (typeof opts.columnStyles === 'object') {
|
|
5193
|
+
colStyle = () => opts.columnStyles;
|
|
5194
|
+
}
|
|
5195
|
+
}
|
|
5196
|
+
if (!colStyle) colStyle = () => ({});
|
|
5197
|
+
this._colStyle = normalizedColumnStyle.bind(this, defaultColStyle, colStyle);
|
|
5198
|
+
let rowStyle;
|
|
5199
|
+
if (opts.rowStyles) {
|
|
5200
|
+
if (Array.isArray(opts.rowStyles)) {
|
|
5201
|
+
rowStyle = i => opts.rowStyles[i];
|
|
5202
|
+
} else if (typeof opts.rowStyles === 'function') {
|
|
5203
|
+
rowStyle = memoize(i => opts.rowStyles(i), 10);
|
|
5204
|
+
} else if (typeof opts.rowStyles === 'object') {
|
|
5205
|
+
rowStyle = () => opts.rowStyles;
|
|
5206
|
+
}
|
|
5207
|
+
}
|
|
5208
|
+
if (!rowStyle) rowStyle = () => ({});
|
|
5209
|
+
this._rowStyle = normalizedRowStyle.bind(this, defaultRowStyle, rowStyle);
|
|
5210
|
+
}
|
|
5211
|
+
function normalizeText(text) {
|
|
5212
|
+
if (text != null) text = `${text}`;
|
|
5213
|
+
return text;
|
|
5214
|
+
}
|
|
5215
|
+
function normalizeCell(cell, rowIndex, colIndex) {
|
|
5216
|
+
const colStyle = this._colStyle(colIndex);
|
|
5217
|
+
let rowStyle = this._rowStyle(rowIndex);
|
|
5218
|
+
const font = deepMerge({}, colStyle.font, rowStyle.font, cell.font);
|
|
5219
|
+
const customFont = Object.values(font).filter(v => v != null).length > 0;
|
|
5220
|
+
const doc = this.document;
|
|
5221
|
+
const rollbackFont = doc._fontSource;
|
|
5222
|
+
const rollbackFontSize = doc._fontSize;
|
|
5223
|
+
const rollbackFontFamily = doc._fontFamily;
|
|
5224
|
+
if (customFont) {
|
|
5225
|
+
if (font.src) doc.font(font.src, font.family);
|
|
5226
|
+
if (font.size) doc.fontSize(font.size);
|
|
5227
|
+
rowStyle = this._rowStyle(rowIndex);
|
|
5228
|
+
}
|
|
5229
|
+
cell.padding = normalizeSides(cell.padding);
|
|
5230
|
+
cell.border = normalizeSides(cell.border);
|
|
5231
|
+
cell.borderColor = normalizeSides(cell.borderColor);
|
|
5232
|
+
const config = deepMerge(this._defaultStyle, colStyle, rowStyle, cell);
|
|
5233
|
+
config.rowIndex = rowIndex;
|
|
5234
|
+
config.colIndex = colIndex;
|
|
5235
|
+
config.font = font ?? {};
|
|
5236
|
+
config.customFont = customFont;
|
|
5237
|
+
config.text = normalizeText(config.text);
|
|
5238
|
+
config.rowSpan = config.rowSpan ?? 1;
|
|
5239
|
+
config.colSpan = config.colSpan ?? 1;
|
|
5240
|
+
config.padding = normalizeSides(config.padding, '0.25em', x => doc.sizeToPoint(x, '0.25em'));
|
|
5241
|
+
config.border = normalizeSides(config.border, 1, x => doc.sizeToPoint(x, 1));
|
|
5242
|
+
config.borderColor = normalizeSides(config.borderColor, 'black', x => x ?? 'black');
|
|
5243
|
+
config.align = normalizeAlignment(config.align);
|
|
5244
|
+
config.align.x = config.align.x ?? 'left';
|
|
5245
|
+
config.align.y = config.align.y ?? 'top';
|
|
5246
|
+
config.textStroke = doc.sizeToPoint(config.textStroke, 0);
|
|
5247
|
+
config.textStrokeColor = config.textStrokeColor ?? 'black';
|
|
5248
|
+
config.textColor = config.textColor ?? 'black';
|
|
5249
|
+
config.textOptions = config.textOptions ?? {};
|
|
5250
|
+
config.id = new String(config.id ?? `${this._id}-${rowIndex}-${colIndex}`);
|
|
5251
|
+
config.type = config.type?.toUpperCase() === 'TH' ? 'TH' : 'TD';
|
|
5252
|
+
if (config.scope) {
|
|
5253
|
+
config.scope = config.scope.toLowerCase();
|
|
5254
|
+
if (config.scope === 'row') config.scope = 'Row';else if (config.scope === 'both') config.scope = 'Both';else if (config.scope === 'column') config.scope = 'Column';
|
|
5255
|
+
}
|
|
5256
|
+
if (typeof this.opts.debug === 'boolean') config.debug = this.opts.debug;
|
|
5257
|
+
if (customFont) doc.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5258
|
+
return config;
|
|
5259
|
+
}
|
|
5260
|
+
function normalizeRow(row, rowIndex) {
|
|
5261
|
+
if (!this._cellClaim) this._cellClaim = new Set();
|
|
5262
|
+
let colIndex = 0;
|
|
5263
|
+
return row.map(cell => {
|
|
5264
|
+
if (cell == null || typeof cell !== 'object') cell = {
|
|
5265
|
+
text: cell
|
|
5266
|
+
};
|
|
5267
|
+
while (this._cellClaim.has(`${rowIndex},${colIndex}`)) {
|
|
5268
|
+
colIndex++;
|
|
5269
|
+
}
|
|
5270
|
+
cell = normalizeCell.call(this, cell, rowIndex, colIndex);
|
|
5271
|
+
for (let i = 0; i < cell.rowSpan; i++) {
|
|
5272
|
+
for (let j = 0; j < cell.colSpan; j++) {
|
|
5273
|
+
this._cellClaim.add(`${rowIndex + i},${colIndex + j}`);
|
|
5274
|
+
}
|
|
5275
|
+
}
|
|
5276
|
+
colIndex += cell.colSpan;
|
|
5277
|
+
return cell;
|
|
5278
|
+
});
|
|
5279
|
+
}
|
|
5280
|
+
|
|
5281
|
+
function ensure(row) {
|
|
5282
|
+
this._columnWidths = [];
|
|
5283
|
+
ensureColumnWidths.call(this, row.reduce((a, cell) => a + cell.colSpan, 0));
|
|
5284
|
+
this._rowHeights = [];
|
|
5285
|
+
this._rowYPos = [this._position.y];
|
|
5286
|
+
this._rowBuffer = new Set();
|
|
5287
|
+
}
|
|
5288
|
+
function ensureColumnWidths(numCols) {
|
|
5289
|
+
let starColumnIndexes = [];
|
|
5290
|
+
let starMinAcc = 0;
|
|
5291
|
+
let unclaimedWidth = this._maxWidth;
|
|
5292
|
+
for (let i = 0; i < numCols; i++) {
|
|
5293
|
+
let col = this._colStyle(i);
|
|
5294
|
+
if (col.width === '*') {
|
|
5295
|
+
starColumnIndexes[i] = col;
|
|
5296
|
+
starMinAcc += col.minWidth;
|
|
5297
|
+
} else {
|
|
5298
|
+
unclaimedWidth -= col.width;
|
|
5299
|
+
this._columnWidths[i] = col.width;
|
|
5300
|
+
}
|
|
5301
|
+
}
|
|
5302
|
+
let starColCount = starColumnIndexes.reduce(x => x + 1, 0);
|
|
5303
|
+
if (starMinAcc >= unclaimedWidth) {
|
|
5304
|
+
starColumnIndexes.forEach((cell, i) => {
|
|
5305
|
+
this._columnWidths[i] = cell.minWidth;
|
|
5306
|
+
});
|
|
5307
|
+
} else if (starColCount > 0) {
|
|
5308
|
+
starColumnIndexes.forEach((col, i) => {
|
|
5309
|
+
let starSize = unclaimedWidth / starColCount;
|
|
5310
|
+
this._columnWidths[i] = Math.max(starSize, col.minWidth);
|
|
5311
|
+
if (col.maxWidth > 0) {
|
|
5312
|
+
this._columnWidths[i] = Math.min(this._columnWidths[i], col.maxWidth);
|
|
5313
|
+
}
|
|
5314
|
+
unclaimedWidth -= this._columnWidths[i];
|
|
5315
|
+
starColCount--;
|
|
5316
|
+
});
|
|
5317
|
+
}
|
|
5318
|
+
let tempX = this._position.x;
|
|
5319
|
+
this._columnXPos = Array.from(this._columnWidths, v => {
|
|
5320
|
+
const t = tempX;
|
|
5321
|
+
tempX += v;
|
|
5322
|
+
return t;
|
|
5323
|
+
});
|
|
5324
|
+
}
|
|
5325
|
+
function measure(row, rowIndex) {
|
|
5326
|
+
row.forEach(cell => this._rowBuffer.add(cell));
|
|
5327
|
+
if (rowIndex > 0) {
|
|
5328
|
+
this._rowYPos[rowIndex] = this._rowYPos[rowIndex - 1] + this._rowHeights[rowIndex - 1];
|
|
5329
|
+
}
|
|
5330
|
+
const rowStyle = this._rowStyle(rowIndex);
|
|
5331
|
+
let toRender = [];
|
|
5332
|
+
this._rowBuffer.forEach(cell => {
|
|
5333
|
+
if (cell.rowIndex + cell.rowSpan - 1 === rowIndex) {
|
|
5334
|
+
toRender.push(measureCell.call(this, cell, rowStyle.height));
|
|
5335
|
+
this._rowBuffer.delete(cell);
|
|
5336
|
+
}
|
|
5337
|
+
});
|
|
5338
|
+
let rowHeight = rowStyle.height;
|
|
5339
|
+
if (rowHeight === 'auto') {
|
|
5340
|
+
rowHeight = toRender.reduce((acc, cell) => {
|
|
5341
|
+
let minHeight = cell.textBounds.height + cell.padding.top + cell.padding.bottom;
|
|
5342
|
+
for (let i = 0; i < cell.rowSpan - 1; i++) {
|
|
5343
|
+
minHeight -= this._rowHeights[cell.rowIndex + i];
|
|
5344
|
+
}
|
|
5345
|
+
return Math.max(acc, minHeight);
|
|
5346
|
+
}, 0);
|
|
5347
|
+
}
|
|
5348
|
+
rowHeight = Math.max(rowHeight, rowStyle.minHeight);
|
|
5349
|
+
if (rowStyle.maxHeight > 0) {
|
|
5350
|
+
rowHeight = Math.min(rowHeight, rowStyle.maxHeight);
|
|
5351
|
+
}
|
|
5352
|
+
this._rowHeights[rowIndex] = rowHeight;
|
|
5353
|
+
let newPage = false;
|
|
5354
|
+
if (rowHeight > this.document.page.contentHeight) {
|
|
5355
|
+
console.warn(new Error(`Row ${rowIndex} requested more than the safe page height, row has been clamped`).stack.slice(7));
|
|
5356
|
+
this._rowHeights[rowIndex] = this.document.page.maxY() - this._rowYPos[rowIndex];
|
|
5357
|
+
} else if (this._rowYPos[rowIndex] + rowHeight >= this.document.page.maxY()) {
|
|
5358
|
+
this._rowYPos[rowIndex] = this.document.page.margins.top;
|
|
5359
|
+
newPage = true;
|
|
5360
|
+
}
|
|
5361
|
+
return {
|
|
5362
|
+
newPage,
|
|
5363
|
+
toRender: toRender.map(cell => measureCell.call(this, cell, rowHeight))
|
|
5364
|
+
};
|
|
5365
|
+
}
|
|
5366
|
+
function measureCell(cell, rowHeight) {
|
|
5367
|
+
let cellWidth = 0;
|
|
5368
|
+
for (let i = 0; i < cell.colSpan; i++) {
|
|
5369
|
+
cellWidth += this._columnWidths[cell.colIndex + i];
|
|
5370
|
+
}
|
|
5371
|
+
let cellHeight = rowHeight;
|
|
5372
|
+
if (cellHeight === 'auto') {
|
|
5373
|
+
cellHeight = this.document.page.contentHeight;
|
|
5374
|
+
} else {
|
|
5375
|
+
for (let i = 0; i < cell.rowSpan - 1; i++) {
|
|
5376
|
+
cellHeight += this._rowHeights[cell.rowIndex + i];
|
|
5377
|
+
}
|
|
5378
|
+
}
|
|
5379
|
+
const textAllocatedWidth = cellWidth - cell.padding.left - cell.padding.right;
|
|
5380
|
+
const textAllocatedHeight = cellHeight - cell.padding.top - cell.padding.bottom;
|
|
5381
|
+
const rotation = cell.textOptions.rotation ?? 0;
|
|
5382
|
+
const {
|
|
5383
|
+
width: textMaxWidth,
|
|
5384
|
+
height: textMaxHeight
|
|
5385
|
+
} = computeBounds(rotation, textAllocatedWidth, textAllocatedHeight);
|
|
5386
|
+
const textOptions = {
|
|
5387
|
+
align: cell.align.x,
|
|
5388
|
+
ellipsis: true,
|
|
5389
|
+
stroke: cell.textStroke > 0,
|
|
5390
|
+
fill: true,
|
|
5391
|
+
width: textMaxWidth,
|
|
5392
|
+
height: textMaxHeight,
|
|
5393
|
+
rotation,
|
|
5394
|
+
...cell.textOptions
|
|
5395
|
+
};
|
|
5396
|
+
let textBounds = {
|
|
5397
|
+
x: 0,
|
|
5398
|
+
y: 0,
|
|
5399
|
+
width: 0,
|
|
5400
|
+
height: 0
|
|
5401
|
+
};
|
|
5402
|
+
if (cell.text) {
|
|
5403
|
+
const rollbackFont = this.document._fontSource;
|
|
5404
|
+
const rollbackFontSize = this.document._fontSize;
|
|
5405
|
+
const rollbackFontFamily = this.document._fontFamily;
|
|
5406
|
+
if (cell.font?.src) this.document.font(cell.font.src, cell.font?.family);
|
|
5407
|
+
if (cell.font?.size) this.document.fontSize(cell.font.size);
|
|
5408
|
+
const unRotatedTextBounds = this.document.boundsOfString(cell.text, 0, 0, {
|
|
5409
|
+
...textOptions,
|
|
5410
|
+
rotation: 0
|
|
5411
|
+
});
|
|
5412
|
+
textOptions.width = unRotatedTextBounds.width;
|
|
5413
|
+
textOptions.height = unRotatedTextBounds.height;
|
|
5414
|
+
textBounds = this.document.boundsOfString(cell.text, 0, 0, textOptions);
|
|
5415
|
+
this.document.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5416
|
+
}
|
|
5417
|
+
return {
|
|
5418
|
+
...cell,
|
|
5419
|
+
textOptions,
|
|
5420
|
+
x: this._columnXPos[cell.colIndex],
|
|
5421
|
+
y: this._rowYPos[cell.rowIndex],
|
|
5422
|
+
textX: this._columnXPos[cell.colIndex] + cell.padding.left,
|
|
5423
|
+
textY: this._rowYPos[cell.rowIndex] + cell.padding.top,
|
|
5424
|
+
width: cellWidth,
|
|
5425
|
+
height: cellHeight,
|
|
5426
|
+
textAllocatedHeight,
|
|
5427
|
+
textAllocatedWidth,
|
|
5428
|
+
textBounds
|
|
5429
|
+
};
|
|
5430
|
+
}
|
|
5431
|
+
function computeBounds(rotation, allocWidth, allocHeight) {
|
|
5432
|
+
let textMaxWidth, textMaxHeight;
|
|
5433
|
+
const cos = cosine(rotation);
|
|
5434
|
+
const sin = sine(rotation);
|
|
5435
|
+
if (rotation === 0 || rotation === 180) {
|
|
5436
|
+
textMaxWidth = allocWidth;
|
|
5437
|
+
textMaxHeight = allocHeight;
|
|
5438
|
+
} else if (rotation === 90 || rotation === 270) {
|
|
5439
|
+
textMaxWidth = allocHeight;
|
|
5440
|
+
textMaxHeight = allocWidth;
|
|
5441
|
+
} else if (rotation < 90 || rotation > 180 && rotation < 270) {
|
|
5442
|
+
textMaxWidth = allocWidth / (2 * cos);
|
|
5443
|
+
textMaxHeight = allocWidth / (2 * sin);
|
|
5444
|
+
} else {
|
|
5445
|
+
textMaxHeight = allocWidth / (2 * cos);
|
|
5446
|
+
textMaxWidth = allocWidth / (2 * sin);
|
|
5447
|
+
}
|
|
5448
|
+
const EF = sin * textMaxWidth;
|
|
5449
|
+
const FG = cos * textMaxHeight;
|
|
5450
|
+
if (EF + FG > allocHeight) {
|
|
5451
|
+
const denominator = cos * cos - sin * sin;
|
|
5452
|
+
if (rotation === 0 || rotation === 180) {
|
|
5453
|
+
textMaxWidth = allocWidth;
|
|
5454
|
+
textMaxHeight = allocHeight;
|
|
5455
|
+
} else if (rotation === 90 || rotation === 270) {
|
|
5456
|
+
textMaxWidth = allocHeight;
|
|
5457
|
+
textMaxHeight = allocWidth;
|
|
5458
|
+
} else if (rotation < 90 || rotation > 180 && rotation < 270) {
|
|
5459
|
+
textMaxWidth = (allocWidth * cos - allocHeight * sin) / denominator;
|
|
5460
|
+
textMaxHeight = (allocHeight * cos - allocWidth * sin) / denominator;
|
|
5461
|
+
} else {
|
|
5462
|
+
textMaxHeight = (allocWidth * cos - allocHeight * sin) / denominator;
|
|
5463
|
+
textMaxWidth = (allocHeight * cos - allocWidth * sin) / denominator;
|
|
5464
|
+
}
|
|
5465
|
+
}
|
|
5466
|
+
return {
|
|
5467
|
+
width: Math.abs(textMaxWidth),
|
|
5468
|
+
height: Math.abs(textMaxHeight)
|
|
5469
|
+
};
|
|
5470
|
+
}
|
|
5471
|
+
|
|
5472
|
+
function accommodateTable() {
|
|
5473
|
+
const structParent = this.opts.structParent;
|
|
5474
|
+
if (structParent) {
|
|
5475
|
+
this._tableStruct = this.document.struct('Table');
|
|
5476
|
+
this._tableStruct.dictionary.data.ID = this._id;
|
|
5477
|
+
if (structParent instanceof PDFStructureElement) {
|
|
5478
|
+
structParent.add(this._tableStruct);
|
|
5479
|
+
} else if (structParent instanceof PDFDocument) {
|
|
5480
|
+
structParent.addStructure(this._tableStruct);
|
|
5481
|
+
}
|
|
5482
|
+
this._headerRowLookup = {};
|
|
5483
|
+
this._headerColumnLookup = {};
|
|
5484
|
+
}
|
|
5485
|
+
}
|
|
5486
|
+
function accommodateCleanup() {
|
|
5487
|
+
if (this._tableStruct) this._tableStruct.end();
|
|
5488
|
+
}
|
|
5489
|
+
function accessibleRow(row, rowIndex, renderCell) {
|
|
5490
|
+
const rowStruct = this.document.struct('TR');
|
|
5491
|
+
rowStruct.dictionary.data.ID = new String(`${this._id}-${rowIndex}`);
|
|
5492
|
+
this._tableStruct.add(rowStruct);
|
|
5493
|
+
row.forEach(cell => renderCell(cell, rowStruct));
|
|
5494
|
+
rowStruct.end();
|
|
5495
|
+
}
|
|
5496
|
+
function accessibleCell(cell, rowStruct, callback) {
|
|
5497
|
+
const doc = this.document;
|
|
5498
|
+
const cellStruct = doc.struct(cell.type, {
|
|
5499
|
+
title: cell.title
|
|
5500
|
+
});
|
|
5501
|
+
cellStruct.dictionary.data.ID = cell.id;
|
|
5502
|
+
rowStruct.add(cellStruct);
|
|
5503
|
+
const padding = cell.padding;
|
|
5504
|
+
const border = cell.border;
|
|
5505
|
+
const attributes = {
|
|
5506
|
+
O: 'Table',
|
|
5507
|
+
Width: cell.width,
|
|
5508
|
+
Height: cell.height,
|
|
5509
|
+
Padding: [padding.top, padding.bottom, padding.left, padding.right],
|
|
5510
|
+
RowSpan: cell.rowSpan > 1 ? cell.rowSpan : undefined,
|
|
5511
|
+
ColSpan: cell.colSpan > 1 ? cell.colSpan : undefined,
|
|
5512
|
+
BorderThickness: [border.top, border.bottom, border.left, border.right]
|
|
5513
|
+
};
|
|
5514
|
+
if (cell.type === 'TH') {
|
|
5515
|
+
if (cell.scope === 'Row' || cell.scope === 'Both') {
|
|
5516
|
+
for (let i = 0; i < cell.rowSpan; i++) {
|
|
5517
|
+
if (!this._headerRowLookup[cell.rowIndex + i]) {
|
|
5518
|
+
this._headerRowLookup[cell.rowIndex + i] = [];
|
|
5519
|
+
}
|
|
5520
|
+
this._headerRowLookup[cell.rowIndex + i].push(cell.id);
|
|
5521
|
+
}
|
|
5522
|
+
attributes.Scope = cell.scope;
|
|
5523
|
+
}
|
|
5524
|
+
if (cell.scope === 'Column' || cell.scope === 'Both') {
|
|
5525
|
+
for (let i = 0; i < cell.colSpan; i++) {
|
|
5526
|
+
if (!this._headerColumnLookup[cell.colIndex + i]) {
|
|
5527
|
+
this._headerColumnLookup[cell.colIndex + i] = [];
|
|
5528
|
+
}
|
|
5529
|
+
this._headerColumnLookup[cell.colIndex + i].push(cell.id);
|
|
5530
|
+
}
|
|
5531
|
+
attributes.Scope = cell.scope;
|
|
5532
|
+
}
|
|
5533
|
+
}
|
|
5534
|
+
const Headers = new Set([...Array.from({
|
|
5535
|
+
length: cell.colSpan
|
|
5536
|
+
}, (_, i) => this._headerColumnLookup[cell.colIndex + i]).flat(), ...Array.from({
|
|
5537
|
+
length: cell.rowSpan
|
|
5538
|
+
}, (_, i) => this._headerRowLookup[cell.rowIndex + i]).flat()].filter(Boolean));
|
|
5539
|
+
if (Headers.size) attributes.Headers = Array.from(Headers);
|
|
5540
|
+
const normalizeColor = doc._normalizeColor;
|
|
5541
|
+
if (cell.backgroundColor != null) {
|
|
5542
|
+
attributes.BackgroundColor = normalizeColor(cell.backgroundColor);
|
|
5543
|
+
}
|
|
5544
|
+
const hasBorder = [border.top, border.bottom, border.left, border.right];
|
|
5545
|
+
if (hasBorder.some(x => x)) {
|
|
5546
|
+
const borderColor = cell.borderColor;
|
|
5547
|
+
attributes.BorderColor = [hasBorder[0] ? normalizeColor(borderColor.top) : null, hasBorder[1] ? normalizeColor(borderColor.bottom) : null, hasBorder[2] ? normalizeColor(borderColor.left) : null, hasBorder[3] ? normalizeColor(borderColor.right) : null];
|
|
5548
|
+
}
|
|
5549
|
+
Object.keys(attributes).forEach(key => attributes[key] === undefined && delete attributes[key]);
|
|
5550
|
+
cellStruct.dictionary.data.A = doc.ref(attributes);
|
|
5551
|
+
cellStruct.add(callback);
|
|
5552
|
+
cellStruct.end();
|
|
5553
|
+
cellStruct.dictionary.data.A.end();
|
|
5554
|
+
}
|
|
5555
|
+
|
|
5556
|
+
function renderRow(row, rowIndex) {
|
|
5557
|
+
if (this._tableStruct) {
|
|
5558
|
+
accessibleRow.call(this, row, rowIndex, renderCell.bind(this));
|
|
5559
|
+
} else {
|
|
5560
|
+
row.forEach(cell => renderCell.call(this, cell));
|
|
5561
|
+
}
|
|
5562
|
+
return this._rowYPos[rowIndex] + this._rowHeights[rowIndex];
|
|
5563
|
+
}
|
|
5564
|
+
function renderCell(cell, rowStruct) {
|
|
5565
|
+
const cellRenderer = () => {
|
|
5566
|
+
if (cell.backgroundColor != null) {
|
|
5567
|
+
this.document.save().rect(cell.x, cell.y, cell.width, cell.height).fill(cell.backgroundColor).restore();
|
|
5568
|
+
}
|
|
5569
|
+
renderBorder.call(this, cell.border, cell.borderColor, cell.x, cell.y, cell.width, cell.height);
|
|
5570
|
+
if (cell.debug) {
|
|
5571
|
+
this.document.save();
|
|
5572
|
+
this.document.dash(1, {
|
|
5573
|
+
space: 1
|
|
5574
|
+
}).lineWidth(1).strokeOpacity(0.3);
|
|
5575
|
+
this.document.rect(cell.x, cell.y, cell.width, cell.height).stroke('green');
|
|
5576
|
+
this.document.restore();
|
|
5577
|
+
}
|
|
5578
|
+
if (cell.text) renderCellText.call(this, cell);
|
|
5579
|
+
};
|
|
5580
|
+
if (rowStruct) accessibleCell.call(this, cell, rowStruct, cellRenderer);else cellRenderer();
|
|
5581
|
+
}
|
|
5582
|
+
function renderCellText(cell) {
|
|
5583
|
+
const doc = this.document;
|
|
5584
|
+
const rollbackFont = doc._fontSource;
|
|
5585
|
+
const rollbackFontSize = doc._fontSize;
|
|
5586
|
+
const rollbackFontFamily = doc._fontFamily;
|
|
5587
|
+
if (cell.customFont) {
|
|
5588
|
+
if (cell.font.src) doc.font(cell.font.src, cell.font.family);
|
|
5589
|
+
if (cell.font.size) doc.fontSize(cell.font.size);
|
|
5590
|
+
}
|
|
5591
|
+
const x = cell.textX;
|
|
5592
|
+
const y = cell.textY;
|
|
5593
|
+
const Ah = cell.textAllocatedHeight;
|
|
5594
|
+
const Aw = cell.textAllocatedWidth;
|
|
5595
|
+
const Cw = cell.textBounds.width;
|
|
5596
|
+
const Ch = cell.textBounds.height;
|
|
5597
|
+
const Ox = -cell.textBounds.x;
|
|
5598
|
+
const Oy = -cell.textBounds.y;
|
|
5599
|
+
const PxScale = cell.align.x === 'right' ? 1 : cell.align.x === 'center' ? 0.5 : 0;
|
|
5600
|
+
const Px = (Aw - Cw) * PxScale;
|
|
5601
|
+
const PyScale = cell.align.y === 'bottom' ? 1 : cell.align.y === 'center' ? 0.5 : 0;
|
|
5602
|
+
const Py = (Ah - Ch) * PyScale;
|
|
5603
|
+
const dx = Px + Ox;
|
|
5604
|
+
const dy = Py + Oy;
|
|
5605
|
+
if (cell.debug) {
|
|
5606
|
+
doc.save();
|
|
5607
|
+
doc.dash(1, {
|
|
5608
|
+
space: 1
|
|
5609
|
+
}).lineWidth(1).strokeOpacity(0.3);
|
|
5610
|
+
if (cell.text) {
|
|
5611
|
+
doc.moveTo(x + Px, y).lineTo(x + Px, y + Ah).moveTo(x + Px + Cw, y).lineTo(x + Px + Cw, y + Ah).stroke('blue').moveTo(x, y + Py).lineTo(x + Aw, y + Py).moveTo(x, y + Py + Ch).lineTo(x + Aw, y + Py + Ch).stroke('green');
|
|
5612
|
+
}
|
|
5613
|
+
doc.rect(x, y, Aw, Ah).stroke('orange');
|
|
5614
|
+
doc.restore();
|
|
5615
|
+
}
|
|
5616
|
+
doc.save().rect(x, y, Aw, Ah).clip();
|
|
5617
|
+
doc.fillColor(cell.textColor).strokeColor(cell.textStrokeColor);
|
|
5618
|
+
if (cell.textStroke > 0) doc.lineWidth(cell.textStroke);
|
|
5619
|
+
doc.text(cell.text, x + dx, y + dy, cell.textOptions);
|
|
5620
|
+
doc.restore();
|
|
5621
|
+
if (cell.font) doc.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5622
|
+
}
|
|
5623
|
+
function renderBorder(border, borderColor, x, y, width, height, mask) {
|
|
5624
|
+
border = Object.fromEntries(Object.entries(border).map(_ref => {
|
|
5625
|
+
let [k, v] = _ref;
|
|
5626
|
+
return [k, mask && !mask[k] ? 0 : v];
|
|
5627
|
+
}));
|
|
5628
|
+
const doc = this.document;
|
|
5629
|
+
if ([border.right, border.bottom, border.left].every(val => val === border.top)) {
|
|
5630
|
+
if (border.top > 0) {
|
|
5631
|
+
doc.save().lineWidth(border.top).rect(x, y, width, height).stroke(borderColor.top).restore();
|
|
5632
|
+
}
|
|
5633
|
+
} else {
|
|
5634
|
+
if (border.top > 0) {
|
|
5635
|
+
doc.save().lineWidth(border.top).moveTo(x, y).lineTo(x + width, y).stroke(borderColor.top).restore();
|
|
5636
|
+
}
|
|
5637
|
+
if (border.right > 0) {
|
|
5638
|
+
doc.save().lineWidth(border.right).moveTo(x + width, y).lineTo(x + width, y + height).stroke(borderColor.right).restore();
|
|
5639
|
+
}
|
|
5640
|
+
if (border.bottom > 0) {
|
|
5641
|
+
doc.save().lineWidth(border.bottom).moveTo(x + width, y + height).lineTo(x, y + height).stroke(borderColor.bottom).restore();
|
|
5642
|
+
}
|
|
5643
|
+
if (border.left > 0) {
|
|
5644
|
+
doc.save().lineWidth(border.left).moveTo(x, y + height).lineTo(x, y).stroke(borderColor.left).restore();
|
|
5645
|
+
}
|
|
5646
|
+
}
|
|
5647
|
+
}
|
|
5648
|
+
|
|
5649
|
+
class PDFTable {
|
|
5650
|
+
constructor(document) {
|
|
5651
|
+
let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
5652
|
+
this.document = document;
|
|
5653
|
+
this.opts = Object.freeze(opts);
|
|
5654
|
+
normalizeTable.call(this);
|
|
5655
|
+
accommodateTable.call(this);
|
|
5656
|
+
this._currRowIndex = 0;
|
|
5657
|
+
this._ended = false;
|
|
5658
|
+
if (opts.data) {
|
|
5659
|
+
for (const row of opts.data) this.row(row);
|
|
5660
|
+
return this.end();
|
|
5661
|
+
}
|
|
5662
|
+
}
|
|
5663
|
+
row(row) {
|
|
5664
|
+
let lastRow = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
5665
|
+
if (this._ended) {
|
|
5666
|
+
throw new Error(`Table was marked as ended on row ${this._currRowIndex}`);
|
|
5667
|
+
}
|
|
5668
|
+
row = Array.from(row);
|
|
5669
|
+
row = normalizeRow.call(this, row, this._currRowIndex);
|
|
5670
|
+
if (this._currRowIndex === 0) ensure.call(this, row);
|
|
5671
|
+
const {
|
|
5672
|
+
newPage,
|
|
5673
|
+
toRender
|
|
5674
|
+
} = measure.call(this, row, this._currRowIndex);
|
|
5675
|
+
if (newPage) this.document.continueOnNewPage();
|
|
5676
|
+
const yPos = renderRow.call(this, toRender, this._currRowIndex);
|
|
5677
|
+
this.document.x = this._position.x;
|
|
5678
|
+
this.document.y = yPos;
|
|
5679
|
+
if (lastRow) return this.end();
|
|
5680
|
+
this._currRowIndex++;
|
|
5681
|
+
return this;
|
|
5682
|
+
}
|
|
5683
|
+
end() {
|
|
5684
|
+
while (this._rowBuffer?.size) this.row([]);
|
|
5685
|
+
this._ended = true;
|
|
5686
|
+
accommodateCleanup.call(this);
|
|
5687
|
+
return this.document;
|
|
5688
|
+
}
|
|
5689
|
+
}
|
|
5690
|
+
|
|
5691
|
+
var TableMixin = {
|
|
5692
|
+
initTables() {
|
|
5693
|
+
this._tableIndex = 0;
|
|
5694
|
+
},
|
|
5695
|
+
table(opts) {
|
|
5696
|
+
return new PDFTable(this, opts);
|
|
5697
|
+
}
|
|
5698
|
+
};
|
|
5699
|
+
|
|
5361
5700
|
class PDFMetadata {
|
|
5362
5701
|
constructor() {
|
|
5363
5702
|
this._metadata = `
|
|
@@ -5401,7 +5740,7 @@ var MetadataMixin = {
|
|
|
5401
5740
|
_addInfo() {
|
|
5402
5741
|
this.appendXML(`
|
|
5403
5742
|
<rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/">
|
|
5404
|
-
<xmp:CreateDate>${this.info.CreationDate.toISOString().split('.')[0] +
|
|
5743
|
+
<xmp:CreateDate>${this.info.CreationDate.toISOString().split('.')[0] + 'Z'}</xmp:CreateDate>
|
|
5405
5744
|
<xmp:CreatorTool>${this.info.Creator}</xmp:CreatorTool>
|
|
5406
5745
|
</rdf:Description>
|
|
5407
5746
|
`);
|
|
@@ -5454,11 +5793,6 @@ var MetadataMixin = {
|
|
|
5454
5793
|
endMetadata() {
|
|
5455
5794
|
this._addInfo();
|
|
5456
5795
|
this.metadata.end();
|
|
5457
|
-
|
|
5458
|
-
/*
|
|
5459
|
-
Metadata was introduced in PDF 1.4, so adding it to 1.3
|
|
5460
|
-
will likely only take up more space.
|
|
5461
|
-
*/
|
|
5462
5796
|
if (this.version != 1.3) {
|
|
5463
5797
|
this.metadataRef = this.ref({
|
|
5464
5798
|
length: this.metadata.getLength(),
|
|
@@ -5473,17 +5807,11 @@ var MetadataMixin = {
|
|
|
5473
5807
|
}
|
|
5474
5808
|
};
|
|
5475
5809
|
|
|
5476
|
-
/*
|
|
5477
|
-
PDFDocument - represents an entire PDF document
|
|
5478
|
-
By Devon Govett
|
|
5479
|
-
*/
|
|
5480
5810
|
class PDFDocument extends stream.Readable {
|
|
5481
5811
|
constructor() {
|
|
5482
5812
|
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
5483
5813
|
super(options);
|
|
5484
5814
|
this.options = options;
|
|
5485
|
-
|
|
5486
|
-
// PDF version
|
|
5487
5815
|
switch (options.pdfVersion) {
|
|
5488
5816
|
case '1.4':
|
|
5489
5817
|
this.version = 1.4;
|
|
@@ -5502,13 +5830,9 @@ class PDFDocument extends stream.Readable {
|
|
|
5502
5830
|
this.version = 1.3;
|
|
5503
5831
|
break;
|
|
5504
5832
|
}
|
|
5505
|
-
|
|
5506
|
-
// Whether streams should be compressed
|
|
5507
5833
|
this.compress = this.options.compress != null ? this.options.compress : true;
|
|
5508
5834
|
this._pageBuffer = [];
|
|
5509
5835
|
this._pageBufferStart = 0;
|
|
5510
|
-
|
|
5511
|
-
// The PDF object store
|
|
5512
5836
|
this._offsets = [];
|
|
5513
5837
|
this._waiting = 0;
|
|
5514
5838
|
this._ended = false;
|
|
@@ -5529,11 +5853,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5529
5853
|
if (this.options.lang) {
|
|
5530
5854
|
this._root.data.Lang = new String(this.options.lang);
|
|
5531
5855
|
}
|
|
5532
|
-
|
|
5533
|
-
// The current page
|
|
5534
5856
|
this.page = null;
|
|
5535
|
-
|
|
5536
|
-
// Initialize mixins
|
|
5537
5857
|
this.initMetadata();
|
|
5538
5858
|
this.initColor();
|
|
5539
5859
|
this.initVector();
|
|
@@ -5542,9 +5862,8 @@ class PDFDocument extends stream.Readable {
|
|
|
5542
5862
|
this.initImages();
|
|
5543
5863
|
this.initOutline();
|
|
5544
5864
|
this.initMarkings(options);
|
|
5865
|
+
this.initTables();
|
|
5545
5866
|
this.initSubset(options);
|
|
5546
|
-
|
|
5547
|
-
// Initialize the metadata
|
|
5548
5867
|
this.info = {
|
|
5549
5868
|
Producer: 'PDFKit',
|
|
5550
5869
|
Creator: 'PDFKit',
|
|
@@ -5561,21 +5880,10 @@ class PDFDocument extends stream.Readable {
|
|
|
5561
5880
|
DisplayDocTitle: true
|
|
5562
5881
|
});
|
|
5563
5882
|
}
|
|
5564
|
-
|
|
5565
|
-
// Generate file ID
|
|
5566
5883
|
this._id = PDFSecurity.generateFileID(this.info);
|
|
5567
|
-
|
|
5568
|
-
// Initialize security settings
|
|
5569
5884
|
this._security = PDFSecurity.create(this, options);
|
|
5570
|
-
|
|
5571
|
-
// Write the header
|
|
5572
|
-
// PDF version
|
|
5573
5885
|
this._write(`%PDF-${this.version}`);
|
|
5574
|
-
|
|
5575
|
-
// 4 binary chars, as recommended by the spec
|
|
5576
5886
|
this._write('%\xFF\xFF\xFF\xFF');
|
|
5577
|
-
|
|
5578
|
-
// Add the first page
|
|
5579
5887
|
if (this.options.autoFirstPage !== false) {
|
|
5580
5888
|
this.addPage();
|
|
5581
5889
|
}
|
|
@@ -5586,27 +5894,16 @@ class PDFDocument extends stream.Readable {
|
|
|
5586
5894
|
options
|
|
5587
5895
|
} = this);
|
|
5588
5896
|
}
|
|
5589
|
-
|
|
5590
|
-
// end the current page if needed
|
|
5591
5897
|
if (!this.options.bufferPages) {
|
|
5592
5898
|
this.flushPages();
|
|
5593
5899
|
}
|
|
5594
|
-
|
|
5595
|
-
// create a page object
|
|
5596
5900
|
this.page = new PDFPage(this, options);
|
|
5597
5901
|
this._pageBuffer.push(this.page);
|
|
5598
|
-
|
|
5599
|
-
// add the page to the object store
|
|
5600
5902
|
const pages = this._root.data.Pages.data;
|
|
5601
5903
|
pages.Kids.push(this.page.dictionary);
|
|
5602
5904
|
pages.Count++;
|
|
5603
|
-
|
|
5604
|
-
// reset x and y coordinates
|
|
5605
5905
|
this.x = this.page.margins.left;
|
|
5606
5906
|
this.y = this.page.margins.top;
|
|
5607
|
-
|
|
5608
|
-
// flip PDF coordinate system so that the origin is in
|
|
5609
|
-
// the top left rather than the bottom left
|
|
5610
5907
|
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
5611
5908
|
this.transform(1, 0, 0, -1, 0, this.page.height);
|
|
5612
5909
|
this.emit('pageAdded');
|
|
@@ -5614,7 +5911,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5614
5911
|
}
|
|
5615
5912
|
continueOnNewPage(options) {
|
|
5616
5913
|
const pageMarkings = this.endPageMarkings(this.page);
|
|
5617
|
-
this.addPage(options);
|
|
5914
|
+
this.addPage(options ?? this.page._options);
|
|
5618
5915
|
this.initPageMarkings(pageMarkings);
|
|
5619
5916
|
return this;
|
|
5620
5917
|
}
|
|
@@ -5632,8 +5929,6 @@ class PDFDocument extends stream.Readable {
|
|
|
5632
5929
|
return this.page = page;
|
|
5633
5930
|
}
|
|
5634
5931
|
flushPages() {
|
|
5635
|
-
// this local variable exists so we're future-proof against
|
|
5636
|
-
// reentrant calls to flushPages.
|
|
5637
5932
|
const pages = this._pageBuffer;
|
|
5638
5933
|
this._pageBuffer = [];
|
|
5639
5934
|
this._pageBufferStart += pages.length;
|
|
@@ -5657,13 +5952,10 @@ class PDFDocument extends stream.Readable {
|
|
|
5657
5952
|
}
|
|
5658
5953
|
addNamedEmbeddedFile(name, ref) {
|
|
5659
5954
|
if (!this._root.data.Names.data.EmbeddedFiles) {
|
|
5660
|
-
// disabling /Limits for this tree fixes attachments not showing in Adobe Reader
|
|
5661
5955
|
this._root.data.Names.data.EmbeddedFiles = new PDFNameTree({
|
|
5662
5956
|
limits: false
|
|
5663
5957
|
});
|
|
5664
5958
|
}
|
|
5665
|
-
|
|
5666
|
-
// add filespec to EmbeddedFiles
|
|
5667
5959
|
this._root.data.Names.data.EmbeddedFiles.add(name, ref);
|
|
5668
5960
|
}
|
|
5669
5961
|
addNamedJavaScript(name, js) {
|
|
@@ -5678,19 +5970,17 @@ class PDFDocument extends stream.Readable {
|
|
|
5678
5970
|
}
|
|
5679
5971
|
ref(data) {
|
|
5680
5972
|
const ref = new PDFReference(this, this._offsets.length + 1, data);
|
|
5681
|
-
this._offsets.push(null);
|
|
5973
|
+
this._offsets.push(null);
|
|
5682
5974
|
this._waiting++;
|
|
5683
5975
|
return ref;
|
|
5684
5976
|
}
|
|
5685
5977
|
_read() {}
|
|
5686
|
-
// do nothing, but this method is required by node
|
|
5687
|
-
|
|
5688
5978
|
_write(data) {
|
|
5689
5979
|
if (!Buffer.isBuffer(data)) {
|
|
5690
5980
|
data = Buffer.from(data + '\n', 'binary');
|
|
5691
5981
|
}
|
|
5692
5982
|
this.push(data);
|
|
5693
|
-
|
|
5983
|
+
this._offset += data.length;
|
|
5694
5984
|
}
|
|
5695
5985
|
addContent(data) {
|
|
5696
5986
|
this.page.write(data);
|
|
@@ -5700,7 +5990,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5700
5990
|
this._offsets[ref.id - 1] = ref.offset;
|
|
5701
5991
|
if (--this._waiting === 0 && this._ended) {
|
|
5702
5992
|
this._finalize();
|
|
5703
|
-
|
|
5993
|
+
this._ended = false;
|
|
5704
5994
|
}
|
|
5705
5995
|
}
|
|
5706
5996
|
end() {
|
|
@@ -5737,13 +6027,12 @@ class PDFDocument extends stream.Readable {
|
|
|
5737
6027
|
this._security.end();
|
|
5738
6028
|
}
|
|
5739
6029
|
if (this._waiting === 0) {
|
|
5740
|
-
|
|
6030
|
+
this._finalize();
|
|
5741
6031
|
} else {
|
|
5742
|
-
|
|
6032
|
+
this._ended = true;
|
|
5743
6033
|
}
|
|
5744
6034
|
}
|
|
5745
6035
|
_finalize() {
|
|
5746
|
-
// generate xref
|
|
5747
6036
|
const xRefOffset = this._offset;
|
|
5748
6037
|
this._write('xref');
|
|
5749
6038
|
this._write(`0 ${this._offsets.length + 1}`);
|
|
@@ -5752,8 +6041,6 @@ class PDFDocument extends stream.Readable {
|
|
|
5752
6041
|
offset = `0000000000${offset}`.slice(-10);
|
|
5753
6042
|
this._write(offset + ' 00000 n ');
|
|
5754
6043
|
}
|
|
5755
|
-
|
|
5756
|
-
// trailer
|
|
5757
6044
|
const trailer = {
|
|
5758
6045
|
Size: this._offsets.length + 1,
|
|
5759
6046
|
Root: this._root,
|
|
@@ -5768,9 +6055,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5768
6055
|
this._write('startxref');
|
|
5769
6056
|
this._write(`${xRefOffset}`);
|
|
5770
6057
|
this._write('%%EOF');
|
|
5771
|
-
|
|
5772
|
-
// end the stream
|
|
5773
|
-
return this.push(null);
|
|
6058
|
+
this.push(null);
|
|
5774
6059
|
}
|
|
5775
6060
|
toString() {
|
|
5776
6061
|
return '[object PDFDocument]';
|
|
@@ -5791,7 +6076,8 @@ mixin(MarkingsMixin);
|
|
|
5791
6076
|
mixin(AcroFormMixin);
|
|
5792
6077
|
mixin(AttachmentsMixin);
|
|
5793
6078
|
mixin(SubsetMixin);
|
|
6079
|
+
mixin(TableMixin);
|
|
5794
6080
|
PDFDocument.LineWrapper = LineWrapper;
|
|
5795
6081
|
|
|
5796
|
-
export default
|
|
6082
|
+
export { PDFDocument as default };
|
|
5797
6083
|
//# sourceMappingURL=pdfkit.es.js.map
|