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.js
CHANGED
|
@@ -10,23 +10,15 @@ var LineBreaker = require('linebreak');
|
|
|
10
10
|
var exif = require('jpeg-exif');
|
|
11
11
|
var PNG = require('png-js');
|
|
12
12
|
|
|
13
|
-
/*
|
|
14
|
-
PDFAbstractReference - abstract class for PDF reference
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
13
|
class PDFAbstractReference {
|
|
18
14
|
toString() {
|
|
19
15
|
throw new Error('Must be implemented by subclasses');
|
|
20
16
|
}
|
|
21
17
|
}
|
|
22
18
|
|
|
23
|
-
/*
|
|
24
|
-
PDFTree - abstract base class for name and number tree objects
|
|
25
|
-
*/
|
|
26
19
|
class PDFTree {
|
|
27
20
|
constructor(options = {}) {
|
|
28
21
|
this._items = {};
|
|
29
|
-
// disable /Limits output for this tree
|
|
30
22
|
this.limits = typeof options.limits === 'boolean' ? options.limits : true;
|
|
31
23
|
}
|
|
32
24
|
add(key, val) {
|
|
@@ -36,7 +28,6 @@ class PDFTree {
|
|
|
36
28
|
return this._items[key];
|
|
37
29
|
}
|
|
38
30
|
toString() {
|
|
39
|
-
// Needs to be sorted by key
|
|
40
31
|
const sortedKeys = Object.keys(this._items).sort((a, b) => this._compareKeys(a, b));
|
|
41
32
|
const out = ['<<'];
|
|
42
33
|
if (this.limits && sortedKeys.length > 1) {
|
|
@@ -52,23 +43,37 @@ class PDFTree {
|
|
|
52
43
|
out.push('>>');
|
|
53
44
|
return out.join('\n');
|
|
54
45
|
}
|
|
55
|
-
_compareKeys(
|
|
56
|
-
) {
|
|
46
|
+
_compareKeys() {
|
|
57
47
|
throw new Error('Must be implemented by subclasses');
|
|
58
48
|
}
|
|
59
49
|
_keysName() {
|
|
60
50
|
throw new Error('Must be implemented by subclasses');
|
|
61
51
|
}
|
|
62
|
-
_dataForKey(
|
|
63
|
-
) {
|
|
52
|
+
_dataForKey() {
|
|
64
53
|
throw new Error('Must be implemented by subclasses');
|
|
65
54
|
}
|
|
66
55
|
}
|
|
67
56
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
57
|
+
class SpotColor {
|
|
58
|
+
constructor(doc, name, C, M, Y, K) {
|
|
59
|
+
this.id = 'CS' + Object.keys(doc.spotColors).length;
|
|
60
|
+
this.name = name;
|
|
61
|
+
this.values = [C, M, Y, K];
|
|
62
|
+
this.ref = doc.ref(['Separation', this.name, 'DeviceCMYK', {
|
|
63
|
+
Range: [0, 1, 0, 1, 0, 1, 0, 1],
|
|
64
|
+
C0: [0, 0, 0, 0],
|
|
65
|
+
C1: this.values.map(value => value / 100),
|
|
66
|
+
FunctionType: 2,
|
|
67
|
+
Domain: [0, 1],
|
|
68
|
+
N: 1
|
|
69
|
+
}]);
|
|
70
|
+
this.ref.end();
|
|
71
|
+
}
|
|
72
|
+
toString() {
|
|
73
|
+
return `${this.ref.id} 0 R`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
72
77
|
const pad = (str, length) => (Array(length + 1).join('0') + str).slice(-length);
|
|
73
78
|
const escapableRe = /[\n\r\t\b\f()\\]/g;
|
|
74
79
|
const escapable = {
|
|
@@ -81,8 +86,6 @@ const escapable = {
|
|
|
81
86
|
'(': '\\(',
|
|
82
87
|
')': '\\)'
|
|
83
88
|
};
|
|
84
|
-
|
|
85
|
-
// Convert little endian UTF-16 to big endian
|
|
86
89
|
const swapBytes = function (buff) {
|
|
87
90
|
const l = buff.length;
|
|
88
91
|
if (l & 0x01) {
|
|
@@ -98,14 +101,10 @@ const swapBytes = function (buff) {
|
|
|
98
101
|
};
|
|
99
102
|
class PDFObject {
|
|
100
103
|
static convert(object, encryptFn = 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, data = {}) {
|
|
183
166
|
super();
|
|
@@ -190,7 +173,7 @@ class PDFReference extends PDFAbstractReference {
|
|
|
190
173
|
this.buffer = [];
|
|
191
174
|
}
|
|
192
175
|
write(chunk) {
|
|
193
|
-
if (!
|
|
176
|
+
if (!(chunk instanceof Uint8Array)) {
|
|
194
177
|
chunk = Buffer.from(chunk + '\n', 'binary');
|
|
195
178
|
}
|
|
196
179
|
this.uncompressedLength += chunk.length;
|
|
@@ -200,14 +183,14 @@ class PDFReference extends PDFAbstractReference {
|
|
|
200
183
|
this.buffer.push(chunk);
|
|
201
184
|
this.data.Length += chunk.length;
|
|
202
185
|
if (this.compress) {
|
|
203
|
-
|
|
186
|
+
this.data.Filter = 'FlateDecode';
|
|
204
187
|
}
|
|
205
188
|
}
|
|
206
189
|
end(chunk) {
|
|
207
190
|
if (chunk) {
|
|
208
191
|
this.write(chunk);
|
|
209
192
|
}
|
|
210
|
-
|
|
193
|
+
this.finalize();
|
|
211
194
|
}
|
|
212
195
|
finalize() {
|
|
213
196
|
this.offset = this.document._offset;
|
|
@@ -227,7 +210,7 @@ class PDFReference extends PDFAbstractReference {
|
|
|
227
210
|
if (this.buffer.length) {
|
|
228
211
|
this.document._write('stream');
|
|
229
212
|
this.document._write(this.buffer);
|
|
230
|
-
this.buffer = [];
|
|
213
|
+
this.buffer = [];
|
|
231
214
|
this.document._write('\nendstream');
|
|
232
215
|
}
|
|
233
216
|
this.document._write('endobj');
|
|
@@ -238,10 +221,69 @@ class PDFReference extends PDFAbstractReference {
|
|
|
238
221
|
}
|
|
239
222
|
}
|
|
240
223
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
224
|
+
function PDFNumber(n) {
|
|
225
|
+
return Math.fround(n);
|
|
226
|
+
}
|
|
227
|
+
function normalizeSides(sides, defaultDefinition = undefined, transformer = v => v) {
|
|
228
|
+
if (sides == null || typeof sides === 'object' && Object.keys(sides).length === 0) {
|
|
229
|
+
sides = defaultDefinition;
|
|
230
|
+
}
|
|
231
|
+
if (sides == null || typeof sides !== 'object') {
|
|
232
|
+
sides = {
|
|
233
|
+
top: sides,
|
|
234
|
+
right: sides,
|
|
235
|
+
bottom: sides,
|
|
236
|
+
left: sides
|
|
237
|
+
};
|
|
238
|
+
} else if (Array.isArray(sides)) {
|
|
239
|
+
if (sides.length === 2) {
|
|
240
|
+
sides = {
|
|
241
|
+
vertical: sides[0],
|
|
242
|
+
horizontal: sides[1]
|
|
243
|
+
};
|
|
244
|
+
} else {
|
|
245
|
+
sides = {
|
|
246
|
+
top: sides[0],
|
|
247
|
+
right: sides[1],
|
|
248
|
+
bottom: sides[2],
|
|
249
|
+
left: sides[3]
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if ('vertical' in sides || 'horizontal' in sides) {
|
|
254
|
+
sides = {
|
|
255
|
+
top: sides.vertical,
|
|
256
|
+
right: sides.horizontal,
|
|
257
|
+
bottom: sides.vertical,
|
|
258
|
+
left: sides.horizontal
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
top: transformer(sides.top),
|
|
263
|
+
right: transformer(sides.right),
|
|
264
|
+
bottom: transformer(sides.bottom),
|
|
265
|
+
left: transformer(sides.left)
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
const MM_TO_CM = 1 / 10;
|
|
269
|
+
const CM_TO_IN = 1 / 2.54;
|
|
270
|
+
const PX_TO_IN = 1 / 96;
|
|
271
|
+
const IN_TO_PT = 72;
|
|
272
|
+
const PC_TO_PT = 12;
|
|
273
|
+
function cosine(a) {
|
|
274
|
+
if (a === 0) return 1;
|
|
275
|
+
if (a === 90) return 0;
|
|
276
|
+
if (a === 180) return -1;
|
|
277
|
+
if (a === 270) return 0;
|
|
278
|
+
return Math.cos(a * Math.PI / 180);
|
|
279
|
+
}
|
|
280
|
+
function sine(a) {
|
|
281
|
+
if (a === 0) return 0;
|
|
282
|
+
if (a === 90) return 1;
|
|
283
|
+
if (a === 180) return 0;
|
|
284
|
+
if (a === 270) return -1;
|
|
285
|
+
return Math.sin(a * Math.PI / 180);
|
|
286
|
+
}
|
|
245
287
|
|
|
246
288
|
const DEFAULT_MARGINS = {
|
|
247
289
|
top: 72,
|
|
@@ -304,35 +346,19 @@ const SIZES = {
|
|
|
304
346
|
class PDFPage {
|
|
305
347
|
constructor(document, options = {}) {
|
|
306
348
|
this.document = document;
|
|
349
|
+
this._options = options;
|
|
307
350
|
this.size = options.size || 'letter';
|
|
308
351
|
this.layout = options.layout || 'portrait';
|
|
309
|
-
|
|
310
|
-
// process margins
|
|
311
|
-
if (typeof options.margin === 'number') {
|
|
312
|
-
this.margins = {
|
|
313
|
-
top: options.margin,
|
|
314
|
-
left: options.margin,
|
|
315
|
-
bottom: options.margin,
|
|
316
|
-
right: options.margin
|
|
317
|
-
};
|
|
318
|
-
|
|
319
|
-
// default to 1 inch margins
|
|
320
|
-
} else {
|
|
321
|
-
this.margins = options.margins || DEFAULT_MARGINS;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// calculate page dimensions
|
|
325
352
|
const dimensions = Array.isArray(this.size) ? this.size : SIZES[this.size.toUpperCase()];
|
|
326
353
|
this.width = dimensions[this.layout === 'portrait' ? 0 : 1];
|
|
327
354
|
this.height = dimensions[this.layout === 'portrait' ? 1 : 0];
|
|
328
355
|
this.content = this.document.ref();
|
|
329
|
-
|
|
330
|
-
|
|
356
|
+
if (options.font) document.font(options.font, options.fontFamily);
|
|
357
|
+
if (options.fontSize) document.fontSize(options.fontSize);
|
|
358
|
+
this.margins = normalizeSides(options.margin ?? options.margins, DEFAULT_MARGINS, x => document.sizeToPoint(x, 0, this));
|
|
331
359
|
this.resources = this.document.ref({
|
|
332
360
|
ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI']
|
|
333
361
|
});
|
|
334
|
-
|
|
335
|
-
// The page dictionary
|
|
336
362
|
this.dictionary = this.document.ref({
|
|
337
363
|
Type: 'Page',
|
|
338
364
|
Parent: this.document._root.data.Pages,
|
|
@@ -342,8 +368,6 @@ class PDFPage {
|
|
|
342
368
|
});
|
|
343
369
|
this.markings = [];
|
|
344
370
|
}
|
|
345
|
-
|
|
346
|
-
// Lazily create these objects
|
|
347
371
|
get fonts() {
|
|
348
372
|
const data = this.resources.data;
|
|
349
373
|
return data.Font != null ? data.Font : data.Font = {};
|
|
@@ -372,204 +396,86 @@ class PDFPage {
|
|
|
372
396
|
const data = this.dictionary.data;
|
|
373
397
|
return data.StructParents != null ? data.StructParents : data.StructParents = this.document.createStructParentTreeNextKey();
|
|
374
398
|
}
|
|
399
|
+
get contentWidth() {
|
|
400
|
+
return this.width - this.margins.left - this.margins.right;
|
|
401
|
+
}
|
|
402
|
+
get contentHeight() {
|
|
403
|
+
return this.height - this.margins.top - this.margins.bottom;
|
|
404
|
+
}
|
|
375
405
|
maxY() {
|
|
376
406
|
return this.height - this.margins.bottom;
|
|
377
407
|
}
|
|
378
408
|
write(chunk) {
|
|
379
409
|
return this.content.write(chunk);
|
|
380
410
|
}
|
|
411
|
+
_setTabOrder() {
|
|
412
|
+
if (!this.dictionary.Tabs && this.document.hasMarkInfoDictionary()) {
|
|
413
|
+
this.dictionary.data.Tabs = 'S';
|
|
414
|
+
}
|
|
415
|
+
}
|
|
381
416
|
end() {
|
|
417
|
+
this._setTabOrder();
|
|
382
418
|
this.dictionary.end();
|
|
419
|
+
this.resources.data.ColorSpace = this.resources.data.ColorSpace || {};
|
|
420
|
+
for (let color of Object.values(this.document.spotColors)) {
|
|
421
|
+
this.resources.data.ColorSpace[color.id] = color;
|
|
422
|
+
}
|
|
383
423
|
this.resources.end();
|
|
384
424
|
return this.content.end();
|
|
385
425
|
}
|
|
386
426
|
}
|
|
387
427
|
|
|
388
|
-
/*
|
|
389
|
-
PDFNameTree - represents a name tree object
|
|
390
|
-
*/
|
|
391
428
|
class PDFNameTree extends PDFTree {
|
|
392
429
|
_compareKeys(a, b) {
|
|
393
430
|
return a.localeCompare(b);
|
|
394
431
|
}
|
|
395
432
|
_keysName() {
|
|
396
|
-
return
|
|
433
|
+
return 'Names';
|
|
397
434
|
}
|
|
398
435
|
_dataForKey(k) {
|
|
399
436
|
return new String(k);
|
|
400
437
|
}
|
|
401
438
|
}
|
|
402
439
|
|
|
403
|
-
/**
|
|
404
|
-
* Check if value is in a range group.
|
|
405
|
-
* @param {number} value
|
|
406
|
-
* @param {number[]} rangeGroup
|
|
407
|
-
* @returns {boolean}
|
|
408
|
-
*/
|
|
409
440
|
function inRange(value, rangeGroup) {
|
|
410
441
|
if (value < rangeGroup[0]) return false;
|
|
411
442
|
let startRange = 0;
|
|
412
443
|
let endRange = rangeGroup.length / 2;
|
|
413
444
|
while (startRange <= endRange) {
|
|
414
445
|
const middleRange = Math.floor((startRange + endRange) / 2);
|
|
415
|
-
|
|
416
|
-
// actual array index
|
|
417
446
|
const arrayIndex = middleRange * 2;
|
|
418
|
-
|
|
419
|
-
// Check if value is in range pointed by actual index
|
|
420
447
|
if (value >= rangeGroup[arrayIndex] && value <= rangeGroup[arrayIndex + 1]) {
|
|
421
448
|
return true;
|
|
422
449
|
}
|
|
423
450
|
if (value > rangeGroup[arrayIndex + 1]) {
|
|
424
|
-
// Search Right Side Of Array
|
|
425
451
|
startRange = middleRange + 1;
|
|
426
452
|
} else {
|
|
427
|
-
// Search Left Side Of Array
|
|
428
453
|
endRange = middleRange - 1;
|
|
429
454
|
}
|
|
430
455
|
}
|
|
431
456
|
return false;
|
|
432
457
|
}
|
|
433
458
|
|
|
434
|
-
// prettier-ignore-start
|
|
435
|
-
/**
|
|
436
|
-
* A.1 Unassigned code points in Unicode 3.2
|
|
437
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-A.1
|
|
438
|
-
*/
|
|
439
459
|
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];
|
|
440
|
-
// prettier-ignore-end
|
|
441
|
-
|
|
442
460
|
const isUnassignedCodePoint = character => inRange(character, unassigned_code_points);
|
|
443
|
-
|
|
444
|
-
// prettier-ignore-start
|
|
445
|
-
/**
|
|
446
|
-
* B.1 Commonly mapped to nothing
|
|
447
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-B.1
|
|
448
|
-
*/
|
|
449
461
|
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];
|
|
450
|
-
// prettier-ignore-end
|
|
451
|
-
|
|
452
462
|
const isCommonlyMappedToNothing = character => inRange(character, commonly_mapped_to_nothing);
|
|
453
|
-
|
|
454
|
-
// prettier-ignore-start
|
|
455
|
-
/**
|
|
456
|
-
* C.1.2 Non-ASCII space characters
|
|
457
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.1.2
|
|
458
|
-
*/
|
|
459
|
-
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 */];
|
|
460
|
-
// prettier-ignore-end
|
|
461
|
-
|
|
463
|
+
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];
|
|
462
464
|
const isNonASCIISpaceCharacter = character => inRange(character, non_ASCII_space_characters);
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
const
|
|
466
|
-
/**
|
|
467
|
-
* C.2.2 Non-ASCII control characters
|
|
468
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.2.2
|
|
469
|
-
*/
|
|
470
|
-
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] */];
|
|
471
|
-
const non_character_codepoints = [
|
|
472
|
-
/**
|
|
473
|
-
* C.4 Non-character code points
|
|
474
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.4
|
|
475
|
-
*/
|
|
476
|
-
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] */];
|
|
477
|
-
|
|
478
|
-
/**
|
|
479
|
-
* 2.3. Prohibited Output
|
|
480
|
-
*/
|
|
481
|
-
const prohibited_characters = [
|
|
482
|
-
/**
|
|
483
|
-
* C.2.1 ASCII control characters
|
|
484
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.2.1
|
|
485
|
-
*/
|
|
486
|
-
0, 0x001f /* [CONTROL CHARACTERS] */, 0x007f, 0x007f /* DELETE */,
|
|
487
|
-
/**
|
|
488
|
-
* C.8 Change display properties or are deprecated
|
|
489
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.8
|
|
490
|
-
*/
|
|
491
|
-
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 */,
|
|
492
|
-
/**
|
|
493
|
-
* C.7 Inappropriate for canonical representation
|
|
494
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.7
|
|
495
|
-
*/
|
|
496
|
-
0x2ff0, 0x2ffb /* [IDEOGRAPHIC DESCRIPTION CHARACTERS] */,
|
|
497
|
-
/**
|
|
498
|
-
* C.5 Surrogate codes
|
|
499
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.5
|
|
500
|
-
*/
|
|
501
|
-
0xd800, 0xdfff,
|
|
502
|
-
/**
|
|
503
|
-
* C.3 Private use
|
|
504
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.3
|
|
505
|
-
*/
|
|
506
|
-
0xe000, 0xf8ff /* [PRIVATE USE, PLANE 0] */,
|
|
507
|
-
/**
|
|
508
|
-
* C.6 Inappropriate for plain text
|
|
509
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.6
|
|
510
|
-
*/
|
|
511
|
-
0xfff9, 0xfff9 /* INTERLINEAR ANNOTATION ANCHOR */, 0xfffa, 0xfffa /* INTERLINEAR ANNOTATION SEPARATOR */, 0xfffb, 0xfffb /* INTERLINEAR ANNOTATION TERMINATOR */, 0xfffc, 0xfffc /* OBJECT REPLACEMENT CHARACTER */, 0xfffd, 0xfffd /* REPLACEMENT CHARACTER */,
|
|
512
|
-
/**
|
|
513
|
-
* C.9 Tagging characters
|
|
514
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.9
|
|
515
|
-
*/
|
|
516
|
-
0xe0001, 0xe0001 /* LANGUAGE TAG */, 0xe0020, 0xe007f /* [TAGGING CHARACTERS] */,
|
|
517
|
-
/**
|
|
518
|
-
* C.3 Private use
|
|
519
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.3
|
|
520
|
-
*/
|
|
521
|
-
|
|
522
|
-
0xf0000, 0xffffd /* [PRIVATE USE, PLANE 15] */, 0x100000, 0x10fffd /* [PRIVATE USE, PLANE 16] */];
|
|
523
|
-
// prettier-ignore-end
|
|
524
|
-
|
|
465
|
+
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];
|
|
466
|
+
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];
|
|
467
|
+
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];
|
|
525
468
|
const isProhibitedCharacter = character => inRange(character, non_ASCII_space_characters) || inRange(character, prohibited_characters) || inRange(character, non_ASCII_controls_characters) || inRange(character, non_character_codepoints);
|
|
526
|
-
|
|
527
|
-
// prettier-ignore-start
|
|
528
|
-
/**
|
|
529
|
-
* D.1 Characters with bidirectional property "R" or "AL"
|
|
530
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-D.1
|
|
531
|
-
*/
|
|
532
469
|
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];
|
|
533
|
-
// prettier-ignore-end
|
|
534
|
-
|
|
535
470
|
const isBidirectionalRAL = character => inRange(character, bidirectional_r_al);
|
|
536
|
-
|
|
537
|
-
// prettier-ignore-start
|
|
538
|
-
/**
|
|
539
|
-
* D.2 Characters with bidirectional property "L"
|
|
540
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-D.2
|
|
541
|
-
*/
|
|
542
471
|
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];
|
|
543
|
-
// prettier-ignore-end
|
|
544
|
-
|
|
545
472
|
const isBidirectionalL = character => inRange(character, bidirectional_l);
|
|
546
473
|
|
|
547
|
-
// 2.1. Mapping
|
|
548
|
-
|
|
549
|
-
/**
|
|
550
|
-
* non-ASCII space characters [StringPrep, C.1.2] that can be
|
|
551
|
-
* mapped to SPACE (U+0020)
|
|
552
|
-
*/
|
|
553
474
|
const mapping2space = isNonASCIISpaceCharacter;
|
|
554
|
-
|
|
555
|
-
/**
|
|
556
|
-
* the "commonly mapped to nothing" characters [StringPrep, B.1]
|
|
557
|
-
* that can be mapped to nothing.
|
|
558
|
-
*/
|
|
559
475
|
const mapping2nothing = isCommonlyMappedToNothing;
|
|
560
|
-
|
|
561
|
-
// utils
|
|
562
476
|
const getCodePoint = character => character.codePointAt(0);
|
|
563
477
|
const first = x => x[0];
|
|
564
478
|
const last = x => x[x.length - 1];
|
|
565
|
-
|
|
566
|
-
/**
|
|
567
|
-
* Convert provided string into an array of Unicode Code Points.
|
|
568
|
-
* Based on https://stackoverflow.com/a/21409165/1556249
|
|
569
|
-
* and https://www.npmjs.com/package/code-point-at.
|
|
570
|
-
* @param {string} input
|
|
571
|
-
* @returns {number[]}
|
|
572
|
-
*/
|
|
573
479
|
function toCodePoints(input) {
|
|
574
480
|
const codepoints = [];
|
|
575
481
|
const size = input.length;
|
|
@@ -587,14 +493,6 @@ function toCodePoints(input) {
|
|
|
587
493
|
}
|
|
588
494
|
return codepoints;
|
|
589
495
|
}
|
|
590
|
-
|
|
591
|
-
/**
|
|
592
|
-
* SASLprep.
|
|
593
|
-
* @param {string} input
|
|
594
|
-
* @param {Object} opts
|
|
595
|
-
* @param {boolean} opts.allowUnassigned
|
|
596
|
-
* @returns {string}
|
|
597
|
-
*/
|
|
598
496
|
function saslprep(input, opts = {}) {
|
|
599
497
|
if (typeof input !== 'string') {
|
|
600
498
|
throw new TypeError('Expected string.');
|
|
@@ -602,49 +500,24 @@ function saslprep(input, opts = {}) {
|
|
|
602
500
|
if (input.length === 0) {
|
|
603
501
|
return '';
|
|
604
502
|
}
|
|
605
|
-
|
|
606
|
-
// 1. Map
|
|
607
|
-
const mapped_input = toCodePoints(input)
|
|
608
|
-
// 1.1 mapping to space
|
|
609
|
-
.map(character => mapping2space(character) ? 0x20 : character)
|
|
610
|
-
// 1.2 mapping to nothing
|
|
611
|
-
.filter(character => !mapping2nothing(character));
|
|
612
|
-
|
|
613
|
-
// 2. Normalize
|
|
503
|
+
const mapped_input = toCodePoints(input).map(character => mapping2space(character) ? 0x20 : character).filter(character => !mapping2nothing(character));
|
|
614
504
|
const normalized_input = String.fromCodePoint.apply(null, mapped_input).normalize('NFKC');
|
|
615
505
|
const normalized_map = toCodePoints(normalized_input);
|
|
616
|
-
|
|
617
|
-
// 3. Prohibit
|
|
618
506
|
const hasProhibited = normalized_map.some(isProhibitedCharacter);
|
|
619
507
|
if (hasProhibited) {
|
|
620
508
|
throw new Error('Prohibited character, see https://tools.ietf.org/html/rfc4013#section-2.3');
|
|
621
509
|
}
|
|
622
|
-
|
|
623
|
-
// Unassigned Code Points
|
|
624
510
|
if (opts.allowUnassigned !== true) {
|
|
625
511
|
const hasUnassigned = normalized_map.some(isUnassignedCodePoint);
|
|
626
512
|
if (hasUnassigned) {
|
|
627
513
|
throw new Error('Unassigned code point, see https://tools.ietf.org/html/rfc4013#section-2.5');
|
|
628
514
|
}
|
|
629
515
|
}
|
|
630
|
-
|
|
631
|
-
// 4. check bidi
|
|
632
|
-
|
|
633
516
|
const hasBidiRAL = normalized_map.some(isBidirectionalRAL);
|
|
634
517
|
const hasBidiL = normalized_map.some(isBidirectionalL);
|
|
635
|
-
|
|
636
|
-
// 4.1 If a string contains any RandALCat character, the string MUST NOT
|
|
637
|
-
// contain any LCat character.
|
|
638
518
|
if (hasBidiRAL && hasBidiL) {
|
|
639
519
|
throw new Error('String must not contain RandALCat and LCat at the same time,' + ' see https://tools.ietf.org/html/rfc3454#section-6');
|
|
640
520
|
}
|
|
641
|
-
|
|
642
|
-
/**
|
|
643
|
-
* 4.2 If a string contains any RandALCat character, a RandALCat
|
|
644
|
-
* character MUST be the first character of the string, and a
|
|
645
|
-
* RandALCat character MUST be the last character of the string.
|
|
646
|
-
*/
|
|
647
|
-
|
|
648
521
|
const isFirstBidiRAL = isBidirectionalRAL(getCodePoint(first(normalized_input)));
|
|
649
522
|
const isLastBidiRAL = isBidirectionalRAL(getCodePoint(last(normalized_input)));
|
|
650
523
|
if (hasBidiRAL && !(isFirstBidiRAL && isLastBidiRAL)) {
|
|
@@ -653,15 +526,10 @@ function saslprep(input, opts = {}) {
|
|
|
653
526
|
return normalized_input;
|
|
654
527
|
}
|
|
655
528
|
|
|
656
|
-
/*
|
|
657
|
-
PDFSecurity - represents PDF security settings
|
|
658
|
-
By Yang Liu <hi@zesik.com>
|
|
659
|
-
*/
|
|
660
529
|
class PDFSecurity {
|
|
661
530
|
static generateFileID(info = {}) {
|
|
662
531
|
let infoStr = `${info.CreationDate.getTime()}\n`;
|
|
663
532
|
for (let key in info) {
|
|
664
|
-
// eslint-disable-next-line no-prototype-builtins
|
|
665
533
|
if (!info.hasOwnProperty(key)) {
|
|
666
534
|
continue;
|
|
667
535
|
}
|
|
@@ -992,9 +860,9 @@ function wordArrayToBuffer(wordArray) {
|
|
|
992
860
|
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];
|
|
993
861
|
|
|
994
862
|
const {
|
|
995
|
-
number
|
|
863
|
+
number: number$2
|
|
996
864
|
} = PDFObject;
|
|
997
|
-
class PDFGradient {
|
|
865
|
+
class PDFGradient$1 {
|
|
998
866
|
constructor(doc) {
|
|
999
867
|
this.doc = doc;
|
|
1000
868
|
this.stops = [];
|
|
@@ -1035,8 +903,6 @@ class PDFGradient {
|
|
|
1035
903
|
}
|
|
1036
904
|
this.embedded = true;
|
|
1037
905
|
this.matrix = m;
|
|
1038
|
-
|
|
1039
|
-
// if the last stop comes before 100%, add a copy at 100%
|
|
1040
906
|
const last = this.stops[stopsLength - 1];
|
|
1041
907
|
if (last[0] < 1) {
|
|
1042
908
|
this.stops.push([1, last[1], last[2]]);
|
|
@@ -1059,14 +925,11 @@ class PDFGradient {
|
|
|
1059
925
|
stops.push(fn);
|
|
1060
926
|
fn.end();
|
|
1061
927
|
}
|
|
1062
|
-
|
|
1063
|
-
// if there are only two stops, we don't need a stitching function
|
|
1064
928
|
if (stopsLength === 1) {
|
|
1065
929
|
fn = stops[0];
|
|
1066
930
|
} else {
|
|
1067
931
|
fn = this.doc.ref({
|
|
1068
932
|
FunctionType: 3,
|
|
1069
|
-
// stitching function
|
|
1070
933
|
Domain: [0, 1],
|
|
1071
934
|
Functions: stops,
|
|
1072
935
|
Bounds: bounds,
|
|
@@ -1081,7 +944,7 @@ class PDFGradient {
|
|
|
1081
944
|
Type: 'Pattern',
|
|
1082
945
|
PatternType: 2,
|
|
1083
946
|
Shading: shader,
|
|
1084
|
-
Matrix: this.matrix.map(number)
|
|
947
|
+
Matrix: this.matrix.map(number$2)
|
|
1085
948
|
});
|
|
1086
949
|
pattern.end();
|
|
1087
950
|
if (this.stops.some(stop => stop[2] < 1)) {
|
|
@@ -1147,7 +1010,6 @@ class PDFGradient {
|
|
|
1147
1010
|
return pattern;
|
|
1148
1011
|
}
|
|
1149
1012
|
apply(stroke) {
|
|
1150
|
-
// apply gradient transform to existing document ctm
|
|
1151
1013
|
const [m0, m1, m2, m3, m4, m5] = this.doc._ctm;
|
|
1152
1014
|
const [m11, m12, m21, m22, dx, dy] = this.transform;
|
|
1153
1015
|
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];
|
|
@@ -1159,7 +1021,7 @@ class PDFGradient {
|
|
|
1159
1021
|
return this.doc.addContent(`/${this.id} ${op}`);
|
|
1160
1022
|
}
|
|
1161
1023
|
}
|
|
1162
|
-
class PDFLinearGradient extends PDFGradient {
|
|
1024
|
+
class PDFLinearGradient$1 extends PDFGradient$1 {
|
|
1163
1025
|
constructor(doc, x1, y1, x2, y2) {
|
|
1164
1026
|
super(doc);
|
|
1165
1027
|
this.x1 = x1;
|
|
@@ -1177,10 +1039,10 @@ class PDFLinearGradient extends PDFGradient {
|
|
|
1177
1039
|
});
|
|
1178
1040
|
}
|
|
1179
1041
|
opacityGradient() {
|
|
1180
|
-
return new PDFLinearGradient(this.doc, this.x1, this.y1, this.x2, this.y2);
|
|
1042
|
+
return new PDFLinearGradient$1(this.doc, this.x1, this.y1, this.x2, this.y2);
|
|
1181
1043
|
}
|
|
1182
1044
|
}
|
|
1183
|
-
class PDFRadialGradient extends PDFGradient {
|
|
1045
|
+
class PDFRadialGradient$1 extends PDFGradient$1 {
|
|
1184
1046
|
constructor(doc, x1, y1, r1, x2, y2, r2) {
|
|
1185
1047
|
super(doc);
|
|
1186
1048
|
this.doc = doc;
|
|
@@ -1201,21 +1063,17 @@ class PDFRadialGradient extends PDFGradient {
|
|
|
1201
1063
|
});
|
|
1202
1064
|
}
|
|
1203
1065
|
opacityGradient() {
|
|
1204
|
-
return new PDFRadialGradient(this.doc, this.x1, this.y1, this.r1, this.x2, this.y2, this.r2);
|
|
1066
|
+
return new PDFRadialGradient$1(this.doc, this.x1, this.y1, this.r1, this.x2, this.y2, this.r2);
|
|
1205
1067
|
}
|
|
1206
1068
|
}
|
|
1207
1069
|
var Gradient = {
|
|
1208
|
-
PDFGradient,
|
|
1209
|
-
PDFLinearGradient,
|
|
1210
|
-
PDFRadialGradient
|
|
1070
|
+
PDFGradient: PDFGradient$1,
|
|
1071
|
+
PDFLinearGradient: PDFLinearGradient$1,
|
|
1072
|
+
PDFRadialGradient: PDFRadialGradient$1
|
|
1211
1073
|
};
|
|
1212
1074
|
|
|
1213
|
-
/*
|
|
1214
|
-
PDF tiling pattern support. Uncolored only.
|
|
1215
|
-
*/
|
|
1216
|
-
|
|
1217
1075
|
const underlyingColorSpaces = ['DeviceCMYK', 'DeviceRGB'];
|
|
1218
|
-
class PDFTilingPattern {
|
|
1076
|
+
class PDFTilingPattern$1 {
|
|
1219
1077
|
constructor(doc, bBox, xStep, yStep, stream) {
|
|
1220
1078
|
this.doc = doc;
|
|
1221
1079
|
this.bBox = bBox;
|
|
@@ -1224,23 +1082,16 @@ class PDFTilingPattern {
|
|
|
1224
1082
|
this.stream = stream;
|
|
1225
1083
|
}
|
|
1226
1084
|
createPattern() {
|
|
1227
|
-
// no resources needed for our current usage
|
|
1228
|
-
// required entry
|
|
1229
1085
|
const resources = this.doc.ref();
|
|
1230
1086
|
resources.end();
|
|
1231
|
-
// apply default transform matrix (flipped in the default doc._ctm)
|
|
1232
|
-
// see document.js & gradient.js
|
|
1233
1087
|
const [m0, m1, m2, m3, m4, m5] = this.doc._ctm;
|
|
1234
1088
|
const [m11, m12, m21, m22, dx, dy] = [1, 0, 0, 1, 0, 0];
|
|
1235
1089
|
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];
|
|
1236
1090
|
const pattern = this.doc.ref({
|
|
1237
1091
|
Type: 'Pattern',
|
|
1238
1092
|
PatternType: 1,
|
|
1239
|
-
// tiling
|
|
1240
1093
|
PaintType: 2,
|
|
1241
|
-
// 1-colored, 2-uncolored
|
|
1242
1094
|
TilingType: 2,
|
|
1243
|
-
// 2-no distortion
|
|
1244
1095
|
BBox: this.bBox,
|
|
1245
1096
|
XStep: this.xStep,
|
|
1246
1097
|
YStep: this.yStep,
|
|
@@ -1251,8 +1102,6 @@ class PDFTilingPattern {
|
|
|
1251
1102
|
return pattern;
|
|
1252
1103
|
}
|
|
1253
1104
|
embedPatternColorSpaces() {
|
|
1254
|
-
// map each pattern to an underlying color space
|
|
1255
|
-
// and embed on each page
|
|
1256
1105
|
underlyingColorSpaces.forEach(csName => {
|
|
1257
1106
|
const csId = this.getPatternColorSpaceId(csName);
|
|
1258
1107
|
if (this.doc.page.colorSpaces[csId]) return;
|
|
@@ -1270,47 +1119,40 @@ class PDFTilingPattern {
|
|
|
1270
1119
|
this.id = 'P' + this.doc._patternCount;
|
|
1271
1120
|
this.pattern = this.createPattern();
|
|
1272
1121
|
}
|
|
1273
|
-
|
|
1274
|
-
// patterns are embedded in each page
|
|
1275
1122
|
if (!this.doc.page.patterns[this.id]) {
|
|
1276
1123
|
this.doc.page.patterns[this.id] = this.pattern;
|
|
1277
1124
|
}
|
|
1278
1125
|
}
|
|
1279
1126
|
apply(stroke, patternColor) {
|
|
1280
|
-
// do any embedding/creating that might be needed
|
|
1281
1127
|
this.embedPatternColorSpaces();
|
|
1282
1128
|
this.embed();
|
|
1283
1129
|
const normalizedColor = this.doc._normalizeColor(patternColor);
|
|
1284
1130
|
if (!normalizedColor) throw Error(`invalid pattern color. (value: ${patternColor})`);
|
|
1285
|
-
|
|
1286
|
-
// select one of the pattern color spaces
|
|
1287
1131
|
const csId = this.getPatternColorSpaceId(this.doc._getColorSpace(normalizedColor));
|
|
1288
1132
|
this.doc._setColorSpace(csId, stroke);
|
|
1289
|
-
|
|
1290
|
-
// stroke/fill using the pattern and color (in the above underlying color space)
|
|
1291
1133
|
const op = stroke ? 'SCN' : 'scn';
|
|
1292
1134
|
return this.doc.addContent(`${normalizedColor.join(' ')} /${this.id} ${op}`);
|
|
1293
1135
|
}
|
|
1294
1136
|
}
|
|
1295
1137
|
var pattern = {
|
|
1296
|
-
PDFTilingPattern
|
|
1138
|
+
PDFTilingPattern: PDFTilingPattern$1
|
|
1297
1139
|
};
|
|
1298
1140
|
|
|
1299
1141
|
const {
|
|
1300
|
-
PDFGradient
|
|
1301
|
-
PDFLinearGradient
|
|
1302
|
-
PDFRadialGradient
|
|
1142
|
+
PDFGradient,
|
|
1143
|
+
PDFLinearGradient,
|
|
1144
|
+
PDFRadialGradient
|
|
1303
1145
|
} = Gradient;
|
|
1304
1146
|
const {
|
|
1305
|
-
PDFTilingPattern
|
|
1147
|
+
PDFTilingPattern
|
|
1306
1148
|
} = pattern;
|
|
1307
1149
|
var ColorMixin = {
|
|
1308
1150
|
initColor() {
|
|
1309
|
-
|
|
1151
|
+
this.spotColors = {};
|
|
1310
1152
|
this._opacityRegistry = {};
|
|
1311
1153
|
this._opacityCount = 0;
|
|
1312
1154
|
this._patternCount = 0;
|
|
1313
|
-
|
|
1155
|
+
this._gradCount = 0;
|
|
1314
1156
|
},
|
|
1315
1157
|
_normalizeColor(color) {
|
|
1316
1158
|
if (typeof color === 'string') {
|
|
@@ -1322,13 +1164,13 @@ var ColorMixin = {
|
|
|
1322
1164
|
color = [hex >> 16, hex >> 8 & 0xff, hex & 0xff];
|
|
1323
1165
|
} else if (namedColors[color]) {
|
|
1324
1166
|
color = namedColors[color];
|
|
1167
|
+
} else if (this.spotColors[color]) {
|
|
1168
|
+
return this.spotColors[color];
|
|
1325
1169
|
}
|
|
1326
1170
|
}
|
|
1327
1171
|
if (Array.isArray(color)) {
|
|
1328
|
-
// RGB
|
|
1329
1172
|
if (color.length === 3) {
|
|
1330
1173
|
color = color.map(part => part / 255);
|
|
1331
|
-
// CMYK
|
|
1332
1174
|
} else if (color.length === 4) {
|
|
1333
1175
|
color = color.map(part => part / 100);
|
|
1334
1176
|
}
|
|
@@ -1337,15 +1179,13 @@ var ColorMixin = {
|
|
|
1337
1179
|
return null;
|
|
1338
1180
|
},
|
|
1339
1181
|
_setColor(color, stroke) {
|
|
1340
|
-
if (color instanceof PDFGradient
|
|
1182
|
+
if (color instanceof PDFGradient) {
|
|
1341
1183
|
color.apply(stroke);
|
|
1342
1184
|
return true;
|
|
1343
|
-
|
|
1344
|
-
} else if (Array.isArray(color) && color[0] instanceof PDFTilingPattern$1) {
|
|
1185
|
+
} else if (Array.isArray(color) && color[0] instanceof PDFTilingPattern) {
|
|
1345
1186
|
color[0].apply(stroke, color[1]);
|
|
1346
1187
|
return true;
|
|
1347
1188
|
}
|
|
1348
|
-
// any other case should be a normal color and not a pattern
|
|
1349
1189
|
return this._setColorCore(color, stroke);
|
|
1350
1190
|
},
|
|
1351
1191
|
_setColorCore(color, stroke) {
|
|
@@ -1356,8 +1196,12 @@ var ColorMixin = {
|
|
|
1356
1196
|
const op = stroke ? 'SCN' : 'scn';
|
|
1357
1197
|
const space = this._getColorSpace(color);
|
|
1358
1198
|
this._setColorSpace(space, stroke);
|
|
1359
|
-
color
|
|
1360
|
-
|
|
1199
|
+
if (color instanceof SpotColor) {
|
|
1200
|
+
this.page.colorSpaces[color.id] = color.ref;
|
|
1201
|
+
this.addContent(`1 ${op}`);
|
|
1202
|
+
} else {
|
|
1203
|
+
this.addContent(`${color.join(' ')} ${op}`);
|
|
1204
|
+
}
|
|
1361
1205
|
return true;
|
|
1362
1206
|
},
|
|
1363
1207
|
_setColorSpace(space, stroke) {
|
|
@@ -1365,6 +1209,9 @@ var ColorMixin = {
|
|
|
1365
1209
|
return this.addContent(`/${space} ${op}`);
|
|
1366
1210
|
},
|
|
1367
1211
|
_getColorSpace(color) {
|
|
1212
|
+
if (color instanceof SpotColor) {
|
|
1213
|
+
return color.id;
|
|
1214
|
+
}
|
|
1368
1215
|
return color.length === 4 ? 'DeviceCMYK' : 'DeviceRGB';
|
|
1369
1216
|
},
|
|
1370
1217
|
fillColor(color, opacity) {
|
|
@@ -1372,9 +1219,6 @@ var ColorMixin = {
|
|
|
1372
1219
|
if (set) {
|
|
1373
1220
|
this.fillOpacity(opacity);
|
|
1374
1221
|
}
|
|
1375
|
-
|
|
1376
|
-
// save this for text wrapper, which needs to reset
|
|
1377
|
-
// the fill color on new pages
|
|
1378
1222
|
this._fillColor = [color, opacity];
|
|
1379
1223
|
return this;
|
|
1380
1224
|
},
|
|
@@ -1431,13 +1275,18 @@ var ColorMixin = {
|
|
|
1431
1275
|
return this.addContent(`/${name} gs`);
|
|
1432
1276
|
},
|
|
1433
1277
|
linearGradient(x1, y1, x2, y2) {
|
|
1434
|
-
return new PDFLinearGradient
|
|
1278
|
+
return new PDFLinearGradient(this, x1, y1, x2, y2);
|
|
1435
1279
|
},
|
|
1436
1280
|
radialGradient(x1, y1, r1, x2, y2, r2) {
|
|
1437
|
-
return new PDFRadialGradient
|
|
1281
|
+
return new PDFRadialGradient(this, x1, y1, r1, x2, y2, r2);
|
|
1438
1282
|
},
|
|
1439
1283
|
pattern(bbox, xStep, yStep, stream) {
|
|
1440
|
-
return new PDFTilingPattern
|
|
1284
|
+
return new PDFTilingPattern(this, bbox, xStep, yStep, stream);
|
|
1285
|
+
},
|
|
1286
|
+
addSpotColor(name, C, M, Y, K) {
|
|
1287
|
+
const color = new SpotColor(this, name, C, M, Y, K);
|
|
1288
|
+
this.spotColors[name] = color;
|
|
1289
|
+
return this;
|
|
1441
1290
|
}
|
|
1442
1291
|
};
|
|
1443
1292
|
var namedColors = {
|
|
@@ -1625,7 +1474,6 @@ const parse = function (path) {
|
|
|
1625
1474
|
if (parameters[c] != null) {
|
|
1626
1475
|
params = parameters[c];
|
|
1627
1476
|
if (cmd) {
|
|
1628
|
-
// save existing command
|
|
1629
1477
|
if (curArg.length > 0) {
|
|
1630
1478
|
args[args.length] = +curArg;
|
|
1631
1479
|
}
|
|
@@ -1643,14 +1491,11 @@ const parse = function (path) {
|
|
|
1643
1491
|
continue;
|
|
1644
1492
|
}
|
|
1645
1493
|
if (args.length === params) {
|
|
1646
|
-
// handle reused commands
|
|
1647
1494
|
ret[ret.length] = {
|
|
1648
1495
|
cmd,
|
|
1649
1496
|
args
|
|
1650
1497
|
};
|
|
1651
1498
|
args = [+curArg];
|
|
1652
|
-
|
|
1653
|
-
// handle assumed commands
|
|
1654
1499
|
if (cmd === 'M') {
|
|
1655
1500
|
cmd = 'L';
|
|
1656
1501
|
}
|
|
@@ -1661,8 +1506,6 @@ const parse = function (path) {
|
|
|
1661
1506
|
args[args.length] = +curArg;
|
|
1662
1507
|
}
|
|
1663
1508
|
foundDecimal = c === '.';
|
|
1664
|
-
|
|
1665
|
-
// fix for negative numbers or repeated decimals with no delimeter between commands
|
|
1666
1509
|
curArg = ['-', '.'].includes(c) ? c : '';
|
|
1667
1510
|
} else {
|
|
1668
1511
|
curArg += c;
|
|
@@ -1671,18 +1514,13 @@ const parse = function (path) {
|
|
|
1671
1514
|
}
|
|
1672
1515
|
}
|
|
1673
1516
|
}
|
|
1674
|
-
|
|
1675
|
-
// add the last command
|
|
1676
1517
|
if (curArg.length > 0) {
|
|
1677
1518
|
if (args.length === params) {
|
|
1678
|
-
// handle reused commands
|
|
1679
1519
|
ret[ret.length] = {
|
|
1680
1520
|
cmd,
|
|
1681
1521
|
args
|
|
1682
1522
|
};
|
|
1683
1523
|
args = [+curArg];
|
|
1684
|
-
|
|
1685
|
-
// handle assumed commands
|
|
1686
1524
|
if (cmd === 'M') {
|
|
1687
1525
|
cmd = 'L';
|
|
1688
1526
|
}
|
|
@@ -1700,10 +1538,7 @@ const parse = function (path) {
|
|
|
1700
1538
|
return ret;
|
|
1701
1539
|
};
|
|
1702
1540
|
const apply = function (commands, doc) {
|
|
1703
|
-
// current point, control point, and subpath starting point
|
|
1704
1541
|
cx = cy = px = py = sx = sy = 0;
|
|
1705
|
-
|
|
1706
|
-
// run the commands
|
|
1707
1542
|
for (let i = 0; i < commands.length; i++) {
|
|
1708
1543
|
const c = commands[i];
|
|
1709
1544
|
if (typeof runners[c.cmd] === 'function') {
|
|
@@ -1867,8 +1702,6 @@ const solveArc = function (doc, x, y, coords) {
|
|
|
1867
1702
|
doc.bezierCurveTo(...bez);
|
|
1868
1703
|
}
|
|
1869
1704
|
};
|
|
1870
|
-
|
|
1871
|
-
// from Inkscape svgtopdf, thanks!
|
|
1872
1705
|
const arcToSegments = function (x, y, rx, ry, large, sweep, rotateX, ox, oy) {
|
|
1873
1706
|
const th = rotateX * (Math.PI / 180);
|
|
1874
1707
|
const sin_th = Math.sin(th);
|
|
@@ -1944,18 +1777,14 @@ class SVGPath {
|
|
|
1944
1777
|
const {
|
|
1945
1778
|
number: number$1
|
|
1946
1779
|
} = PDFObject;
|
|
1947
|
-
|
|
1948
|
-
// This constant is used to approximate a symmetrical arc using a cubic
|
|
1949
|
-
// Bezier curve.
|
|
1950
1780
|
const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);
|
|
1951
1781
|
var VectorMixin = {
|
|
1952
1782
|
initVector() {
|
|
1953
|
-
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
1954
|
-
|
|
1783
|
+
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
1784
|
+
this._ctmStack = [];
|
|
1955
1785
|
},
|
|
1956
1786
|
save() {
|
|
1957
1787
|
this._ctmStack.push(this._ctm.slice());
|
|
1958
|
-
// TODO: save/restore colorspace and styles so not setting it unnessesarily all the time?
|
|
1959
1788
|
return this.addContent('q');
|
|
1960
1789
|
},
|
|
1961
1790
|
restore() {
|
|
@@ -2028,8 +1857,6 @@ var VectorMixin = {
|
|
|
2028
1857
|
r = 0;
|
|
2029
1858
|
}
|
|
2030
1859
|
r = Math.min(r, 0.5 * w, 0.5 * h);
|
|
2031
|
-
|
|
2032
|
-
// amount to inset control points from corners (see `ellipse`)
|
|
2033
1860
|
const c = r * (1.0 - KAPPA);
|
|
2034
1861
|
this.moveTo(x + r, y);
|
|
2035
1862
|
this.lineTo(x + w - r, y);
|
|
@@ -2043,7 +1870,6 @@ var VectorMixin = {
|
|
|
2043
1870
|
return this.closePath();
|
|
2044
1871
|
},
|
|
2045
1872
|
ellipse(x, y, r1, r2) {
|
|
2046
|
-
// based on http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas/2173084#2173084
|
|
2047
1873
|
if (r2 == null) {
|
|
2048
1874
|
r2 = r1;
|
|
2049
1875
|
}
|
|
@@ -2073,10 +1899,8 @@ var VectorMixin = {
|
|
|
2073
1899
|
const HALF_PI = 0.5 * Math.PI;
|
|
2074
1900
|
let deltaAng = endAngle - startAngle;
|
|
2075
1901
|
if (Math.abs(deltaAng) > TWO_PI) {
|
|
2076
|
-
// draw only full circle if more than that is specified
|
|
2077
1902
|
deltaAng = TWO_PI;
|
|
2078
1903
|
} else if (deltaAng !== 0 && anticlockwise !== deltaAng < 0) {
|
|
2079
|
-
// necessary to flip direction of rendering
|
|
2080
1904
|
const dir = anticlockwise ? -1 : 1;
|
|
2081
1905
|
deltaAng = dir * TWO_PI + deltaAng;
|
|
2082
1906
|
}
|
|
@@ -2084,38 +1908,21 @@ var VectorMixin = {
|
|
|
2084
1908
|
const segAng = deltaAng / numSegs;
|
|
2085
1909
|
const handleLen = segAng / HALF_PI * KAPPA * radius;
|
|
2086
1910
|
let curAng = startAngle;
|
|
2087
|
-
|
|
2088
|
-
// component distances between anchor point and control point
|
|
2089
1911
|
let deltaCx = -Math.sin(curAng) * handleLen;
|
|
2090
1912
|
let deltaCy = Math.cos(curAng) * handleLen;
|
|
2091
|
-
|
|
2092
|
-
// anchor point
|
|
2093
1913
|
let ax = x + Math.cos(curAng) * radius;
|
|
2094
1914
|
let ay = y + Math.sin(curAng) * radius;
|
|
2095
|
-
|
|
2096
|
-
// calculate and render segments
|
|
2097
1915
|
this.moveTo(ax, ay);
|
|
2098
1916
|
for (let segIdx = 0; segIdx < numSegs; segIdx++) {
|
|
2099
|
-
// starting control point
|
|
2100
1917
|
const cp1x = ax + deltaCx;
|
|
2101
1918
|
const cp1y = ay + deltaCy;
|
|
2102
|
-
|
|
2103
|
-
// step angle
|
|
2104
1919
|
curAng += segAng;
|
|
2105
|
-
|
|
2106
|
-
// next anchor point
|
|
2107
1920
|
ax = x + Math.cos(curAng) * radius;
|
|
2108
1921
|
ay = y + Math.sin(curAng) * radius;
|
|
2109
|
-
|
|
2110
|
-
// next control point delta
|
|
2111
1922
|
deltaCx = -Math.sin(curAng) * handleLen;
|
|
2112
1923
|
deltaCy = Math.cos(curAng) * handleLen;
|
|
2113
|
-
|
|
2114
|
-
// ending control point
|
|
2115
1924
|
const cp2x = ax - deltaCx;
|
|
2116
1925
|
const cp2y = ay - deltaCy;
|
|
2117
|
-
|
|
2118
|
-
// render segment
|
|
2119
1926
|
this.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, ax, ay);
|
|
2120
1927
|
}
|
|
2121
1928
|
return this;
|
|
@@ -2176,9 +1983,7 @@ var VectorMixin = {
|
|
|
2176
1983
|
return this.addContent(`W${this._windingRule(rule)} n`);
|
|
2177
1984
|
},
|
|
2178
1985
|
transform(m11, m12, m21, m22, dx, dy) {
|
|
2179
|
-
// keep track of the current transformation matrix
|
|
2180
1986
|
if (m11 === 1 && m12 === 0 && m21 === 0 && m22 === 1 && dx === 0 && dy === 0) {
|
|
2181
|
-
// Ignore identity transforms
|
|
2182
1987
|
return this;
|
|
2183
1988
|
}
|
|
2184
1989
|
const m = this._ctm;
|
|
@@ -2342,7 +2147,6 @@ class AFMFont {
|
|
|
2342
2147
|
this.boundingBoxes = {};
|
|
2343
2148
|
this.kernPairs = {};
|
|
2344
2149
|
this.parse();
|
|
2345
|
-
// todo: remove charWidths since appears to not be used
|
|
2346
2150
|
this.charWidths = new Array(256);
|
|
2347
2151
|
for (let char = 0; char <= 255; char++) {
|
|
2348
2152
|
this.charWidths[char] = this.glyphWidths[characters[char]];
|
|
@@ -2449,21 +2253,17 @@ class PDFFont {
|
|
|
2449
2253
|
return;
|
|
2450
2254
|
}
|
|
2451
2255
|
this.embed();
|
|
2452
|
-
|
|
2256
|
+
this.embedded = true;
|
|
2453
2257
|
}
|
|
2454
2258
|
embed() {
|
|
2455
2259
|
throw new Error('Must be implemented by subclasses');
|
|
2456
2260
|
}
|
|
2457
|
-
lineHeight(size, includeGap) {
|
|
2458
|
-
if (includeGap == null) {
|
|
2459
|
-
includeGap = false;
|
|
2460
|
-
}
|
|
2261
|
+
lineHeight(size, includeGap = false) {
|
|
2461
2262
|
const gap = includeGap ? this.lineGap : 0;
|
|
2462
2263
|
return (this.ascender + gap - this.descender) / 1000 * size;
|
|
2463
2264
|
}
|
|
2464
2265
|
}
|
|
2465
2266
|
|
|
2466
|
-
// This insanity is so bundlers can inline the font files
|
|
2467
2267
|
const STANDARD_FONTS = {
|
|
2468
2268
|
Courier() {
|
|
2469
2269
|
return fs.readFileSync(__dirname + '/data/Courier.afm', 'utf8');
|
|
@@ -2591,8 +2391,6 @@ class EmbeddedFont extends PDFFont {
|
|
|
2591
2391
|
}
|
|
2592
2392
|
layoutRun(text, features) {
|
|
2593
2393
|
const run = this.font.layout(text, features);
|
|
2594
|
-
|
|
2595
|
-
// Normalize position values
|
|
2596
2394
|
for (let i = 0; i < run.positions.length; i++) {
|
|
2597
2395
|
const position = run.positions[i];
|
|
2598
2396
|
for (let key in position) {
|
|
@@ -2615,16 +2413,12 @@ class EmbeddedFont extends PDFFont {
|
|
|
2615
2413
|
return run;
|
|
2616
2414
|
}
|
|
2617
2415
|
layout(text, features, onlyWidth) {
|
|
2618
|
-
// Skip the cache if any user defined features are applied
|
|
2619
2416
|
if (features) {
|
|
2620
2417
|
return this.layoutRun(text, features);
|
|
2621
2418
|
}
|
|
2622
2419
|
let glyphs = onlyWidth ? null : [];
|
|
2623
2420
|
let positions = onlyWidth ? null : [];
|
|
2624
2421
|
let advanceWidth = 0;
|
|
2625
|
-
|
|
2626
|
-
// Split the string by words to increase cache efficiency.
|
|
2627
|
-
// For this purpose, spaces and tabs are a good enough delimeter.
|
|
2628
2422
|
let last = 0;
|
|
2629
2423
|
let index = 0;
|
|
2630
2424
|
while (index <= text.length) {
|
|
@@ -2677,7 +2471,7 @@ class EmbeddedFont extends PDFFont {
|
|
|
2677
2471
|
if (isCFF) {
|
|
2678
2472
|
fontFile.data.Subtype = 'CIDFontType0C';
|
|
2679
2473
|
}
|
|
2680
|
-
|
|
2474
|
+
fontFile.end(this.subset.encode());
|
|
2681
2475
|
const familyClass = ((this.font['OS/2'] != null ? this.font['OS/2'].sFamilyClass : undefined) || 0) >> 8;
|
|
2682
2476
|
let flags = 0;
|
|
2683
2477
|
if (this.font.post.isFixedPitch) {
|
|
@@ -2686,17 +2480,15 @@ class EmbeddedFont extends PDFFont {
|
|
|
2686
2480
|
if (1 <= familyClass && familyClass <= 7) {
|
|
2687
2481
|
flags |= 1 << 1;
|
|
2688
2482
|
}
|
|
2689
|
-
flags |= 1 << 2;
|
|
2483
|
+
flags |= 1 << 2;
|
|
2690
2484
|
if (familyClass === 10) {
|
|
2691
2485
|
flags |= 1 << 3;
|
|
2692
2486
|
}
|
|
2693
2487
|
if (this.font.head.macStyle.italic) {
|
|
2694
2488
|
flags |= 1 << 6;
|
|
2695
2489
|
}
|
|
2696
|
-
|
|
2697
|
-
// generate a tag (6 uppercase letters. 17 is the char code offset from '0' to 'A'. 73 will map to 'Z')
|
|
2698
2490
|
const tag = [1, 2, 3, 4, 5, 6].map(i => String.fromCharCode((this.id.charCodeAt(i) || 73) + 17)).join('');
|
|
2699
|
-
const name = tag + '+' + this.font.postscriptName;
|
|
2491
|
+
const name = tag + '+' + this.font.postscriptName?.replaceAll(' ', '_');
|
|
2700
2492
|
const {
|
|
2701
2493
|
bbox
|
|
2702
2494
|
} = this.font;
|
|
@@ -2711,8 +2503,7 @@ class EmbeddedFont extends PDFFont {
|
|
|
2711
2503
|
CapHeight: (this.font.capHeight || this.font.ascent) * this.scale,
|
|
2712
2504
|
XHeight: (this.font.xHeight || 0) * this.scale,
|
|
2713
2505
|
StemV: 0
|
|
2714
|
-
});
|
|
2715
|
-
|
|
2506
|
+
});
|
|
2716
2507
|
if (isCFF) {
|
|
2717
2508
|
descriptor.data.FontFile3 = fontFile;
|
|
2718
2509
|
} else {
|
|
@@ -2754,17 +2545,11 @@ class EmbeddedFont extends PDFFont {
|
|
|
2754
2545
|
};
|
|
2755
2546
|
return this.dictionary.end();
|
|
2756
2547
|
}
|
|
2757
|
-
|
|
2758
|
-
// Maps the glyph ids encoded in the PDF back to unicode strings
|
|
2759
|
-
// Because of ligature substitutions and the like, there may be one or more
|
|
2760
|
-
// unicode characters represented by each glyph.
|
|
2761
2548
|
toUnicodeCmap() {
|
|
2762
2549
|
const cmap = this.document.ref();
|
|
2763
2550
|
const entries = [];
|
|
2764
2551
|
for (let codePoints of this.unicode) {
|
|
2765
2552
|
const encoded = [];
|
|
2766
|
-
|
|
2767
|
-
// encode codePoints to utf16
|
|
2768
2553
|
for (let value of codePoints) {
|
|
2769
2554
|
if (value > 0xffff) {
|
|
2770
2555
|
value -= 0x10000;
|
|
@@ -2818,12 +2603,10 @@ class PDFFontFactory {
|
|
|
2818
2603
|
}
|
|
2819
2604
|
src = fs.readFileSync(src);
|
|
2820
2605
|
}
|
|
2821
|
-
if (
|
|
2606
|
+
if (src instanceof Uint8Array) {
|
|
2822
2607
|
font = fontkit.create(src, family);
|
|
2823
|
-
} else if (src instanceof Uint8Array) {
|
|
2824
|
-
font = fontkit.create(Buffer.from(src), family);
|
|
2825
2608
|
} else if (src instanceof ArrayBuffer) {
|
|
2826
|
-
font = fontkit.create(
|
|
2609
|
+
font = fontkit.create(new Uint8Array(src), family);
|
|
2827
2610
|
}
|
|
2828
2611
|
if (font == null) {
|
|
2829
2612
|
throw new Error('Not a supported font format or standard PDF font.');
|
|
@@ -2832,20 +2615,27 @@ class PDFFontFactory {
|
|
|
2832
2615
|
}
|
|
2833
2616
|
}
|
|
2834
2617
|
|
|
2618
|
+
const isEqualFont = (font1, font2) => {
|
|
2619
|
+
if (font1.font._tables?.head?.checkSumAdjustment !== font2.font._tables?.head?.checkSumAdjustment) {
|
|
2620
|
+
return false;
|
|
2621
|
+
}
|
|
2622
|
+
if (JSON.stringify(font1.font._tables?.name?.records) !== JSON.stringify(font2.font._tables?.name?.records)) {
|
|
2623
|
+
return false;
|
|
2624
|
+
}
|
|
2625
|
+
return true;
|
|
2626
|
+
};
|
|
2835
2627
|
var FontsMixin = {
|
|
2836
|
-
initFonts(defaultFont = 'Helvetica') {
|
|
2837
|
-
// Lookup table for embedded fonts
|
|
2628
|
+
initFonts(defaultFont = 'Helvetica', defaultFontFamily = null, defaultFontSize = 12) {
|
|
2838
2629
|
this._fontFamilies = {};
|
|
2839
2630
|
this._fontCount = 0;
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
this._fontSize =
|
|
2631
|
+
this._fontSource = defaultFont;
|
|
2632
|
+
this._fontFamily = defaultFontFamily;
|
|
2633
|
+
this._fontSize = defaultFontSize;
|
|
2843
2634
|
this._font = null;
|
|
2635
|
+
this._remSize = defaultFontSize;
|
|
2844
2636
|
this._registeredFonts = {};
|
|
2845
|
-
|
|
2846
|
-
// Set the default font
|
|
2847
2637
|
if (defaultFont) {
|
|
2848
|
-
this.font(defaultFont);
|
|
2638
|
+
this.font(defaultFont, defaultFontFamily);
|
|
2849
2639
|
}
|
|
2850
2640
|
},
|
|
2851
2641
|
font(src, family, size) {
|
|
@@ -2854,8 +2644,6 @@ var FontsMixin = {
|
|
|
2854
2644
|
size = family;
|
|
2855
2645
|
family = null;
|
|
2856
2646
|
}
|
|
2857
|
-
|
|
2858
|
-
// check registered fonts if src is a string
|
|
2859
2647
|
if (typeof src === 'string' && this._registeredFonts[src]) {
|
|
2860
2648
|
cacheKey = src;
|
|
2861
2649
|
({
|
|
@@ -2868,28 +2656,21 @@ var FontsMixin = {
|
|
|
2868
2656
|
cacheKey = null;
|
|
2869
2657
|
}
|
|
2870
2658
|
}
|
|
2659
|
+
this._fontSource = src;
|
|
2660
|
+
this._fontFamily = family;
|
|
2871
2661
|
if (size != null) {
|
|
2872
2662
|
this.fontSize(size);
|
|
2873
2663
|
}
|
|
2874
|
-
|
|
2875
|
-
// fast path: check if the font is already in the PDF
|
|
2876
2664
|
if (font = this._fontFamilies[cacheKey]) {
|
|
2877
2665
|
this._font = font;
|
|
2878
2666
|
return this;
|
|
2879
2667
|
}
|
|
2880
|
-
|
|
2881
|
-
// load the font
|
|
2882
2668
|
const id = `F${++this._fontCount}`;
|
|
2883
2669
|
this._font = PDFFontFactory.open(this, src, family, id);
|
|
2884
|
-
|
|
2885
|
-
// check for existing font familes with the same name already in the PDF
|
|
2886
|
-
// useful if the font was passed as a buffer
|
|
2887
|
-
if (font = this._fontFamilies[this._font.name]) {
|
|
2670
|
+
if ((font = this._fontFamilies[this._font.name]) && isEqualFont(this._font, font)) {
|
|
2888
2671
|
this._font = font;
|
|
2889
2672
|
return this;
|
|
2890
2673
|
}
|
|
2891
|
-
|
|
2892
|
-
// save the font for reuse later
|
|
2893
2674
|
if (cacheKey) {
|
|
2894
2675
|
this._fontFamilies[cacheKey] = this._font;
|
|
2895
2676
|
}
|
|
@@ -2899,13 +2680,10 @@ var FontsMixin = {
|
|
|
2899
2680
|
return this;
|
|
2900
2681
|
},
|
|
2901
2682
|
fontSize(_fontSize) {
|
|
2902
|
-
this._fontSize = _fontSize;
|
|
2683
|
+
this._fontSize = this.sizeToPoint(_fontSize);
|
|
2903
2684
|
return this;
|
|
2904
2685
|
},
|
|
2905
2686
|
currentLineHeight(includeGap) {
|
|
2906
|
-
if (includeGap == null) {
|
|
2907
|
-
includeGap = false;
|
|
2908
|
-
}
|
|
2909
2687
|
return this._font.lineHeight(this._fontSize, includeGap);
|
|
2910
2688
|
},
|
|
2911
2689
|
registerFont(name, src, family) {
|
|
@@ -2914,6 +2692,64 @@ var FontsMixin = {
|
|
|
2914
2692
|
family
|
|
2915
2693
|
};
|
|
2916
2694
|
return this;
|
|
2695
|
+
},
|
|
2696
|
+
sizeToPoint(size, defaultValue = 0, page = this.page, percentageWidth = undefined) {
|
|
2697
|
+
if (!percentageWidth) percentageWidth = this._fontSize;
|
|
2698
|
+
if (typeof defaultValue !== 'number') defaultValue = this.sizeToPoint(defaultValue);
|
|
2699
|
+
if (size === undefined) return defaultValue;
|
|
2700
|
+
if (typeof size === 'number') return size;
|
|
2701
|
+
if (typeof size === 'boolean') return Number(size);
|
|
2702
|
+
const match = String(size).match(/((\d+)?(\.\d+)?)(em|in|px|cm|mm|pc|ex|ch|rem|vw|vh|vmin|vmax|%|pt)?/);
|
|
2703
|
+
if (!match) throw new Error(`Unsupported size '${size}'`);
|
|
2704
|
+
let multiplier;
|
|
2705
|
+
switch (match[4]) {
|
|
2706
|
+
case 'em':
|
|
2707
|
+
multiplier = this._fontSize;
|
|
2708
|
+
break;
|
|
2709
|
+
case 'in':
|
|
2710
|
+
multiplier = IN_TO_PT;
|
|
2711
|
+
break;
|
|
2712
|
+
case 'px':
|
|
2713
|
+
multiplier = PX_TO_IN * IN_TO_PT;
|
|
2714
|
+
break;
|
|
2715
|
+
case 'cm':
|
|
2716
|
+
multiplier = CM_TO_IN * IN_TO_PT;
|
|
2717
|
+
break;
|
|
2718
|
+
case 'mm':
|
|
2719
|
+
multiplier = MM_TO_CM * CM_TO_IN * IN_TO_PT;
|
|
2720
|
+
break;
|
|
2721
|
+
case 'pc':
|
|
2722
|
+
multiplier = PC_TO_PT;
|
|
2723
|
+
break;
|
|
2724
|
+
case 'ex':
|
|
2725
|
+
multiplier = this.currentLineHeight();
|
|
2726
|
+
break;
|
|
2727
|
+
case 'ch':
|
|
2728
|
+
multiplier = this.widthOfString('0');
|
|
2729
|
+
break;
|
|
2730
|
+
case 'rem':
|
|
2731
|
+
multiplier = this._remSize;
|
|
2732
|
+
break;
|
|
2733
|
+
case 'vw':
|
|
2734
|
+
multiplier = page.width / 100;
|
|
2735
|
+
break;
|
|
2736
|
+
case 'vh':
|
|
2737
|
+
multiplier = page.height / 100;
|
|
2738
|
+
break;
|
|
2739
|
+
case 'vmin':
|
|
2740
|
+
multiplier = Math.min(page.width, page.height) / 100;
|
|
2741
|
+
break;
|
|
2742
|
+
case 'vmax':
|
|
2743
|
+
multiplier = Math.max(page.width, page.height) / 100;
|
|
2744
|
+
break;
|
|
2745
|
+
case '%':
|
|
2746
|
+
multiplier = percentageWidth / 100;
|
|
2747
|
+
break;
|
|
2748
|
+
case 'pt':
|
|
2749
|
+
default:
|
|
2750
|
+
multiplier = 1;
|
|
2751
|
+
}
|
|
2752
|
+
return multiplier * Number(match[1]);
|
|
2917
2753
|
}
|
|
2918
2754
|
};
|
|
2919
2755
|
|
|
@@ -2923,12 +2759,13 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2923
2759
|
constructor(document, options) {
|
|
2924
2760
|
super();
|
|
2925
2761
|
this.document = document;
|
|
2926
|
-
this.
|
|
2927
|
-
this.
|
|
2928
|
-
this.
|
|
2762
|
+
this.horizontalScaling = options.horizontalScaling || 100;
|
|
2763
|
+
this.indent = (options.indent || 0) * this.horizontalScaling / 100;
|
|
2764
|
+
this.characterSpacing = (options.characterSpacing || 0) * this.horizontalScaling / 100;
|
|
2765
|
+
this.wordSpacing = (options.wordSpacing === 0) * this.horizontalScaling / 100;
|
|
2929
2766
|
this.columns = options.columns || 1;
|
|
2930
|
-
this.columnGap = options.columnGap != null ? options.columnGap : 18
|
|
2931
|
-
this.lineWidth = (options.width - this.columnGap * (this.columns - 1)) / this.columns;
|
|
2767
|
+
this.columnGap = (options.columnGap != null ? options.columnGap : 18) * this.horizontalScaling / 100;
|
|
2768
|
+
this.lineWidth = (options.width * this.horizontalScaling / 100 - this.columnGap * (this.columns - 1)) / this.columns;
|
|
2932
2769
|
this.spaceLeft = this.lineWidth;
|
|
2933
2770
|
this.startX = this.document.x;
|
|
2934
2771
|
this.startY = this.document.y;
|
|
@@ -2936,36 +2773,30 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2936
2773
|
this.ellipsis = options.ellipsis;
|
|
2937
2774
|
this.continuedX = 0;
|
|
2938
2775
|
this.features = options.features;
|
|
2939
|
-
|
|
2940
|
-
// calculate the maximum Y position the text can appear at
|
|
2941
2776
|
if (options.height != null) {
|
|
2942
2777
|
this.height = options.height;
|
|
2943
|
-
this.maxY = this.startY + options.height;
|
|
2778
|
+
this.maxY = PDFNumber(this.startY + options.height);
|
|
2944
2779
|
} else {
|
|
2945
|
-
this.maxY = this.document.page.maxY();
|
|
2780
|
+
this.maxY = PDFNumber(this.document.page.maxY());
|
|
2946
2781
|
}
|
|
2947
|
-
|
|
2948
|
-
// handle paragraph indents
|
|
2949
2782
|
this.on('firstLine', options => {
|
|
2950
|
-
// if this is the first line of the text segment, and
|
|
2951
|
-
// we're continuing where we left off, indent that much
|
|
2952
|
-
// otherwise use the user specified indent option
|
|
2953
2783
|
const indent = this.continuedX || this.indent;
|
|
2954
2784
|
this.document.x += indent;
|
|
2955
2785
|
this.lineWidth -= indent;
|
|
2956
|
-
|
|
2786
|
+
if (options.indentAllLines) {
|
|
2787
|
+
return;
|
|
2788
|
+
}
|
|
2789
|
+
this.once('line', () => {
|
|
2957
2790
|
this.document.x -= indent;
|
|
2958
2791
|
this.lineWidth += indent;
|
|
2959
2792
|
if (options.continued && !this.continuedX) {
|
|
2960
2793
|
this.continuedX = this.indent;
|
|
2961
2794
|
}
|
|
2962
2795
|
if (!options.continued) {
|
|
2963
|
-
|
|
2796
|
+
this.continuedX = 0;
|
|
2964
2797
|
}
|
|
2965
2798
|
});
|
|
2966
2799
|
});
|
|
2967
|
-
|
|
2968
|
-
// handle left aligning last lines of paragraphs
|
|
2969
2800
|
this.on('lastLine', options => {
|
|
2970
2801
|
const {
|
|
2971
2802
|
align
|
|
@@ -2974,7 +2805,7 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2974
2805
|
options.align = 'left';
|
|
2975
2806
|
}
|
|
2976
2807
|
this.lastLine = true;
|
|
2977
|
-
|
|
2808
|
+
this.once('line', () => {
|
|
2978
2809
|
this.document.y += options.paragraphGap || 0;
|
|
2979
2810
|
options.align = align;
|
|
2980
2811
|
return this.lastLine = false;
|
|
@@ -2991,7 +2822,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2991
2822
|
return w + this.wordWidth(HYPHEN) <= this.spaceLeft;
|
|
2992
2823
|
}
|
|
2993
2824
|
eachWord(text, fn) {
|
|
2994
|
-
// setup a unicode line breaker
|
|
2995
2825
|
let bk;
|
|
2996
2826
|
const breaker = new LineBreaker(text);
|
|
2997
2827
|
let last = null;
|
|
@@ -3000,19 +2830,12 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3000
2830
|
var shouldContinue;
|
|
3001
2831
|
let word = text.slice((last != null ? last.position : undefined) || 0, bk.position);
|
|
3002
2832
|
let w = wordWidths[word] != null ? wordWidths[word] : wordWidths[word] = this.wordWidth(word);
|
|
3003
|
-
|
|
3004
|
-
// if the word is longer than the whole line, chop it up
|
|
3005
|
-
// TODO: break by grapheme clusters, not JS string characters
|
|
3006
2833
|
if (w > this.lineWidth + this.continuedX) {
|
|
3007
|
-
// make some fake break objects
|
|
3008
2834
|
let lbk = last;
|
|
3009
2835
|
const fbk = {};
|
|
3010
2836
|
while (word.length) {
|
|
3011
|
-
// fit as much of the word as possible into the space we have
|
|
3012
2837
|
var l, mightGrow;
|
|
3013
2838
|
if (w > this.spaceLeft) {
|
|
3014
|
-
// start our check at the end of our available space - this method is faster than a loop of each character and it resolves
|
|
3015
|
-
// an issue with long loops when processing massive words, such as a huge number of spaces
|
|
3016
2839
|
l = Math.ceil(this.spaceLeft / (w / word.length));
|
|
3017
2840
|
w = this.wordWidth(word.slice(0, l));
|
|
3018
2841
|
mightGrow = w <= this.spaceLeft && l < word.length;
|
|
@@ -3020,7 +2843,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3020
2843
|
l = word.length;
|
|
3021
2844
|
}
|
|
3022
2845
|
let mustShrink = w > this.spaceLeft && l > 0;
|
|
3023
|
-
// shrink or grow word as necessary after our near-guess above
|
|
3024
2846
|
while (mustShrink || mightGrow) {
|
|
3025
2847
|
if (mustShrink) {
|
|
3026
2848
|
w = this.wordWidth(word.slice(0, --l));
|
|
@@ -3031,20 +2853,14 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3031
2853
|
mightGrow = w <= this.spaceLeft && l < word.length;
|
|
3032
2854
|
}
|
|
3033
2855
|
}
|
|
3034
|
-
|
|
3035
|
-
// check for the edge case where a single character cannot fit into a line.
|
|
3036
2856
|
if (l === 0 && this.spaceLeft === this.lineWidth) {
|
|
3037
2857
|
l = 1;
|
|
3038
2858
|
}
|
|
3039
|
-
|
|
3040
|
-
// send a required break unless this is the last piece and a linebreak is not specified
|
|
3041
2859
|
fbk.required = bk.required || l < word.length;
|
|
3042
2860
|
shouldContinue = fn(word.slice(0, l), w, fbk, lbk);
|
|
3043
2861
|
lbk = {
|
|
3044
2862
|
required: false
|
|
3045
2863
|
};
|
|
3046
|
-
|
|
3047
|
-
// get the remaining piece of the word
|
|
3048
2864
|
word = word.slice(l);
|
|
3049
2865
|
w = this.wordWidth(word);
|
|
3050
2866
|
if (shouldContinue === false) {
|
|
@@ -3052,7 +2868,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3052
2868
|
}
|
|
3053
2869
|
}
|
|
3054
2870
|
} else {
|
|
3055
|
-
// otherwise just emit the break as it was given to us
|
|
3056
2871
|
shouldContinue = fn(word, w, bk, last);
|
|
3057
2872
|
}
|
|
3058
2873
|
if (shouldContinue === false) {
|
|
@@ -3062,23 +2877,19 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3062
2877
|
}
|
|
3063
2878
|
}
|
|
3064
2879
|
wrap(text, options) {
|
|
3065
|
-
|
|
2880
|
+
this.horizontalScaling = options.horizontalScaling || 100;
|
|
3066
2881
|
if (options.indent != null) {
|
|
3067
|
-
this.indent = options.indent;
|
|
2882
|
+
this.indent = options.indent * this.horizontalScaling / 100;
|
|
3068
2883
|
}
|
|
3069
2884
|
if (options.characterSpacing != null) {
|
|
3070
|
-
this.characterSpacing = options.characterSpacing;
|
|
2885
|
+
this.characterSpacing = options.characterSpacing * this.horizontalScaling / 100;
|
|
3071
2886
|
}
|
|
3072
2887
|
if (options.wordSpacing != null) {
|
|
3073
|
-
this.wordSpacing = options.wordSpacing;
|
|
2888
|
+
this.wordSpacing = options.wordSpacing * this.horizontalScaling / 100;
|
|
3074
2889
|
}
|
|
3075
2890
|
if (options.ellipsis != null) {
|
|
3076
2891
|
this.ellipsis = options.ellipsis;
|
|
3077
2892
|
}
|
|
3078
|
-
|
|
3079
|
-
// make sure we're actually on the page
|
|
3080
|
-
// and that the first line of is never by
|
|
3081
|
-
// itself at the bottom of a page (orphans)
|
|
3082
2893
|
const nextY = this.document.y + this.document.currentLineHeight(true);
|
|
3083
2894
|
if (this.document.y > this.maxY || nextY > this.maxY) {
|
|
3084
2895
|
this.nextSection();
|
|
@@ -3089,7 +2900,7 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3089
2900
|
let lc = 0;
|
|
3090
2901
|
let {
|
|
3091
2902
|
y
|
|
3092
|
-
} = this.document;
|
|
2903
|
+
} = this.document;
|
|
3093
2904
|
const emitLine = () => {
|
|
3094
2905
|
options.textWidth = textWidth + this.wordSpacing * (wc - 1);
|
|
3095
2906
|
options.wordCount = wc;
|
|
@@ -3112,23 +2923,17 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3112
2923
|
wc++;
|
|
3113
2924
|
}
|
|
3114
2925
|
if (bk.required || !this.canFit(word, w)) {
|
|
3115
|
-
// if the user specified a max height and an ellipsis, and is about to pass the
|
|
3116
|
-
// max height and max columns after the next line, append the ellipsis
|
|
3117
2926
|
const lh = this.document.currentLineHeight(true);
|
|
3118
|
-
if (this.height != null && this.ellipsis && this.document.y + lh * 2 > this.maxY && this.column >= this.columns) {
|
|
2927
|
+
if (this.height != null && this.ellipsis && PDFNumber(this.document.y + lh * 2) > this.maxY && this.column >= this.columns) {
|
|
3119
2928
|
if (this.ellipsis === true) {
|
|
3120
2929
|
this.ellipsis = '…';
|
|
3121
|
-
}
|
|
2930
|
+
}
|
|
3122
2931
|
buffer = buffer.replace(/\s+$/, '');
|
|
3123
2932
|
textWidth = this.wordWidth(buffer + this.ellipsis);
|
|
3124
|
-
|
|
3125
|
-
// remove characters from the buffer until the ellipsis fits
|
|
3126
|
-
// to avoid infinite loop need to stop while-loop if buffer is empty string
|
|
3127
2933
|
while (buffer && textWidth > this.lineWidth) {
|
|
3128
2934
|
buffer = buffer.slice(0, -1).replace(/\s+$/, '');
|
|
3129
2935
|
textWidth = this.wordWidth(buffer + this.ellipsis);
|
|
3130
2936
|
}
|
|
3131
|
-
// need to add ellipsis only if there is enough space for it
|
|
3132
2937
|
if (textWidth <= this.lineWidth) {
|
|
3133
2938
|
buffer = buffer + this.ellipsis;
|
|
3134
2939
|
}
|
|
@@ -3143,35 +2948,25 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3143
2948
|
}
|
|
3144
2949
|
this.emit('lastLine', options, this);
|
|
3145
2950
|
}
|
|
3146
|
-
|
|
3147
|
-
// Previous entry is a soft hyphen - add visible hyphen.
|
|
3148
2951
|
if (buffer[buffer.length - 1] == SOFT_HYPHEN) {
|
|
3149
2952
|
buffer = buffer.slice(0, -1) + HYPHEN;
|
|
3150
2953
|
this.spaceLeft -= this.wordWidth(HYPHEN);
|
|
3151
2954
|
}
|
|
3152
2955
|
emitLine();
|
|
3153
|
-
|
|
3154
|
-
// if we've reached the edge of the page,
|
|
3155
|
-
// continue on a new page or column
|
|
3156
|
-
if (this.document.y + lh > this.maxY) {
|
|
2956
|
+
if (PDFNumber(this.document.y + lh) > this.maxY) {
|
|
3157
2957
|
const shouldContinue = this.nextSection();
|
|
3158
|
-
|
|
3159
|
-
// stop if we reached the maximum height
|
|
3160
2958
|
if (!shouldContinue) {
|
|
3161
2959
|
wc = 0;
|
|
3162
2960
|
buffer = '';
|
|
3163
2961
|
return false;
|
|
3164
2962
|
}
|
|
3165
2963
|
}
|
|
3166
|
-
|
|
3167
|
-
// reset the space left and buffer
|
|
3168
2964
|
if (bk.required) {
|
|
3169
2965
|
this.spaceLeft = this.lineWidth;
|
|
3170
2966
|
buffer = '';
|
|
3171
2967
|
textWidth = 0;
|
|
3172
2968
|
return wc = 0;
|
|
3173
2969
|
} else {
|
|
3174
|
-
// reset the space left and buffer
|
|
3175
2970
|
this.spaceLeft = this.lineWidth - w;
|
|
3176
2971
|
buffer = word;
|
|
3177
2972
|
textWidth = w;
|
|
@@ -3186,25 +2981,19 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3186
2981
|
emitLine();
|
|
3187
2982
|
}
|
|
3188
2983
|
this.emit('sectionEnd', options, this);
|
|
3189
|
-
|
|
3190
|
-
// if the wrap is set to be continued, save the X position
|
|
3191
|
-
// to start the first line of the next segment at, and reset
|
|
3192
|
-
// the y position
|
|
3193
2984
|
if (options.continued === true) {
|
|
3194
2985
|
if (lc > 1) {
|
|
3195
2986
|
this.continuedX = 0;
|
|
3196
2987
|
}
|
|
3197
2988
|
this.continuedX += options.textWidth || 0;
|
|
3198
|
-
|
|
2989
|
+
this.document.y = y;
|
|
3199
2990
|
} else {
|
|
3200
|
-
|
|
2991
|
+
this.document.x = this.startX;
|
|
3201
2992
|
}
|
|
3202
2993
|
}
|
|
3203
2994
|
nextSection(options) {
|
|
3204
2995
|
this.emit('sectionEnd', options, this);
|
|
3205
2996
|
if (++this.column > this.columns) {
|
|
3206
|
-
// if a max height was specified by the user, we're done.
|
|
3207
|
-
// otherwise, the default is to make a new page at the bottom.
|
|
3208
2997
|
if (this.height != null) {
|
|
3209
2998
|
return false;
|
|
3210
2999
|
}
|
|
@@ -3228,15 +3017,14 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3228
3017
|
}
|
|
3229
3018
|
|
|
3230
3019
|
const {
|
|
3231
|
-
number
|
|
3020
|
+
number
|
|
3232
3021
|
} = PDFObject;
|
|
3233
3022
|
var TextMixin = {
|
|
3234
3023
|
initText() {
|
|
3235
3024
|
this._line = this._line.bind(this);
|
|
3236
|
-
// Current coordinates
|
|
3237
3025
|
this.x = 0;
|
|
3238
3026
|
this.y = 0;
|
|
3239
|
-
|
|
3027
|
+
this._lineGap = 0;
|
|
3240
3028
|
},
|
|
3241
3029
|
lineGap(_lineGap) {
|
|
3242
3030
|
this._lineGap = _lineGap;
|
|
@@ -3258,11 +3046,7 @@ var TextMixin = {
|
|
|
3258
3046
|
},
|
|
3259
3047
|
_text(text, x, y, options, lineCallback) {
|
|
3260
3048
|
options = this._initOptions(x, y, options);
|
|
3261
|
-
|
|
3262
|
-
// Convert text to a string
|
|
3263
3049
|
text = text == null ? '' : `${text}`;
|
|
3264
|
-
|
|
3265
|
-
// if the wordSpacing option is specified, remove multiple consecutive spaces
|
|
3266
3050
|
if (options.wordSpacing) {
|
|
3267
3051
|
text = text.replace(/\s{2,}/g, ' ');
|
|
3268
3052
|
}
|
|
@@ -3271,8 +3055,12 @@ var TextMixin = {
|
|
|
3271
3055
|
options.structParent.add(this.struct(options.structType || 'P', [this.markStructureContent(options.structType || 'P')]));
|
|
3272
3056
|
}
|
|
3273
3057
|
};
|
|
3274
|
-
|
|
3275
|
-
|
|
3058
|
+
if (options.rotation !== 0) {
|
|
3059
|
+
this.save();
|
|
3060
|
+
this.rotate(-options.rotation, {
|
|
3061
|
+
origin: [this.x, this.y]
|
|
3062
|
+
});
|
|
3063
|
+
}
|
|
3276
3064
|
if (options.width) {
|
|
3277
3065
|
let wrapper = this._wrapper;
|
|
3278
3066
|
if (!wrapper) {
|
|
@@ -3283,21 +3071,113 @@ var TextMixin = {
|
|
|
3283
3071
|
this._wrapper = options.continued ? wrapper : null;
|
|
3284
3072
|
this._textOptions = options.continued ? options : null;
|
|
3285
3073
|
wrapper.wrap(text, options);
|
|
3286
|
-
|
|
3287
|
-
// render paragraphs as single lines
|
|
3288
3074
|
} else {
|
|
3289
3075
|
for (let line of text.split('\n')) {
|
|
3290
3076
|
addStructure();
|
|
3291
3077
|
lineCallback(line, options);
|
|
3292
3078
|
}
|
|
3293
3079
|
}
|
|
3080
|
+
if (options.rotation !== 0) this.restore();
|
|
3294
3081
|
return this;
|
|
3295
3082
|
},
|
|
3296
3083
|
text(text, x, y, options) {
|
|
3297
3084
|
return this._text(text, x, y, options, this._line);
|
|
3298
3085
|
},
|
|
3299
3086
|
widthOfString(string, options = {}) {
|
|
3300
|
-
|
|
3087
|
+
const horizontalScaling = options.horizontalScaling || 100;
|
|
3088
|
+
return (this._font.widthOfString(string, this._fontSize, options.features) + (options.characterSpacing || 0) * (string.length - 1)) * horizontalScaling / 100;
|
|
3089
|
+
},
|
|
3090
|
+
boundsOfString(string, x, y, options) {
|
|
3091
|
+
options = this._initOptions(x, y, options);
|
|
3092
|
+
({
|
|
3093
|
+
x,
|
|
3094
|
+
y
|
|
3095
|
+
} = this);
|
|
3096
|
+
const lineGap = options.lineGap ?? this._lineGap ?? 0;
|
|
3097
|
+
const lineHeight = this.currentLineHeight(true) + lineGap;
|
|
3098
|
+
let contentWidth = 0;
|
|
3099
|
+
string = String(string ?? '');
|
|
3100
|
+
if (options.wordSpacing) {
|
|
3101
|
+
string = string.replace(/\s{2,}/g, ' ');
|
|
3102
|
+
}
|
|
3103
|
+
if (options.width) {
|
|
3104
|
+
let wrapper = new LineWrapper(this, options);
|
|
3105
|
+
wrapper.on('line', (text, options) => {
|
|
3106
|
+
this.y += lineHeight;
|
|
3107
|
+
text = text.replace(/\n/g, '');
|
|
3108
|
+
if (text.length) {
|
|
3109
|
+
let wordSpacing = options.wordSpacing ?? 0;
|
|
3110
|
+
const characterSpacing = options.characterSpacing ?? 0;
|
|
3111
|
+
if (options.width && options.align === 'justify') {
|
|
3112
|
+
const words = text.trim().split(/\s+/);
|
|
3113
|
+
const textWidth = this.widthOfString(text.replace(/\s+/g, ''), options);
|
|
3114
|
+
const spaceWidth = this.widthOfString(' ') + characterSpacing;
|
|
3115
|
+
wordSpacing = Math.max(0, (options.lineWidth - textWidth) / Math.max(1, words.length - 1) - spaceWidth);
|
|
3116
|
+
}
|
|
3117
|
+
contentWidth = Math.max(contentWidth, options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1));
|
|
3118
|
+
}
|
|
3119
|
+
});
|
|
3120
|
+
wrapper.wrap(string, options);
|
|
3121
|
+
} else {
|
|
3122
|
+
for (let line of string.split('\n')) {
|
|
3123
|
+
const lineWidth = this.widthOfString(line, options);
|
|
3124
|
+
this.y += lineHeight;
|
|
3125
|
+
contentWidth = Math.max(contentWidth, lineWidth);
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
let contentHeight = this.y - y;
|
|
3129
|
+
if (options.height) contentHeight = Math.min(contentHeight, options.height);
|
|
3130
|
+
this.x = x;
|
|
3131
|
+
this.y = y;
|
|
3132
|
+
if (options.rotation === 0) {
|
|
3133
|
+
return {
|
|
3134
|
+
x,
|
|
3135
|
+
y,
|
|
3136
|
+
width: contentWidth,
|
|
3137
|
+
height: contentHeight
|
|
3138
|
+
};
|
|
3139
|
+
} else if (options.rotation === 90) {
|
|
3140
|
+
return {
|
|
3141
|
+
x: x,
|
|
3142
|
+
y: y - contentWidth,
|
|
3143
|
+
width: contentHeight,
|
|
3144
|
+
height: contentWidth
|
|
3145
|
+
};
|
|
3146
|
+
} else if (options.rotation === 180) {
|
|
3147
|
+
return {
|
|
3148
|
+
x: x - contentWidth,
|
|
3149
|
+
y: y - contentHeight,
|
|
3150
|
+
width: contentWidth,
|
|
3151
|
+
height: contentHeight
|
|
3152
|
+
};
|
|
3153
|
+
} else if (options.rotation === 270) {
|
|
3154
|
+
return {
|
|
3155
|
+
x: x - contentHeight,
|
|
3156
|
+
y: y,
|
|
3157
|
+
width: contentHeight,
|
|
3158
|
+
height: contentWidth
|
|
3159
|
+
};
|
|
3160
|
+
}
|
|
3161
|
+
const cos = cosine(options.rotation);
|
|
3162
|
+
const sin = sine(options.rotation);
|
|
3163
|
+
const x1 = x;
|
|
3164
|
+
const y1 = y;
|
|
3165
|
+
const x2 = x + contentWidth * cos;
|
|
3166
|
+
const y2 = y - contentWidth * sin;
|
|
3167
|
+
const x3 = x + contentWidth * cos + contentHeight * sin;
|
|
3168
|
+
const y3 = y - contentWidth * sin + contentHeight * cos;
|
|
3169
|
+
const x4 = x + contentHeight * sin;
|
|
3170
|
+
const y4 = y + contentHeight * cos;
|
|
3171
|
+
const xMin = Math.min(x1, x2, x3, x4);
|
|
3172
|
+
const xMax = Math.max(x1, x2, x3, x4);
|
|
3173
|
+
const yMin = Math.min(y1, y2, y3, y4);
|
|
3174
|
+
const yMax = Math.max(y1, y2, y3, y4);
|
|
3175
|
+
return {
|
|
3176
|
+
x: xMin,
|
|
3177
|
+
y: yMin,
|
|
3178
|
+
width: xMax - xMin,
|
|
3179
|
+
height: yMax - yMin
|
|
3180
|
+
};
|
|
3301
3181
|
},
|
|
3302
3182
|
heightOfString(text, options) {
|
|
3303
3183
|
const {
|
|
@@ -3305,11 +3185,10 @@ var TextMixin = {
|
|
|
3305
3185
|
y
|
|
3306
3186
|
} = this;
|
|
3307
3187
|
options = this._initOptions(options);
|
|
3308
|
-
options.height = Infinity;
|
|
3309
|
-
|
|
3188
|
+
options.height = Infinity;
|
|
3310
3189
|
const lineGap = options.lineGap || this._lineGap || 0;
|
|
3311
3190
|
this._text(text, this.x, this.y, options, () => {
|
|
3312
|
-
|
|
3191
|
+
this.y += this.currentLineHeight(true) + lineGap;
|
|
3313
3192
|
});
|
|
3314
3193
|
const height = this.y - y;
|
|
3315
3194
|
this.x = x;
|
|
@@ -3407,12 +3286,12 @@ var TextMixin = {
|
|
|
3407
3286
|
wrapper.on('sectionStart', () => {
|
|
3408
3287
|
const pos = indent + itemIndent * (level - 1);
|
|
3409
3288
|
this.x += pos;
|
|
3410
|
-
|
|
3289
|
+
wrapper.lineWidth -= pos;
|
|
3411
3290
|
});
|
|
3412
3291
|
wrapper.on('sectionEnd', () => {
|
|
3413
3292
|
const pos = indent + itemIndent * (level - 1);
|
|
3414
3293
|
this.x -= pos;
|
|
3415
|
-
|
|
3294
|
+
wrapper.lineWidth += pos;
|
|
3416
3295
|
});
|
|
3417
3296
|
wrapper.wrap(listItem, options);
|
|
3418
3297
|
};
|
|
@@ -3426,11 +3305,7 @@ var TextMixin = {
|
|
|
3426
3305
|
options = x;
|
|
3427
3306
|
x = null;
|
|
3428
3307
|
}
|
|
3429
|
-
|
|
3430
|
-
// clone options object
|
|
3431
3308
|
const result = Object.assign({}, options);
|
|
3432
|
-
|
|
3433
|
-
// extend options with previous values for continued text
|
|
3434
3309
|
if (this._textOptions) {
|
|
3435
3310
|
for (let key in this._textOptions) {
|
|
3436
3311
|
const val = this._textOptions[key];
|
|
@@ -3441,16 +3316,12 @@ var TextMixin = {
|
|
|
3441
3316
|
}
|
|
3442
3317
|
}
|
|
3443
3318
|
}
|
|
3444
|
-
|
|
3445
|
-
// Update the current position
|
|
3446
3319
|
if (x != null) {
|
|
3447
3320
|
this.x = x;
|
|
3448
3321
|
}
|
|
3449
3322
|
if (y != null) {
|
|
3450
3323
|
this.y = y;
|
|
3451
3324
|
}
|
|
3452
|
-
|
|
3453
|
-
// wrap to margins if no x or y position passed
|
|
3454
3325
|
if (result.lineBreak !== false) {
|
|
3455
3326
|
if (result.width == null) {
|
|
3456
3327
|
result.width = this.page.width - this.x - this.page.margins.right;
|
|
@@ -3462,17 +3333,18 @@ var TextMixin = {
|
|
|
3462
3333
|
}
|
|
3463
3334
|
if (result.columnGap == null) {
|
|
3464
3335
|
result.columnGap = 18;
|
|
3465
|
-
}
|
|
3466
|
-
|
|
3336
|
+
}
|
|
3337
|
+
result.rotation = Number(options.rotation ?? 0) % 360;
|
|
3338
|
+
if (result.rotation < 0) result.rotation += 360;
|
|
3467
3339
|
return result;
|
|
3468
3340
|
},
|
|
3469
3341
|
_line(text, options = {}, wrapper) {
|
|
3470
3342
|
this._fragment(text, this.x, this.y, options);
|
|
3471
3343
|
const lineGap = options.lineGap || this._lineGap || 0;
|
|
3472
3344
|
if (!wrapper) {
|
|
3473
|
-
|
|
3345
|
+
this.x += this.widthOfString(text, options);
|
|
3474
3346
|
} else {
|
|
3475
|
-
|
|
3347
|
+
this.y += this.currentLineHeight(true) + lineGap;
|
|
3476
3348
|
}
|
|
3477
3349
|
},
|
|
3478
3350
|
_fragment(text, x, y, options) {
|
|
@@ -3481,13 +3353,10 @@ var TextMixin = {
|
|
|
3481
3353
|
if (text.length === 0) {
|
|
3482
3354
|
return;
|
|
3483
3355
|
}
|
|
3484
|
-
|
|
3485
|
-
// handle options
|
|
3486
3356
|
const align = options.align || 'left';
|
|
3487
3357
|
let wordSpacing = options.wordSpacing || 0;
|
|
3488
3358
|
const characterSpacing = options.characterSpacing || 0;
|
|
3489
|
-
|
|
3490
|
-
// text alignments
|
|
3359
|
+
const horizontalScaling = options.horizontalScaling || 100;
|
|
3491
3360
|
if (options.width) {
|
|
3492
3361
|
switch (align) {
|
|
3493
3362
|
case 'right':
|
|
@@ -3498,7 +3367,6 @@ var TextMixin = {
|
|
|
3498
3367
|
x += options.lineWidth / 2 - options.textWidth / 2;
|
|
3499
3368
|
break;
|
|
3500
3369
|
case 'justify':
|
|
3501
|
-
// calculate the word spacing value
|
|
3502
3370
|
words = text.trim().split(/\s+/);
|
|
3503
3371
|
textWidth = this.widthOfString(text.replace(/\s+/g, ''), options);
|
|
3504
3372
|
var spaceWidth = this.widthOfString(' ') + characterSpacing;
|
|
@@ -3506,8 +3374,6 @@ var TextMixin = {
|
|
|
3506
3374
|
break;
|
|
3507
3375
|
}
|
|
3508
3376
|
}
|
|
3509
|
-
|
|
3510
|
-
// text baseline alignments based on http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
|
|
3511
3377
|
if (typeof options.baseline === 'number') {
|
|
3512
3378
|
dy = -options.baseline;
|
|
3513
3379
|
} else {
|
|
@@ -3540,11 +3406,7 @@ var TextMixin = {
|
|
|
3540
3406
|
}
|
|
3541
3407
|
dy = dy / 1000 * this._fontSize;
|
|
3542
3408
|
}
|
|
3543
|
-
|
|
3544
|
-
// calculate the actual rendered width of the string after word and character spacing
|
|
3545
3409
|
const renderedWidth = options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1);
|
|
3546
|
-
|
|
3547
|
-
// create link annotations if the link option is given
|
|
3548
3410
|
if (options.link != null) {
|
|
3549
3411
|
this.link(x, y, renderedWidth, this.currentLineHeight(), options.link);
|
|
3550
3412
|
}
|
|
@@ -3554,8 +3416,6 @@ var TextMixin = {
|
|
|
3554
3416
|
if (options.destination != null) {
|
|
3555
3417
|
this.addNamedDestination(options.destination, 'XYZ', x, y, null);
|
|
3556
3418
|
}
|
|
3557
|
-
|
|
3558
|
-
// create underline
|
|
3559
3419
|
if (options.underline) {
|
|
3560
3420
|
this.save();
|
|
3561
3421
|
if (!options.stroke) {
|
|
@@ -3569,8 +3429,6 @@ var TextMixin = {
|
|
|
3569
3429
|
this.stroke();
|
|
3570
3430
|
this.restore();
|
|
3571
3431
|
}
|
|
3572
|
-
|
|
3573
|
-
// create strikethrough line
|
|
3574
3432
|
if (options.strike) {
|
|
3575
3433
|
this.save();
|
|
3576
3434
|
if (!options.stroke) {
|
|
@@ -3585,8 +3443,6 @@ var TextMixin = {
|
|
|
3585
3443
|
this.restore();
|
|
3586
3444
|
}
|
|
3587
3445
|
this.save();
|
|
3588
|
-
|
|
3589
|
-
// oblique (angle in degrees or boolean)
|
|
3590
3446
|
if (options.oblique) {
|
|
3591
3447
|
let skew;
|
|
3592
3448
|
if (typeof options.oblique === 'number') {
|
|
@@ -3598,40 +3454,24 @@ var TextMixin = {
|
|
|
3598
3454
|
this.transform(1, 0, skew, 1, -skew * dy, 0);
|
|
3599
3455
|
this.transform(1, 0, 0, 1, -x, -y);
|
|
3600
3456
|
}
|
|
3601
|
-
|
|
3602
|
-
// flip coordinate system
|
|
3603
3457
|
this.transform(1, 0, 0, -1, 0, this.page.height);
|
|
3604
3458
|
y = this.page.height - y - dy;
|
|
3605
|
-
|
|
3606
|
-
// add current font to page if necessary
|
|
3607
3459
|
if (this.page.fonts[this._font.id] == null) {
|
|
3608
3460
|
this.page.fonts[this._font.id] = this._font.ref();
|
|
3609
3461
|
}
|
|
3610
|
-
|
|
3611
|
-
// begin the text object
|
|
3612
3462
|
this.addContent('BT');
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
this.addContent(`1 0 0 1 ${number$2(x)} ${number$2(y)} Tm`);
|
|
3616
|
-
|
|
3617
|
-
// font and font size
|
|
3618
|
-
this.addContent(`/${this._font.id} ${number$2(this._fontSize)} Tf`);
|
|
3619
|
-
|
|
3620
|
-
// rendering mode
|
|
3463
|
+
this.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
|
|
3464
|
+
this.addContent(`/${this._font.id} ${number(this._fontSize)} Tf`);
|
|
3621
3465
|
const mode = options.fill && options.stroke ? 2 : options.stroke ? 1 : 0;
|
|
3622
3466
|
if (mode) {
|
|
3623
3467
|
this.addContent(`${mode} Tr`);
|
|
3624
3468
|
}
|
|
3625
|
-
|
|
3626
|
-
// Character spacing
|
|
3627
3469
|
if (characterSpacing) {
|
|
3628
|
-
this.addContent(`${number
|
|
3470
|
+
this.addContent(`${number(characterSpacing)} Tc`);
|
|
3471
|
+
}
|
|
3472
|
+
if (horizontalScaling !== 100) {
|
|
3473
|
+
this.addContent(`${horizontalScaling} Tz`);
|
|
3629
3474
|
}
|
|
3630
|
-
|
|
3631
|
-
// Add the actual text
|
|
3632
|
-
// If we have a word spacing value, we need to encode each word separately
|
|
3633
|
-
// since the normal Tw operator only works on character code 32, which isn't
|
|
3634
|
-
// used for embedded fonts.
|
|
3635
3475
|
if (wordSpacing) {
|
|
3636
3476
|
words = text.trim().split(/\s+/);
|
|
3637
3477
|
wordSpacing += this.widthOfString(' ') + characterSpacing;
|
|
@@ -3642,9 +3482,6 @@ var TextMixin = {
|
|
|
3642
3482
|
const [encodedWord, positionsWord] = this._font.encode(word, options.features);
|
|
3643
3483
|
encoded = encoded.concat(encodedWord);
|
|
3644
3484
|
positions = positions.concat(positionsWord);
|
|
3645
|
-
|
|
3646
|
-
// add the word spacing to the end of the word
|
|
3647
|
-
// clone object because of cache
|
|
3648
3485
|
const space = {};
|
|
3649
3486
|
const object = positions[positions.length - 1];
|
|
3650
3487
|
for (let key in object) {
|
|
@@ -3661,60 +3498,42 @@ var TextMixin = {
|
|
|
3661
3498
|
const commands = [];
|
|
3662
3499
|
let last = 0;
|
|
3663
3500
|
let hadOffset = false;
|
|
3664
|
-
|
|
3665
|
-
// Adds a segment of text to the TJ command buffer
|
|
3666
3501
|
const addSegment = cur => {
|
|
3667
3502
|
if (last < cur) {
|
|
3668
3503
|
const hex = encoded.slice(last, cur).join('');
|
|
3669
3504
|
const advance = positions[cur - 1].xAdvance - positions[cur - 1].advanceWidth;
|
|
3670
|
-
commands.push(`<${hex}> ${number
|
|
3505
|
+
commands.push(`<${hex}> ${number(-advance)}`);
|
|
3671
3506
|
}
|
|
3672
|
-
|
|
3507
|
+
last = cur;
|
|
3673
3508
|
};
|
|
3674
|
-
|
|
3675
|
-
// Flushes the current TJ commands to the output stream
|
|
3676
3509
|
const flush = i => {
|
|
3677
3510
|
addSegment(i);
|
|
3678
3511
|
if (commands.length > 0) {
|
|
3679
3512
|
this.addContent(`[${commands.join(' ')}] TJ`);
|
|
3680
|
-
|
|
3513
|
+
commands.length = 0;
|
|
3681
3514
|
}
|
|
3682
3515
|
};
|
|
3683
3516
|
for (i = 0; i < positions.length; i++) {
|
|
3684
|
-
// If we have an x or y offset, we have to break out of the current TJ command
|
|
3685
|
-
// so we can move the text position.
|
|
3686
3517
|
const pos = positions[i];
|
|
3687
3518
|
if (pos.xOffset || pos.yOffset) {
|
|
3688
|
-
// Flush the current buffer
|
|
3689
3519
|
flush(i);
|
|
3690
|
-
|
|
3691
|
-
// Move the text position and flush just the current character
|
|
3692
|
-
this.addContent(`1 0 0 1 ${number$2(x + pos.xOffset * scale)} ${number$2(y + pos.yOffset * scale)} Tm`);
|
|
3520
|
+
this.addContent(`1 0 0 1 ${number(x + pos.xOffset * scale)} ${number(y + pos.yOffset * scale)} Tm`);
|
|
3693
3521
|
flush(i + 1);
|
|
3694
3522
|
hadOffset = true;
|
|
3695
3523
|
} else {
|
|
3696
|
-
// If the last character had an offset, reset the text position
|
|
3697
3524
|
if (hadOffset) {
|
|
3698
|
-
this.addContent(`1 0 0 1 ${number
|
|
3525
|
+
this.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
|
|
3699
3526
|
hadOffset = false;
|
|
3700
3527
|
}
|
|
3701
|
-
|
|
3702
|
-
// Group segments that don't have any advance adjustments
|
|
3703
3528
|
if (pos.xAdvance - pos.advanceWidth !== 0) {
|
|
3704
3529
|
addSegment(i + 1);
|
|
3705
3530
|
}
|
|
3706
3531
|
}
|
|
3707
3532
|
x += pos.xAdvance * scale;
|
|
3708
3533
|
}
|
|
3709
|
-
|
|
3710
|
-
// Flush any remaining commands
|
|
3711
3534
|
flush(i);
|
|
3712
|
-
|
|
3713
|
-
// end the text object
|
|
3714
3535
|
this.addContent('ET');
|
|
3715
|
-
|
|
3716
|
-
// restore flipped coordinate system
|
|
3717
|
-
return this.restore();
|
|
3536
|
+
this.restore();
|
|
3718
3537
|
}
|
|
3719
3538
|
};
|
|
3720
3539
|
|
|
@@ -3732,8 +3551,6 @@ class JPEG {
|
|
|
3732
3551
|
if (this.data.readUInt16BE(0) !== 0xffd8) {
|
|
3733
3552
|
throw 'SOI not found in JPEG';
|
|
3734
3553
|
}
|
|
3735
|
-
|
|
3736
|
-
// Parse the EXIF orientation
|
|
3737
3554
|
this.orientation = exif.fromBuffer(this.data).Orientation || 1;
|
|
3738
3555
|
let pos = 2;
|
|
3739
3556
|
while (pos < this.data.length) {
|
|
@@ -3770,16 +3587,10 @@ class JPEG {
|
|
|
3770
3587
|
ColorSpace: this.colorSpace,
|
|
3771
3588
|
Filter: 'DCTDecode'
|
|
3772
3589
|
});
|
|
3773
|
-
|
|
3774
|
-
// add extra decode params for CMYK images. By swapping the
|
|
3775
|
-
// min and max values from the default, we invert the colors. See
|
|
3776
|
-
// section 4.8.4 of the spec.
|
|
3777
3590
|
if (this.colorSpace === 'DeviceCMYK') {
|
|
3778
3591
|
this.obj.data['Decode'] = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0];
|
|
3779
3592
|
}
|
|
3780
3593
|
this.obj.end(this.data);
|
|
3781
|
-
|
|
3782
|
-
// free memory
|
|
3783
3594
|
return this.data = null;
|
|
3784
3595
|
}
|
|
3785
3596
|
}
|
|
@@ -3822,24 +3633,14 @@ class PNGImage {
|
|
|
3822
3633
|
if (this.image.palette.length === 0) {
|
|
3823
3634
|
this.obj.data['ColorSpace'] = this.image.colorSpace;
|
|
3824
3635
|
} else {
|
|
3825
|
-
// embed the color palette in the PDF as an object stream
|
|
3826
3636
|
const palette = this.document.ref();
|
|
3827
3637
|
palette.end(Buffer.from(this.image.palette));
|
|
3828
|
-
|
|
3829
|
-
// build the color space array for the image
|
|
3830
3638
|
this.obj.data['ColorSpace'] = ['Indexed', 'DeviceRGB', this.image.palette.length / 3 - 1, palette];
|
|
3831
3639
|
}
|
|
3832
|
-
|
|
3833
|
-
// For PNG color types 0, 2 and 3, the transparency data is stored in
|
|
3834
|
-
// a dedicated PNG chunk.
|
|
3835
3640
|
if (this.image.transparency.grayscale != null) {
|
|
3836
|
-
// Use Color Key Masking (spec section 4.8.5)
|
|
3837
|
-
// An array with N elements, where N is two times the number of color components.
|
|
3838
3641
|
const val = this.image.transparency.grayscale;
|
|
3839
3642
|
this.obj.data['Mask'] = [val, val];
|
|
3840
3643
|
} else if (this.image.transparency.rgb) {
|
|
3841
|
-
// Use Color Key Masking (spec section 4.8.5)
|
|
3842
|
-
// An array with N elements, where N is two times the number of color components.
|
|
3843
3644
|
const {
|
|
3844
3645
|
rgb
|
|
3845
3646
|
} = this.image.transparency;
|
|
@@ -3849,14 +3650,9 @@ class PNGImage {
|
|
|
3849
3650
|
}
|
|
3850
3651
|
this.obj.data['Mask'] = mask;
|
|
3851
3652
|
} else if (this.image.transparency.indexed) {
|
|
3852
|
-
// Create a transparency SMask for the image based on the data
|
|
3853
|
-
// in the PLTE and tRNS sections. See below for details on SMasks.
|
|
3854
3653
|
dataDecoded = true;
|
|
3855
3654
|
return this.loadIndexedAlphaChannel();
|
|
3856
3655
|
} else if (hasAlphaChannel) {
|
|
3857
|
-
// For PNG color types 4 and 6, the transparency data is stored as a alpha
|
|
3858
|
-
// channel mixed in with the main image data. Separate this data out into an
|
|
3859
|
-
// SMask object and store it separately in the PDF.
|
|
3860
3656
|
dataDecoded = true;
|
|
3861
3657
|
return this.splitAlphaChannel();
|
|
3862
3658
|
}
|
|
@@ -3880,11 +3676,7 @@ class PNGImage {
|
|
|
3880
3676
|
sMask.end(this.alphaChannel);
|
|
3881
3677
|
this.obj.data['SMask'] = sMask;
|
|
3882
3678
|
}
|
|
3883
|
-
|
|
3884
|
-
// add the actual image data
|
|
3885
3679
|
this.obj.end(this.imgData);
|
|
3886
|
-
|
|
3887
|
-
// free memory
|
|
3888
3680
|
this.image = null;
|
|
3889
3681
|
return this.imgData = null;
|
|
3890
3682
|
}
|
|
@@ -3897,7 +3689,6 @@ class PNGImage {
|
|
|
3897
3689
|
const alphaChannel = Buffer.alloc(pixelCount);
|
|
3898
3690
|
let i = p = a = 0;
|
|
3899
3691
|
const len = pixels.length;
|
|
3900
|
-
// For 16bit images copy only most significant byte (MSB) - PNG data is always stored in network byte order (MSB first)
|
|
3901
3692
|
const skipByteCount = this.image.bits === 16 ? 1 : 0;
|
|
3902
3693
|
while (i < len) {
|
|
3903
3694
|
for (let colorIndex = 0; colorIndex < colorCount; colorIndex++) {
|
|
@@ -3932,10 +3723,6 @@ class PNGImage {
|
|
|
3932
3723
|
}
|
|
3933
3724
|
}
|
|
3934
3725
|
|
|
3935
|
-
/*
|
|
3936
|
-
PDFImage - embeds images in PDF documents
|
|
3937
|
-
By Devon Govett
|
|
3938
|
-
*/
|
|
3939
3726
|
class PDFImage {
|
|
3940
3727
|
static open(src, label) {
|
|
3941
3728
|
let data;
|
|
@@ -3967,17 +3754,16 @@ class PDFImage {
|
|
|
3967
3754
|
var ImagesMixin = {
|
|
3968
3755
|
initImages() {
|
|
3969
3756
|
this._imageRegistry = {};
|
|
3970
|
-
|
|
3757
|
+
this._imageCount = 0;
|
|
3971
3758
|
},
|
|
3972
3759
|
image(src, x, y, options = {}) {
|
|
3973
|
-
let bh, bp, bw, image, ip, left, left1,
|
|
3760
|
+
let bh, bp, bw, image, ip, left, left1, originX, originY;
|
|
3974
3761
|
if (typeof x === 'object') {
|
|
3975
3762
|
options = x;
|
|
3976
3763
|
x = null;
|
|
3977
3764
|
}
|
|
3978
|
-
|
|
3979
|
-
// Ignore orientation based on document options or image options
|
|
3980
3765
|
const ignoreOrientation = options.ignoreOrientation || options.ignoreOrientation !== false && this.options.ignoreOrientation;
|
|
3766
|
+
const inDocumentFlow = typeof y !== 'number';
|
|
3981
3767
|
x = (left = x != null ? x : options.x) != null ? left : this.x;
|
|
3982
3768
|
y = (left1 = y != null ? y : options.y) != null ? left1 : this.y;
|
|
3983
3769
|
if (typeof src === 'string') {
|
|
@@ -4000,8 +3786,6 @@ var ImagesMixin = {
|
|
|
4000
3786
|
width,
|
|
4001
3787
|
height
|
|
4002
3788
|
} = image;
|
|
4003
|
-
|
|
4004
|
-
// If EXIF orientation calls for it, swap width and height
|
|
4005
3789
|
if (!ignoreOrientation && image.orientation > 4) {
|
|
4006
3790
|
[width, height] = [height, width];
|
|
4007
3791
|
}
|
|
@@ -4053,80 +3837,70 @@ var ImagesMixin = {
|
|
|
4053
3837
|
y = y + bh - h;
|
|
4054
3838
|
}
|
|
4055
3839
|
}
|
|
3840
|
+
let rotateAngle = 0;
|
|
3841
|
+
let xTransform = x;
|
|
3842
|
+
let yTransform = y;
|
|
3843
|
+
let hTransform = h;
|
|
3844
|
+
let wTransform = w;
|
|
4056
3845
|
if (!ignoreOrientation) {
|
|
4057
3846
|
switch (image.orientation) {
|
|
4058
|
-
// No orientation (need to flip image, though, because of the default transform matrix on the document)
|
|
4059
3847
|
default:
|
|
4060
3848
|
case 1:
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
rotateAngle = 0;
|
|
3849
|
+
hTransform = -h;
|
|
3850
|
+
yTransform += h;
|
|
4064
3851
|
break;
|
|
4065
|
-
// Flip Horizontal
|
|
4066
3852
|
case 2:
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
rotateAngle = 0;
|
|
3853
|
+
wTransform = -w;
|
|
3854
|
+
hTransform = -h;
|
|
3855
|
+
xTransform += w;
|
|
3856
|
+
yTransform += h;
|
|
4072
3857
|
break;
|
|
4073
|
-
// Rotate 180 degrees
|
|
4074
3858
|
case 3:
|
|
4075
3859
|
originX = x;
|
|
4076
3860
|
originY = y;
|
|
4077
|
-
|
|
4078
|
-
|
|
3861
|
+
hTransform = -h;
|
|
3862
|
+
xTransform -= w;
|
|
4079
3863
|
rotateAngle = 180;
|
|
4080
3864
|
break;
|
|
4081
|
-
// Flip vertical
|
|
4082
3865
|
case 4:
|
|
4083
|
-
// Do nothing, image will be flipped
|
|
4084
|
-
|
|
4085
3866
|
break;
|
|
4086
|
-
// Flip horizontally and rotate 270 degrees CW
|
|
4087
3867
|
case 5:
|
|
4088
3868
|
originX = x;
|
|
4089
3869
|
originY = y;
|
|
4090
|
-
|
|
4091
|
-
|
|
3870
|
+
wTransform = h;
|
|
3871
|
+
hTransform = w;
|
|
3872
|
+
yTransform -= hTransform;
|
|
4092
3873
|
rotateAngle = 90;
|
|
4093
3874
|
break;
|
|
4094
|
-
// Rotate 90 degrees CW
|
|
4095
3875
|
case 6:
|
|
4096
3876
|
originX = x;
|
|
4097
3877
|
originY = y;
|
|
4098
|
-
|
|
4099
|
-
|
|
3878
|
+
wTransform = h;
|
|
3879
|
+
hTransform = -w;
|
|
4100
3880
|
rotateAngle = 90;
|
|
4101
3881
|
break;
|
|
4102
|
-
// Flip horizontally and rotate 90 degrees CW
|
|
4103
3882
|
case 7:
|
|
4104
3883
|
originX = x;
|
|
4105
3884
|
originY = y;
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
x -= w;
|
|
3885
|
+
hTransform = -w;
|
|
3886
|
+
wTransform = -h;
|
|
3887
|
+
xTransform += h;
|
|
4110
3888
|
rotateAngle = 90;
|
|
4111
3889
|
break;
|
|
4112
|
-
// Rotate 270 degrees CW
|
|
4113
3890
|
case 8:
|
|
4114
3891
|
originX = x;
|
|
4115
3892
|
originY = y;
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
3893
|
+
wTransform = h;
|
|
3894
|
+
hTransform = -w;
|
|
3895
|
+
xTransform -= h;
|
|
3896
|
+
yTransform += w;
|
|
4120
3897
|
rotateAngle = -90;
|
|
4121
3898
|
break;
|
|
4122
3899
|
}
|
|
4123
3900
|
} else {
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
rotateAngle = 0;
|
|
3901
|
+
hTransform = -h;
|
|
3902
|
+
yTransform += h;
|
|
4127
3903
|
}
|
|
4128
|
-
|
|
4129
|
-
// create link annotations if the link option is given
|
|
4130
3904
|
if (options.link != null) {
|
|
4131
3905
|
this.link(x, y, w, h, options.link);
|
|
4132
3906
|
}
|
|
@@ -4136,9 +3910,7 @@ var ImagesMixin = {
|
|
|
4136
3910
|
if (options.destination != null) {
|
|
4137
3911
|
this.addNamedDestination(options.destination, 'XYZ', x, y, null);
|
|
4138
3912
|
}
|
|
4139
|
-
|
|
4140
|
-
// Set the current y position to below the image if it is in the document flow
|
|
4141
|
-
if (this.y === y) {
|
|
3913
|
+
if (inDocumentFlow) {
|
|
4142
3914
|
this.y += h;
|
|
4143
3915
|
}
|
|
4144
3916
|
this.save();
|
|
@@ -4147,7 +3919,7 @@ var ImagesMixin = {
|
|
|
4147
3919
|
origin: [originX, originY]
|
|
4148
3920
|
});
|
|
4149
3921
|
}
|
|
4150
|
-
this.transform(
|
|
3922
|
+
this.transform(wTransform, 0, 0, hTransform, xTransform, yTransform);
|
|
4151
3923
|
this.addContent(`/${image.label} Do`);
|
|
4152
3924
|
this.restore();
|
|
4153
3925
|
return this;
|
|
@@ -4173,19 +3945,17 @@ var AnnotationsMixin = {
|
|
|
4173
3945
|
options.Rect = this._convertRect(x, y, w, h);
|
|
4174
3946
|
options.Border = [0, 0, 0];
|
|
4175
3947
|
if (options.Subtype === 'Link' && typeof options.F === 'undefined') {
|
|
4176
|
-
options.F = 1 << 2;
|
|
3948
|
+
options.F = 1 << 2;
|
|
4177
3949
|
}
|
|
4178
3950
|
if (options.Subtype !== 'Link') {
|
|
4179
3951
|
if (options.C == null) {
|
|
4180
3952
|
options.C = this._normalizeColor(options.color || [0, 0, 0]);
|
|
4181
3953
|
}
|
|
4182
|
-
}
|
|
3954
|
+
}
|
|
4183
3955
|
delete options.color;
|
|
4184
3956
|
if (typeof options.Dest === 'string') {
|
|
4185
3957
|
options.Dest = new String(options.Dest);
|
|
4186
3958
|
}
|
|
4187
|
-
|
|
4188
|
-
// Capitalize keys
|
|
4189
3959
|
for (let key in options) {
|
|
4190
3960
|
const val = options[key];
|
|
4191
3961
|
options[key[0].toUpperCase() + key.slice(1)] = val;
|
|
@@ -4198,7 +3968,9 @@ var AnnotationsMixin = {
|
|
|
4198
3968
|
note(x, y, w, h, contents, options = {}) {
|
|
4199
3969
|
options.Subtype = 'Text';
|
|
4200
3970
|
options.Contents = new String(contents);
|
|
4201
|
-
options.Name
|
|
3971
|
+
if (options.Name == null) {
|
|
3972
|
+
options.Name = 'Comment';
|
|
3973
|
+
}
|
|
4202
3974
|
if (options.color == null) {
|
|
4203
3975
|
options.color = [243, 223, 92];
|
|
4204
3976
|
}
|
|
@@ -4216,7 +3988,6 @@ var AnnotationsMixin = {
|
|
|
4216
3988
|
link(x, y, w, h, url, options = {}) {
|
|
4217
3989
|
options.Subtype = 'Link';
|
|
4218
3990
|
if (typeof url === 'number') {
|
|
4219
|
-
// Link to a page in the document (the page must already exist)
|
|
4220
3991
|
const pages = this._root.data.Pages.data;
|
|
4221
3992
|
if (url >= 0 && url < pages.Kids.length) {
|
|
4222
3993
|
options.A = this.ref({
|
|
@@ -4228,7 +3999,6 @@ var AnnotationsMixin = {
|
|
|
4228
3999
|
throw new Error(`The document has no page ${url}`);
|
|
4229
4000
|
}
|
|
4230
4001
|
} else {
|
|
4231
|
-
// Link to an external url
|
|
4232
4002
|
options.A = this.ref({
|
|
4233
4003
|
S: 'URI',
|
|
4234
4004
|
URI: new String(url)
|
|
@@ -4281,14 +4051,11 @@ var AnnotationsMixin = {
|
|
|
4281
4051
|
return this.annotate(x, y, w, h, options);
|
|
4282
4052
|
},
|
|
4283
4053
|
fileAnnotation(x, y, w, h, file = {}, options = {}) {
|
|
4284
|
-
// create hidden file
|
|
4285
4054
|
const filespec = this.file(file.src, Object.assign({
|
|
4286
4055
|
hidden: true
|
|
4287
4056
|
}, file));
|
|
4288
4057
|
options.Subtype = 'FileAttachment';
|
|
4289
4058
|
options.FS = filespec;
|
|
4290
|
-
|
|
4291
|
-
// add description from filespec unless description (Contents) has already been set
|
|
4292
4059
|
if (options.Contents) {
|
|
4293
4060
|
options.Contents = new String(options.Contents);
|
|
4294
4061
|
} else if (filespec.data.Desc) {
|
|
@@ -4297,14 +4064,9 @@ var AnnotationsMixin = {
|
|
|
4297
4064
|
return this.annotate(x, y, w, h, options);
|
|
4298
4065
|
},
|
|
4299
4066
|
_convertRect(x1, y1, w, h) {
|
|
4300
|
-
// flip y1 and y2
|
|
4301
4067
|
let y2 = y1;
|
|
4302
4068
|
y1 += h;
|
|
4303
|
-
|
|
4304
|
-
// make x2
|
|
4305
4069
|
let x2 = x1 + w;
|
|
4306
|
-
|
|
4307
|
-
// apply current transformation matrix to points
|
|
4308
4070
|
const [m0, m1, m2, m3, m4, m5] = this._ctm;
|
|
4309
4071
|
x1 = m0 * x1 + m2 * y1 + m4;
|
|
4310
4072
|
y1 = m1 * x1 + m3 * y1 + m5;
|
|
@@ -4366,7 +4128,7 @@ class PDFOutline {
|
|
|
4366
4128
|
|
|
4367
4129
|
var OutlineMixin = {
|
|
4368
4130
|
initOutline() {
|
|
4369
|
-
|
|
4131
|
+
this.outline = new PDFOutline(this, null, null, null);
|
|
4370
4132
|
},
|
|
4371
4133
|
endOutline() {
|
|
4372
4134
|
this.outline.endOutline();
|
|
@@ -4377,11 +4139,6 @@ var OutlineMixin = {
|
|
|
4377
4139
|
}
|
|
4378
4140
|
};
|
|
4379
4141
|
|
|
4380
|
-
/*
|
|
4381
|
-
PDFStructureContent - a reference to a marked structure content
|
|
4382
|
-
By Ben Schmidt
|
|
4383
|
-
*/
|
|
4384
|
-
|
|
4385
4142
|
class PDFStructureContent {
|
|
4386
4143
|
constructor(pageRef, mcid) {
|
|
4387
4144
|
this.refs = [{
|
|
@@ -4394,10 +4151,6 @@ class PDFStructureContent {
|
|
|
4394
4151
|
}
|
|
4395
4152
|
}
|
|
4396
4153
|
|
|
4397
|
-
/*
|
|
4398
|
-
PDFStructureElement - represents an element in the PDF logical structure tree
|
|
4399
|
-
By Ben Schmidt
|
|
4400
|
-
*/
|
|
4401
4154
|
class PDFStructureElement {
|
|
4402
4155
|
constructor(document, type, options = {}, children = null) {
|
|
4403
4156
|
this.document = document;
|
|
@@ -4405,7 +4158,6 @@ class PDFStructureElement {
|
|
|
4405
4158
|
this._ended = false;
|
|
4406
4159
|
this._flushed = false;
|
|
4407
4160
|
this.dictionary = document.ref({
|
|
4408
|
-
// Type: "StructElem",
|
|
4409
4161
|
S: type
|
|
4410
4162
|
});
|
|
4411
4163
|
const data = this.dictionary.data;
|
|
@@ -4454,7 +4206,6 @@ class PDFStructureElement {
|
|
|
4454
4206
|
this._addContentToParentTree(child);
|
|
4455
4207
|
}
|
|
4456
4208
|
if (typeof child === 'function' && this._attached) {
|
|
4457
|
-
// _contentForClosure() adds the content to the parent tree
|
|
4458
4209
|
child = this._contentForClosure(child);
|
|
4459
4210
|
}
|
|
4460
4211
|
this._children.push(child);
|
|
@@ -4530,10 +4281,6 @@ class PDFStructureElement {
|
|
|
4530
4281
|
this.dictionary.data.K = [];
|
|
4531
4282
|
this._children.forEach(child => this._flushChild(child));
|
|
4532
4283
|
this.dictionary.end();
|
|
4533
|
-
|
|
4534
|
-
// free memory used by children; the dictionary itself may still be
|
|
4535
|
-
// referenced by a parent structure element or root, but we can
|
|
4536
|
-
// at least trim the tree here
|
|
4537
4284
|
this._children = [];
|
|
4538
4285
|
this.dictionary.data.K = null;
|
|
4539
4286
|
this._flushed = true;
|
|
@@ -4554,7 +4301,7 @@ class PDFStructureElement {
|
|
|
4554
4301
|
this.dictionary.data.K.push(mcid);
|
|
4555
4302
|
} else {
|
|
4556
4303
|
this.dictionary.data.K.push({
|
|
4557
|
-
Type:
|
|
4304
|
+
Type: 'MCR',
|
|
4558
4305
|
Pg: pageRef,
|
|
4559
4306
|
MCID: mcid
|
|
4560
4307
|
});
|
|
@@ -4564,25 +4311,18 @@ class PDFStructureElement {
|
|
|
4564
4311
|
}
|
|
4565
4312
|
}
|
|
4566
4313
|
|
|
4567
|
-
/*
|
|
4568
|
-
PDFNumberTree - represents a number tree object
|
|
4569
|
-
*/
|
|
4570
4314
|
class PDFNumberTree extends PDFTree {
|
|
4571
4315
|
_compareKeys(a, b) {
|
|
4572
4316
|
return parseInt(a) - parseInt(b);
|
|
4573
4317
|
}
|
|
4574
4318
|
_keysName() {
|
|
4575
|
-
return
|
|
4319
|
+
return 'Nums';
|
|
4576
4320
|
}
|
|
4577
4321
|
_dataForKey(k) {
|
|
4578
4322
|
return parseInt(k);
|
|
4579
4323
|
}
|
|
4580
4324
|
}
|
|
4581
4325
|
|
|
4582
|
-
/*
|
|
4583
|
-
Markings mixin - support marked content sequences in content streams
|
|
4584
|
-
By Ben Schmidt
|
|
4585
|
-
*/
|
|
4586
4326
|
var MarkingsMixin = {
|
|
4587
4327
|
initMarkings(options) {
|
|
4588
4328
|
this.structChildren = [];
|
|
@@ -4701,6 +4441,9 @@ var MarkingsMixin = {
|
|
|
4701
4441
|
}
|
|
4702
4442
|
return this._root.data.MarkInfo;
|
|
4703
4443
|
},
|
|
4444
|
+
hasMarkInfoDictionary() {
|
|
4445
|
+
return !!this._root.data.MarkInfo;
|
|
4446
|
+
},
|
|
4704
4447
|
getStructTreeRoot() {
|
|
4705
4448
|
if (!this._root.data.StructTreeRoot) {
|
|
4706
4449
|
this._root.data.StructTreeRoot = this.ref({
|
|
@@ -4715,7 +4458,6 @@ var MarkingsMixin = {
|
|
|
4715
4458
|
return this.getStructTreeRoot().data.ParentTree;
|
|
4716
4459
|
},
|
|
4717
4460
|
createStructParentTreeNextKey() {
|
|
4718
|
-
// initialise the MarkInfo dictionary
|
|
4719
4461
|
this.getMarkInfoDictionary();
|
|
4720
4462
|
const structTreeRoot = this.getStructTreeRoot();
|
|
4721
4463
|
const key = structTreeRoot.data.ParentTreeNextKey++;
|
|
@@ -4779,10 +4521,6 @@ const FORMAT_DEFAULT = {
|
|
|
4779
4521
|
}
|
|
4780
4522
|
};
|
|
4781
4523
|
var AcroFormMixin = {
|
|
4782
|
-
/**
|
|
4783
|
-
* Must call if adding AcroForms to a document. Must also call font() before
|
|
4784
|
-
* this method to set the default font.
|
|
4785
|
-
*/
|
|
4786
4524
|
initForm() {
|
|
4787
4525
|
if (!this._font) {
|
|
4788
4526
|
throw new Error('Must set a font before calling initForm method');
|
|
@@ -4805,9 +4543,6 @@ var AcroFormMixin = {
|
|
|
4805
4543
|
this._root.data.AcroForm = AcroForm;
|
|
4806
4544
|
return this;
|
|
4807
4545
|
},
|
|
4808
|
-
/**
|
|
4809
|
-
* Called automatically by document.js
|
|
4810
|
-
*/
|
|
4811
4546
|
endAcroForm() {
|
|
4812
4547
|
if (this._root.data.AcroForm) {
|
|
4813
4548
|
if (!Object.keys(this._acroform.fonts).length && !this._acroform.defaultFont) {
|
|
@@ -4833,38 +4568,18 @@ var AcroFormMixin = {
|
|
|
4833
4568
|
}
|
|
4834
4569
|
return this;
|
|
4835
4570
|
},
|
|
4836
|
-
/**
|
|
4837
|
-
* Creates and adds a form field to the document. Form fields are intermediate
|
|
4838
|
-
* nodes in a PDF form that are used to specify form name heirarchy and form
|
|
4839
|
-
* value defaults.
|
|
4840
|
-
* @param {string} name - field name (T attribute in field dictionary)
|
|
4841
|
-
* @param {object} options - other attributes to include in field dictionary
|
|
4842
|
-
*/
|
|
4843
4571
|
formField(name, options = {}) {
|
|
4844
4572
|
let fieldDict = this._fieldDict(name, null, options);
|
|
4845
4573
|
let fieldRef = this.ref(fieldDict);
|
|
4846
4574
|
this._addToParent(fieldRef);
|
|
4847
4575
|
return fieldRef;
|
|
4848
4576
|
},
|
|
4849
|
-
/**
|
|
4850
|
-
* Creates and adds a Form Annotation to the document. Form annotations are
|
|
4851
|
-
* called Widget annotations internally within a PDF file.
|
|
4852
|
-
* @param {string} name - form field name (T attribute of widget annotation
|
|
4853
|
-
* dictionary)
|
|
4854
|
-
* @param {number} x
|
|
4855
|
-
* @param {number} y
|
|
4856
|
-
* @param {number} w
|
|
4857
|
-
* @param {number} h
|
|
4858
|
-
* @param {object} options
|
|
4859
|
-
*/
|
|
4860
4577
|
formAnnotation(name, type, x, y, w, h, options = {}) {
|
|
4861
4578
|
let fieldDict = this._fieldDict(name, type, options);
|
|
4862
4579
|
fieldDict.Subtype = 'Widget';
|
|
4863
4580
|
if (fieldDict.F === undefined) {
|
|
4864
|
-
fieldDict.F = 4;
|
|
4581
|
+
fieldDict.F = 4;
|
|
4865
4582
|
}
|
|
4866
|
-
|
|
4867
|
-
// Add Field annot to page, and get it's ref
|
|
4868
4583
|
this.annotate(x, y, w, h, fieldDict);
|
|
4869
4584
|
let annotRef = this.page.annotations[this.page.annotations.length - 1];
|
|
4870
4585
|
return this._addToParent(annotRef);
|
|
@@ -5025,23 +4740,18 @@ var AcroFormMixin = {
|
|
|
5025
4740
|
delete options.align;
|
|
5026
4741
|
}
|
|
5027
4742
|
if (result !== 0) {
|
|
5028
|
-
options.Q = result;
|
|
4743
|
+
options.Q = result;
|
|
5029
4744
|
}
|
|
5030
4745
|
return options;
|
|
5031
4746
|
},
|
|
5032
4747
|
_resolveFont(options) {
|
|
5033
|
-
// add current font to document-level AcroForm dict if necessary
|
|
5034
4748
|
if (this._acroform.fonts[this._font.id] == null) {
|
|
5035
4749
|
this._acroform.fonts[this._font.id] = this._font.ref();
|
|
5036
4750
|
}
|
|
5037
|
-
|
|
5038
|
-
// add current font to field's resource dict (RD) if not the default acroform font
|
|
5039
4751
|
if (this._acroform.defaultFont !== this._font.name) {
|
|
5040
4752
|
options.DR = {
|
|
5041
4753
|
Font: {}
|
|
5042
4754
|
};
|
|
5043
|
-
|
|
5044
|
-
// Get the fontSize option. If not set use auto sizing
|
|
5045
4755
|
const fontSize = options.fontSize || 0;
|
|
5046
4756
|
options.DR.Font[this._font.id] = this._font.ref();
|
|
5047
4757
|
options.DA = new String(`/${this._font.id} ${fontSize} Tf 0 g`);
|
|
@@ -5093,19 +4803,6 @@ var AcroFormMixin = {
|
|
|
5093
4803
|
};
|
|
5094
4804
|
|
|
5095
4805
|
var AttachmentsMixin = {
|
|
5096
|
-
/**
|
|
5097
|
-
* Embed contents of `src` in PDF
|
|
5098
|
-
* @param {Buffer | ArrayBuffer | string} src input Buffer, ArrayBuffer, base64 encoded string or path to file
|
|
5099
|
-
* @param {object} options
|
|
5100
|
-
* * options.name: filename to be shown in PDF, will use `src` if none set
|
|
5101
|
-
* * options.type: filetype to be shown in PDF
|
|
5102
|
-
* * options.description: description to be shown in PDF
|
|
5103
|
-
* * options.hidden: if true, do not add attachment to EmbeddedFiles dictionary. Useful for file attachment annotations
|
|
5104
|
-
* * options.creationDate: override creation date
|
|
5105
|
-
* * options.modifiedDate: override modified date
|
|
5106
|
-
* * options.relationship: Relationship between the PDF document and its attached file. Can be 'Alternative', 'Data', 'Source', 'Supplement' or 'Unspecified'.
|
|
5107
|
-
* @returns filespec reference
|
|
5108
|
-
*/
|
|
5109
4806
|
file(src, options = {}) {
|
|
5110
4807
|
options.name = options.name || src;
|
|
5111
4808
|
options.relationship = options.relationship || 'Unspecified';
|
|
@@ -5133,8 +4830,6 @@ var AttachmentsMixin = {
|
|
|
5133
4830
|
if (!data) {
|
|
5134
4831
|
throw new Error(`Could not read contents of file at filepath ${src}`);
|
|
5135
4832
|
}
|
|
5136
|
-
|
|
5137
|
-
// update CreationDate and ModDate
|
|
5138
4833
|
const {
|
|
5139
4834
|
birthtime,
|
|
5140
4835
|
ctime
|
|
@@ -5143,26 +4838,18 @@ var AttachmentsMixin = {
|
|
|
5143
4838
|
refBody.Params.ModDate = ctime;
|
|
5144
4839
|
}
|
|
5145
4840
|
}
|
|
5146
|
-
|
|
5147
|
-
// override creation date and modified date
|
|
5148
4841
|
if (options.creationDate instanceof Date) {
|
|
5149
4842
|
refBody.Params.CreationDate = options.creationDate;
|
|
5150
4843
|
}
|
|
5151
4844
|
if (options.modifiedDate instanceof Date) {
|
|
5152
4845
|
refBody.Params.ModDate = options.modifiedDate;
|
|
5153
4846
|
}
|
|
5154
|
-
// add optional subtype
|
|
5155
4847
|
if (options.type) {
|
|
5156
4848
|
refBody.Subtype = options.type.replace('/', '#2F');
|
|
5157
4849
|
}
|
|
5158
|
-
|
|
5159
|
-
// add checksum and size information
|
|
5160
4850
|
const checksum = CryptoJS.MD5(CryptoJS.lib.WordArray.create(new Uint8Array(data)));
|
|
5161
4851
|
refBody.Params.CheckSum = new String(checksum);
|
|
5162
4852
|
refBody.Params.Size = data.byteLength;
|
|
5163
|
-
|
|
5164
|
-
// save some space when embedding the same file again
|
|
5165
|
-
// if a file with the same name and metadata exists, reuse its reference
|
|
5166
4853
|
let ref;
|
|
5167
4854
|
if (!this._fileRegistry) this._fileRegistry = {};
|
|
5168
4855
|
let file = this._fileRegistry[options.name];
|
|
@@ -5176,7 +4863,6 @@ var AttachmentsMixin = {
|
|
|
5176
4863
|
ref
|
|
5177
4864
|
};
|
|
5178
4865
|
}
|
|
5179
|
-
// add filespec for embedded file
|
|
5180
4866
|
const fileSpecBody = {
|
|
5181
4867
|
Type: 'Filespec',
|
|
5182
4868
|
AFRelationship: options.relationship,
|
|
@@ -5194,8 +4880,6 @@ var AttachmentsMixin = {
|
|
|
5194
4880
|
if (!options.hidden) {
|
|
5195
4881
|
this.addNamedEmbeddedFile(options.name, filespec);
|
|
5196
4882
|
}
|
|
5197
|
-
|
|
5198
|
-
// Add file to the catalogue to be PDF/A3 compliant
|
|
5199
4883
|
if (this._root.data.AF) {
|
|
5200
4884
|
this._root.data.AF.push(filespec);
|
|
5201
4885
|
} else {
|
|
@@ -5204,8 +4888,6 @@ var AttachmentsMixin = {
|
|
|
5204
4888
|
return filespec;
|
|
5205
4889
|
}
|
|
5206
4890
|
};
|
|
5207
|
-
|
|
5208
|
-
/** check two embedded file metadata objects for equality */
|
|
5209
4891
|
function isEqual(a, b) {
|
|
5210
4892
|
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());
|
|
5211
4893
|
}
|
|
@@ -5216,7 +4898,6 @@ var PDFA = {
|
|
|
5216
4898
|
this.subset_conformance = pSubset.charAt(pSubset.length - 1).toUpperCase();
|
|
5217
4899
|
this.subset = parseInt(pSubset.charAt(pSubset.length - 2));
|
|
5218
4900
|
} else {
|
|
5219
|
-
// Default to Basic conformance when user doesn't specify
|
|
5220
4901
|
this.subset_conformance = 'B';
|
|
5221
4902
|
this.subset = parseInt(pSubset.charAt(pSubset.length - 1));
|
|
5222
4903
|
}
|
|
@@ -5301,6 +4982,642 @@ var SubsetMixin = {
|
|
|
5301
4982
|
}
|
|
5302
4983
|
};
|
|
5303
4984
|
|
|
4985
|
+
const ROW_FIELDS = ['height', 'minHeight', 'maxHeight'];
|
|
4986
|
+
const COLUMN_FIELDS = ['width', 'minWidth', 'maxWidth'];
|
|
4987
|
+
function memoize(fn, maxSize) {
|
|
4988
|
+
const cache = new Map();
|
|
4989
|
+
return function (...args) {
|
|
4990
|
+
const key = args[0];
|
|
4991
|
+
if (!cache.has(key)) {
|
|
4992
|
+
cache.set(key, fn(...args));
|
|
4993
|
+
if (cache.size > maxSize) cache.delete(cache.keys().next());
|
|
4994
|
+
}
|
|
4995
|
+
return cache.get(key);
|
|
4996
|
+
};
|
|
4997
|
+
}
|
|
4998
|
+
function isObject(item) {
|
|
4999
|
+
return item && typeof item === 'object' && !Array.isArray(item);
|
|
5000
|
+
}
|
|
5001
|
+
function deepMerge(target, ...sources) {
|
|
5002
|
+
if (!isObject(target)) return target;
|
|
5003
|
+
target = deepClone(target);
|
|
5004
|
+
for (const source of sources) {
|
|
5005
|
+
if (isObject(source)) {
|
|
5006
|
+
for (const key in source) {
|
|
5007
|
+
if (isObject(source[key])) {
|
|
5008
|
+
if (!(key in target)) target[key] = {};
|
|
5009
|
+
target[key] = deepMerge(target[key], source[key]);
|
|
5010
|
+
} else if (source[key] !== undefined) {
|
|
5011
|
+
target[key] = deepClone(source[key]);
|
|
5012
|
+
}
|
|
5013
|
+
}
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
return target;
|
|
5017
|
+
}
|
|
5018
|
+
function deepClone(obj) {
|
|
5019
|
+
let result = obj;
|
|
5020
|
+
if (typeof obj == 'object') {
|
|
5021
|
+
result = Array.isArray(obj) ? [] : {};
|
|
5022
|
+
for (const key in obj) result[key] = deepClone(obj[key]);
|
|
5023
|
+
}
|
|
5024
|
+
return result;
|
|
5025
|
+
}
|
|
5026
|
+
|
|
5027
|
+
function normalizedDefaultStyle(defaultStyleInternal) {
|
|
5028
|
+
let defaultStyle = defaultStyleInternal;
|
|
5029
|
+
if (typeof defaultStyle !== 'object') defaultStyle = {
|
|
5030
|
+
text: defaultStyle
|
|
5031
|
+
};
|
|
5032
|
+
const defaultRowStyle = Object.fromEntries(Object.entries(defaultStyle).filter(([k]) => ROW_FIELDS.includes(k)));
|
|
5033
|
+
const defaultColStyle = Object.fromEntries(Object.entries(defaultStyle).filter(([k]) => COLUMN_FIELDS.includes(k)));
|
|
5034
|
+
defaultStyle.padding = normalizeSides(defaultStyle.padding);
|
|
5035
|
+
defaultStyle.border = normalizeSides(defaultStyle.border);
|
|
5036
|
+
defaultStyle.borderColor = normalizeSides(defaultStyle.borderColor);
|
|
5037
|
+
defaultStyle.align = normalizeAlignment(defaultStyle.align);
|
|
5038
|
+
return {
|
|
5039
|
+
defaultStyle,
|
|
5040
|
+
defaultRowStyle,
|
|
5041
|
+
defaultColStyle
|
|
5042
|
+
};
|
|
5043
|
+
}
|
|
5044
|
+
function normalizedRowStyle(defaultRowStyle, rowStyleInternal, i) {
|
|
5045
|
+
let rowStyle = rowStyleInternal(i);
|
|
5046
|
+
if (rowStyle == null || typeof rowStyle !== 'object') {
|
|
5047
|
+
rowStyle = {
|
|
5048
|
+
height: rowStyle
|
|
5049
|
+
};
|
|
5050
|
+
}
|
|
5051
|
+
rowStyle.padding = normalizeSides(rowStyle.padding);
|
|
5052
|
+
rowStyle.border = normalizeSides(rowStyle.border);
|
|
5053
|
+
rowStyle.borderColor = normalizeSides(rowStyle.borderColor);
|
|
5054
|
+
rowStyle.align = normalizeAlignment(rowStyle.align);
|
|
5055
|
+
rowStyle = deepMerge(defaultRowStyle, rowStyle);
|
|
5056
|
+
const document = this.document;
|
|
5057
|
+
const page = document.page;
|
|
5058
|
+
const contentHeight = page.contentHeight;
|
|
5059
|
+
if (rowStyle.height == null || rowStyle.height === 'auto') {
|
|
5060
|
+
rowStyle.height = 'auto';
|
|
5061
|
+
} else {
|
|
5062
|
+
rowStyle.height = document.sizeToPoint(rowStyle.height, 0, page, contentHeight);
|
|
5063
|
+
}
|
|
5064
|
+
rowStyle.minHeight = document.sizeToPoint(rowStyle.minHeight, 0, page, contentHeight);
|
|
5065
|
+
rowStyle.maxHeight = document.sizeToPoint(rowStyle.maxHeight, 0, page, contentHeight);
|
|
5066
|
+
return rowStyle;
|
|
5067
|
+
}
|
|
5068
|
+
function normalizedColumnStyle(defaultColStyle, colStyleInternal, i) {
|
|
5069
|
+
let colStyle = colStyleInternal(i);
|
|
5070
|
+
if (colStyle == null || typeof colStyle !== 'object') {
|
|
5071
|
+
colStyle = {
|
|
5072
|
+
width: colStyle
|
|
5073
|
+
};
|
|
5074
|
+
}
|
|
5075
|
+
colStyle.padding = normalizeSides(colStyle.padding);
|
|
5076
|
+
colStyle.border = normalizeSides(colStyle.border);
|
|
5077
|
+
colStyle.borderColor = normalizeSides(colStyle.borderColor);
|
|
5078
|
+
colStyle.align = normalizeAlignment(colStyle.align);
|
|
5079
|
+
colStyle = deepMerge(defaultColStyle, colStyle);
|
|
5080
|
+
if (colStyle.width == null || colStyle.width === '*') {
|
|
5081
|
+
colStyle.width = '*';
|
|
5082
|
+
} else {
|
|
5083
|
+
colStyle.width = this.document.sizeToPoint(colStyle.width, 0, this.document.page, this._maxWidth);
|
|
5084
|
+
}
|
|
5085
|
+
colStyle.minWidth = this.document.sizeToPoint(colStyle.minWidth, 0, this.document.page, this._maxWidth);
|
|
5086
|
+
colStyle.maxWidth = this.document.sizeToPoint(colStyle.maxWidth, 0, this.document.page, this._maxWidth);
|
|
5087
|
+
return colStyle;
|
|
5088
|
+
}
|
|
5089
|
+
function normalizeAlignment(align) {
|
|
5090
|
+
return align == null || typeof align === 'string' ? {
|
|
5091
|
+
x: align,
|
|
5092
|
+
y: align
|
|
5093
|
+
} : align;
|
|
5094
|
+
}
|
|
5095
|
+
|
|
5096
|
+
function normalizeTable() {
|
|
5097
|
+
const doc = this.document;
|
|
5098
|
+
const opts = this.opts;
|
|
5099
|
+
let index = doc._tableIndex++;
|
|
5100
|
+
this._id = new String(opts.id ?? `table-${index}`);
|
|
5101
|
+
this._position = {
|
|
5102
|
+
x: doc.sizeToPoint(opts.position?.x, doc.x),
|
|
5103
|
+
y: doc.sizeToPoint(opts.position?.y, doc.y)
|
|
5104
|
+
};
|
|
5105
|
+
this._maxWidth = doc.sizeToPoint(opts.maxWidth, doc.page.width - doc.page.margins.right - this._position.x);
|
|
5106
|
+
const {
|
|
5107
|
+
defaultStyle,
|
|
5108
|
+
defaultColStyle,
|
|
5109
|
+
defaultRowStyle
|
|
5110
|
+
} = normalizedDefaultStyle(opts.defaultStyle);
|
|
5111
|
+
this._defaultStyle = defaultStyle;
|
|
5112
|
+
let colStyle;
|
|
5113
|
+
if (opts.columnStyles) {
|
|
5114
|
+
if (Array.isArray(opts.columnStyles)) {
|
|
5115
|
+
colStyle = i => opts.columnStyles[i];
|
|
5116
|
+
} else if (typeof opts.columnStyles === 'function') {
|
|
5117
|
+
colStyle = memoize(i => opts.columnStyles(i), Infinity);
|
|
5118
|
+
} else if (typeof opts.columnStyles === 'object') {
|
|
5119
|
+
colStyle = () => opts.columnStyles;
|
|
5120
|
+
}
|
|
5121
|
+
}
|
|
5122
|
+
if (!colStyle) colStyle = () => ({});
|
|
5123
|
+
this._colStyle = normalizedColumnStyle.bind(this, defaultColStyle, colStyle);
|
|
5124
|
+
let rowStyle;
|
|
5125
|
+
if (opts.rowStyles) {
|
|
5126
|
+
if (Array.isArray(opts.rowStyles)) {
|
|
5127
|
+
rowStyle = i => opts.rowStyles[i];
|
|
5128
|
+
} else if (typeof opts.rowStyles === 'function') {
|
|
5129
|
+
rowStyle = memoize(i => opts.rowStyles(i), 10);
|
|
5130
|
+
} else if (typeof opts.rowStyles === 'object') {
|
|
5131
|
+
rowStyle = () => opts.rowStyles;
|
|
5132
|
+
}
|
|
5133
|
+
}
|
|
5134
|
+
if (!rowStyle) rowStyle = () => ({});
|
|
5135
|
+
this._rowStyle = normalizedRowStyle.bind(this, defaultRowStyle, rowStyle);
|
|
5136
|
+
}
|
|
5137
|
+
function normalizeText(text) {
|
|
5138
|
+
if (text != null) text = `${text}`;
|
|
5139
|
+
return text;
|
|
5140
|
+
}
|
|
5141
|
+
function normalizeCell(cell, rowIndex, colIndex) {
|
|
5142
|
+
const colStyle = this._colStyle(colIndex);
|
|
5143
|
+
let rowStyle = this._rowStyle(rowIndex);
|
|
5144
|
+
const font = deepMerge({}, colStyle.font, rowStyle.font, cell.font);
|
|
5145
|
+
const customFont = Object.values(font).filter(v => v != null).length > 0;
|
|
5146
|
+
const doc = this.document;
|
|
5147
|
+
const rollbackFont = doc._fontSource;
|
|
5148
|
+
const rollbackFontSize = doc._fontSize;
|
|
5149
|
+
const rollbackFontFamily = doc._fontFamily;
|
|
5150
|
+
if (customFont) {
|
|
5151
|
+
if (font.src) doc.font(font.src, font.family);
|
|
5152
|
+
if (font.size) doc.fontSize(font.size);
|
|
5153
|
+
rowStyle = this._rowStyle(rowIndex);
|
|
5154
|
+
}
|
|
5155
|
+
cell.padding = normalizeSides(cell.padding);
|
|
5156
|
+
cell.border = normalizeSides(cell.border);
|
|
5157
|
+
cell.borderColor = normalizeSides(cell.borderColor);
|
|
5158
|
+
const config = deepMerge(this._defaultStyle, colStyle, rowStyle, cell);
|
|
5159
|
+
config.rowIndex = rowIndex;
|
|
5160
|
+
config.colIndex = colIndex;
|
|
5161
|
+
config.font = font ?? {};
|
|
5162
|
+
config.customFont = customFont;
|
|
5163
|
+
config.text = normalizeText(config.text);
|
|
5164
|
+
config.rowSpan = config.rowSpan ?? 1;
|
|
5165
|
+
config.colSpan = config.colSpan ?? 1;
|
|
5166
|
+
config.padding = normalizeSides(config.padding, '0.25em', x => doc.sizeToPoint(x, '0.25em'));
|
|
5167
|
+
config.border = normalizeSides(config.border, 1, x => doc.sizeToPoint(x, 1));
|
|
5168
|
+
config.borderColor = normalizeSides(config.borderColor, 'black', x => x ?? 'black');
|
|
5169
|
+
config.align = normalizeAlignment(config.align);
|
|
5170
|
+
config.align.x = config.align.x ?? 'left';
|
|
5171
|
+
config.align.y = config.align.y ?? 'top';
|
|
5172
|
+
config.textStroke = doc.sizeToPoint(config.textStroke, 0);
|
|
5173
|
+
config.textStrokeColor = config.textStrokeColor ?? 'black';
|
|
5174
|
+
config.textColor = config.textColor ?? 'black';
|
|
5175
|
+
config.textOptions = config.textOptions ?? {};
|
|
5176
|
+
config.id = new String(config.id ?? `${this._id}-${rowIndex}-${colIndex}`);
|
|
5177
|
+
config.type = config.type?.toUpperCase() === 'TH' ? 'TH' : 'TD';
|
|
5178
|
+
if (config.scope) {
|
|
5179
|
+
config.scope = config.scope.toLowerCase();
|
|
5180
|
+
if (config.scope === 'row') config.scope = 'Row';else if (config.scope === 'both') config.scope = 'Both';else if (config.scope === 'column') config.scope = 'Column';
|
|
5181
|
+
}
|
|
5182
|
+
if (typeof this.opts.debug === 'boolean') config.debug = this.opts.debug;
|
|
5183
|
+
if (customFont) doc.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5184
|
+
return config;
|
|
5185
|
+
}
|
|
5186
|
+
function normalizeRow(row, rowIndex) {
|
|
5187
|
+
if (!this._cellClaim) this._cellClaim = new Set();
|
|
5188
|
+
let colIndex = 0;
|
|
5189
|
+
return row.map(cell => {
|
|
5190
|
+
if (cell == null || typeof cell !== 'object') cell = {
|
|
5191
|
+
text: cell
|
|
5192
|
+
};
|
|
5193
|
+
while (this._cellClaim.has(`${rowIndex},${colIndex}`)) {
|
|
5194
|
+
colIndex++;
|
|
5195
|
+
}
|
|
5196
|
+
cell = normalizeCell.call(this, cell, rowIndex, colIndex);
|
|
5197
|
+
for (let i = 0; i < cell.rowSpan; i++) {
|
|
5198
|
+
for (let j = 0; j < cell.colSpan; j++) {
|
|
5199
|
+
this._cellClaim.add(`${rowIndex + i},${colIndex + j}`);
|
|
5200
|
+
}
|
|
5201
|
+
}
|
|
5202
|
+
colIndex += cell.colSpan;
|
|
5203
|
+
return cell;
|
|
5204
|
+
});
|
|
5205
|
+
}
|
|
5206
|
+
|
|
5207
|
+
function ensure(row) {
|
|
5208
|
+
this._columnWidths = [];
|
|
5209
|
+
ensureColumnWidths.call(this, row.reduce((a, cell) => a + cell.colSpan, 0));
|
|
5210
|
+
this._rowHeights = [];
|
|
5211
|
+
this._rowYPos = [this._position.y];
|
|
5212
|
+
this._rowBuffer = new Set();
|
|
5213
|
+
}
|
|
5214
|
+
function ensureColumnWidths(numCols) {
|
|
5215
|
+
let starColumnIndexes = [];
|
|
5216
|
+
let starMinAcc = 0;
|
|
5217
|
+
let unclaimedWidth = this._maxWidth;
|
|
5218
|
+
for (let i = 0; i < numCols; i++) {
|
|
5219
|
+
let col = this._colStyle(i);
|
|
5220
|
+
if (col.width === '*') {
|
|
5221
|
+
starColumnIndexes[i] = col;
|
|
5222
|
+
starMinAcc += col.minWidth;
|
|
5223
|
+
} else {
|
|
5224
|
+
unclaimedWidth -= col.width;
|
|
5225
|
+
this._columnWidths[i] = col.width;
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
let starColCount = starColumnIndexes.reduce(x => x + 1, 0);
|
|
5229
|
+
if (starMinAcc >= unclaimedWidth) {
|
|
5230
|
+
starColumnIndexes.forEach((cell, i) => {
|
|
5231
|
+
this._columnWidths[i] = cell.minWidth;
|
|
5232
|
+
});
|
|
5233
|
+
} else if (starColCount > 0) {
|
|
5234
|
+
starColumnIndexes.forEach((col, i) => {
|
|
5235
|
+
let starSize = unclaimedWidth / starColCount;
|
|
5236
|
+
this._columnWidths[i] = Math.max(starSize, col.minWidth);
|
|
5237
|
+
if (col.maxWidth > 0) {
|
|
5238
|
+
this._columnWidths[i] = Math.min(this._columnWidths[i], col.maxWidth);
|
|
5239
|
+
}
|
|
5240
|
+
unclaimedWidth -= this._columnWidths[i];
|
|
5241
|
+
starColCount--;
|
|
5242
|
+
});
|
|
5243
|
+
}
|
|
5244
|
+
let tempX = this._position.x;
|
|
5245
|
+
this._columnXPos = Array.from(this._columnWidths, v => {
|
|
5246
|
+
const t = tempX;
|
|
5247
|
+
tempX += v;
|
|
5248
|
+
return t;
|
|
5249
|
+
});
|
|
5250
|
+
}
|
|
5251
|
+
function measure(row, rowIndex) {
|
|
5252
|
+
row.forEach(cell => this._rowBuffer.add(cell));
|
|
5253
|
+
if (rowIndex > 0) {
|
|
5254
|
+
this._rowYPos[rowIndex] = this._rowYPos[rowIndex - 1] + this._rowHeights[rowIndex - 1];
|
|
5255
|
+
}
|
|
5256
|
+
const rowStyle = this._rowStyle(rowIndex);
|
|
5257
|
+
let toRender = [];
|
|
5258
|
+
this._rowBuffer.forEach(cell => {
|
|
5259
|
+
if (cell.rowIndex + cell.rowSpan - 1 === rowIndex) {
|
|
5260
|
+
toRender.push(measureCell.call(this, cell, rowStyle.height));
|
|
5261
|
+
this._rowBuffer.delete(cell);
|
|
5262
|
+
}
|
|
5263
|
+
});
|
|
5264
|
+
let rowHeight = rowStyle.height;
|
|
5265
|
+
if (rowHeight === 'auto') {
|
|
5266
|
+
rowHeight = toRender.reduce((acc, cell) => {
|
|
5267
|
+
let minHeight = cell.textBounds.height + cell.padding.top + cell.padding.bottom;
|
|
5268
|
+
for (let i = 0; i < cell.rowSpan - 1; i++) {
|
|
5269
|
+
minHeight -= this._rowHeights[cell.rowIndex + i];
|
|
5270
|
+
}
|
|
5271
|
+
return Math.max(acc, minHeight);
|
|
5272
|
+
}, 0);
|
|
5273
|
+
}
|
|
5274
|
+
rowHeight = Math.max(rowHeight, rowStyle.minHeight);
|
|
5275
|
+
if (rowStyle.maxHeight > 0) {
|
|
5276
|
+
rowHeight = Math.min(rowHeight, rowStyle.maxHeight);
|
|
5277
|
+
}
|
|
5278
|
+
this._rowHeights[rowIndex] = rowHeight;
|
|
5279
|
+
let newPage = false;
|
|
5280
|
+
if (rowHeight > this.document.page.contentHeight) {
|
|
5281
|
+
console.warn(new Error(`Row ${rowIndex} requested more than the safe page height, row has been clamped`).stack.slice(7));
|
|
5282
|
+
this._rowHeights[rowIndex] = this.document.page.maxY() - this._rowYPos[rowIndex];
|
|
5283
|
+
} else if (this._rowYPos[rowIndex] + rowHeight >= this.document.page.maxY()) {
|
|
5284
|
+
this._rowYPos[rowIndex] = this.document.page.margins.top;
|
|
5285
|
+
newPage = true;
|
|
5286
|
+
}
|
|
5287
|
+
return {
|
|
5288
|
+
newPage,
|
|
5289
|
+
toRender: toRender.map(cell => measureCell.call(this, cell, rowHeight))
|
|
5290
|
+
};
|
|
5291
|
+
}
|
|
5292
|
+
function measureCell(cell, rowHeight) {
|
|
5293
|
+
let cellWidth = 0;
|
|
5294
|
+
for (let i = 0; i < cell.colSpan; i++) {
|
|
5295
|
+
cellWidth += this._columnWidths[cell.colIndex + i];
|
|
5296
|
+
}
|
|
5297
|
+
let cellHeight = rowHeight;
|
|
5298
|
+
if (cellHeight === 'auto') {
|
|
5299
|
+
cellHeight = this.document.page.contentHeight;
|
|
5300
|
+
} else {
|
|
5301
|
+
for (let i = 0; i < cell.rowSpan - 1; i++) {
|
|
5302
|
+
cellHeight += this._rowHeights[cell.rowIndex + i];
|
|
5303
|
+
}
|
|
5304
|
+
}
|
|
5305
|
+
const textAllocatedWidth = cellWidth - cell.padding.left - cell.padding.right;
|
|
5306
|
+
const textAllocatedHeight = cellHeight - cell.padding.top - cell.padding.bottom;
|
|
5307
|
+
const rotation = cell.textOptions.rotation ?? 0;
|
|
5308
|
+
const {
|
|
5309
|
+
width: textMaxWidth,
|
|
5310
|
+
height: textMaxHeight
|
|
5311
|
+
} = computeBounds(rotation, textAllocatedWidth, textAllocatedHeight);
|
|
5312
|
+
const textOptions = {
|
|
5313
|
+
align: cell.align.x,
|
|
5314
|
+
ellipsis: true,
|
|
5315
|
+
stroke: cell.textStroke > 0,
|
|
5316
|
+
fill: true,
|
|
5317
|
+
width: textMaxWidth,
|
|
5318
|
+
height: textMaxHeight,
|
|
5319
|
+
rotation,
|
|
5320
|
+
...cell.textOptions
|
|
5321
|
+
};
|
|
5322
|
+
let textBounds = {
|
|
5323
|
+
x: 0,
|
|
5324
|
+
y: 0,
|
|
5325
|
+
width: 0,
|
|
5326
|
+
height: 0
|
|
5327
|
+
};
|
|
5328
|
+
if (cell.text) {
|
|
5329
|
+
const rollbackFont = this.document._fontSource;
|
|
5330
|
+
const rollbackFontSize = this.document._fontSize;
|
|
5331
|
+
const rollbackFontFamily = this.document._fontFamily;
|
|
5332
|
+
if (cell.font?.src) this.document.font(cell.font.src, cell.font?.family);
|
|
5333
|
+
if (cell.font?.size) this.document.fontSize(cell.font.size);
|
|
5334
|
+
const unRotatedTextBounds = this.document.boundsOfString(cell.text, 0, 0, {
|
|
5335
|
+
...textOptions,
|
|
5336
|
+
rotation: 0
|
|
5337
|
+
});
|
|
5338
|
+
textOptions.width = unRotatedTextBounds.width;
|
|
5339
|
+
textOptions.height = unRotatedTextBounds.height;
|
|
5340
|
+
textBounds = this.document.boundsOfString(cell.text, 0, 0, textOptions);
|
|
5341
|
+
this.document.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5342
|
+
}
|
|
5343
|
+
return {
|
|
5344
|
+
...cell,
|
|
5345
|
+
textOptions,
|
|
5346
|
+
x: this._columnXPos[cell.colIndex],
|
|
5347
|
+
y: this._rowYPos[cell.rowIndex],
|
|
5348
|
+
textX: this._columnXPos[cell.colIndex] + cell.padding.left,
|
|
5349
|
+
textY: this._rowYPos[cell.rowIndex] + cell.padding.top,
|
|
5350
|
+
width: cellWidth,
|
|
5351
|
+
height: cellHeight,
|
|
5352
|
+
textAllocatedHeight,
|
|
5353
|
+
textAllocatedWidth,
|
|
5354
|
+
textBounds
|
|
5355
|
+
};
|
|
5356
|
+
}
|
|
5357
|
+
function computeBounds(rotation, allocWidth, allocHeight) {
|
|
5358
|
+
let textMaxWidth, textMaxHeight;
|
|
5359
|
+
const cos = cosine(rotation);
|
|
5360
|
+
const sin = sine(rotation);
|
|
5361
|
+
if (rotation === 0 || rotation === 180) {
|
|
5362
|
+
textMaxWidth = allocWidth;
|
|
5363
|
+
textMaxHeight = allocHeight;
|
|
5364
|
+
} else if (rotation === 90 || rotation === 270) {
|
|
5365
|
+
textMaxWidth = allocHeight;
|
|
5366
|
+
textMaxHeight = allocWidth;
|
|
5367
|
+
} else if (rotation < 90 || rotation > 180 && rotation < 270) {
|
|
5368
|
+
textMaxWidth = allocWidth / (2 * cos);
|
|
5369
|
+
textMaxHeight = allocWidth / (2 * sin);
|
|
5370
|
+
} else {
|
|
5371
|
+
textMaxHeight = allocWidth / (2 * cos);
|
|
5372
|
+
textMaxWidth = allocWidth / (2 * sin);
|
|
5373
|
+
}
|
|
5374
|
+
const EF = sin * textMaxWidth;
|
|
5375
|
+
const FG = cos * textMaxHeight;
|
|
5376
|
+
if (EF + FG > allocHeight) {
|
|
5377
|
+
const denominator = cos * cos - sin * sin;
|
|
5378
|
+
if (rotation === 0 || rotation === 180) {
|
|
5379
|
+
textMaxWidth = allocWidth;
|
|
5380
|
+
textMaxHeight = allocHeight;
|
|
5381
|
+
} else if (rotation === 90 || rotation === 270) {
|
|
5382
|
+
textMaxWidth = allocHeight;
|
|
5383
|
+
textMaxHeight = allocWidth;
|
|
5384
|
+
} else if (rotation < 90 || rotation > 180 && rotation < 270) {
|
|
5385
|
+
textMaxWidth = (allocWidth * cos - allocHeight * sin) / denominator;
|
|
5386
|
+
textMaxHeight = (allocHeight * cos - allocWidth * sin) / denominator;
|
|
5387
|
+
} else {
|
|
5388
|
+
textMaxHeight = (allocWidth * cos - allocHeight * sin) / denominator;
|
|
5389
|
+
textMaxWidth = (allocHeight * cos - allocWidth * sin) / denominator;
|
|
5390
|
+
}
|
|
5391
|
+
}
|
|
5392
|
+
return {
|
|
5393
|
+
width: Math.abs(textMaxWidth),
|
|
5394
|
+
height: Math.abs(textMaxHeight)
|
|
5395
|
+
};
|
|
5396
|
+
}
|
|
5397
|
+
|
|
5398
|
+
function accommodateTable() {
|
|
5399
|
+
const structParent = this.opts.structParent;
|
|
5400
|
+
if (structParent) {
|
|
5401
|
+
this._tableStruct = this.document.struct('Table');
|
|
5402
|
+
this._tableStruct.dictionary.data.ID = this._id;
|
|
5403
|
+
if (structParent instanceof PDFStructureElement) {
|
|
5404
|
+
structParent.add(this._tableStruct);
|
|
5405
|
+
} else if (structParent instanceof PDFDocument) {
|
|
5406
|
+
structParent.addStructure(this._tableStruct);
|
|
5407
|
+
}
|
|
5408
|
+
this._headerRowLookup = {};
|
|
5409
|
+
this._headerColumnLookup = {};
|
|
5410
|
+
}
|
|
5411
|
+
}
|
|
5412
|
+
function accommodateCleanup() {
|
|
5413
|
+
if (this._tableStruct) this._tableStruct.end();
|
|
5414
|
+
}
|
|
5415
|
+
function accessibleRow(row, rowIndex, renderCell) {
|
|
5416
|
+
const rowStruct = this.document.struct('TR');
|
|
5417
|
+
rowStruct.dictionary.data.ID = new String(`${this._id}-${rowIndex}`);
|
|
5418
|
+
this._tableStruct.add(rowStruct);
|
|
5419
|
+
row.forEach(cell => renderCell(cell, rowStruct));
|
|
5420
|
+
rowStruct.end();
|
|
5421
|
+
}
|
|
5422
|
+
function accessibleCell(cell, rowStruct, callback) {
|
|
5423
|
+
const doc = this.document;
|
|
5424
|
+
const cellStruct = doc.struct(cell.type, {
|
|
5425
|
+
title: cell.title
|
|
5426
|
+
});
|
|
5427
|
+
cellStruct.dictionary.data.ID = cell.id;
|
|
5428
|
+
rowStruct.add(cellStruct);
|
|
5429
|
+
const padding = cell.padding;
|
|
5430
|
+
const border = cell.border;
|
|
5431
|
+
const attributes = {
|
|
5432
|
+
O: 'Table',
|
|
5433
|
+
Width: cell.width,
|
|
5434
|
+
Height: cell.height,
|
|
5435
|
+
Padding: [padding.top, padding.bottom, padding.left, padding.right],
|
|
5436
|
+
RowSpan: cell.rowSpan > 1 ? cell.rowSpan : undefined,
|
|
5437
|
+
ColSpan: cell.colSpan > 1 ? cell.colSpan : undefined,
|
|
5438
|
+
BorderThickness: [border.top, border.bottom, border.left, border.right]
|
|
5439
|
+
};
|
|
5440
|
+
if (cell.type === 'TH') {
|
|
5441
|
+
if (cell.scope === 'Row' || cell.scope === 'Both') {
|
|
5442
|
+
for (let i = 0; i < cell.rowSpan; i++) {
|
|
5443
|
+
if (!this._headerRowLookup[cell.rowIndex + i]) {
|
|
5444
|
+
this._headerRowLookup[cell.rowIndex + i] = [];
|
|
5445
|
+
}
|
|
5446
|
+
this._headerRowLookup[cell.rowIndex + i].push(cell.id);
|
|
5447
|
+
}
|
|
5448
|
+
attributes.Scope = cell.scope;
|
|
5449
|
+
}
|
|
5450
|
+
if (cell.scope === 'Column' || cell.scope === 'Both') {
|
|
5451
|
+
for (let i = 0; i < cell.colSpan; i++) {
|
|
5452
|
+
if (!this._headerColumnLookup[cell.colIndex + i]) {
|
|
5453
|
+
this._headerColumnLookup[cell.colIndex + i] = [];
|
|
5454
|
+
}
|
|
5455
|
+
this._headerColumnLookup[cell.colIndex + i].push(cell.id);
|
|
5456
|
+
}
|
|
5457
|
+
attributes.Scope = cell.scope;
|
|
5458
|
+
}
|
|
5459
|
+
}
|
|
5460
|
+
const Headers = new Set([...Array.from({
|
|
5461
|
+
length: cell.colSpan
|
|
5462
|
+
}, (_, i) => this._headerColumnLookup[cell.colIndex + i]).flat(), ...Array.from({
|
|
5463
|
+
length: cell.rowSpan
|
|
5464
|
+
}, (_, i) => this._headerRowLookup[cell.rowIndex + i]).flat()].filter(Boolean));
|
|
5465
|
+
if (Headers.size) attributes.Headers = Array.from(Headers);
|
|
5466
|
+
const normalizeColor = doc._normalizeColor;
|
|
5467
|
+
if (cell.backgroundColor != null) {
|
|
5468
|
+
attributes.BackgroundColor = normalizeColor(cell.backgroundColor);
|
|
5469
|
+
}
|
|
5470
|
+
const hasBorder = [border.top, border.bottom, border.left, border.right];
|
|
5471
|
+
if (hasBorder.some(x => x)) {
|
|
5472
|
+
const borderColor = cell.borderColor;
|
|
5473
|
+
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];
|
|
5474
|
+
}
|
|
5475
|
+
Object.keys(attributes).forEach(key => attributes[key] === undefined && delete attributes[key]);
|
|
5476
|
+
cellStruct.dictionary.data.A = doc.ref(attributes);
|
|
5477
|
+
cellStruct.add(callback);
|
|
5478
|
+
cellStruct.end();
|
|
5479
|
+
cellStruct.dictionary.data.A.end();
|
|
5480
|
+
}
|
|
5481
|
+
|
|
5482
|
+
function renderRow(row, rowIndex) {
|
|
5483
|
+
if (this._tableStruct) {
|
|
5484
|
+
accessibleRow.call(this, row, rowIndex, renderCell.bind(this));
|
|
5485
|
+
} else {
|
|
5486
|
+
row.forEach(cell => renderCell.call(this, cell));
|
|
5487
|
+
}
|
|
5488
|
+
return this._rowYPos[rowIndex] + this._rowHeights[rowIndex];
|
|
5489
|
+
}
|
|
5490
|
+
function renderCell(cell, rowStruct) {
|
|
5491
|
+
const cellRenderer = () => {
|
|
5492
|
+
if (cell.backgroundColor != null) {
|
|
5493
|
+
this.document.save().rect(cell.x, cell.y, cell.width, cell.height).fill(cell.backgroundColor).restore();
|
|
5494
|
+
}
|
|
5495
|
+
renderBorder.call(this, cell.border, cell.borderColor, cell.x, cell.y, cell.width, cell.height);
|
|
5496
|
+
if (cell.debug) {
|
|
5497
|
+
this.document.save();
|
|
5498
|
+
this.document.dash(1, {
|
|
5499
|
+
space: 1
|
|
5500
|
+
}).lineWidth(1).strokeOpacity(0.3);
|
|
5501
|
+
this.document.rect(cell.x, cell.y, cell.width, cell.height).stroke('green');
|
|
5502
|
+
this.document.restore();
|
|
5503
|
+
}
|
|
5504
|
+
if (cell.text) renderCellText.call(this, cell);
|
|
5505
|
+
};
|
|
5506
|
+
if (rowStruct) accessibleCell.call(this, cell, rowStruct, cellRenderer);else cellRenderer();
|
|
5507
|
+
}
|
|
5508
|
+
function renderCellText(cell) {
|
|
5509
|
+
const doc = this.document;
|
|
5510
|
+
const rollbackFont = doc._fontSource;
|
|
5511
|
+
const rollbackFontSize = doc._fontSize;
|
|
5512
|
+
const rollbackFontFamily = doc._fontFamily;
|
|
5513
|
+
if (cell.customFont) {
|
|
5514
|
+
if (cell.font.src) doc.font(cell.font.src, cell.font.family);
|
|
5515
|
+
if (cell.font.size) doc.fontSize(cell.font.size);
|
|
5516
|
+
}
|
|
5517
|
+
const x = cell.textX;
|
|
5518
|
+
const y = cell.textY;
|
|
5519
|
+
const Ah = cell.textAllocatedHeight;
|
|
5520
|
+
const Aw = cell.textAllocatedWidth;
|
|
5521
|
+
const Cw = cell.textBounds.width;
|
|
5522
|
+
const Ch = cell.textBounds.height;
|
|
5523
|
+
const Ox = -cell.textBounds.x;
|
|
5524
|
+
const Oy = -cell.textBounds.y;
|
|
5525
|
+
const PxScale = cell.align.x === 'right' ? 1 : cell.align.x === 'center' ? 0.5 : 0;
|
|
5526
|
+
const Px = (Aw - Cw) * PxScale;
|
|
5527
|
+
const PyScale = cell.align.y === 'bottom' ? 1 : cell.align.y === 'center' ? 0.5 : 0;
|
|
5528
|
+
const Py = (Ah - Ch) * PyScale;
|
|
5529
|
+
const dx = Px + Ox;
|
|
5530
|
+
const dy = Py + Oy;
|
|
5531
|
+
if (cell.debug) {
|
|
5532
|
+
doc.save();
|
|
5533
|
+
doc.dash(1, {
|
|
5534
|
+
space: 1
|
|
5535
|
+
}).lineWidth(1).strokeOpacity(0.3);
|
|
5536
|
+
if (cell.text) {
|
|
5537
|
+
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');
|
|
5538
|
+
}
|
|
5539
|
+
doc.rect(x, y, Aw, Ah).stroke('orange');
|
|
5540
|
+
doc.restore();
|
|
5541
|
+
}
|
|
5542
|
+
doc.save().rect(x, y, Aw, Ah).clip();
|
|
5543
|
+
doc.fillColor(cell.textColor).strokeColor(cell.textStrokeColor);
|
|
5544
|
+
if (cell.textStroke > 0) doc.lineWidth(cell.textStroke);
|
|
5545
|
+
doc.text(cell.text, x + dx, y + dy, cell.textOptions);
|
|
5546
|
+
doc.restore();
|
|
5547
|
+
if (cell.font) doc.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5548
|
+
}
|
|
5549
|
+
function renderBorder(border, borderColor, x, y, width, height, mask) {
|
|
5550
|
+
border = Object.fromEntries(Object.entries(border).map(([k, v]) => [k, mask && !mask[k] ? 0 : v]));
|
|
5551
|
+
const doc = this.document;
|
|
5552
|
+
if ([border.right, border.bottom, border.left].every(val => val === border.top)) {
|
|
5553
|
+
if (border.top > 0) {
|
|
5554
|
+
doc.save().lineWidth(border.top).rect(x, y, width, height).stroke(borderColor.top).restore();
|
|
5555
|
+
}
|
|
5556
|
+
} else {
|
|
5557
|
+
if (border.top > 0) {
|
|
5558
|
+
doc.save().lineWidth(border.top).moveTo(x, y).lineTo(x + width, y).stroke(borderColor.top).restore();
|
|
5559
|
+
}
|
|
5560
|
+
if (border.right > 0) {
|
|
5561
|
+
doc.save().lineWidth(border.right).moveTo(x + width, y).lineTo(x + width, y + height).stroke(borderColor.right).restore();
|
|
5562
|
+
}
|
|
5563
|
+
if (border.bottom > 0) {
|
|
5564
|
+
doc.save().lineWidth(border.bottom).moveTo(x + width, y + height).lineTo(x, y + height).stroke(borderColor.bottom).restore();
|
|
5565
|
+
}
|
|
5566
|
+
if (border.left > 0) {
|
|
5567
|
+
doc.save().lineWidth(border.left).moveTo(x, y + height).lineTo(x, y).stroke(borderColor.left).restore();
|
|
5568
|
+
}
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
|
|
5572
|
+
class PDFTable {
|
|
5573
|
+
constructor(document, opts = {}) {
|
|
5574
|
+
this.document = document;
|
|
5575
|
+
this.opts = Object.freeze(opts);
|
|
5576
|
+
normalizeTable.call(this);
|
|
5577
|
+
accommodateTable.call(this);
|
|
5578
|
+
this._currRowIndex = 0;
|
|
5579
|
+
this._ended = false;
|
|
5580
|
+
if (opts.data) {
|
|
5581
|
+
for (const row of opts.data) this.row(row);
|
|
5582
|
+
return this.end();
|
|
5583
|
+
}
|
|
5584
|
+
}
|
|
5585
|
+
row(row, lastRow = false) {
|
|
5586
|
+
if (this._ended) {
|
|
5587
|
+
throw new Error(`Table was marked as ended on row ${this._currRowIndex}`);
|
|
5588
|
+
}
|
|
5589
|
+
row = Array.from(row);
|
|
5590
|
+
row = normalizeRow.call(this, row, this._currRowIndex);
|
|
5591
|
+
if (this._currRowIndex === 0) ensure.call(this, row);
|
|
5592
|
+
const {
|
|
5593
|
+
newPage,
|
|
5594
|
+
toRender
|
|
5595
|
+
} = measure.call(this, row, this._currRowIndex);
|
|
5596
|
+
if (newPage) this.document.continueOnNewPage();
|
|
5597
|
+
const yPos = renderRow.call(this, toRender, this._currRowIndex);
|
|
5598
|
+
this.document.x = this._position.x;
|
|
5599
|
+
this.document.y = yPos;
|
|
5600
|
+
if (lastRow) return this.end();
|
|
5601
|
+
this._currRowIndex++;
|
|
5602
|
+
return this;
|
|
5603
|
+
}
|
|
5604
|
+
end() {
|
|
5605
|
+
while (this._rowBuffer?.size) this.row([]);
|
|
5606
|
+
this._ended = true;
|
|
5607
|
+
accommodateCleanup.call(this);
|
|
5608
|
+
return this.document;
|
|
5609
|
+
}
|
|
5610
|
+
}
|
|
5611
|
+
|
|
5612
|
+
var TableMixin = {
|
|
5613
|
+
initTables() {
|
|
5614
|
+
this._tableIndex = 0;
|
|
5615
|
+
},
|
|
5616
|
+
table(opts) {
|
|
5617
|
+
return new PDFTable(this, opts);
|
|
5618
|
+
}
|
|
5619
|
+
};
|
|
5620
|
+
|
|
5304
5621
|
class PDFMetadata {
|
|
5305
5622
|
constructor() {
|
|
5306
5623
|
this._metadata = `
|
|
@@ -5342,7 +5659,7 @@ var MetadataMixin = {
|
|
|
5342
5659
|
_addInfo() {
|
|
5343
5660
|
this.appendXML(`
|
|
5344
5661
|
<rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/">
|
|
5345
|
-
<xmp:CreateDate>${this.info.CreationDate.toISOString().split('.')[0] +
|
|
5662
|
+
<xmp:CreateDate>${this.info.CreationDate.toISOString().split('.')[0] + 'Z'}</xmp:CreateDate>
|
|
5346
5663
|
<xmp:CreatorTool>${this.info.Creator}</xmp:CreatorTool>
|
|
5347
5664
|
</rdf:Description>
|
|
5348
5665
|
`);
|
|
@@ -5395,11 +5712,6 @@ var MetadataMixin = {
|
|
|
5395
5712
|
endMetadata() {
|
|
5396
5713
|
this._addInfo();
|
|
5397
5714
|
this.metadata.end();
|
|
5398
|
-
|
|
5399
|
-
/*
|
|
5400
|
-
Metadata was introduced in PDF 1.4, so adding it to 1.3
|
|
5401
|
-
will likely only take up more space.
|
|
5402
|
-
*/
|
|
5403
5715
|
if (this.version != 1.3) {
|
|
5404
5716
|
this.metadataRef = this.ref({
|
|
5405
5717
|
length: this.metadata.getLength(),
|
|
@@ -5414,16 +5726,10 @@ var MetadataMixin = {
|
|
|
5414
5726
|
}
|
|
5415
5727
|
};
|
|
5416
5728
|
|
|
5417
|
-
/*
|
|
5418
|
-
PDFDocument - represents an entire PDF document
|
|
5419
|
-
By Devon Govett
|
|
5420
|
-
*/
|
|
5421
5729
|
class PDFDocument extends stream.Readable {
|
|
5422
5730
|
constructor(options = {}) {
|
|
5423
5731
|
super(options);
|
|
5424
5732
|
this.options = options;
|
|
5425
|
-
|
|
5426
|
-
// PDF version
|
|
5427
5733
|
switch (options.pdfVersion) {
|
|
5428
5734
|
case '1.4':
|
|
5429
5735
|
this.version = 1.4;
|
|
@@ -5442,13 +5748,9 @@ class PDFDocument extends stream.Readable {
|
|
|
5442
5748
|
this.version = 1.3;
|
|
5443
5749
|
break;
|
|
5444
5750
|
}
|
|
5445
|
-
|
|
5446
|
-
// Whether streams should be compressed
|
|
5447
5751
|
this.compress = this.options.compress != null ? this.options.compress : true;
|
|
5448
5752
|
this._pageBuffer = [];
|
|
5449
5753
|
this._pageBufferStart = 0;
|
|
5450
|
-
|
|
5451
|
-
// The PDF object store
|
|
5452
5754
|
this._offsets = [];
|
|
5453
5755
|
this._waiting = 0;
|
|
5454
5756
|
this._ended = false;
|
|
@@ -5469,11 +5771,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5469
5771
|
if (this.options.lang) {
|
|
5470
5772
|
this._root.data.Lang = new String(this.options.lang);
|
|
5471
5773
|
}
|
|
5472
|
-
|
|
5473
|
-
// The current page
|
|
5474
5774
|
this.page = null;
|
|
5475
|
-
|
|
5476
|
-
// Initialize mixins
|
|
5477
5775
|
this.initMetadata();
|
|
5478
5776
|
this.initColor();
|
|
5479
5777
|
this.initVector();
|
|
@@ -5482,9 +5780,8 @@ class PDFDocument extends stream.Readable {
|
|
|
5482
5780
|
this.initImages();
|
|
5483
5781
|
this.initOutline();
|
|
5484
5782
|
this.initMarkings(options);
|
|
5783
|
+
this.initTables();
|
|
5485
5784
|
this.initSubset(options);
|
|
5486
|
-
|
|
5487
|
-
// Initialize the metadata
|
|
5488
5785
|
this.info = {
|
|
5489
5786
|
Producer: 'PDFKit',
|
|
5490
5787
|
Creator: 'PDFKit',
|
|
@@ -5501,21 +5798,10 @@ class PDFDocument extends stream.Readable {
|
|
|
5501
5798
|
DisplayDocTitle: true
|
|
5502
5799
|
});
|
|
5503
5800
|
}
|
|
5504
|
-
|
|
5505
|
-
// Generate file ID
|
|
5506
5801
|
this._id = PDFSecurity.generateFileID(this.info);
|
|
5507
|
-
|
|
5508
|
-
// Initialize security settings
|
|
5509
5802
|
this._security = PDFSecurity.create(this, options);
|
|
5510
|
-
|
|
5511
|
-
// Write the header
|
|
5512
|
-
// PDF version
|
|
5513
5803
|
this._write(`%PDF-${this.version}`);
|
|
5514
|
-
|
|
5515
|
-
// 4 binary chars, as recommended by the spec
|
|
5516
5804
|
this._write('%\xFF\xFF\xFF\xFF');
|
|
5517
|
-
|
|
5518
|
-
// Add the first page
|
|
5519
5805
|
if (this.options.autoFirstPage !== false) {
|
|
5520
5806
|
this.addPage();
|
|
5521
5807
|
}
|
|
@@ -5526,27 +5812,16 @@ class PDFDocument extends stream.Readable {
|
|
|
5526
5812
|
options
|
|
5527
5813
|
} = this);
|
|
5528
5814
|
}
|
|
5529
|
-
|
|
5530
|
-
// end the current page if needed
|
|
5531
5815
|
if (!this.options.bufferPages) {
|
|
5532
5816
|
this.flushPages();
|
|
5533
5817
|
}
|
|
5534
|
-
|
|
5535
|
-
// create a page object
|
|
5536
5818
|
this.page = new PDFPage(this, options);
|
|
5537
5819
|
this._pageBuffer.push(this.page);
|
|
5538
|
-
|
|
5539
|
-
// add the page to the object store
|
|
5540
5820
|
const pages = this._root.data.Pages.data;
|
|
5541
5821
|
pages.Kids.push(this.page.dictionary);
|
|
5542
5822
|
pages.Count++;
|
|
5543
|
-
|
|
5544
|
-
// reset x and y coordinates
|
|
5545
5823
|
this.x = this.page.margins.left;
|
|
5546
5824
|
this.y = this.page.margins.top;
|
|
5547
|
-
|
|
5548
|
-
// flip PDF coordinate system so that the origin is in
|
|
5549
|
-
// the top left rather than the bottom left
|
|
5550
5825
|
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
5551
5826
|
this.transform(1, 0, 0, -1, 0, this.page.height);
|
|
5552
5827
|
this.emit('pageAdded');
|
|
@@ -5554,7 +5829,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5554
5829
|
}
|
|
5555
5830
|
continueOnNewPage(options) {
|
|
5556
5831
|
const pageMarkings = this.endPageMarkings(this.page);
|
|
5557
|
-
this.addPage(options);
|
|
5832
|
+
this.addPage(options ?? this.page._options);
|
|
5558
5833
|
this.initPageMarkings(pageMarkings);
|
|
5559
5834
|
return this;
|
|
5560
5835
|
}
|
|
@@ -5572,8 +5847,6 @@ class PDFDocument extends stream.Readable {
|
|
|
5572
5847
|
return this.page = page;
|
|
5573
5848
|
}
|
|
5574
5849
|
flushPages() {
|
|
5575
|
-
// this local variable exists so we're future-proof against
|
|
5576
|
-
// reentrant calls to flushPages.
|
|
5577
5850
|
const pages = this._pageBuffer;
|
|
5578
5851
|
this._pageBuffer = [];
|
|
5579
5852
|
this._pageBufferStart += pages.length;
|
|
@@ -5594,13 +5867,10 @@ class PDFDocument extends stream.Readable {
|
|
|
5594
5867
|
}
|
|
5595
5868
|
addNamedEmbeddedFile(name, ref) {
|
|
5596
5869
|
if (!this._root.data.Names.data.EmbeddedFiles) {
|
|
5597
|
-
// disabling /Limits for this tree fixes attachments not showing in Adobe Reader
|
|
5598
5870
|
this._root.data.Names.data.EmbeddedFiles = new PDFNameTree({
|
|
5599
5871
|
limits: false
|
|
5600
5872
|
});
|
|
5601
5873
|
}
|
|
5602
|
-
|
|
5603
|
-
// add filespec to EmbeddedFiles
|
|
5604
5874
|
this._root.data.Names.data.EmbeddedFiles.add(name, ref);
|
|
5605
5875
|
}
|
|
5606
5876
|
addNamedJavaScript(name, js) {
|
|
@@ -5615,19 +5885,17 @@ class PDFDocument extends stream.Readable {
|
|
|
5615
5885
|
}
|
|
5616
5886
|
ref(data) {
|
|
5617
5887
|
const ref = new PDFReference(this, this._offsets.length + 1, data);
|
|
5618
|
-
this._offsets.push(null);
|
|
5888
|
+
this._offsets.push(null);
|
|
5619
5889
|
this._waiting++;
|
|
5620
5890
|
return ref;
|
|
5621
5891
|
}
|
|
5622
5892
|
_read() {}
|
|
5623
|
-
// do nothing, but this method is required by node
|
|
5624
|
-
|
|
5625
5893
|
_write(data) {
|
|
5626
5894
|
if (!Buffer.isBuffer(data)) {
|
|
5627
5895
|
data = Buffer.from(data + '\n', 'binary');
|
|
5628
5896
|
}
|
|
5629
5897
|
this.push(data);
|
|
5630
|
-
|
|
5898
|
+
this._offset += data.length;
|
|
5631
5899
|
}
|
|
5632
5900
|
addContent(data) {
|
|
5633
5901
|
this.page.write(data);
|
|
@@ -5637,7 +5905,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5637
5905
|
this._offsets[ref.id - 1] = ref.offset;
|
|
5638
5906
|
if (--this._waiting === 0 && this._ended) {
|
|
5639
5907
|
this._finalize();
|
|
5640
|
-
|
|
5908
|
+
this._ended = false;
|
|
5641
5909
|
}
|
|
5642
5910
|
}
|
|
5643
5911
|
end() {
|
|
@@ -5674,13 +5942,12 @@ class PDFDocument extends stream.Readable {
|
|
|
5674
5942
|
this._security.end();
|
|
5675
5943
|
}
|
|
5676
5944
|
if (this._waiting === 0) {
|
|
5677
|
-
|
|
5945
|
+
this._finalize();
|
|
5678
5946
|
} else {
|
|
5679
|
-
|
|
5947
|
+
this._ended = true;
|
|
5680
5948
|
}
|
|
5681
5949
|
}
|
|
5682
5950
|
_finalize() {
|
|
5683
|
-
// generate xref
|
|
5684
5951
|
const xRefOffset = this._offset;
|
|
5685
5952
|
this._write('xref');
|
|
5686
5953
|
this._write(`0 ${this._offsets.length + 1}`);
|
|
@@ -5689,8 +5956,6 @@ class PDFDocument extends stream.Readable {
|
|
|
5689
5956
|
offset = `0000000000${offset}`.slice(-10);
|
|
5690
5957
|
this._write(offset + ' 00000 n ');
|
|
5691
5958
|
}
|
|
5692
|
-
|
|
5693
|
-
// trailer
|
|
5694
5959
|
const trailer = {
|
|
5695
5960
|
Size: this._offsets.length + 1,
|
|
5696
5961
|
Root: this._root,
|
|
@@ -5705,9 +5970,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5705
5970
|
this._write('startxref');
|
|
5706
5971
|
this._write(`${xRefOffset}`);
|
|
5707
5972
|
this._write('%%EOF');
|
|
5708
|
-
|
|
5709
|
-
// end the stream
|
|
5710
|
-
return this.push(null);
|
|
5973
|
+
this.push(null);
|
|
5711
5974
|
}
|
|
5712
5975
|
toString() {
|
|
5713
5976
|
return '[object PDFDocument]';
|
|
@@ -5728,6 +5991,7 @@ mixin(MarkingsMixin);
|
|
|
5728
5991
|
mixin(AcroFormMixin);
|
|
5729
5992
|
mixin(AttachmentsMixin);
|
|
5730
5993
|
mixin(SubsetMixin);
|
|
5994
|
+
mixin(TableMixin);
|
|
5731
5995
|
PDFDocument.LineWrapper = LineWrapper;
|
|
5732
5996
|
|
|
5733
5997
|
module.exports = PDFDocument;
|