pdf-lite 1.3.1 → 1.3.2

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/README.md CHANGED
@@ -13,10 +13,10 @@ PRs and issues are welcome!
13
13
 
14
14
  ## Features
15
15
 
16
- - **Zero dependencies**: No external libraries are required, making it lightweight and easy to integrate.
17
16
  - **Type-safe**: Built with TypeScript, ensuring type safety and reducing runtime errors.
18
17
  - **Browser and Node.js support**: Works seamlessly in both environments, allowing for versatile usage.
19
18
  - **Low-level API**: Provides a low-level API for advanced users who want to manipulate PDF files directly, as well as a higher-level API for easier usage.
19
+ - **Minimal dependencies**: A small number external libraries are required, making it lightweight and easy to integrate.
20
20
 
21
21
  ## Installation
22
22
 
@@ -44,7 +44,8 @@ export class PdfAcroFormField extends PdfIndirectObject {
44
44
  * Gets the field type
45
45
  */
46
46
  get fieldType() {
47
- const ft = this.content.get('FT')?.value;
47
+ const ft = this.content.get('FT')?.value ??
48
+ this.parent?.content.get('FT')?.value;
48
49
  switch (ft) {
49
50
  case 'Tx':
50
51
  return 'Text';
@@ -128,7 +129,7 @@ export class PdfAcroFormField extends PdfIndirectObject {
128
129
  * Gets the default value
129
130
  */
130
131
  get defaultValue() {
131
- const dv = this.content.get('DV');
132
+ const dv = this.content.get('DV') ?? this.parent?.content.get('DV');
132
133
  if (dv instanceof PdfString) {
133
134
  return dv.value;
134
135
  }
@@ -150,7 +151,8 @@ export class PdfAcroFormField extends PdfIndirectObject {
150
151
  }
151
152
  }
152
153
  get value() {
153
- const v = this.content.get('V');
154
+ // V may be on this field or inherited from parent (parent/kids split)
155
+ const v = this.content.get('V') ?? this.parent?.content.get('V');
154
156
  if (v instanceof PdfString) {
155
157
  // UTF-16BE strings should always use UTF-16BE decoding regardless of font encoding
156
158
  if (v.isUTF16BE) {
@@ -170,19 +172,21 @@ export class PdfAcroFormField extends PdfIndirectObject {
170
172
  if (this.value === val) {
171
173
  return;
172
174
  }
175
+ // In a parent/kids split, V should be set on the parent field
176
+ const target = this.parent ?? this;
173
177
  const fieldType = this.fieldType;
174
178
  if (fieldType === 'Button') {
175
179
  val = val instanceof PdfString ? val.value : val;
176
180
  if (val.trim() === '') {
177
- this.content.delete('V');
181
+ target.content.delete('V');
178
182
  this.content.delete('AS');
179
183
  return;
180
184
  }
181
- this.content.set('V', new PdfName(val));
185
+ target.content.set('V', new PdfName(val));
182
186
  this.content.set('AS', new PdfName(val));
183
187
  }
184
188
  else {
185
- this.content.set('V', val instanceof PdfString ? val : new PdfString(val));
189
+ target.content.set('V', val instanceof PdfString ? val : new PdfString(val));
186
190
  }
187
191
  if (this.defaultGenerateAppearance) {
188
192
  this.generateAppearance();
@@ -190,25 +194,26 @@ export class PdfAcroFormField extends PdfIndirectObject {
190
194
  }
191
195
  get checked() {
192
196
  if (this.fieldType === 'Button') {
193
- const v = this.content.get('V');
197
+ const v = this.content.get('V') ?? this.parent?.content.get('V');
194
198
  return v instanceof PdfName && v.value === 'Yes';
195
199
  }
196
200
  return false;
197
201
  }
198
202
  set checked(isChecked) {
199
203
  if (this.fieldType === 'Button') {
204
+ const target = this.parent ?? this;
200
205
  if (isChecked) {
201
- this.content.set('V', new PdfName('Yes'));
206
+ target.content.set('V', new PdfName('Yes'));
202
207
  this.content.set('AS', new PdfName('Yes'));
203
208
  }
204
209
  else {
205
- this.content.set('V', new PdfName('Off'));
210
+ target.content.set('V', new PdfName('Off'));
206
211
  this.content.set('AS', new PdfName('Off'));
207
212
  }
208
213
  }
209
214
  }
210
215
  get fontSize() {
211
- const da = this.content.get('DA')?.as(PdfString)?.value || '';
216
+ const da = this.defaultAppearance || '';
212
217
  const match = da.match(/\/[A-Za-z0-9_-]+\s+([\d.]+)\s+Tf/);
213
218
  if (match) {
214
219
  return parseFloat(match[1]);
@@ -216,7 +221,7 @@ export class PdfAcroFormField extends PdfIndirectObject {
216
221
  return null;
217
222
  }
218
223
  set fontSize(size) {
219
- const da = this.content.get('DA')?.as(PdfString)?.value || '';
224
+ const da = this.defaultAppearance || '';
220
225
  if (!da) {
221
226
  this.content.set('DA', new PdfString(`/F1 ${size} Tf 0 g`));
222
227
  return;
@@ -225,7 +230,7 @@ export class PdfAcroFormField extends PdfIndirectObject {
225
230
  this.content.set('DA', new PdfString(updatedDa));
226
231
  }
227
232
  get fontName() {
228
- const da = this.content.get('DA')?.as(PdfString)?.value || '';
233
+ const da = this.defaultAppearance || '';
229
234
  const match = da.match(/\/([A-Za-z0-9_-]+)\s+[\d.]+\s+Tf/);
230
235
  if (match) {
231
236
  return match[1];
@@ -233,7 +238,7 @@ export class PdfAcroFormField extends PdfIndirectObject {
233
238
  return null;
234
239
  }
235
240
  set fontName(fontName) {
236
- const da = this.content.get('DA')?.as(PdfString)?.value || '';
241
+ const da = this.defaultAppearance || '';
237
242
  if (!da) {
238
243
  this.content.set('DA', new PdfString(`/${fontName} 12 Tf 0 g`));
239
244
  return;
@@ -253,7 +258,7 @@ export class PdfAcroFormField extends PdfIndirectObject {
253
258
  }
254
259
  const resourceName = font.resourceName;
255
260
  const currentSize = this.fontSize ?? 12;
256
- const da = this.content.get('DA')?.as(PdfString)?.value || '';
261
+ const da = this.defaultAppearance || '';
257
262
  if (!da) {
258
263
  this.content.set('DA', new PdfString(`/${resourceName} ${currentSize} Tf 0 g`));
259
264
  return;
@@ -265,7 +270,9 @@ export class PdfAcroFormField extends PdfIndirectObject {
265
270
  * Gets field flags (bitwise combination of field attributes)
266
271
  */
267
272
  get flags() {
268
- return this.content.get('Ff')?.as(PdfNumber)?.value ?? 0;
273
+ return (this.content.get('Ff')?.as(PdfNumber)?.value ??
274
+ this.parent?.content.get('Ff')?.as(PdfNumber)?.value ??
275
+ 0);
269
276
  }
270
277
  /**
271
278
  * Sets field flags
@@ -364,7 +371,9 @@ export class PdfAcroFormField extends PdfIndirectObject {
364
371
  * 0 = left-justified, 1 = centered, 2 = right-justified
365
372
  */
366
373
  get quadding() {
367
- return this.content.get('Q')?.as(PdfNumber)?.value ?? 0;
374
+ return (this.content.get('Q')?.as(PdfNumber)?.value ??
375
+ this.parent?.content.get('Q')?.as(PdfNumber)?.value ??
376
+ 0);
368
377
  }
369
378
  /**
370
379
  * Sets the quadding (text alignment) for this field.
@@ -378,7 +387,8 @@ export class PdfAcroFormField extends PdfIndirectObject {
378
387
  * Returns an array of option strings.
379
388
  */
380
389
  get options() {
381
- const opt = this.content.get('Opt')?.as((PdfArray));
390
+ const opt = this.content.get('Opt')?.as((PdfArray)) ??
391
+ this.parent?.content.get('Opt')?.as((PdfArray));
382
392
  if (!opt)
383
393
  return [];
384
394
  return opt.items.map((item) => item.value);
@@ -396,7 +406,9 @@ export class PdfAcroFormField extends PdfIndirectObject {
396
406
  this.content.set('Opt', optArray);
397
407
  }
398
408
  get defaultAppearance() {
399
- return this.content.get('DA')?.as(PdfString)?.value ?? null;
409
+ return (this.content.get('DA')?.as(PdfString)?.value ??
410
+ this.parent?.content.get('DA')?.as(PdfString)?.value ??
411
+ null);
400
412
  }
401
413
  set defaultAppearance(da) {
402
414
  this.content.set('DA', new PdfString(da));
@@ -747,8 +759,9 @@ export class PdfAcroFormField extends PdfIndirectObject {
747
759
  const [x1, y1, x2, y2] = rect;
748
760
  const width = x2 - x1;
749
761
  const height = y2 - y1;
750
- // Get the default appearance string
751
- const da = this.content.get('DA')?.as(PdfString)?.value;
762
+ // Get the default appearance string (may be inherited from parent)
763
+ const da = this.content.get('DA')?.as(PdfString)?.value ??
764
+ this.parent?.content.get('DA')?.as(PdfString)?.value;
752
765
  if (!da)
753
766
  return false;
754
767
  // Get the field value
@@ -858,6 +871,25 @@ EMC
858
871
  new PdfNumber(width),
859
872
  new PdfNumber(height),
860
873
  ]));
874
+ // Add font resources so Acrobat can resolve the font name.
875
+ // Prefer the field's own DR (which has correctly resolved refs in incremental updates),
876
+ // then fall back to the AcroForm-level DR.
877
+ const fieldDR = this.content
878
+ .get('DR')
879
+ ?.as(PdfDictionary);
880
+ const acroformDR = this.form?.defaultResources;
881
+ const fontSource = fieldDR?.get('Font')?.as(PdfDictionary) ??
882
+ acroformDR?.get('Font')?.as(PdfDictionary);
883
+ if (fontSource && fontName) {
884
+ const fontRef = fontSource.get(fontName);
885
+ if (fontRef) {
886
+ const resourceFontDict = new PdfDictionary();
887
+ resourceFontDict.set(fontName, fontRef);
888
+ const resourcesDict = new PdfDictionary();
889
+ resourcesDict.set('Font', resourceFontDict);
890
+ appearanceDict.set('Resources', resourcesDict);
891
+ }
892
+ }
861
893
  const stream = new PdfStream({
862
894
  header: appearanceDict,
863
895
  original: contentStream,
@@ -978,8 +1010,9 @@ Q
978
1010
  const [x1, y1, x2, y2] = rect;
979
1011
  const width = x2 - x1;
980
1012
  const height = y2 - y1;
981
- // Get the default appearance string
982
- const da = this.content.get('DA')?.as(PdfString)?.value;
1013
+ // Get the default appearance string (may be inherited from parent)
1014
+ const da = this.content.get('DA')?.as(PdfString)?.value ??
1015
+ this.parent?.content.get('DA')?.as(PdfString)?.value;
983
1016
  if (!da)
984
1017
  return false;
985
1018
  const value = this.value;
@@ -1045,6 +1078,23 @@ EMC
1045
1078
  new PdfNumber(width),
1046
1079
  new PdfNumber(height),
1047
1080
  ]));
1081
+ // Add font resources so Acrobat can resolve the font name.
1082
+ const fieldDR = this.content
1083
+ .get('DR')
1084
+ ?.as(PdfDictionary);
1085
+ const acroformDR = this.form?.defaultResources;
1086
+ const fontSource = fieldDR?.get('Font')?.as(PdfDictionary) ??
1087
+ acroformDR?.get('Font')?.as(PdfDictionary);
1088
+ if (fontSource && fontName) {
1089
+ const fontRef = fontSource.get(fontName);
1090
+ if (fontRef) {
1091
+ const resourceFontDict = new PdfDictionary();
1092
+ resourceFontDict.set(fontName, fontRef);
1093
+ const resourcesDict = new PdfDictionary();
1094
+ resourcesDict.set('Font', resourceFontDict);
1095
+ appearanceDict.set('Resources', resourcesDict);
1096
+ }
1097
+ }
1048
1098
  const stream = new PdfStream({
1049
1099
  header: appearanceDict,
1050
1100
  original: contentStream,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdf-lite",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "exports": {