@kittl/pdfkit 0.17.3 → 0.17.5
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/.yarn/install-state.gz +0 -0
- package/.yarn/releases/yarn-4.13.0.cjs +940 -0
- package/.yarnrc.yml +3 -0
- package/CHANGELOG.md +14 -0
- package/README.md +11 -4
- package/js/pdfkit.es.js +631 -172
- package/js/pdfkit.es.js.map +1 -1
- package/js/pdfkit.js +629 -172
- package/js/pdfkit.js.map +1 -1
- package/js/pdfkit.standalone.js +21437 -42180
- package/js/writeSvg.es.js +3684 -0
- package/js/writeSvg.es.js.map +1 -0
- package/js/writeSvg.js +3686 -0
- package/js/writeSvg.js.map +1 -0
- package/js/write_svg.es.js +3706 -0
- package/js/write_svg.es.js.map +1 -0
- package/js/write_svg.js +3708 -0
- package/js/write_svg.js.map +1 -0
- package/package.json +22 -8
- package/types/pdfkit.d.ts +1160 -0
- package/types/write_svg.d.ts +76 -0
- package/js/pdfkit.es5.js +0 -6091
- package/js/pdfkit.es5.js.map +0 -1
- package/js/pdfkit.esnext.js +0 -5392
- package/js/pdfkit.esnext.js.map +0 -1
package/js/pdfkit.es.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import stream from 'stream';
|
|
2
2
|
import zlib from 'zlib';
|
|
3
|
-
import
|
|
3
|
+
import { concatBytes } from '@noble/hashes/utils';
|
|
4
|
+
import md5 from 'js-md5';
|
|
5
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
6
|
+
import { cbc, ecb } from '@noble/ciphers/aes';
|
|
4
7
|
import fs from 'fs';
|
|
5
8
|
import * as fontkit from 'fontkit';
|
|
6
9
|
import { EventEmitter } from 'events';
|
|
7
10
|
import LineBreaker from 'linebreak';
|
|
8
|
-
import exif from 'jpeg-exif';
|
|
9
11
|
import PNG from 'png-js';
|
|
10
12
|
|
|
11
13
|
class PDFAbstractReference {
|
|
@@ -363,6 +365,7 @@ class PDFPage {
|
|
|
363
365
|
this._options = options;
|
|
364
366
|
this.size = options.size || 'letter';
|
|
365
367
|
this.layout = options.layout || 'portrait';
|
|
368
|
+
this.userUnit = options.userUnit || 1.0;
|
|
366
369
|
const dimensions = Array.isArray(this.size) ? this.size : SIZES[this.size.toUpperCase()];
|
|
367
370
|
this.width = dimensions[this.layout === 'portrait' ? 0 : 1];
|
|
368
371
|
this.height = dimensions[this.layout === 'portrait' ? 1 : 0];
|
|
@@ -378,7 +381,8 @@ class PDFPage {
|
|
|
378
381
|
Parent: this.document._root.data.Pages,
|
|
379
382
|
MediaBox: [0, 0, this.width, this.height],
|
|
380
383
|
Contents: this.content,
|
|
381
|
-
Resources: this.resources
|
|
384
|
+
Resources: this.resources,
|
|
385
|
+
UserUnit: this.userUnit
|
|
382
386
|
});
|
|
383
387
|
this.markings = [];
|
|
384
388
|
}
|
|
@@ -434,6 +438,7 @@ class PDFPage {
|
|
|
434
438
|
for (let color of Object.values(this.document.spotColors)) {
|
|
435
439
|
this.resources.data.ColorSpace[color.id] = color;
|
|
436
440
|
}
|
|
441
|
+
this.document._writeSpaceToResources(this.resources);
|
|
437
442
|
this.resources.end();
|
|
438
443
|
return this.content.end();
|
|
439
444
|
}
|
|
@@ -451,6 +456,59 @@ class PDFNameTree extends PDFTree {
|
|
|
451
456
|
}
|
|
452
457
|
}
|
|
453
458
|
|
|
459
|
+
function md5Hash(data) {
|
|
460
|
+
return new Uint8Array(md5.arrayBuffer(data));
|
|
461
|
+
}
|
|
462
|
+
function md5Hex(data) {
|
|
463
|
+
return md5(data);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function sha256Hash(data) {
|
|
467
|
+
return sha256(data);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function aesCbcEncrypt(data, key, iv) {
|
|
471
|
+
let padding = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
|
|
472
|
+
return cbc(key, iv, {
|
|
473
|
+
disablePadding: !padding
|
|
474
|
+
}).encrypt(data);
|
|
475
|
+
}
|
|
476
|
+
function aesEcbEncrypt(data, key) {
|
|
477
|
+
return ecb(key, {
|
|
478
|
+
disablePadding: true
|
|
479
|
+
}).encrypt(data);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function rc4(data, key) {
|
|
483
|
+
const s = new Uint8Array(256);
|
|
484
|
+
for (let i = 0; i < 256; i++) {
|
|
485
|
+
s[i] = i;
|
|
486
|
+
}
|
|
487
|
+
let j = 0;
|
|
488
|
+
for (let i = 0; i < 256; i++) {
|
|
489
|
+
j = j + s[i] + key[i % key.length] & 0xff;
|
|
490
|
+
[s[i], s[j]] = [s[j], s[i]];
|
|
491
|
+
}
|
|
492
|
+
const output = new Uint8Array(data.length);
|
|
493
|
+
for (let i = 0, j = 0, k = 0; k < data.length; k++) {
|
|
494
|
+
i = i + 1 & 0xff;
|
|
495
|
+
j = j + s[i] & 0xff;
|
|
496
|
+
[s[i], s[j]] = [s[j], s[i]];
|
|
497
|
+
output[k] = data[k] ^ s[s[i] + s[j] & 0xff];
|
|
498
|
+
}
|
|
499
|
+
return output;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function randomBytes(length) {
|
|
503
|
+
const bytes = new Uint8Array(length);
|
|
504
|
+
if (globalThis.crypto?.getRandomValues) {
|
|
505
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
506
|
+
} else {
|
|
507
|
+
require('crypto').randomFillSync(bytes);
|
|
508
|
+
}
|
|
509
|
+
return bytes;
|
|
510
|
+
}
|
|
511
|
+
|
|
454
512
|
function inRange(value, rangeGroup) {
|
|
455
513
|
if (value < rangeGroup[0]) return false;
|
|
456
514
|
let startRange = 0;
|
|
@@ -551,10 +609,10 @@ class PDFSecurity {
|
|
|
551
609
|
}
|
|
552
610
|
infoStr += `${key}: ${info[key].valueOf()}\n`;
|
|
553
611
|
}
|
|
554
|
-
return
|
|
612
|
+
return Buffer.from(md5Hash(infoStr));
|
|
555
613
|
}
|
|
556
614
|
static generateRandomWordArray(bytes) {
|
|
557
|
-
return
|
|
615
|
+
return randomBytes(bytes);
|
|
558
616
|
}
|
|
559
617
|
static create(document) {
|
|
560
618
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -648,8 +706,8 @@ class PDFSecurity {
|
|
|
648
706
|
encDict.StrF = 'StdCF';
|
|
649
707
|
}
|
|
650
708
|
encDict.R = r;
|
|
651
|
-
encDict.O =
|
|
652
|
-
encDict.U =
|
|
709
|
+
encDict.O = Buffer.from(ownerPasswordEntry);
|
|
710
|
+
encDict.U = Buffer.from(userPasswordEntry);
|
|
653
711
|
encDict.P = permissions;
|
|
654
712
|
}
|
|
655
713
|
_setupEncryptionV5(encDict, options) {
|
|
@@ -659,10 +717,10 @@ class PDFSecurity {
|
|
|
659
717
|
const processedOwnerPassword = options.ownerPassword ? processPasswordR5(options.ownerPassword) : processedUserPassword;
|
|
660
718
|
this.encryptionKey = getEncryptionKeyR5(PDFSecurity.generateRandomWordArray);
|
|
661
719
|
const userPasswordEntry = getUserPasswordR5(processedUserPassword, PDFSecurity.generateRandomWordArray);
|
|
662
|
-
const userKeySalt =
|
|
720
|
+
const userKeySalt = userPasswordEntry.slice(40, 48);
|
|
663
721
|
const userEncryptionKeyEntry = getUserEncryptionKeyR5(processedUserPassword, userKeySalt, this.encryptionKey);
|
|
664
722
|
const ownerPasswordEntry = getOwnerPasswordR5(processedOwnerPassword, userPasswordEntry, PDFSecurity.generateRandomWordArray);
|
|
665
|
-
const ownerKeySalt =
|
|
723
|
+
const ownerKeySalt = ownerPasswordEntry.slice(40, 48);
|
|
666
724
|
const ownerEncryptionKeyEntry = getOwnerEncryptionKeyR5(processedOwnerPassword, ownerKeySalt, userPasswordEntry, this.encryptionKey);
|
|
667
725
|
const permsEntry = getEncryptedPermissionsR5(permissions, this.encryptionKey, PDFSecurity.generateRandomWordArray);
|
|
668
726
|
encDict.V = 5;
|
|
@@ -677,36 +735,37 @@ class PDFSecurity {
|
|
|
677
735
|
encDict.StmF = 'StdCF';
|
|
678
736
|
encDict.StrF = 'StdCF';
|
|
679
737
|
encDict.R = 5;
|
|
680
|
-
encDict.O =
|
|
681
|
-
encDict.OE =
|
|
682
|
-
encDict.U =
|
|
683
|
-
encDict.UE =
|
|
738
|
+
encDict.O = Buffer.from(ownerPasswordEntry);
|
|
739
|
+
encDict.OE = Buffer.from(ownerEncryptionKeyEntry);
|
|
740
|
+
encDict.U = Buffer.from(userPasswordEntry);
|
|
741
|
+
encDict.UE = Buffer.from(userEncryptionKeyEntry);
|
|
684
742
|
encDict.P = permissions;
|
|
685
|
-
encDict.Perms =
|
|
743
|
+
encDict.Perms = Buffer.from(permsEntry);
|
|
686
744
|
}
|
|
687
745
|
getEncryptFn(obj, gen) {
|
|
688
746
|
let digest;
|
|
689
747
|
if (this.version < 5) {
|
|
690
|
-
|
|
748
|
+
const suffix = new Uint8Array([obj & 0xff, obj >> 8 & 0xff, obj >> 16 & 0xff, gen & 0xff, gen >> 8 & 0xff]);
|
|
749
|
+
digest = concatBytes(this.encryptionKey, suffix);
|
|
691
750
|
}
|
|
692
751
|
if (this.version === 1 || this.version === 2) {
|
|
693
|
-
let key =
|
|
694
|
-
|
|
695
|
-
|
|
752
|
+
let key = md5Hash(digest);
|
|
753
|
+
const keyLen = Math.min(16, this.keyBits / 8 + 5);
|
|
754
|
+
key = key.slice(0, keyLen);
|
|
755
|
+
return buffer => Buffer.from(rc4(new Uint8Array(buffer), key));
|
|
696
756
|
}
|
|
697
757
|
let key;
|
|
698
758
|
if (this.version === 4) {
|
|
699
|
-
|
|
759
|
+
const saltMarker = new Uint8Array([0x73, 0x41, 0x6c, 0x54]);
|
|
760
|
+
key = md5Hash(concatBytes(digest, saltMarker));
|
|
700
761
|
} else {
|
|
701
762
|
key = this.encryptionKey;
|
|
702
763
|
}
|
|
703
764
|
const iv = PDFSecurity.generateRandomWordArray(16);
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
iv
|
|
765
|
+
return buffer => {
|
|
766
|
+
const encrypted = aesCbcEncrypt(new Uint8Array(buffer), key, iv, true);
|
|
767
|
+
return Buffer.from(concatBytes(iv, encrypted));
|
|
708
768
|
};
|
|
709
|
-
return buffer => wordArrayToBuffer(iv.clone().concat(CryptoJS.AES.encrypt(CryptoJS.lib.WordArray.create(buffer), key, options).ciphertext));
|
|
710
769
|
}
|
|
711
770
|
end() {
|
|
712
771
|
this.dictionary.end();
|
|
@@ -759,90 +818,98 @@ function getPermissionsR3() {
|
|
|
759
818
|
return permissions;
|
|
760
819
|
}
|
|
761
820
|
function getUserPasswordR2(encryptionKey) {
|
|
762
|
-
return
|
|
821
|
+
return rc4(processPasswordR2R3R4(), encryptionKey);
|
|
763
822
|
}
|
|
764
823
|
function getUserPasswordR3R4(documentId, encryptionKey) {
|
|
765
|
-
const key = encryptionKey.
|
|
766
|
-
let cipher =
|
|
824
|
+
const key = encryptionKey.slice();
|
|
825
|
+
let cipher = md5Hash(concatBytes(processPasswordR2R3R4(), new Uint8Array(documentId)));
|
|
767
826
|
for (let i = 0; i < 20; i++) {
|
|
768
|
-
const
|
|
769
|
-
for (let j = 0; j <
|
|
770
|
-
|
|
827
|
+
const xorKey = new Uint8Array(key.length);
|
|
828
|
+
for (let j = 0; j < key.length; j++) {
|
|
829
|
+
xorKey[j] = encryptionKey[j] ^ i;
|
|
771
830
|
}
|
|
772
|
-
cipher =
|
|
831
|
+
cipher = rc4(cipher, xorKey);
|
|
773
832
|
}
|
|
774
|
-
|
|
833
|
+
const result = new Uint8Array(32);
|
|
834
|
+
result.set(cipher);
|
|
835
|
+
return result;
|
|
775
836
|
}
|
|
776
837
|
function getOwnerPasswordR2R3R4(r, keyBits, paddedUserPassword, paddedOwnerPassword) {
|
|
777
838
|
let digest = paddedOwnerPassword;
|
|
778
839
|
let round = r >= 3 ? 51 : 1;
|
|
779
840
|
for (let i = 0; i < round; i++) {
|
|
780
|
-
digest =
|
|
841
|
+
digest = md5Hash(digest);
|
|
781
842
|
}
|
|
782
|
-
const
|
|
783
|
-
key
|
|
843
|
+
const keyLen = keyBits / 8;
|
|
844
|
+
let key = digest.slice(0, keyLen);
|
|
784
845
|
let cipher = paddedUserPassword;
|
|
785
846
|
round = r >= 3 ? 20 : 1;
|
|
786
847
|
for (let i = 0; i < round; i++) {
|
|
787
|
-
const
|
|
788
|
-
for (let j = 0; j <
|
|
789
|
-
|
|
848
|
+
const xorKey = new Uint8Array(keyLen);
|
|
849
|
+
for (let j = 0; j < keyLen; j++) {
|
|
850
|
+
xorKey[j] = key[j] ^ i;
|
|
790
851
|
}
|
|
791
|
-
cipher =
|
|
852
|
+
cipher = rc4(cipher, xorKey);
|
|
792
853
|
}
|
|
793
854
|
return cipher;
|
|
794
855
|
}
|
|
795
856
|
function getEncryptionKeyR2R3R4(r, keyBits, documentId, paddedUserPassword, ownerPasswordEntry, permissions) {
|
|
796
|
-
|
|
857
|
+
const permBytes = new Uint8Array([permissions & 0xff, permissions >> 8 & 0xff, permissions >> 16 & 0xff, permissions >> 24 & 0xff]);
|
|
858
|
+
let key = concatBytes(paddedUserPassword, ownerPasswordEntry, permBytes, new Uint8Array(documentId));
|
|
797
859
|
const round = r >= 3 ? 51 : 1;
|
|
860
|
+
const keyLen = keyBits / 8;
|
|
798
861
|
for (let i = 0; i < round; i++) {
|
|
799
|
-
key =
|
|
800
|
-
key
|
|
862
|
+
key = md5Hash(key);
|
|
863
|
+
key = key.slice(0, keyLen);
|
|
801
864
|
}
|
|
802
865
|
return key;
|
|
803
866
|
}
|
|
804
867
|
function getUserPasswordR5(processedUserPassword, generateRandomWordArray) {
|
|
805
868
|
const validationSalt = generateRandomWordArray(8);
|
|
806
869
|
const keySalt = generateRandomWordArray(8);
|
|
807
|
-
|
|
870
|
+
const hash = sha256Hash(concatBytes(processedUserPassword, validationSalt));
|
|
871
|
+
return concatBytes(hash, validationSalt, keySalt);
|
|
808
872
|
}
|
|
809
873
|
function getUserEncryptionKeyR5(processedUserPassword, userKeySalt, encryptionKey) {
|
|
810
|
-
const key =
|
|
811
|
-
const
|
|
812
|
-
|
|
813
|
-
padding: CryptoJS.pad.NoPadding,
|
|
814
|
-
iv: CryptoJS.lib.WordArray.create(null, 16)
|
|
815
|
-
};
|
|
816
|
-
return CryptoJS.AES.encrypt(encryptionKey, key, options).ciphertext;
|
|
874
|
+
const key = sha256Hash(concatBytes(processedUserPassword, userKeySalt));
|
|
875
|
+
const iv = new Uint8Array(16);
|
|
876
|
+
return aesCbcEncrypt(encryptionKey, key, iv, false);
|
|
817
877
|
}
|
|
818
878
|
function getOwnerPasswordR5(processedOwnerPassword, userPasswordEntry, generateRandomWordArray) {
|
|
819
879
|
const validationSalt = generateRandomWordArray(8);
|
|
820
880
|
const keySalt = generateRandomWordArray(8);
|
|
821
|
-
|
|
881
|
+
const hash = sha256Hash(concatBytes(processedOwnerPassword, validationSalt, userPasswordEntry));
|
|
882
|
+
return concatBytes(hash, validationSalt, keySalt);
|
|
822
883
|
}
|
|
823
884
|
function getOwnerEncryptionKeyR5(processedOwnerPassword, ownerKeySalt, userPasswordEntry, encryptionKey) {
|
|
824
|
-
const key =
|
|
825
|
-
const
|
|
826
|
-
|
|
827
|
-
padding: CryptoJS.pad.NoPadding,
|
|
828
|
-
iv: CryptoJS.lib.WordArray.create(null, 16)
|
|
829
|
-
};
|
|
830
|
-
return CryptoJS.AES.encrypt(encryptionKey, key, options).ciphertext;
|
|
885
|
+
const key = sha256Hash(concatBytes(processedOwnerPassword, ownerKeySalt, userPasswordEntry));
|
|
886
|
+
const iv = new Uint8Array(16);
|
|
887
|
+
return aesCbcEncrypt(encryptionKey, key, iv, false);
|
|
831
888
|
}
|
|
832
889
|
function getEncryptionKeyR5(generateRandomWordArray) {
|
|
833
890
|
return generateRandomWordArray(32);
|
|
834
891
|
}
|
|
835
892
|
function getEncryptedPermissionsR5(permissions, encryptionKey, generateRandomWordArray) {
|
|
836
|
-
const
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
893
|
+
const data = new Uint8Array(16);
|
|
894
|
+
data[0] = permissions & 0xff;
|
|
895
|
+
data[1] = permissions >> 8 & 0xff;
|
|
896
|
+
data[2] = permissions >> 16 & 0xff;
|
|
897
|
+
data[3] = permissions >> 24 & 0xff;
|
|
898
|
+
data[4] = 0xff;
|
|
899
|
+
data[5] = 0xff;
|
|
900
|
+
data[6] = 0xff;
|
|
901
|
+
data[7] = 0xff;
|
|
902
|
+
data[8] = 0x54;
|
|
903
|
+
data[9] = 0x61;
|
|
904
|
+
data[10] = 0x64;
|
|
905
|
+
data[11] = 0x62;
|
|
906
|
+
const randomPart = generateRandomWordArray(4);
|
|
907
|
+
data.set(randomPart, 12);
|
|
908
|
+
return aesEcbEncrypt(data, encryptionKey);
|
|
842
909
|
}
|
|
843
910
|
function processPasswordR2R3R4() {
|
|
844
911
|
let password = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
845
|
-
const out =
|
|
912
|
+
const out = new Uint8Array(32);
|
|
846
913
|
const length = password.length;
|
|
847
914
|
let index = 0;
|
|
848
915
|
while (index < length && index < 32) {
|
|
@@ -857,27 +924,17 @@ function processPasswordR2R3R4() {
|
|
|
857
924
|
out[index] = PASSWORD_PADDING[index - length];
|
|
858
925
|
index++;
|
|
859
926
|
}
|
|
860
|
-
return
|
|
927
|
+
return out;
|
|
861
928
|
}
|
|
862
929
|
function processPasswordR5() {
|
|
863
930
|
let password = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
864
931
|
password = unescape(encodeURIComponent(saslprep(password)));
|
|
865
932
|
const length = Math.min(127, password.length);
|
|
866
|
-
const out =
|
|
933
|
+
const out = new Uint8Array(length);
|
|
867
934
|
for (let i = 0; i < length; i++) {
|
|
868
935
|
out[i] = password.charCodeAt(i);
|
|
869
936
|
}
|
|
870
|
-
return
|
|
871
|
-
}
|
|
872
|
-
function lsbFirstWord(data) {
|
|
873
|
-
return (data & 0xff) << 24 | (data & 0xff00) << 8 | data >> 8 & 0xff00 | data >> 24 & 0xff;
|
|
874
|
-
}
|
|
875
|
-
function wordArrayToBuffer(wordArray) {
|
|
876
|
-
const byteArray = [];
|
|
877
|
-
for (let i = 0; i < wordArray.sigBytes; i++) {
|
|
878
|
-
byteArray.push(wordArray.words[Math.floor(i / 4)] >> 8 * (3 - i % 4) & 0xff);
|
|
879
|
-
}
|
|
880
|
-
return Buffer.from(byteArray);
|
|
937
|
+
return out;
|
|
881
938
|
}
|
|
882
939
|
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];
|
|
883
940
|
|
|
@@ -897,14 +954,18 @@ class PDFGradient$1 {
|
|
|
897
954
|
}
|
|
898
955
|
color = this.doc._normalizeColor(color);
|
|
899
956
|
if (this.stops.length === 0) {
|
|
900
|
-
if (
|
|
901
|
-
this._colorSpace =
|
|
902
|
-
} else if (color.length === 4) {
|
|
903
|
-
this._colorSpace = 'DeviceCMYK';
|
|
904
|
-
} else if (color.length === 1) {
|
|
905
|
-
this._colorSpace = 'DeviceGray';
|
|
957
|
+
if (this._activeColorProfile) {
|
|
958
|
+
this._colorSpace = this._activeColorProfile.ref;
|
|
906
959
|
} else {
|
|
907
|
-
|
|
960
|
+
if (color.length === 3) {
|
|
961
|
+
this._colorSpace = 'DeviceRGB';
|
|
962
|
+
} else if (color.length === 4) {
|
|
963
|
+
this._colorSpace = 'DeviceCMYK';
|
|
964
|
+
} else if (color.length === 1) {
|
|
965
|
+
this._colorSpace = 'DeviceGray';
|
|
966
|
+
} else {
|
|
967
|
+
throw new Error('Unknown color space');
|
|
968
|
+
}
|
|
908
969
|
}
|
|
909
970
|
} else if (this._colorSpace === 'DeviceRGB' && color.length !== 3 || this._colorSpace === 'DeviceCMYK' && color.length !== 4 || this._colorSpace === 'DeviceGray' && color.length !== 1) {
|
|
910
971
|
throw new Error('All gradient stops must use the same color space');
|
|
@@ -1175,6 +1236,7 @@ var ColorMixin = {
|
|
|
1175
1236
|
this._opacityCount = 0;
|
|
1176
1237
|
this._patternCount = 0;
|
|
1177
1238
|
this._gradCount = 0;
|
|
1239
|
+
this._activeColorProfile = null;
|
|
1178
1240
|
},
|
|
1179
1241
|
_normalizeColor(color) {
|
|
1180
1242
|
if (typeof color === 'string') {
|
|
@@ -1234,6 +1296,13 @@ var ColorMixin = {
|
|
|
1234
1296
|
if (color instanceof SpotColor) {
|
|
1235
1297
|
return color.id;
|
|
1236
1298
|
}
|
|
1299
|
+
if (this._activeColorProfile) {
|
|
1300
|
+
const profile = this._activeColorProfile;
|
|
1301
|
+
if (profile.channels !== color.length) {
|
|
1302
|
+
throw Error("Profile channels don't match color channels");
|
|
1303
|
+
}
|
|
1304
|
+
return profile.label;
|
|
1305
|
+
}
|
|
1237
1306
|
return color.length === 4 ? 'DeviceCMYK' : 'DeviceRGB';
|
|
1238
1307
|
},
|
|
1239
1308
|
fillColor(color, opacity) {
|
|
@@ -1263,6 +1332,18 @@ var ColorMixin = {
|
|
|
1263
1332
|
this._doOpacity(null, opacity);
|
|
1264
1333
|
return this;
|
|
1265
1334
|
},
|
|
1335
|
+
beginColorSpace(label) {
|
|
1336
|
+
const profile = this._colorProfiles[label];
|
|
1337
|
+
if (!profile) {
|
|
1338
|
+
throw Error('Invalid color space label, the profile should be set first');
|
|
1339
|
+
}
|
|
1340
|
+
this._activeColorProfile = profile;
|
|
1341
|
+
return this;
|
|
1342
|
+
},
|
|
1343
|
+
endColorSpace() {
|
|
1344
|
+
this._activeColorProfile = null;
|
|
1345
|
+
return this;
|
|
1346
|
+
},
|
|
1266
1347
|
_doOpacity(fillOpacity, strokeOpacity) {
|
|
1267
1348
|
let dictionary, name;
|
|
1268
1349
|
if (fillOpacity == null && strokeOpacity == null) {
|
|
@@ -1485,86 +1566,176 @@ const parameters = {
|
|
|
1485
1566
|
Z: 0,
|
|
1486
1567
|
z: 0
|
|
1487
1568
|
};
|
|
1569
|
+
const isCommand = function (c) {
|
|
1570
|
+
return c in parameters;
|
|
1571
|
+
};
|
|
1572
|
+
const isWsp = function (c) {
|
|
1573
|
+
const codePoint = c.codePointAt(0);
|
|
1574
|
+
return codePoint === 0x20 || codePoint === 0x9 || codePoint === 0xd || codePoint === 0xa;
|
|
1575
|
+
};
|
|
1576
|
+
const isDigit = function (c) {
|
|
1577
|
+
const codePoint = c.codePointAt(0);
|
|
1578
|
+
if (codePoint == null) {
|
|
1579
|
+
return false;
|
|
1580
|
+
}
|
|
1581
|
+
return 48 <= codePoint && codePoint <= 57;
|
|
1582
|
+
};
|
|
1583
|
+
const readNumber = function (string, cursor) {
|
|
1584
|
+
let i = cursor;
|
|
1585
|
+
let value = '';
|
|
1586
|
+
let state = 'none';
|
|
1587
|
+
for (; i < string.length; i += 1) {
|
|
1588
|
+
const c = string[i];
|
|
1589
|
+
if (c === '+' || c === '-') {
|
|
1590
|
+
if (state === 'none') {
|
|
1591
|
+
state = 'sign';
|
|
1592
|
+
value += c;
|
|
1593
|
+
continue;
|
|
1594
|
+
}
|
|
1595
|
+
if (state === 'e') {
|
|
1596
|
+
state = 'exponent_sign';
|
|
1597
|
+
value += c;
|
|
1598
|
+
continue;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
if (isDigit(c)) {
|
|
1602
|
+
if (state === 'none' || state === 'sign' || state === 'whole') {
|
|
1603
|
+
state = 'whole';
|
|
1604
|
+
value += c;
|
|
1605
|
+
continue;
|
|
1606
|
+
}
|
|
1607
|
+
if (state === 'decimal_point' || state === 'decimal') {
|
|
1608
|
+
state = 'decimal';
|
|
1609
|
+
value += c;
|
|
1610
|
+
continue;
|
|
1611
|
+
}
|
|
1612
|
+
if (state === 'e' || state === 'exponent_sign' || state === 'exponent') {
|
|
1613
|
+
state = 'exponent';
|
|
1614
|
+
value += c;
|
|
1615
|
+
continue;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
if (c === '.') {
|
|
1619
|
+
if (state === 'none' || state === 'sign' || state === 'whole') {
|
|
1620
|
+
state = 'decimal_point';
|
|
1621
|
+
value += c;
|
|
1622
|
+
continue;
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
if (c === 'E' || c === 'e') {
|
|
1626
|
+
if (state === 'whole' || state === 'decimal_point' || state === 'decimal') {
|
|
1627
|
+
state = 'e';
|
|
1628
|
+
value += c;
|
|
1629
|
+
continue;
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
break;
|
|
1633
|
+
}
|
|
1634
|
+
const number = Number.parseFloat(value);
|
|
1635
|
+
if (Number.isNaN(number)) {
|
|
1636
|
+
return [cursor, null];
|
|
1637
|
+
}
|
|
1638
|
+
return [i - 1, number];
|
|
1639
|
+
};
|
|
1488
1640
|
const parse = function (path) {
|
|
1489
|
-
|
|
1490
|
-
|
|
1641
|
+
const pathData = [];
|
|
1642
|
+
let command = null;
|
|
1491
1643
|
let args = [];
|
|
1492
|
-
let
|
|
1493
|
-
let
|
|
1494
|
-
let
|
|
1495
|
-
for (let
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1644
|
+
let argsCount = 0;
|
|
1645
|
+
let canHaveComma = false;
|
|
1646
|
+
let hadComma = false;
|
|
1647
|
+
for (let i = 0; i < path.length; i += 1) {
|
|
1648
|
+
const c = path.charAt(i);
|
|
1649
|
+
if (isWsp(c)) {
|
|
1650
|
+
continue;
|
|
1651
|
+
}
|
|
1652
|
+
if (canHaveComma && c === ',') {
|
|
1653
|
+
if (hadComma) {
|
|
1654
|
+
break;
|
|
1655
|
+
}
|
|
1656
|
+
hadComma = true;
|
|
1657
|
+
continue;
|
|
1658
|
+
}
|
|
1659
|
+
if (isCommand(c)) {
|
|
1660
|
+
if (hadComma) {
|
|
1661
|
+
return pathData;
|
|
1662
|
+
}
|
|
1663
|
+
if (command == null) {
|
|
1664
|
+
if (c !== 'M' && c !== 'm') {
|
|
1665
|
+
return pathData;
|
|
1666
|
+
}
|
|
1667
|
+
} else {
|
|
1668
|
+
if (args.length !== 0) {
|
|
1669
|
+
return pathData;
|
|
1501
1670
|
}
|
|
1502
|
-
ret[ret.length] = {
|
|
1503
|
-
cmd,
|
|
1504
|
-
args
|
|
1505
|
-
};
|
|
1506
|
-
args = [];
|
|
1507
|
-
curArg = '';
|
|
1508
|
-
foundDecimal = false;
|
|
1509
|
-
}
|
|
1510
|
-
cmd = c;
|
|
1511
|
-
} else if ([' ', ','].includes(c) || c === '-' && curArg.length > 0 && curArg[curArg.length - 1] !== 'e' || c === '.' && foundDecimal) {
|
|
1512
|
-
if (curArg.length === 0) {
|
|
1513
|
-
continue;
|
|
1514
1671
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1672
|
+
command = c;
|
|
1673
|
+
args = [];
|
|
1674
|
+
argsCount = parameters[command];
|
|
1675
|
+
canHaveComma = false;
|
|
1676
|
+
if (argsCount === 0) {
|
|
1677
|
+
pathData.push({
|
|
1678
|
+
command,
|
|
1518
1679
|
args
|
|
1519
|
-
};
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1680
|
+
});
|
|
1681
|
+
}
|
|
1682
|
+
continue;
|
|
1683
|
+
}
|
|
1684
|
+
if (command == null) {
|
|
1685
|
+
return pathData;
|
|
1686
|
+
}
|
|
1687
|
+
let newCursor = i;
|
|
1688
|
+
let number = null;
|
|
1689
|
+
if (command === 'A' || command === 'a') {
|
|
1690
|
+
const position = args.length;
|
|
1691
|
+
if (position === 0 || position === 1) {
|
|
1692
|
+
if (c !== '+' && c !== '-') {
|
|
1693
|
+
[newCursor, number] = readNumber(path, i);
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
if (position === 2 || position === 5 || position === 6) {
|
|
1697
|
+
[newCursor, number] = readNumber(path, i);
|
|
1698
|
+
}
|
|
1699
|
+
if (position === 3 || position === 4) {
|
|
1700
|
+
if (c === '0') {
|
|
1701
|
+
number = 0;
|
|
1523
1702
|
}
|
|
1524
|
-
if (
|
|
1525
|
-
|
|
1703
|
+
if (c === '1') {
|
|
1704
|
+
number = 1;
|
|
1526
1705
|
}
|
|
1527
|
-
} else {
|
|
1528
|
-
args[args.length] = +curArg;
|
|
1529
1706
|
}
|
|
1530
|
-
foundDecimal = c === '.';
|
|
1531
|
-
curArg = ['-', '.'].includes(c) ? c : '';
|
|
1532
1707
|
} else {
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
}
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1708
|
+
[newCursor, number] = readNumber(path, i);
|
|
1709
|
+
}
|
|
1710
|
+
if (number == null) {
|
|
1711
|
+
return pathData;
|
|
1712
|
+
}
|
|
1713
|
+
args.push(number);
|
|
1714
|
+
canHaveComma = true;
|
|
1715
|
+
hadComma = false;
|
|
1716
|
+
i = newCursor;
|
|
1717
|
+
if (args.length === argsCount) {
|
|
1718
|
+
pathData.push({
|
|
1719
|
+
command,
|
|
1543
1720
|
args
|
|
1544
|
-
};
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
cmd = 'L';
|
|
1721
|
+
});
|
|
1722
|
+
if (command === 'M') {
|
|
1723
|
+
command = 'L';
|
|
1548
1724
|
}
|
|
1549
|
-
if (
|
|
1550
|
-
|
|
1725
|
+
if (command === 'm') {
|
|
1726
|
+
command = 'l';
|
|
1551
1727
|
}
|
|
1552
|
-
|
|
1553
|
-
args[args.length] = +curArg;
|
|
1728
|
+
args = [];
|
|
1554
1729
|
}
|
|
1555
1730
|
}
|
|
1556
|
-
|
|
1557
|
-
cmd,
|
|
1558
|
-
args
|
|
1559
|
-
};
|
|
1560
|
-
return ret;
|
|
1731
|
+
return pathData;
|
|
1561
1732
|
};
|
|
1562
1733
|
const apply = function (commands, doc) {
|
|
1563
1734
|
cx = cy = px = py = sx = sy = 0;
|
|
1564
1735
|
for (let i = 0; i < commands.length; i++) {
|
|
1565
1736
|
const c = commands[i];
|
|
1566
|
-
if (typeof runners[c.
|
|
1567
|
-
runners[c.
|
|
1737
|
+
if (typeof runners[c.command] === 'function') {
|
|
1738
|
+
runners[c.command](doc, c.args);
|
|
1568
1739
|
}
|
|
1569
1740
|
}
|
|
1570
1741
|
};
|
|
@@ -2603,7 +2774,7 @@ begincmap
|
|
|
2603
2774
|
1 begincodespacerange
|
|
2604
2775
|
<0000><ffff>
|
|
2605
2776
|
endcodespacerange
|
|
2606
|
-
|
|
2777
|
+
${ranges.length} beginbfrange
|
|
2607
2778
|
${ranges.join('\n')}
|
|
2608
2779
|
endbfrange
|
|
2609
2780
|
endcmap
|
|
@@ -2788,6 +2959,7 @@ class LineWrapper extends EventEmitter {
|
|
|
2788
2959
|
this.document = document;
|
|
2789
2960
|
this.horizontalScaling = options.horizontalScaling || 100;
|
|
2790
2961
|
this.indent = (options.indent || 0) * this.horizontalScaling / 100;
|
|
2962
|
+
this.indentAllLines = options.indentAllLines || false;
|
|
2791
2963
|
this.characterSpacing = (options.characterSpacing || 0) * this.horizontalScaling / 100;
|
|
2792
2964
|
this.wordSpacing = (options.wordSpacing === 0) * this.horizontalScaling / 100;
|
|
2793
2965
|
this.columns = options.columns || 1;
|
|
@@ -3029,7 +3201,13 @@ class LineWrapper extends EventEmitter {
|
|
|
3029
3201
|
this.column = 1;
|
|
3030
3202
|
this.startY = this.document.page.margins.top;
|
|
3031
3203
|
this.maxY = this.document.page.maxY();
|
|
3032
|
-
this.
|
|
3204
|
+
if (this.indentAllLines) {
|
|
3205
|
+
const indent = this.continuedX || this.indent;
|
|
3206
|
+
this.document.x += indent;
|
|
3207
|
+
this.lineWidth -= indent;
|
|
3208
|
+
} else {
|
|
3209
|
+
this.document.x = this.startX;
|
|
3210
|
+
}
|
|
3033
3211
|
if (this.document._fillColor) {
|
|
3034
3212
|
this.document.fillColor(...this.document._fillColor);
|
|
3035
3213
|
}
|
|
@@ -3439,7 +3617,11 @@ var TextMixin = {
|
|
|
3439
3617
|
}
|
|
3440
3618
|
const renderedWidth = options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1);
|
|
3441
3619
|
if (options.link != null) {
|
|
3442
|
-
|
|
3620
|
+
const linkOptions = {};
|
|
3621
|
+
if (this._currentStructureElement && this._currentStructureElement.dictionary.data.S === 'Link') {
|
|
3622
|
+
linkOptions.structParent = this._currentStructureElement;
|
|
3623
|
+
}
|
|
3624
|
+
this.link(x, y, renderedWidth, this.currentLineHeight(), options.link, linkOptions);
|
|
3443
3625
|
}
|
|
3444
3626
|
if (options.goTo != null) {
|
|
3445
3627
|
this.goTo(x, y, renderedWidth, this.currentLineHeight(), options.goTo);
|
|
@@ -3568,6 +3750,47 @@ var TextMixin = {
|
|
|
3568
3750
|
}
|
|
3569
3751
|
};
|
|
3570
3752
|
|
|
3753
|
+
const parseExifOrientation = data => {
|
|
3754
|
+
if (!data || data.length < 20) return null;
|
|
3755
|
+
let pos = 2;
|
|
3756
|
+
while (pos < data.length - 4) {
|
|
3757
|
+
while (pos < data.length && data[pos] !== 0xff) pos++;
|
|
3758
|
+
if (pos >= data.length - 4) return null;
|
|
3759
|
+
const marker = data.readUInt16BE(pos);
|
|
3760
|
+
pos += 2;
|
|
3761
|
+
if (marker === 0xffda) return null;
|
|
3762
|
+
if (marker >= 0xffd0 && marker <= 0xffd9 || marker === 0xff01) continue;
|
|
3763
|
+
if (pos + 2 > data.length) return null;
|
|
3764
|
+
const segmentLength = data.readUInt16BE(pos);
|
|
3765
|
+
if (marker === 0xffe1 && pos + 8 <= data.length) {
|
|
3766
|
+
const exifHeader = data.subarray(pos + 2, pos + 8).toString('binary');
|
|
3767
|
+
if (exifHeader === 'Exif\x00\x00') {
|
|
3768
|
+
const tiffStart = pos + 8;
|
|
3769
|
+
if (tiffStart + 8 > data.length) return null;
|
|
3770
|
+
const byteOrder = data.subarray(tiffStart, tiffStart + 2).toString('ascii');
|
|
3771
|
+
const isLittleEndian = byteOrder === 'II';
|
|
3772
|
+
if (!isLittleEndian && byteOrder !== 'MM') return null;
|
|
3773
|
+
const read16 = isLittleEndian ? o => data.readUInt16LE(o) : o => data.readUInt16BE(o);
|
|
3774
|
+
const read32 = isLittleEndian ? o => data.readUInt32LE(o) : o => data.readUInt32BE(o);
|
|
3775
|
+
if (read16(tiffStart + 2) !== 42) return null;
|
|
3776
|
+
const ifdPos = tiffStart + read32(tiffStart + 4);
|
|
3777
|
+
if (ifdPos + 2 > data.length) return null;
|
|
3778
|
+
const entryCount = read16(ifdPos);
|
|
3779
|
+
for (let i = 0; i < entryCount; i++) {
|
|
3780
|
+
const entryPos = ifdPos + 2 + i * 12;
|
|
3781
|
+
if (entryPos + 12 > data.length) return null;
|
|
3782
|
+
if (read16(entryPos) === 0x0112) {
|
|
3783
|
+
const value = read16(entryPos + 8);
|
|
3784
|
+
return value >= 1 && value <= 8 ? value : null;
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
return null;
|
|
3788
|
+
}
|
|
3789
|
+
}
|
|
3790
|
+
pos += segmentLength;
|
|
3791
|
+
}
|
|
3792
|
+
return null;
|
|
3793
|
+
};
|
|
3571
3794
|
const MARKERS = [0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc5, 0xffc6, 0xffc7, 0xffc8, 0xffc9, 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf];
|
|
3572
3795
|
const COLOR_SPACE_MAP = {
|
|
3573
3796
|
1: 'DeviceGray',
|
|
@@ -3582,9 +3805,11 @@ class JPEG {
|
|
|
3582
3805
|
if (this.data.readUInt16BE(0) !== 0xffd8) {
|
|
3583
3806
|
throw 'SOI not found in JPEG';
|
|
3584
3807
|
}
|
|
3585
|
-
this.orientation =
|
|
3808
|
+
this.orientation = parseExifOrientation(this.data) || 1;
|
|
3586
3809
|
let pos = 2;
|
|
3587
3810
|
while (pos < this.data.length) {
|
|
3811
|
+
while (pos < this.data.length && this.data[pos] !== 0xff) pos++;
|
|
3812
|
+
if (pos >= this.data.length) break;
|
|
3588
3813
|
marker = this.data.readUInt16BE(pos);
|
|
3589
3814
|
pos += 2;
|
|
3590
3815
|
if (MARKERS.includes(marker)) {
|
|
@@ -3736,12 +3961,16 @@ class PNGImage {
|
|
|
3736
3961
|
}
|
|
3737
3962
|
loadIndexedAlphaChannel() {
|
|
3738
3963
|
const transparency = this.image.transparency.indexed;
|
|
3964
|
+
const isInterlaced = this.image.interlaceMethod === 1;
|
|
3739
3965
|
return this.image.decodePixels(pixels => {
|
|
3740
3966
|
const alphaChannel = Buffer.alloc(this.width * this.height);
|
|
3741
3967
|
let i = 0;
|
|
3742
3968
|
for (let j = 0, end = pixels.length; j < end; j++) {
|
|
3743
3969
|
alphaChannel[i++] = transparency[pixels[j]];
|
|
3744
3970
|
}
|
|
3971
|
+
if (isInterlaced) {
|
|
3972
|
+
this.imgData = zlib.deflateSync(Buffer.from(pixels));
|
|
3973
|
+
}
|
|
3745
3974
|
this.alphaChannel = zlib.deflateSync(alphaChannel);
|
|
3746
3975
|
return this.finalize();
|
|
3747
3976
|
});
|
|
@@ -3754,16 +3983,108 @@ class PNGImage {
|
|
|
3754
3983
|
}
|
|
3755
3984
|
}
|
|
3756
3985
|
|
|
3986
|
+
class BitmapImage {
|
|
3987
|
+
constructor(data, label, properties) {
|
|
3988
|
+
this.label = label;
|
|
3989
|
+
this.data = data;
|
|
3990
|
+
this.width = properties.width;
|
|
3991
|
+
this.height = properties.height;
|
|
3992
|
+
this.channels = properties.channels;
|
|
3993
|
+
this.colorSpace = properties.colorSpace;
|
|
3994
|
+
this.hasAlphaChannel = properties.hasAlphaChannel;
|
|
3995
|
+
this.obj = null;
|
|
3996
|
+
}
|
|
3997
|
+
embed(document) {
|
|
3998
|
+
if (this.obj) {
|
|
3999
|
+
return;
|
|
4000
|
+
}
|
|
4001
|
+
this.document = document;
|
|
4002
|
+
if (!(this.data instanceof Uint8Array && this.data.length === this.channels * this.width * this.height)) {
|
|
4003
|
+
throw Error("Invalid bitmap, data doesn't match the given properties.");
|
|
4004
|
+
}
|
|
4005
|
+
if (this.colorSpace) {
|
|
4006
|
+
const profile = this.document._colorProfiles[this.colorSpace];
|
|
4007
|
+
if (!profile) {
|
|
4008
|
+
throw Error("PDFDocument doesn't support bitmap color space.");
|
|
4009
|
+
}
|
|
4010
|
+
const channels = this.hasAlphaChannel ? this.channels - 1 : this.channels;
|
|
4011
|
+
if (profile.channels !== channels) {
|
|
4012
|
+
throw Error("Color profile doesn't support image channels");
|
|
4013
|
+
}
|
|
4014
|
+
this.colorSpace = profile.ref;
|
|
4015
|
+
} else {
|
|
4016
|
+
if (!this.hasAlphaChannel) {
|
|
4017
|
+
this.colorSpace = this.channels === 4 ? 'DeviceCMYK' : 'DeviceRGB';
|
|
4018
|
+
} else {
|
|
4019
|
+
this.colorSpace = this.channels === 5 ? 'DeviceCMYK' : 'DeviceRGB';
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
let pixelData = this.data;
|
|
4023
|
+
let alphaData = undefined;
|
|
4024
|
+
if (this.hasAlphaChannel) {
|
|
4025
|
+
const pixelChannels = this.channels - 1;
|
|
4026
|
+
pixelData = new Uint8Array(pixelChannels * this.width * this.height);
|
|
4027
|
+
alphaData = new Uint8Array(this.width * this.height);
|
|
4028
|
+
if (this.channels === 4) {
|
|
4029
|
+
for (let src = 0, dst = 0, a = 0; a < this.data.length; src += 4, dst += 3, a++) {
|
|
4030
|
+
pixelData[dst] = this.data[src];
|
|
4031
|
+
pixelData[dst + 1] = this.data[src + 1];
|
|
4032
|
+
pixelData[dst + 2] = this.data[src + 2];
|
|
4033
|
+
alphaData[a] = this.data[src + 3];
|
|
4034
|
+
}
|
|
4035
|
+
} else if (this.channels === 5) {
|
|
4036
|
+
for (let src = 0, dst = 0, a = 0; a < this.data.length; src += 5, dst += 4, a++) {
|
|
4037
|
+
pixelData[dst] = this.data[src];
|
|
4038
|
+
pixelData[dst + 1] = this.data[src + 1];
|
|
4039
|
+
pixelData[dst + 2] = this.data[src + 2];
|
|
4040
|
+
pixelData[dst + 3] = this.data[src + 3];
|
|
4041
|
+
alphaData[a] = this.data[src + 4];
|
|
4042
|
+
}
|
|
4043
|
+
} else {
|
|
4044
|
+
for (let src = 0, dst = 0, a = 0; a < this.data.length; src += this.channels, dst += pixelChannels, a++) {
|
|
4045
|
+
for (let j = 0; j < pixelChannels; j++) {
|
|
4046
|
+
pixelData[dst + j] = this.data[src + j];
|
|
4047
|
+
}
|
|
4048
|
+
alphaData[a] = this.data[src + pixelChannels];
|
|
4049
|
+
}
|
|
4050
|
+
}
|
|
4051
|
+
}
|
|
4052
|
+
this.obj = this.document.ref({
|
|
4053
|
+
Type: 'XObject',
|
|
4054
|
+
Subtype: 'Image',
|
|
4055
|
+
BitsPerComponent: 8,
|
|
4056
|
+
Width: this.width,
|
|
4057
|
+
Height: this.height,
|
|
4058
|
+
ColorSpace: this.colorSpace
|
|
4059
|
+
});
|
|
4060
|
+
if (alphaData) {
|
|
4061
|
+
const sMask = this.document.ref({
|
|
4062
|
+
Type: 'XObject',
|
|
4063
|
+
Subtype: 'Image',
|
|
4064
|
+
Height: this.height,
|
|
4065
|
+
Width: this.width,
|
|
4066
|
+
BitsPerComponent: 8,
|
|
4067
|
+
ColorSpace: 'DeviceGray',
|
|
4068
|
+
Decode: [0, 1]
|
|
4069
|
+
});
|
|
4070
|
+
sMask.end(alphaData);
|
|
4071
|
+
this.obj.data['SMask'] = sMask;
|
|
4072
|
+
}
|
|
4073
|
+
this.obj.end(pixelData);
|
|
4074
|
+
this.data = null;
|
|
4075
|
+
}
|
|
4076
|
+
}
|
|
4077
|
+
|
|
3757
4078
|
class PDFImage {
|
|
3758
|
-
static open(src, label) {
|
|
4079
|
+
static open(src, label, properties) {
|
|
3759
4080
|
let data;
|
|
3760
|
-
if (Buffer.isBuffer(src)) {
|
|
4081
|
+
if (src instanceof Uint8Array || Buffer.isBuffer(src)) {
|
|
3761
4082
|
data = src;
|
|
3762
4083
|
} else if (src instanceof ArrayBuffer) {
|
|
3763
4084
|
data = Buffer.from(new Uint8Array(src));
|
|
3764
4085
|
} else {
|
|
3765
4086
|
const split = src.split(',');
|
|
3766
|
-
if (split[0].startsWith('data:') && split[0].endsWith(';base64
|
|
4087
|
+
if (split[0].startsWith('data:') && split[0].endsWith(';base64')) {
|
|
3767
4088
|
if (split.length === 1) {
|
|
3768
4089
|
throw Error('Empty base64');
|
|
3769
4090
|
}
|
|
@@ -3775,6 +4096,9 @@ class PDFImage {
|
|
|
3775
4096
|
}
|
|
3776
4097
|
}
|
|
3777
4098
|
}
|
|
4099
|
+
if (properties?.isBitmap) {
|
|
4100
|
+
return new BitmapImage(data, label, properties);
|
|
4101
|
+
}
|
|
3778
4102
|
if (data[0] === 0xff && data[1] === 0xd8) {
|
|
3779
4103
|
return new JPEG(data, label);
|
|
3780
4104
|
} else if (data[0] === 0x89 && data.toString('ascii', 1, 4) === 'PNG') {
|
|
@@ -3959,13 +4283,13 @@ var ImagesMixin = {
|
|
|
3959
4283
|
this.restore();
|
|
3960
4284
|
return this;
|
|
3961
4285
|
},
|
|
3962
|
-
openImage(src) {
|
|
4286
|
+
openImage(src, properties) {
|
|
3963
4287
|
let image;
|
|
3964
4288
|
if (typeof src === 'string') {
|
|
3965
4289
|
image = this._imageRegistry[src];
|
|
3966
4290
|
}
|
|
3967
4291
|
if (!image) {
|
|
3968
|
-
image = PDFImage.open(src, `I${++this._imageCount}
|
|
4292
|
+
image = PDFImage.open(src, `I${++this._imageCount}`, properties);
|
|
3969
4293
|
if (typeof src === 'string') {
|
|
3970
4294
|
this._imageRegistry[src] = image;
|
|
3971
4295
|
}
|
|
@@ -3974,6 +4298,12 @@ var ImagesMixin = {
|
|
|
3974
4298
|
}
|
|
3975
4299
|
};
|
|
3976
4300
|
|
|
4301
|
+
class PDFAnnotationReference {
|
|
4302
|
+
constructor(annotationRef) {
|
|
4303
|
+
this.annotationRef = annotationRef;
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
|
|
3977
4307
|
var AnnotationsMixin = {
|
|
3978
4308
|
annotate(x, y, w, h, options) {
|
|
3979
4309
|
options.Type = 'Annot';
|
|
@@ -3991,12 +4321,18 @@ var AnnotationsMixin = {
|
|
|
3991
4321
|
if (typeof options.Dest === 'string') {
|
|
3992
4322
|
options.Dest = new String(options.Dest);
|
|
3993
4323
|
}
|
|
4324
|
+
const structParent = options.structParent;
|
|
4325
|
+
delete options.structParent;
|
|
3994
4326
|
for (let key in options) {
|
|
3995
4327
|
const val = options[key];
|
|
3996
4328
|
options[key[0].toUpperCase() + key.slice(1)] = val;
|
|
3997
4329
|
}
|
|
3998
4330
|
const ref = this.ref(options);
|
|
3999
4331
|
this.page.annotations.push(ref);
|
|
4332
|
+
if (structParent && typeof structParent.add === 'function') {
|
|
4333
|
+
const annotRef = new PDFAnnotationReference(ref);
|
|
4334
|
+
structParent.add(annotRef);
|
|
4335
|
+
}
|
|
4000
4336
|
ref.end();
|
|
4001
4337
|
return this;
|
|
4002
4338
|
},
|
|
@@ -4043,6 +4379,9 @@ var AnnotationsMixin = {
|
|
|
4043
4379
|
});
|
|
4044
4380
|
options.A.end();
|
|
4045
4381
|
}
|
|
4382
|
+
if (options.structParent && !options.Contents) {
|
|
4383
|
+
options.Contents = new String('');
|
|
4384
|
+
}
|
|
4046
4385
|
return this.annotate(x, y, w, h, options);
|
|
4047
4386
|
},
|
|
4048
4387
|
_markup(x, y, w, h) {
|
|
@@ -4124,16 +4463,27 @@ var AnnotationsMixin = {
|
|
|
4124
4463
|
}
|
|
4125
4464
|
};
|
|
4126
4465
|
|
|
4466
|
+
const DEFAULT_OPTIONS = {
|
|
4467
|
+
top: 0,
|
|
4468
|
+
left: 0,
|
|
4469
|
+
zoom: 0,
|
|
4470
|
+
fit: true,
|
|
4471
|
+
pageNumber: null,
|
|
4472
|
+
expanded: false
|
|
4473
|
+
};
|
|
4127
4474
|
class PDFOutline {
|
|
4128
4475
|
constructor(document, parent, title, dest) {
|
|
4129
|
-
let options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] :
|
|
4130
|
-
expanded: false
|
|
4131
|
-
};
|
|
4476
|
+
let options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : DEFAULT_OPTIONS;
|
|
4132
4477
|
this.document = document;
|
|
4133
4478
|
this.options = options;
|
|
4134
4479
|
this.outlineData = {};
|
|
4135
4480
|
if (dest !== null) {
|
|
4136
|
-
|
|
4481
|
+
const destWidth = dest.data.MediaBox[2];
|
|
4482
|
+
const destHeight = dest.data.MediaBox[3];
|
|
4483
|
+
const top = destHeight - (options.top || 0);
|
|
4484
|
+
const left = destWidth - (options.left || 0);
|
|
4485
|
+
const zoom = options.zoom || 0;
|
|
4486
|
+
this.outlineData['Dest'] = options.fit ? [dest, 'Fit'] : [dest, 'XYZ', left, top, zoom];
|
|
4137
4487
|
}
|
|
4138
4488
|
if (parent !== null) {
|
|
4139
4489
|
this.outlineData['Parent'] = parent;
|
|
@@ -4145,10 +4495,10 @@ class PDFOutline {
|
|
|
4145
4495
|
this.children = [];
|
|
4146
4496
|
}
|
|
4147
4497
|
addItem(title) {
|
|
4148
|
-
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] :
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
const result = new PDFOutline(this.document, this.dictionary, title,
|
|
4498
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_OPTIONS;
|
|
4499
|
+
const pages = this.document._root.data.Pages.data.Kids;
|
|
4500
|
+
const dest = options.pageNumber != null ? pages[options.pageNumber] : this.document.page.dictionary;
|
|
4501
|
+
const result = new PDFOutline(this.document, this.dictionary, title, dest, options);
|
|
4152
4502
|
this.children.push(result);
|
|
4153
4503
|
return result;
|
|
4154
4504
|
}
|
|
@@ -4184,7 +4534,7 @@ var OutlineMixin = {
|
|
|
4184
4534
|
this.outline.endOutline();
|
|
4185
4535
|
if (this.outline.children.length > 0) {
|
|
4186
4536
|
this._root.data.Outlines = this.outline.dictionary;
|
|
4187
|
-
return this._root.data.PageMode = 'UseOutlines';
|
|
4537
|
+
return this._root.data.PageMode = this._root.data.PageMode || 'UseOutlines';
|
|
4188
4538
|
}
|
|
4189
4539
|
}
|
|
4190
4540
|
};
|
|
@@ -4257,6 +4607,9 @@ class PDFStructureElement {
|
|
|
4257
4607
|
if (child instanceof PDFStructureContent) {
|
|
4258
4608
|
this._addContentToParentTree(child);
|
|
4259
4609
|
}
|
|
4610
|
+
if (child instanceof PDFAnnotationReference) {
|
|
4611
|
+
this._addAnnotationToParentTree(child.annotationRef);
|
|
4612
|
+
}
|
|
4260
4613
|
if (typeof child === 'function' && this._attached) {
|
|
4261
4614
|
child = this._contentForClosure(child);
|
|
4262
4615
|
}
|
|
@@ -4273,6 +4626,12 @@ class PDFStructureElement {
|
|
|
4273
4626
|
pageStructParents[mcid] = this.dictionary;
|
|
4274
4627
|
});
|
|
4275
4628
|
}
|
|
4629
|
+
_addAnnotationToParentTree(annotRef) {
|
|
4630
|
+
const parentTreeKey = this.document.createStructParentTreeNextKey();
|
|
4631
|
+
annotRef.data.StructParent = parentTreeKey;
|
|
4632
|
+
const parentTree = this.document.getStructParentTree();
|
|
4633
|
+
parentTree.add(parentTreeKey, this.dictionary);
|
|
4634
|
+
}
|
|
4276
4635
|
setParent(parentRef) {
|
|
4277
4636
|
if (this.dictionary.data.P) {
|
|
4278
4637
|
throw new Error(`Structure element added to more than one parent`);
|
|
@@ -4304,11 +4663,17 @@ class PDFStructureElement {
|
|
|
4304
4663
|
this._flush();
|
|
4305
4664
|
}
|
|
4306
4665
|
_isValidChild(child) {
|
|
4307
|
-
return child instanceof PDFStructureElement || child instanceof PDFStructureContent || typeof child === 'function';
|
|
4666
|
+
return child instanceof PDFStructureElement || child instanceof PDFStructureContent || child instanceof PDFAnnotationReference || typeof child === 'function';
|
|
4308
4667
|
}
|
|
4309
4668
|
_contentForClosure(closure) {
|
|
4310
4669
|
const content = this.document.markStructureContent(this.dictionary.data.S);
|
|
4670
|
+
const prevStructElement = this.document._currentStructureElement;
|
|
4671
|
+
this.document._currentStructureElement = this;
|
|
4672
|
+
const wasEnded = this._ended;
|
|
4673
|
+
this._ended = false;
|
|
4311
4674
|
closure();
|
|
4675
|
+
this._ended = wasEnded;
|
|
4676
|
+
this.document._currentStructureElement = prevStructElement;
|
|
4312
4677
|
this.document.endMarkedContent();
|
|
4313
4678
|
this._addContentToParentTree(content);
|
|
4314
4679
|
return content;
|
|
@@ -4362,6 +4727,15 @@ class PDFStructureElement {
|
|
|
4362
4727
|
}
|
|
4363
4728
|
});
|
|
4364
4729
|
}
|
|
4730
|
+
if (child instanceof PDFAnnotationReference) {
|
|
4731
|
+
const pageRef = this.document.page.dictionary;
|
|
4732
|
+
const objr = {
|
|
4733
|
+
Type: 'OBJR',
|
|
4734
|
+
Obj: child.annotationRef,
|
|
4735
|
+
Pg: pageRef
|
|
4736
|
+
};
|
|
4737
|
+
this.dictionary.data.K.push(objr);
|
|
4738
|
+
}
|
|
4365
4739
|
}
|
|
4366
4740
|
}
|
|
4367
4741
|
|
|
@@ -4457,6 +4831,13 @@ var MarkingsMixin = {
|
|
|
4457
4831
|
endMarkedContent() {
|
|
4458
4832
|
this.page.markings.pop();
|
|
4459
4833
|
this.addContent('EMC');
|
|
4834
|
+
if (this._textOptions) {
|
|
4835
|
+
delete this._textOptions.link;
|
|
4836
|
+
delete this._textOptions.goTo;
|
|
4837
|
+
delete this._textOptions.destination;
|
|
4838
|
+
delete this._textOptions.underline;
|
|
4839
|
+
delete this._textOptions.strike;
|
|
4840
|
+
}
|
|
4460
4841
|
return this;
|
|
4461
4842
|
},
|
|
4462
4843
|
struct(type) {
|
|
@@ -4915,7 +5296,7 @@ var AttachmentsMixin = {
|
|
|
4915
5296
|
if (options.type) {
|
|
4916
5297
|
refBody.Subtype = options.type.replace('/', '#2F');
|
|
4917
5298
|
}
|
|
4918
|
-
const checksum =
|
|
5299
|
+
const checksum = md5Hex(new Uint8Array(data));
|
|
4919
5300
|
refBody.Params.CheckSum = new String(checksum);
|
|
4920
5301
|
refBody.Params.Size = data.byteLength;
|
|
4921
5302
|
let ref;
|
|
@@ -4975,6 +5356,9 @@ var PDFA = {
|
|
|
4975
5356
|
this._addColorOutputIntent();
|
|
4976
5357
|
},
|
|
4977
5358
|
_addColorOutputIntent() {
|
|
5359
|
+
if (this._root.data.OutputIntents && this._root.data.OutputIntents.length !== 0) {
|
|
5360
|
+
return;
|
|
5361
|
+
}
|
|
4978
5362
|
const iccProfile = fs.readFileSync(`${__dirname}/data/sRGB_IEC61966_2_1.icc`);
|
|
4979
5363
|
const colorProfileRef = this.ref({
|
|
4980
5364
|
Length: iccProfile.length,
|
|
@@ -5567,7 +5951,7 @@ function renderRow(row, rowIndex) {
|
|
|
5567
5951
|
function renderCell(cell, rowStruct) {
|
|
5568
5952
|
const cellRenderer = () => {
|
|
5569
5953
|
if (cell.backgroundColor != null) {
|
|
5570
|
-
this.document.save().rect(cell.x, cell.y, cell.width, cell.height).fill(
|
|
5954
|
+
this.document.save().fillColor(cell.backgroundColor).rect(cell.x, cell.y, cell.width, cell.height).fill().restore();
|
|
5571
5955
|
}
|
|
5572
5956
|
renderBorder.call(this, cell.border, cell.borderColor, cell.x, cell.y, cell.width, cell.height);
|
|
5573
5957
|
if (cell.debug) {
|
|
@@ -5631,20 +6015,20 @@ function renderBorder(border, borderColor, x, y, width, height, mask) {
|
|
|
5631
6015
|
const doc = this.document;
|
|
5632
6016
|
if ([border.right, border.bottom, border.left].every(val => val === border.top)) {
|
|
5633
6017
|
if (border.top > 0) {
|
|
5634
|
-
doc.save().lineWidth(border.top).rect(x, y, width, height).stroke(
|
|
6018
|
+
doc.save().lineWidth(border.top).strokeColor(borderColor.top).rect(x, y, width, height).stroke().restore();
|
|
5635
6019
|
}
|
|
5636
6020
|
} else {
|
|
5637
6021
|
if (border.top > 0) {
|
|
5638
|
-
doc.save().lineWidth(border.top).moveTo(x, y).lineTo(x + width, y).stroke(
|
|
6022
|
+
doc.save().lineWidth(border.top).moveTo(x, y).strokeColor(borderColor.top).lineTo(x + width, y).stroke().restore();
|
|
5639
6023
|
}
|
|
5640
6024
|
if (border.right > 0) {
|
|
5641
|
-
doc.save().lineWidth(border.right).moveTo(x + width, y).lineTo(x + width, y + height).stroke(
|
|
6025
|
+
doc.save().lineWidth(border.right).moveTo(x + width, y).strokeColor(borderColor.right).lineTo(x + width, y + height).stroke().restore();
|
|
5642
6026
|
}
|
|
5643
6027
|
if (border.bottom > 0) {
|
|
5644
|
-
doc.save().lineWidth(border.bottom).moveTo(x + width, y + height).lineTo(x, y + height).stroke(
|
|
6028
|
+
doc.save().lineWidth(border.bottom).moveTo(x + width, y + height).strokeColor(borderColor.bottom).lineTo(x, y + height).stroke().restore();
|
|
5645
6029
|
}
|
|
5646
6030
|
if (border.left > 0) {
|
|
5647
|
-
doc.save().lineWidth(border.left).moveTo(x, y + height).lineTo(x, y).stroke(
|
|
6031
|
+
doc.save().lineWidth(border.left).moveTo(x, y + height).strokeColor(borderColor.left).lineTo(x, y).stroke().restore();
|
|
5648
6032
|
}
|
|
5649
6033
|
}
|
|
5650
6034
|
}
|
|
@@ -5810,6 +6194,73 @@ var MetadataMixin = {
|
|
|
5810
6194
|
}
|
|
5811
6195
|
};
|
|
5812
6196
|
|
|
6197
|
+
class ICCProfile {
|
|
6198
|
+
constructor(label, data, channels, alternate) {
|
|
6199
|
+
this.label = label;
|
|
6200
|
+
this.data = data;
|
|
6201
|
+
this.channels = channels;
|
|
6202
|
+
this.alternate = alternate;
|
|
6203
|
+
this.ref = null;
|
|
6204
|
+
this.streamRef = null;
|
|
6205
|
+
}
|
|
6206
|
+
embed(document) {
|
|
6207
|
+
if (this.ref) {
|
|
6208
|
+
return;
|
|
6209
|
+
}
|
|
6210
|
+
this.document = document;
|
|
6211
|
+
this.streamRef = this.document.ref({
|
|
6212
|
+
Alternate: this.alternate,
|
|
6213
|
+
N: this.channels,
|
|
6214
|
+
Length: this.data.length
|
|
6215
|
+
});
|
|
6216
|
+
this.streamRef.end(this.data);
|
|
6217
|
+
this.ref = this.document.ref([`ICCBased ${this.streamRef}`]);
|
|
6218
|
+
this.ref.end();
|
|
6219
|
+
this.data = null;
|
|
6220
|
+
}
|
|
6221
|
+
}
|
|
6222
|
+
|
|
6223
|
+
var ColorSpaceMixin = {
|
|
6224
|
+
initColorSpace() {
|
|
6225
|
+
this._colorProfiles = {};
|
|
6226
|
+
},
|
|
6227
|
+
iccProfile(label, data, channels, alternate) {
|
|
6228
|
+
const profile = new ICCProfile(label, data, channels, alternate);
|
|
6229
|
+
profile.embed(this);
|
|
6230
|
+
this._colorProfiles[label] = profile;
|
|
6231
|
+
return this;
|
|
6232
|
+
},
|
|
6233
|
+
_writeSpaceToResources(resources) {
|
|
6234
|
+
resources.data.ColorSpace = resources.data.ColorSpace || {};
|
|
6235
|
+
Object.entries(this._colorProfiles).forEach(_ref => {
|
|
6236
|
+
let [k, v] = _ref;
|
|
6237
|
+
resources.data.ColorSpace[k] = v.ref;
|
|
6238
|
+
});
|
|
6239
|
+
}
|
|
6240
|
+
};
|
|
6241
|
+
|
|
6242
|
+
var OutputIntent = {
|
|
6243
|
+
initOutputIntent() {
|
|
6244
|
+
this._root.data.OutputIntents = this._root.data.OutputIntents || [];
|
|
6245
|
+
},
|
|
6246
|
+
outputIntent(type, s, info, outputConditionIdentifier, destOutputProfileLabel) {
|
|
6247
|
+
const profile = this._colorProfiles[destOutputProfileLabel];
|
|
6248
|
+
if (profile) {
|
|
6249
|
+
throw Error('Invalid color profile label, the profile should be set first');
|
|
6250
|
+
}
|
|
6251
|
+
const intentRef = this.ref({
|
|
6252
|
+
Type: type,
|
|
6253
|
+
S: s,
|
|
6254
|
+
Info: info,
|
|
6255
|
+
OutputConditionIdentifier: outputConditionIdentifier,
|
|
6256
|
+
DestOutputProfile: profile.ref
|
|
6257
|
+
});
|
|
6258
|
+
intentRef.end();
|
|
6259
|
+
this._root.data.OutputIntents.push(intentRef);
|
|
6260
|
+
return this;
|
|
6261
|
+
}
|
|
6262
|
+
};
|
|
6263
|
+
|
|
5813
6264
|
class PDFDocument extends stream.Readable {
|
|
5814
6265
|
constructor() {
|
|
5815
6266
|
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -5856,8 +6307,13 @@ class PDFDocument extends stream.Readable {
|
|
|
5856
6307
|
if (this.options.lang) {
|
|
5857
6308
|
this._root.data.Lang = new String(this.options.lang);
|
|
5858
6309
|
}
|
|
6310
|
+
if (this.options.pageLayout) {
|
|
6311
|
+
const layout = this.options.pageLayout;
|
|
6312
|
+
this._root.data.PageLayout = layout.charAt(0).toUpperCase() + layout.slice(1);
|
|
6313
|
+
}
|
|
5859
6314
|
this.page = null;
|
|
5860
6315
|
this.initMetadata();
|
|
6316
|
+
this.initColorSpace();
|
|
5861
6317
|
this.initColor();
|
|
5862
6318
|
this.initVector();
|
|
5863
6319
|
this.initFonts(options.font);
|
|
@@ -5867,6 +6323,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5867
6323
|
this.initMarkings(options);
|
|
5868
6324
|
this.initTables();
|
|
5869
6325
|
this.initSubset(options);
|
|
6326
|
+
this.initOutputIntent();
|
|
5870
6327
|
this.info = {
|
|
5871
6328
|
Producer: 'PDFKit',
|
|
5872
6329
|
Creator: 'PDFKit',
|
|
@@ -6068,6 +6525,7 @@ const mixin = methods => {
|
|
|
6068
6525
|
Object.assign(PDFDocument.prototype, methods);
|
|
6069
6526
|
};
|
|
6070
6527
|
mixin(MetadataMixin);
|
|
6528
|
+
mixin(ColorSpaceMixin);
|
|
6071
6529
|
mixin(ColorMixin);
|
|
6072
6530
|
mixin(VectorMixin);
|
|
6073
6531
|
mixin(FontsMixin);
|
|
@@ -6080,6 +6538,7 @@ mixin(AcroFormMixin);
|
|
|
6080
6538
|
mixin(AttachmentsMixin);
|
|
6081
6539
|
mixin(SubsetMixin);
|
|
6082
6540
|
mixin(TableMixin);
|
|
6541
|
+
mixin(OutputIntent);
|
|
6083
6542
|
PDFDocument.LineWrapper = LineWrapper;
|
|
6084
6543
|
|
|
6085
6544
|
export { PDFDocument as default };
|