pdf-lite 1.4.0 → 1.6.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.
Files changed (144) hide show
  1. package/EXAMPLES.md +51 -70
  2. package/README.md +1 -1
  3. package/dist/acroform/appearance/index.d.ts +4 -4
  4. package/dist/acroform/appearance/index.js +4 -4
  5. package/dist/acroform/appearance/{PdfAppearanceStream.d.ts → pdf-appearance-stream.d.ts} +9 -3
  6. package/dist/acroform/appearance/{PdfAppearanceStream.js → pdf-appearance-stream.js} +14 -5
  7. package/dist/acroform/appearance/{PdfButtonAppearanceStream.d.ts → pdf-button-appearance-stream.d.ts} +3 -2
  8. package/dist/acroform/appearance/pdf-button-appearance-stream.js +58 -0
  9. package/dist/acroform/appearance/pdf-choice-appearance-stream.d.ts +22 -0
  10. package/dist/acroform/appearance/pdf-choice-appearance-stream.js +75 -0
  11. package/dist/acroform/appearance/pdf-graphics.d.ts +51 -0
  12. package/dist/acroform/appearance/pdf-graphics.js +239 -0
  13. package/dist/acroform/appearance/{PdfTextAppearanceStream.d.ts → pdf-text-appearance-stream.d.ts} +7 -2
  14. package/dist/acroform/appearance/pdf-text-appearance-stream.js +104 -0
  15. package/dist/acroform/fields/index.d.ts +7 -7
  16. package/dist/acroform/fields/index.js +7 -7
  17. package/dist/acroform/fields/pdf-button-form-field.d.ts +14 -0
  18. package/dist/acroform/fields/pdf-button-form-field.js +70 -0
  19. package/dist/acroform/fields/pdf-choice-form-field.d.ts +19 -0
  20. package/dist/acroform/fields/pdf-choice-form-field.js +112 -0
  21. package/dist/acroform/fields/{PdfFormFieldFlags.d.ts → pdf-form-field-flags.d.ts} +5 -6
  22. package/dist/acroform/fields/{PdfFormFieldFlags.js → pdf-form-field-flags.js} +12 -18
  23. package/dist/acroform/fields/{PdfFormField.d.ts → pdf-form-field.d.ts} +37 -38
  24. package/dist/acroform/fields/pdf-form-field.js +519 -0
  25. package/dist/acroform/fields/{PdfSignatureFormField.d.ts → pdf-signature-form-field.d.ts} +1 -1
  26. package/dist/acroform/fields/{PdfSignatureFormField.js → pdf-signature-form-field.js} +1 -1
  27. package/dist/acroform/fields/{PdfTextFormField.d.ts → pdf-text-form-field.d.ts} +1 -1
  28. package/dist/acroform/fields/{PdfTextFormField.js → pdf-text-form-field.js} +11 -13
  29. package/dist/acroform/fields/types.d.ts +6 -1
  30. package/dist/acroform/index.d.ts +1 -3
  31. package/dist/acroform/index.js +1 -3
  32. package/dist/acroform/pdf-acro-form.d.ts +45 -0
  33. package/dist/acroform/pdf-acro-form.js +203 -0
  34. package/dist/acroform/xfa/index.d.ts +3 -3
  35. package/dist/acroform/xfa/index.js +2 -2
  36. package/dist/acroform/xfa/{PdfXfaData.d.ts → pdf-xfa-data.d.ts} +4 -3
  37. package/dist/acroform/xfa/{PdfXfaData.js → pdf-xfa-data.js} +16 -12
  38. package/dist/acroform/xfa/pdf-xfa-form.d.ts +16 -0
  39. package/dist/acroform/xfa/pdf-xfa-form.js +34 -0
  40. package/dist/annotations/index.d.ts +3 -4
  41. package/dist/annotations/index.js +3 -4
  42. package/dist/annotations/{PdfAnnotationFlags.d.ts → pdf-annotation-flags.d.ts} +3 -4
  43. package/dist/annotations/{PdfAnnotationFlags.js → pdf-annotation-flags.js} +5 -6
  44. package/dist/annotations/{PdfAnnotation.d.ts → pdf-annotation.d.ts} +31 -5
  45. package/dist/annotations/{PdfAnnotation.js → pdf-annotation.js} +31 -19
  46. package/dist/annotations/pdf-default-resources.d.ts +11 -0
  47. package/dist/annotations/pdf-default-resources.js +3 -0
  48. package/dist/annotations/{PdfWidgetAnnotation.d.ts → pdf-widget-annotation.d.ts} +1 -1
  49. package/dist/annotations/{PdfWidgetAnnotation.js → pdf-widget-annotation.js} +1 -1
  50. package/dist/core/decoder.js +1 -1
  51. package/dist/core/objects/pdf-array.d.ts +8 -1
  52. package/dist/core/objects/pdf-array.js +31 -0
  53. package/dist/core/objects/pdf-dictionary.d.ts +2 -0
  54. package/dist/core/objects/pdf-dictionary.js +14 -7
  55. package/dist/core/objects/pdf-hexadecimal.d.ts +1 -0
  56. package/dist/core/objects/pdf-hexadecimal.js +3 -3
  57. package/dist/core/objects/pdf-indirect-object.d.ts +18 -9
  58. package/dist/core/objects/pdf-indirect-object.js +75 -16
  59. package/dist/core/objects/pdf-number.d.ts +1 -0
  60. package/dist/core/objects/pdf-number.js +5 -4
  61. package/dist/core/objects/pdf-object-reference.d.ts +8 -1
  62. package/dist/core/objects/pdf-object-reference.js +14 -0
  63. package/dist/core/objects/pdf-object.d.ts +14 -0
  64. package/dist/core/objects/pdf-object.js +36 -0
  65. package/dist/core/objects/pdf-start-xref.d.ts +1 -0
  66. package/dist/core/objects/pdf-start-xref.js +4 -0
  67. package/dist/core/objects/pdf-stream.d.ts +44 -7
  68. package/dist/core/objects/pdf-stream.js +284 -26
  69. package/dist/core/objects/pdf-string.d.ts +1 -0
  70. package/dist/core/objects/pdf-string.js +3 -6
  71. package/dist/core/objects/pdf-trailer.d.ts +1 -0
  72. package/dist/core/objects/pdf-trailer.js +6 -3
  73. package/dist/core/objects/pdf-xref-table.js +1 -1
  74. package/dist/core/parser/incremental-parser.d.ts +0 -13
  75. package/dist/core/parser/incremental-parser.js +1 -18
  76. package/dist/core/ref.d.ts +3 -1
  77. package/dist/core/ref.js +8 -5
  78. package/dist/core/streams/object-stream.d.ts +1 -1
  79. package/dist/core/streams/object-stream.js +1 -1
  80. package/dist/core/tokens/token.d.ts +2 -1
  81. package/dist/core/tokens/token.js +3 -0
  82. package/dist/errors.d.ts +22 -0
  83. package/dist/errors.js +24 -0
  84. package/dist/fonts/index.d.ts +0 -1
  85. package/dist/fonts/index.js +0 -1
  86. package/dist/fonts/pdf-font.d.ts +94 -32
  87. package/dist/fonts/pdf-font.js +301 -83
  88. package/dist/index.d.ts +1 -0
  89. package/dist/index.js +1 -0
  90. package/dist/pdf/index.d.ts +2 -1
  91. package/dist/pdf/index.js +2 -1
  92. package/dist/pdf/pdf-document.d.ts +61 -36
  93. package/dist/pdf/pdf-document.js +315 -117
  94. package/dist/pdf/pdf-page.d.ts +50 -0
  95. package/dist/pdf/pdf-page.js +144 -0
  96. package/dist/pdf/pdf-pages.d.ts +28 -0
  97. package/dist/pdf/pdf-pages.js +94 -0
  98. package/dist/pdf/pdf-reader.d.ts +5 -1
  99. package/dist/pdf/pdf-reader.js +36 -2
  100. package/dist/pdf/pdf-revision.d.ts +3 -3
  101. package/dist/pdf/pdf-revision.js +7 -7
  102. package/dist/pdf/pdf-xref-lookup.js +34 -14
  103. package/dist/signing/document-security-store.d.ts +14 -17
  104. package/dist/signing/document-security-store.js +19 -34
  105. package/dist/signing/signer.d.ts +23 -8
  106. package/dist/signing/signer.js +51 -17
  107. package/dist/utils/encodePdfText.d.ts +17 -0
  108. package/dist/utils/encodePdfText.js +61 -0
  109. package/dist/utils/index.d.ts +1 -2
  110. package/dist/utils/index.js +1 -2
  111. package/dist/utils/needsCentralWhitespace.d.ts +10 -0
  112. package/dist/utils/needsCentralWhitespace.js +34 -0
  113. package/package.json +3 -3
  114. package/dist/acroform/PdfAcroForm.d.ts +0 -63
  115. package/dist/acroform/PdfAcroForm.js +0 -279
  116. package/dist/acroform/PdfFontEncodingCache.d.ts +0 -16
  117. package/dist/acroform/PdfFontEncodingCache.js +0 -75
  118. package/dist/acroform/acroform.d.ts +0 -9
  119. package/dist/acroform/acroform.js +0 -7
  120. package/dist/acroform/appearance/PdfButtonAppearanceStream.js +0 -54
  121. package/dist/acroform/appearance/PdfChoiceAppearanceStream.d.ts +0 -15
  122. package/dist/acroform/appearance/PdfChoiceAppearanceStream.js +0 -48
  123. package/dist/acroform/appearance/PdfTextAppearanceStream.js +0 -75
  124. package/dist/acroform/fields/PdfButtonFormField.d.ts +0 -9
  125. package/dist/acroform/fields/PdfButtonFormField.js +0 -35
  126. package/dist/acroform/fields/PdfChoiceFormField.d.ts +0 -9
  127. package/dist/acroform/fields/PdfChoiceFormField.js +0 -46
  128. package/dist/acroform/fields/PdfFormField.js +0 -499
  129. package/dist/acroform/manager.d.ts +0 -33
  130. package/dist/acroform/manager.js +0 -51
  131. package/dist/acroform/xfa/PdfXfaForm.d.ts +0 -12
  132. package/dist/acroform/xfa/PdfXfaForm.js +0 -64
  133. package/dist/annotations/PdfAnnotationWriter.d.ts +0 -20
  134. package/dist/annotations/PdfAnnotationWriter.js +0 -76
  135. package/dist/fonts/font-manager.d.ts +0 -127
  136. package/dist/fonts/font-manager.js +0 -378
  137. package/dist/pdf/errors.d.ts +0 -6
  138. package/dist/pdf/errors.js +0 -6
  139. package/dist/utils/predictors.d.ts +0 -113
  140. package/dist/utils/predictors.js +0 -279
  141. /package/dist/acroform/fields/{PdfDefaultAppearance.d.ts → pdf-default-appearance.d.ts} +0 -0
  142. /package/dist/acroform/fields/{PdfDefaultAppearance.js → pdf-default-appearance.js} +0 -0
  143. /package/dist/utils/{IterableReadableStream.d.ts → iterable-readable-stream.d.ts} +0 -0
  144. /package/dist/utils/{IterableReadableStream.js → iterable-readable-stream.js} +0 -0
