pdf-lite 1.5.0 → 1.6.1

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 (93) hide show
  1. package/EXAMPLES.md +51 -70
  2. package/README.md +1 -1
  3. package/dist/acroform/appearance/pdf-button-appearance-stream.d.ts +1 -1
  4. package/dist/acroform/appearance/pdf-button-appearance-stream.js +6 -2
  5. package/dist/acroform/fields/pdf-button-form-field.d.ts +0 -9
  6. package/dist/acroform/fields/pdf-button-form-field.js +7 -39
  7. package/dist/acroform/fields/pdf-choice-form-field.d.ts +2 -1
  8. package/dist/acroform/fields/pdf-choice-form-field.js +19 -38
  9. package/dist/acroform/fields/pdf-default-appearance.js +1 -1
  10. package/dist/acroform/fields/pdf-form-field.d.ts +27 -32
  11. package/dist/acroform/fields/pdf-form-field.js +180 -94
  12. package/dist/acroform/fields/pdf-text-form-field.js +6 -33
  13. package/dist/acroform/fields/types.d.ts +1 -1
  14. package/dist/acroform/index.d.ts +0 -2
  15. package/dist/acroform/index.js +0 -2
  16. package/dist/acroform/pdf-acro-form.d.ts +12 -36
  17. package/dist/acroform/pdf-acro-form.js +111 -201
  18. package/dist/acroform/xfa/pdf-xfa-data.d.ts +4 -3
  19. package/dist/acroform/xfa/pdf-xfa-data.js +16 -12
  20. package/dist/acroform/xfa/pdf-xfa-form.d.ts +9 -4
  21. package/dist/acroform/xfa/pdf-xfa-form.js +17 -39
  22. package/dist/annotations/index.d.ts +0 -1
  23. package/dist/annotations/index.js +0 -1
  24. package/dist/annotations/pdf-annotation.d.ts +7 -2
  25. package/dist/annotations/pdf-annotation.js +30 -19
  26. package/dist/annotations/pdf-default-resources.d.ts +11 -0
  27. package/dist/annotations/pdf-default-resources.js +3 -0
  28. package/dist/core/decoder.js +1 -1
  29. package/dist/core/objects/pdf-array.d.ts +8 -1
  30. package/dist/core/objects/pdf-array.js +31 -0
  31. package/dist/core/objects/pdf-dictionary.d.ts +2 -0
  32. package/dist/core/objects/pdf-dictionary.js +14 -7
  33. package/dist/core/objects/pdf-hexadecimal.d.ts +1 -0
  34. package/dist/core/objects/pdf-hexadecimal.js +3 -3
  35. package/dist/core/objects/pdf-indirect-object.d.ts +18 -9
  36. package/dist/core/objects/pdf-indirect-object.js +75 -16
  37. package/dist/core/objects/pdf-number.d.ts +1 -0
  38. package/dist/core/objects/pdf-number.js +5 -4
  39. package/dist/core/objects/pdf-object-reference.d.ts +8 -1
  40. package/dist/core/objects/pdf-object-reference.js +14 -0
  41. package/dist/core/objects/pdf-object.d.ts +14 -0
  42. package/dist/core/objects/pdf-object.js +36 -0
  43. package/dist/core/objects/pdf-start-xref.d.ts +1 -0
  44. package/dist/core/objects/pdf-start-xref.js +4 -0
  45. package/dist/core/objects/pdf-stream.d.ts +47 -7
  46. package/dist/core/objects/pdf-stream.js +301 -32
  47. package/dist/core/objects/pdf-string.d.ts +1 -0
  48. package/dist/core/objects/pdf-string.js +3 -6
  49. package/dist/core/objects/pdf-trailer.d.ts +1 -0
  50. package/dist/core/objects/pdf-trailer.js +6 -3
  51. package/dist/core/objects/pdf-xref-table.js +1 -1
  52. package/dist/core/ref.d.ts +3 -1
  53. package/dist/core/ref.js +8 -5
  54. package/dist/core/tokens/token.d.ts +2 -1
  55. package/dist/core/tokens/token.js +3 -0
  56. package/dist/fonts/index.d.ts +0 -1
  57. package/dist/fonts/index.js +0 -1
  58. package/dist/fonts/pdf-font.d.ts +32 -27
  59. package/dist/fonts/pdf-font.js +115 -77
  60. package/dist/pdf/index.d.ts +2 -0
  61. package/dist/pdf/index.js +2 -0
  62. package/dist/pdf/pdf-document.d.ts +63 -37
  63. package/dist/pdf/pdf-document.js +351 -135
  64. package/dist/pdf/pdf-page.d.ts +50 -0
  65. package/dist/pdf/pdf-page.js +144 -0
  66. package/dist/pdf/pdf-pages.d.ts +28 -0
  67. package/dist/pdf/pdf-pages.js +94 -0
  68. package/dist/pdf/pdf-reader.d.ts +5 -1
  69. package/dist/pdf/pdf-reader.js +36 -2
  70. package/dist/pdf/pdf-revision.d.ts +3 -3
  71. package/dist/pdf/pdf-revision.js +7 -7
  72. package/dist/pdf/pdf-xref-lookup.js +34 -14
  73. package/dist/signing/document-security-store.d.ts +14 -17
  74. package/dist/signing/document-security-store.js +19 -34
  75. package/dist/signing/signer.d.ts +23 -8
  76. package/dist/signing/signer.js +51 -17
  77. package/dist/utils/index.d.ts +0 -1
  78. package/dist/utils/index.js +0 -1
  79. package/dist/utils/needsCentralWhitespace.d.ts +10 -0
  80. package/dist/utils/needsCentralWhitespace.js +34 -0
  81. package/package.json +3 -3
  82. package/dist/acroform/acroform.d.ts +0 -9
  83. package/dist/acroform/acroform.js +0 -7
  84. package/dist/acroform/manager.d.ts +0 -37
  85. package/dist/acroform/manager.js +0 -57
  86. package/dist/acroform/pdf-font-encoding-cache.d.ts +0 -27
  87. package/dist/acroform/pdf-font-encoding-cache.js +0 -188
  88. package/dist/annotations/pdf-annotation-writer.d.ts +0 -20
  89. package/dist/annotations/pdf-annotation-writer.js +0 -76
  90. package/dist/fonts/manager.d.ts +0 -127
  91. package/dist/fonts/manager.js +0 -378
  92. package/dist/utils/predictors.d.ts +0 -113
  93. package/dist/utils/predictors.js +0 -279