@@ -9,10 +9,20 @@ export class PdfObject {
9
9
  modified = true;
10
10
  /** Indicates whether the object is immutable (cannot be modified) */
11
11
  immutable = false;
12
+ /** Cached byte representation of the object, if available */
13
+ cachedTokens;
12
14
  /** The type of this PDF object */
13
15
  get objectType() {
14
16
  return this.constructor.name;
15
17
  }
18
+ /**
19
+ * Returns true if this object's serialized form ends with a self-delimiting
20
+ * character (e.g., `)`, `>`, `]`, `>>`). Such objects do not require trailing
21
+ * whitespace before the next token.
22
+ */
23
+ get isTrailingDelimited() {
24
+ return false;
25
+ }
16
26
  /** Indicates whether the object has been modified. Override this method if the modified state is determined differently */
17
27
  isModified() {
18
28
  return this.modified;
@@ -27,10 +37,22 @@ export class PdfObject {
27
37
  }
28
38
  /** Sets the immutable state of the object */
29
39
  setImmutable(immutable = true) {
40
+ if (immutable === this.immutable) {
41
+ return;
42
+ }
30
43
  this.immutable = immutable;
44
+ if (immutable) {
45
+ this.cachedTokens = this.toTokens();
46
+ }
47
+ else {
48
+ this.cachedTokens = undefined;
49
+ }
31
50
  }
32
51
  /** Converts the object to an array of PdfTokens, including any pre or post tokens */
33
52
  toTokens() {
53
+ if (this.cachedTokens) {
54
+ return this.cachedTokens;
55
+ }
34
56
  return [
35
57
  ...(this.preTokens ?? []),
36
58
  ...this.tokenize(),
@@ -90,4 +112,18 @@ export class PdfObject {
90
112
  }
91
113
  return true;
92
114
  }
115
+ /**
116
+ * Serializes the document to a Base64-encoded string.
117
+ *
118
+ * @returns A promise that resolves to the PDF document as a Base64 string
119
+ */
120
+ toBase64() {
121
+ const bytes = this.toBytes();
122
+ let binary = '';
123
+ const len = bytes.byteLength;
124
+ for (let i = 0; i < len; i++) {
125
+ binary += String.fromCharCode(bytes[i]);
126
+ }
127
+ return btoa(binary);
128
+ }
93
129
  }
@@ -6,5 +6,6 @@ export declare class PdfStartXRef extends PdfObject {
6
6
  constructor(offset?: number | PdfNumber | Ref<number>);
7
7
  protected tokenize(): import("../index.js").PdfToken[];
8
8
  cloneImpl(): this;
9
+ setModified(modified?: boolean): void;
9
10
  isModified(): boolean;
10
11
  }
@@ -27,6 +27,10 @@ export class PdfStartXRef extends PdfObject {
27
27
  const cloned = new PdfStartXRef(this.offset.clone());
28
28
  return cloned;
29
29
  }
30
+ setModified(modified) {
31
+ super.setModified(modified);
32
+ this.offset.setModified(modified);
33
+ }
30
34
  isModified() {
31
35
  return super.isModified() || this.offset.isModified();
32
36
  }
@@ -1,12 +1,48 @@
1
1
  import { PdfToken } from '../tokens/token.js';
2
2
  import { PdfDictionary } from './pdf-dictionary.js';
3
3
  import { PdfObject } from './pdf-object.js';
4
- import { ByteArray } from '../../types.js';
4
+ import { ByteArray, DecodeParms } from '../../types.js';
5
5
  import { PdfNumber } from './pdf-number.js';
6
6
  import { PdfIndirectObject } from './pdf-indirect-object.js';
7
7
  import { PdfXRefTableEntry } from './pdf-xref-table.js';
8
8
  import { PdfFilter, PdfStreamFilterType } from '../../filters/types.js';
9
+ export declare class PdfStreamPredictor extends PdfDictionary<{
10
+ Predictor?: PdfNumber;
11
+ Columns?: PdfNumber;
12
+ Colors?: PdfNumber;
13
+ BitsPerComponent?: PdfNumber;
14
+ }> {
15
+ static NONE: PdfStreamPredictor;
16
+ static TIFF: PdfStreamPredictor;
17
+ static PNG_NONE: PdfStreamPredictor;
18
+ static PNG_SUB: PdfStreamPredictor;
19
+ static PNG_UP: PdfStreamPredictor;
20
+ static PNG_AVERAGE: PdfStreamPredictor;
21
+ static PNG_PAETH: PdfStreamPredictor;
22
+ static PNG_OPTIMUM: PdfStreamPredictor;
23
+ static XREF_STREAM: PdfStreamPredictor;
24
+ get predictor(): number;
25
+ set predictor(value: number);
26
+ get columns(): number;
27
+ set columns(value: number);
28
+ get colors(): number;
29
+ set colors(value: number);
30
+ get bitsPerComponent(): number;
31
+ set bitsPerComponent(value: number);
32
+ toDecodeParms(): DecodeParms;
33
+ cloneImpl(): this;
34
+ static fromDecodeParms(params: DecodeParms): PdfStreamPredictor;
35
+ static fromDictionary(dict?: PdfDictionary): PdfStreamPredictor | undefined;
36
+ encode(data: ByteArray, filterType?: number): ByteArray;
37
+ decode(data: ByteArray): ByteArray;
38
+ private static tiffDecode;
39
+ private static tiffEncode;
40
+ private static pngDecode;
41
+ private static pngEncode;
42
+ private static paethPredictor;
43
+ }
9
44
  export declare class PdfStream<T extends PdfDictionary = PdfDictionary> extends PdfObject {
45
+ static PdfStreamPredictor: typeof PdfStreamPredictor;
10
46
  header: T;
11
47
  original: ByteArray;
12
48
  preStreamDataTokens?: PdfToken[];
@@ -20,14 +56,15 @@ export declare class PdfStream<T extends PdfDictionary = PdfDictionary> extends
20
56
  set raw(data: ByteArray);
21
57
  get originalAsString(): string;
22
58
  get rawAsString(): string;
59
+ set rawAsString(str: string);
60
+ get data(): ByteArray;
61
+ set data(data: ByteArray);
62
+ get dataAsString(): string;
63
+ set dataAsString(str: string);
23
64
  getFilters(): PdfStreamFilterType[];
24
65
  addFilter(filterName: PdfStreamFilterType): this;
25
- setPredictor(predictorParams: {
26
- Predictor?: number;
27
- Columns?: number;
28
- Colors?: number;
29
- BitsPerComponent?: number;
30
- }): this;
66
+ get predictor(): PdfStreamPredictor | undefined;
67
+ set predictor(predictor: PdfStreamPredictor);
31
68
  removeFilter(filterName: PdfStreamFilterType): this;
32
69
  removePredictor(): this;
33
70
  removeAllFilters(): this;
@@ -12,12 +12,244 @@ import { lzw } from '../../filters/lzw.js';
12
12
  import { runLength } from '../../filters/runlength.js';
13
13
  import { passthroughFilter } from '../../filters/pass-through.js';
14
14
  import { PdfNumber } from './pdf-number.js';
15
- import { Predictor } from '../../utils/predictors.js';
16
15
  import { bytesToPdfObjects } from '../generators.js';
17
16
  import { PdfIndirectObject } from './pdf-indirect-object.js';
18
17
  import { PdfXRefTableEntry } from './pdf-xref-table.js';
19
18
  import { stringToBytes } from '../../utils/stringToBytes.js';
19
+ import { bytesToString } from '../../utils/bytesToString.js';
20
+ export class PdfStreamPredictor extends PdfDictionary {
21
+ static NONE = new PdfStreamPredictor({ Predictor: new PdfNumber(1) });
22
+ static TIFF = new PdfStreamPredictor({ Predictor: new PdfNumber(2) });
23
+ static PNG_NONE = new PdfStreamPredictor({ Predictor: new PdfNumber(10) });
24
+ static PNG_SUB = new PdfStreamPredictor({ Predictor: new PdfNumber(11) });
25
+ static PNG_UP = new PdfStreamPredictor({ Predictor: new PdfNumber(12) });
26
+ static PNG_AVERAGE = new PdfStreamPredictor({
27
+ Predictor: new PdfNumber(13),
28
+ });
29
+ static PNG_PAETH = new PdfStreamPredictor({ Predictor: new PdfNumber(14) });
30
+ static PNG_OPTIMUM = new PdfStreamPredictor({
31
+ Predictor: new PdfNumber(15),
32
+ });
33
+ static XREF_STREAM = new PdfStreamPredictor({
34
+ Predictor: new PdfNumber(12),
35
+ Columns: new PdfNumber(7),
36
+ });
37
+ get predictor() {
38
+ return this.get('Predictor')?.as(PdfNumber)?.value ?? 1;
39
+ }
40
+ set predictor(value) {
41
+ this.set('Predictor', new PdfNumber(value));
42
+ }
43
+ get columns() {
44
+ return this.get('Columns')?.as(PdfNumber)?.value ?? 1;
45
+ }
46
+ set columns(value) {
47
+ this.set('Columns', new PdfNumber(value));
48
+ }
49
+ get colors() {
50
+ return this.get('Colors')?.as(PdfNumber)?.value ?? 1;
51
+ }
52
+ set colors(value) {
53
+ this.set('Colors', new PdfNumber(value));
54
+ }
55
+ get bitsPerComponent() {
56
+ return this.get('BitsPerComponent')?.as(PdfNumber)?.value ?? 8;
57
+ }
58
+ set bitsPerComponent(value) {
59
+ this.set('BitsPerComponent', new PdfNumber(value));
60
+ }
61
+ toDecodeParms() {
62
+ const params = {};
63
+ const predictor = this.get('Predictor')?.as(PdfNumber);
64
+ if (predictor)
65
+ params.Predictor = predictor.value;
66
+ const columns = this.get('Columns')?.as(PdfNumber);
67
+ if (columns)
68
+ params.Columns = columns.value;
69
+ const colors = this.get('Colors')?.as(PdfNumber);
70
+ if (colors)
71
+ params.Colors = colors.value;
72
+ const bpc = this.get('BitsPerComponent')?.as(PdfNumber);
73
+ if (bpc)
74
+ params.BitsPerComponent = bpc.value;
75
+ return params;
76
+ }
77
+ cloneImpl() {
78
+ return PdfStreamPredictor.fromDecodeParms(this.toDecodeParms());
79
+ }
80
+ static fromDecodeParms(params) {
81
+ const predictor = new PdfStreamPredictor();
82
+ if (params.Predictor !== undefined) {
83
+ predictor.predictor = params.Predictor;
84
+ }
85
+ if (params.Columns !== undefined) {
86
+ predictor.columns = params.Columns;
87
+ }
88
+ if (params.Colors !== undefined) {
89
+ predictor.colors = params.Colors;
90
+ }
91
+ if (params.BitsPerComponent !== undefined) {
92
+ predictor.bitsPerComponent = params.BitsPerComponent;
93
+ }
94
+ return predictor;
95
+ }
96
+ static fromDictionary(dict) {
97
+ if (!dict)
98
+ return undefined;
99
+ const predictor = dict.get('Predictor')?.as(PdfNumber)?.value;
100
+ if (predictor === undefined || predictor <= 1 || predictor > 15) {
101
+ return undefined;
102
+ }
103
+ return PdfStreamPredictor.fromDecodeParms({
104
+ Predictor: predictor,
105
+ Columns: dict.get('Columns')?.as(PdfNumber)?.value,
106
+ Colors: dict.get('Colors')?.as(PdfNumber)?.value,
107
+ BitsPerComponent: dict.get('BitsPerComponent')?.as(PdfNumber)
108
+ ?.value,
109
+ });
110
+ }
111
+ encode(data, filterType = 0) {
112
+ const bpp = Math.ceil((this.colors * this.bitsPerComponent) / 8);
113
+ if (this.predictor === 2) {
114
+ return PdfStreamPredictor.tiffEncode(data, this.columns, bpp);
115
+ }
116
+ else if (this.predictor >= 10 && this.predictor <= 15) {
117
+ return PdfStreamPredictor.pngEncode(data, this.columns, bpp, filterType);
118
+ }
119
+ return data;
120
+ }
121
+ decode(data) {
122
+ const bpp = Math.ceil((this.colors * this.bitsPerComponent) / 8);
123
+ if (this.predictor === 2) {
124
+ return PdfStreamPredictor.tiffDecode(data, this.columns, bpp);
125
+ }
126
+ else if (this.predictor >= 10 && this.predictor <= 15) {
127
+ return PdfStreamPredictor.pngDecode(data, this.columns, bpp);
128
+ }
129
+ return data;
130
+ }
131
+ static tiffDecode(data, columns, bpp) {
132
+ const rowLength = columns * bpp;
133
+ const output = new Uint8Array(data.length);
134
+ for (let i = 0; i < data.length; i += rowLength) {
135
+ for (let j = 0; j < rowLength; j++) {
136
+ output[i + j] =
137
+ j < bpp
138
+ ? data[i + j]
139
+ : (data[i + j] + output[i + j - bpp]) & 0xff;
140
+ }
141
+ }
142
+ return output;
143
+ }
144
+ static tiffEncode(data, columns, bpp) {
145
+ const rowLength = columns * bpp;
146
+ const output = new Uint8Array(data.length);
147
+ for (let i = 0; i < data.length; i += rowLength) {
148
+ for (let j = 0; j < rowLength; j++) {
149
+ output[i + j] =
150
+ j < bpp
151
+ ? data[i + j]
152
+ : (data[i + j] - data[i + j - bpp] + 256) & 0xff;
153
+ }
154
+ }
155
+ return output;
156
+ }
157
+ static pngDecode(data, columns, bpp) {
158
+ const rowLength = columns * bpp;
159
+ const output = [];
160
+ for (let i = 0; i < data.length;) {
161
+ const filter = data[i];
162
+ const row = data.slice(i + 1, i + 1 + rowLength);
163
+ const prior = output.slice(output.length - rowLength, output.length);
164
+ const decodedRow = new Uint8Array(rowLength);
165
+ for (let j = 0; j < rowLength; j++) {
166
+ const left = j >= bpp ? decodedRow[j - bpp] : 0;
167
+ const up = prior[j] ?? 0;
168
+ const upperLeft = j >= bpp ? (prior[j - bpp] ?? 0) : 0;
169
+ switch (filter) {
170
+ case 0:
171
+ decodedRow[j] = row[j];
172
+ break;
173
+ case 1:
174
+ decodedRow[j] = (row[j] + left) & 0xff;
175
+ break;
176
+ case 2:
177
+ decodedRow[j] = (row[j] + up) & 0xff;
178
+ break;
179
+ case 3:
180
+ decodedRow[j] =
181
+ (row[j] + Math.floor((left + up) / 2)) & 0xff;
182
+ break;
183
+ case 4:
184
+ decodedRow[j] =
185
+ (row[j] +
186
+ this.paethPredictor(left, up, upperLeft)) &
187
+ 0xff;
188
+ break;
189
+ default:
190
+ throw new Error(`Unsupported PNG filter: ${filter}`);
191
+ }
192
+ }
193
+ output.push(...decodedRow);
194
+ i += 1 + rowLength;
195
+ }
196
+ return new Uint8Array(output);
197
+ }
198
+ static pngEncode(data, columns, bpp, filterType) {
199
+ const rowLength = columns * bpp;
200
+ const output = [];
201
+ let prior = new Uint8Array(rowLength);
202
+ for (let i = 0; i < data.length; i += rowLength) {
203
+ const row = data.slice(i, i + rowLength);
204
+ const encodedRow = new Uint8Array(rowLength);
205
+ for (let j = 0; j < rowLength; j++) {
206
+ const left = j >= bpp ? row[j - bpp] : 0;
207
+ const up = prior[j] ?? 0;
208
+ const upperLeft = j >= bpp ? (prior[j - bpp] ?? 0) : 0;
209
+ switch (filterType) {
210
+ case 0:
211
+ encodedRow[j] = row[j];
212
+ break;
213
+ case 1:
214
+ encodedRow[j] = (row[j] - left + 256) & 0xff;
215
+ break;
216
+ case 2:
217
+ encodedRow[j] = (row[j] - up + 256) & 0xff;
218
+ break;
219
+ case 3:
220
+ encodedRow[j] =
221
+ (row[j] - Math.floor((left + up) / 2) + 256) & 0xff;
222
+ break;
223
+ case 4:
224
+ encodedRow[j] =
225
+ (row[j] -
226
+ this.paethPredictor(left, up, upperLeft) +
227
+ 256) &
228
+ 0xff;
229
+ break;
230
+ default:
231
+ throw new Error(`Unsupported PNG filter: ${filterType}`);
232
+ }
233
+ }
234
+ output.push(filterType, ...encodedRow);
235
+ prior = row;
236
+ }
237
+ return new Uint8Array(output);
238
+ }
239
+ static paethPredictor(a, b, c) {
240
+ const p = a + b - c;
241
+ const pa = Math.abs(p - a);
242
+ const pb = Math.abs(p - b);
243
+ const pc = Math.abs(p - c);
244
+ if (pa <= pb && pa <= pc)
245
+ return a;
246
+ if (pb <= pc)
247
+ return b;
248
+ return c;
249
+ }
250
+ }
20
251
  export class PdfStream extends PdfObject {
252
+ static PdfStreamPredictor = PdfStreamPredictor;
21
253
  header;
22
254
  original;
23
255
  preStreamDataTokens;
@@ -44,18 +276,40 @@ export class PdfStream extends PdfObject {
44
276
  return this.original.slice(0, length);
45
277
  }
46
278
  set raw(data) {
47
- if (this.isImmutable()) {
48
- throw new Error('Cannot modify an immutable PdfStream');
49
- }
50
279
  this.setModified();
51
280
  this.original = data;
52
281
  this.header.set('Length', new PdfNumber(data.length));
53
282
  }
54
283
  get originalAsString() {
55
- return new TextDecoder().decode(this.original);
284
+ return bytesToString(this.original);
56
285
  }
57
286
  get rawAsString() {
58
- return new TextDecoder().decode(this.raw);
287
+ return bytesToString(this.raw);
288
+ }
289
+ set rawAsString(str) {
290
+ this.raw = stringToBytes(str);
291
+ }
292
+ get data() {
293
+ return this.decode();
294
+ }
295
+ set data(data) {
296
+ const filters = this.getFilters();
297
+ const existingPredictor = this.predictor;
298
+ this.removeAllFilters();
299
+ this.header.delete('DecodeParms');
300
+ this.raw = data;
301
+ if (existingPredictor) {
302
+ this.predictor = existingPredictor;
303
+ }
304
+ for (const filter of filters) {
305
+ this.addFilter(filter);
306
+ }
307
+ }
308
+ get dataAsString() {
309
+ return bytesToString(this.data);
310
+ }
311
+ set dataAsString(str) {
312
+ this.data = stringToBytes(str);
59
313
  }
60
314
  getFilters() {
61
315
  const filters = this.header.get('Filter');
@@ -90,23 +344,24 @@ export class PdfStream extends PdfObject {
90
344
  this.raw = filter.encode(this.raw);
91
345
  return this;
92
346
  }
93
- setPredictor(predictorParams) {
94
- let decodeParms = this.header.get('DecodeParms')?.as(PdfDictionary);
95
- if (!decodeParms) {
96
- decodeParms = new PdfDictionary();
97
- this.header.set('DecodeParms', decodeParms);
347
+ get predictor() {
348
+ const raw = this.header.get('DecodeParms');
349
+ if (!raw)
350
+ return undefined;
351
+ if (raw instanceof PdfStreamPredictor) {
352
+ if (raw.get('Predictor') === undefined)
353
+ return undefined;
354
+ return raw;
98
355
  }
99
- else if (decodeParms instanceof PdfDictionary) {
100
- // already a dictionary
356
+ if (raw instanceof PdfDictionary) {
357
+ return PdfStreamPredictor.fromDictionary(raw);
101
358
  }
102
- else {
103
- throw new Error('Invalid DecodeParms entry in PDF stream');
104
- }
105
- for (const [key, value] of Object.entries(predictorParams)) {
106
- decodeParms.set(key, new PdfNumber(value));
107
- }
108
- this.raw = Predictor.encode(this.raw, predictorParams);
109
- return this;
359
+ return undefined;
360
+ }
361
+ set predictor(predictor) {
362
+ const cloned = predictor.cloneImpl();
363
+ this.header.set('DecodeParms', cloned);
364
+ this.raw = cloned.encode(this.raw);
110
365
  }
111
366
  removeFilter(filterName) {
112
367
  let filters = this.header.get('Filter');
@@ -155,9 +410,9 @@ export class PdfStream extends PdfObject {
155
410
  const filter = PdfStream.getFilter(filterName);
156
411
  data = filter.decode(data);
157
412
  }
158
- const predictorParams = Predictor.getDecodeParms(this.header.get('DecodeParms')?.as(PdfDictionary));
159
- if (predictorParams) {
160
- data = Predictor.decode(data, predictorParams);
413
+ const streamPredictor = PdfStreamPredictor.fromDictionary(this.header.get('DecodeParms')?.as(PdfDictionary));
414
+ if (streamPredictor) {
415
+ data = streamPredictor.decode(data);
161
416
  }
162
417
  return data;
163
418
  }
@@ -303,11 +558,14 @@ export class PdfObjStream extends PdfStream {
303
558
  // After that come the actual objects
304
559
  const objectNumber = numbers[i * 2].value;
305
560
  const generationNumber = 0;
306
- yield new PdfIndirectObject({
561
+ const decompressedObject = new PdfIndirectObject({
307
562
  objectNumber,
308
563
  generationNumber,
309
564
  content: obj,
310
- });
565
+ compressed: true,
566
+ }).clone();
567
+ decompressedObject.setModified(false);
568
+ yield decompressedObject;
311
569
  i++;
312
570
  // Stop after we've read N objects
313
571
  if (totalObjects > 0 && i >= totalObjects) {
@@ -21,6 +21,7 @@ export declare class PdfString extends PdfObject {
21
21
  get isUTF16BE(): boolean;
22
22
  set value(str: string);
23
23
  get value(): string;
24
+ get isTrailingDelimited(): boolean;
24
25
  protected tokenize(): PdfStringToken[];
25
26
  cloneImpl(): this;
26
27
  }
@@ -37,9 +37,6 @@ export class PdfString extends PdfObject {
37
37
  return this._raw;
38
38
  }
39
39
  set raw(raw) {
40
- if (this.isImmutable()) {
41
- throw new Error('Cannot modify an immutable PdfString');
42
- }
43
40
  this.setModified();
44
41
  this._raw = raw;
45
42
  // Clear original bytes when modified
@@ -53,9 +50,6 @@ export class PdfString extends PdfObject {
53
50
  return (this.raw.length >= 2 && this.raw[0] === 0xfe && this.raw[1] === 0xff);
54
51
  }
55
52
  set value(str) {
56
- if (this.isImmutable()) {
57
- throw new Error('Cannot modify an immutable PdfString');
58
- }
59
53
  this.setModified();
60
54
  if (needsUnicodeEncoding(str)) {
61
55
  this._raw = encodeAsUTF16BE(str);
@@ -74,6 +68,9 @@ export class PdfString extends PdfObject {
74
68
  // Default: use PDFDocEncoding
75
69
  return decodeFromPDFDocEncoding(this.raw);
76
70
  }
71
+ get isTrailingDelimited() {
72
+ return true;
73
+ }
77
74
  tokenize() {
78
75
  return [new PdfStringToken(this.raw, this._originalBytes)];
79
76
  }
@@ -22,5 +22,6 @@ export declare class PdfTrailer extends PdfObject {
22
22
  constructor(entries: PdfTrailerEntries | PdfDictionary<PdfTrailerEntries>);
23
23
  protected tokenize(): PdfToken[];
24
24
  cloneImpl(): this;
25
+ setModified(modified?: boolean): void;
25
26
  isModified(): boolean;
26
27
  }
@@ -26,9 +26,12 @@ export class PdfTrailer extends PdfObject {
26
26
  const cloned = new PdfTrailer(this.dict.clone());
27
27
  return cloned;
28
28
  }
29
+ setModified(modified) {
30
+ super.setModified(modified);
31
+ this.dict.setModified(modified);
32
+ this.offset.setModified(modified);
33
+ }
29
34
  isModified() {
30
- return (super.isModified() ||
31
- this.dict.isModified() ||
32
- this.offset.isModified);
35
+ return (super.isModified() || this.dict.isModified() || this.offset.modified);
33
36
  }
34
37
  }
@@ -87,7 +87,7 @@ export class PdfXRefTable extends PdfObject {
87
87
  return (super.isModified() ||
88
88
  this.sections.some((section) => section.isModified()) ||
89
89
  this.entries.some((entry) => entry.isModified()) ||
90
- this.offset.isModified);
90
+ this.offset.modified);
91
91
  }
92
92
  addEntryForObject(obj) {
93
93
  const foundEntry = this.entries.find((entry) => entry.objectNumber.value === obj.objectNumber);
@@ -1,17 +1,4 @@
1
1
  import { Parser } from './parser.js';
2
- /**
3
- * Error thrown when the parser needs more input to continue parsing.
4
- */
5
- export declare class NoMoreTokensError extends Error {
6
- }
7
- /**
8
- * Error thrown when the end of file has been reached and no more input is available.
9
- */
10
- export declare class EofReachedError extends Error {
11
- }
12
- export declare class UnexpectedTokenError extends Error {
13
- constructor(expected: string, actual: string | null);
14
- }
15
2
  /**
16
3
  * Abstract base class for incremental parsers that can process input as it becomes available.
17
4
  * Supports buffering, lookahead, and backtracking for complex parsing scenarios.
@@ -1,22 +1,5 @@
1
1
  import { Parser } from './parser.js';
2
- /**
3
- * Error thrown when the parser needs more input to continue parsing.
4
- */
5
- export class NoMoreTokensError extends Error {
6
- }
7
- /**
8
- * Error thrown when the end of file has been reached and no more input is available.
9
- */
10
- export class EofReachedError extends Error {
11
- }
12
- /*
13
- * Error thrown when an unexpected token is encountered during parsing.
14
- */
15
- export class UnexpectedTokenError extends Error {
16
- constructor(expected, actual) {
17
- super(`Unexpected token: expected ${expected}, but got ${actual === null ? 'EOF' : actual}`);
18
- }
19
- }
2
+ import { NoMoreTokensError, EofReachedError } from '../../errors.js';
20
3
  /**
21
4
  * Abstract base class for incremental parsers that can process input as it becomes available.
22
5
  * Supports buffering, lookahead, and backtracking for complex parsing scenarios.
@@ -22,7 +22,7 @@ export declare class Ref<T> {
22
22
  value: T | Ref<T>;
23
23
  /** Registered callbacks for update notifications */
24
24
  callbacks: Array<RefUpdateCallback<T>>;
25
- isModified: boolean;
25
+ modified: boolean;
26
26
  protected immutable: boolean;
27
27
  /**
28
28
  * Creates a new Ref with an initial value.
@@ -31,6 +31,8 @@ export declare class Ref<T> {
31
31
  * @throws Error if attempting to create a self-referencing Ref
32
32
  */
33
33
  constructor(value: T | Ref<T>);
34
+ isModified(): boolean;
35
+ setModified(modified?: boolean): void;
34
36
  setImmutable(immutable?: boolean): void;
35
37
  isImmutable(): boolean;
36
38
  /**
package/dist/core/ref.js CHANGED
@@ -16,7 +16,7 @@ export class Ref {
16
16
  value;
17
17
  /** Registered callbacks for update notifications */
18
18
  callbacks = [];
19
- isModified = false;
19
+ modified = true;
20
20
  immutable = false;
21
21
  /**
22
22
  * Creates a new Ref with an initial value.
@@ -30,6 +30,12 @@ export class Ref {
30
30
  }
31
31
  this.value = value;
32
32
  }
33
+ isModified() {
34
+ return this.modified;
35
+ }
36
+ setModified(modified = true) {
37
+ this.modified = modified;
38
+ }
33
39
  setImmutable(immutable = true) {
34
40
  this.immutable = immutable;
35
41
  }
@@ -49,10 +55,7 @@ export class Ref {
49
55
  const resolvedNewValue = newValue instanceof Ref ? newValue.resolve() : newValue;
50
56
  const oldValue = this.resolve();
51
57
  if (oldValue !== resolvedNewValue) {
52
- if (this.immutable) {
53
- throw new Error(`Cannot update an immutable Ref (${oldValue} -> ${resolvedNewValue})`);
54
- }
55
- this.isModified = true;
58
+ this.modified = true;
56
59
  }
57
60
  this.value = newValue;
58
61
  this.callbacks.forEach((cb) => cb(oldValue, this.resolve()));