@@ -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[];
@@ -21,14 +57,14 @@ export declare class PdfStream<T extends PdfDictionary = PdfDictionary> extends
21
57
  get originalAsString(): string;
22
58
  get rawAsString(): string;
23
59
  set rawAsString(str: string);
60
+ get data(): ByteArray;
61
+ set data(data: ByteArray);
62
+ get dataAsString(): string;
63
+ set dataAsString(str: string);
24
64
  getFilters(): PdfStreamFilterType[];
25
65
  addFilter(filterName: PdfStreamFilterType): this;
26
- setPredictor(predictorParams: {
27
- Predictor?: number;
28
- Columns?: number;
29
- Colors?: number;
30
- BitsPerComponent?: number;
31
- }): this;
66
+ get predictor(): PdfStreamPredictor | undefined;
67
+ set predictor(predictor: PdfStreamPredictor);
32
68
  removeFilter(filterName: PdfStreamFilterType): this;
33
69
  removePredictor(): this;
34
70
  removeAllFilters(): this;
@@ -58,6 +94,9 @@ export declare class PdfStream<T extends PdfDictionary = PdfDictionary> extends
58
94
  static fromString(data: string): PdfStream;
59
95
  }
60
96
  export declare class PdfObjStream extends PdfStream {
97
+ private _parsedObjects?;
98
+ set raw(data: ByteArray);
99
+ get raw(): ByteArray;
61
100
  constructor(options: {
62
101
  header: PdfDictionary;
63
102
  original: ByteArray | string;
@@ -65,6 +104,7 @@ export declare class PdfObjStream extends PdfStream {
65
104
  });
66
105
  static fromObjects(objects: Iterable<PdfIndirectObject>): PdfObjStream;
67
106
  getObjectStream(): Generator<PdfIndirectObject>;
107
+ private getParsedObjects;
68
108
  getObject(options: {
69
109
  objectNumber: number;
70
110
  }): PdfIndirectObject | undefined;
@@ -12,13 +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';
20
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
+ }
21
251
  export class PdfStream extends PdfObject {
252
+ static PdfStreamPredictor = PdfStreamPredictor;
22
253
  header;
23
254
  original;
24
255
  preStreamDataTokens;
@@ -45,9 +276,6 @@ export class PdfStream extends PdfObject {
45
276
  return this.original.slice(0, length);
46
277
  }
47
278
  set raw(data) {
48
- if (this.isImmutable()) {
49
- throw new Error('Cannot modify an immutable PdfStream');
50
- }
51
279
  this.setModified();
52
280
  this.original = data;
53
281
  this.header.set('Length', new PdfNumber(data.length));
@@ -61,6 +289,28 @@ export class PdfStream extends PdfObject {
61
289
  set rawAsString(str) {
62
290
  this.raw = stringToBytes(str);
63
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);
313
+ }
64
314
  getFilters() {
65
315
  const filters = this.header.get('Filter');
66
316
  if (!filters) {
@@ -94,23 +344,24 @@ export class PdfStream extends PdfObject {
94
344
  this.raw = filter.encode(this.raw);
95
345
  return this;
96
346
  }
97
- setPredictor(predictorParams) {
98
- let decodeParms = this.header.get('DecodeParms')?.as(PdfDictionary);
99
- if (!decodeParms) {
100
- decodeParms = new PdfDictionary();
101
- this.header.set('DecodeParms', decodeParms);
102
- }
103
- else if (decodeParms instanceof PdfDictionary) {
104
- // already a dictionary
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;
105
355
  }
106
- else {
107
- throw new Error('Invalid DecodeParms entry in PDF stream');
108
- }
109
- for (const [key, value] of Object.entries(predictorParams)) {
110
- decodeParms.set(key, new PdfNumber(value));
356
+ if (raw instanceof PdfDictionary) {
357
+ return PdfStreamPredictor.fromDictionary(raw);
111
358
  }
112
- this.raw = Predictor.encode(this.raw, predictorParams);
113
- 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);
114
365
  }
115
366
  removeFilter(filterName) {
116
367
  let filters = this.header.get('Filter');
@@ -159,9 +410,9 @@ export class PdfStream extends PdfObject {
159
410
  const filter = PdfStream.getFilter(filterName);
160
411
  data = filter.decode(data);
161
412
  }
162
- const predictorParams = Predictor.getDecodeParms(this.header.get('DecodeParms')?.as(PdfDictionary));
163
- if (predictorParams) {
164
- data = Predictor.decode(data, predictorParams);
413
+ const streamPredictor = PdfStreamPredictor.fromDictionary(this.header.get('DecodeParms')?.as(PdfDictionary));
414
+ if (streamPredictor) {
415
+ data = streamPredictor.decode(data);
165
416
  }
166
417
  return data;
167
418
  }
@@ -235,6 +486,14 @@ export class PdfStream extends PdfObject {
235
486
  }
236
487
  }
237
488
  export class PdfObjStream extends PdfStream {
489
+ _parsedObjects;
490
+ set raw(data) {
491
+ super.raw = data;
492
+ this._parsedObjects = undefined;
493
+ }
494
+ get raw() {
495
+ return super.raw;
496
+ }
238
497
  constructor(options) {
239
498
  super(options);
240
499
  if (!this.isType('ObjStm')) {
@@ -297,8 +556,11 @@ export class PdfObjStream extends PdfStream {
297
556
  const { value: obj, done } = reader.next();
298
557
  if (done)
299
558
  break;
300
- if (obj instanceof PdfNumber) {
301
- // Collect object numbers and byte offsets
559
+ if (obj instanceof PdfNumber &&
560
+ (totalObjects === 0 || numbers.length < totalObjects * 2)) {
561
+ // Collect object numbers and byte offsets from the header section.
562
+ // Stop once we have all 2*N pairs so that object values that happen
563
+ // to be plain integers are not mistakenly treated as header entries.
302
564
  numbers.push(obj);
303
565
  }
304
566
  else {
@@ -307,11 +569,14 @@ export class PdfObjStream extends PdfStream {
307
569
  // After that come the actual objects
308
570
  const objectNumber = numbers[i * 2].value;
309
571
  const generationNumber = 0;
310
- yield new PdfIndirectObject({
572
+ const decompressedObject = new PdfIndirectObject({
311
573
  objectNumber,
312
574
  generationNumber,
313
575
  content: obj,
314
- });
576
+ compressed: true,
577
+ }).clone();
578
+ decompressedObject.setModified(false);
579
+ yield decompressedObject;
315
580
  i++;
316
581
  // Stop after we've read N objects
317
582
  if (totalObjects > 0 && i >= totalObjects) {
@@ -320,16 +585,20 @@ export class PdfObjStream extends PdfStream {
320
585
  }
321
586
  }
322
587
  }
323
- getObject(options) {
324
- for (const obj of this.getObjectStream()) {
325
- if (obj.objectNumber === options.objectNumber) {
326
- return obj;
588
+ getParsedObjects() {
589
+ if (!this._parsedObjects) {
590
+ this._parsedObjects = new Map();
591
+ for (const obj of this.getObjectStream()) {
592
+ this._parsedObjects.set(obj.objectNumber, obj);
327
593
  }
328
594
  }
329
- return undefined;
595
+ return this._parsedObjects;
596
+ }
597
+ getObject(options) {
598
+ return this.getParsedObjects().get(options.objectNumber);
330
599
  }
331
600
  getObjects() {
332
- return Array.from(this.getObjectStream());
601
+ return Array.from(this.getParsedObjects().values());
333
602
  }
334
603
  cloneImpl() {
335
604
  return new PdfObjStream({
@@ -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);
@@ -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
  /**