pdf-lite 1.7.1 → 1.7.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/dist/acroform/appearance/pdf-graphics.d.ts +5 -6
- package/dist/acroform/appearance/pdf-graphics.js +51 -14
- package/dist/acroform/appearance/pdf-text-appearance-stream.js +4 -4
- package/dist/acroform/fields/pdf-form-field.d.ts +2 -0
- package/dist/acroform/fields/pdf-form-field.js +32 -22
- package/dist/acroform/fields/pdf-text-form-field.js +1 -1
- package/dist/acroform/pdf-acro-form.js +14 -4
- package/dist/utils/parse-markdown-segments.d.ts +4 -3
- package/dist/utils/parse-markdown-segments.js +54 -10
- package/package.json +1 -1
|
@@ -65,15 +65,14 @@ export declare class PdfGraphics {
|
|
|
65
65
|
measureTextWidthWithFont(text: string, fontName: string | undefined, fontSize: number): number;
|
|
66
66
|
/**
|
|
67
67
|
* Emits styled text segments into the current BT…ET block.
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* no variant fonts are provided (backward compatible).
|
|
71
|
-
* Each segment is positioned with an absolute Tm so no prior Td is needed.
|
|
68
|
+
* Returns an array of rects for any strikethrough segments so the caller
|
|
69
|
+
* can draw the lines after closing the text object.
|
|
72
70
|
*/
|
|
73
71
|
private showSegments;
|
|
74
72
|
/**
|
|
75
|
-
* Parses a markdown string
|
|
76
|
-
*
|
|
73
|
+
* Parses a markdown string, renders the styled segments inside a BT…ET
|
|
74
|
+
* block, then draws strikethrough lines (if any) as path operations after
|
|
75
|
+
* the text object. Pass `multiline` to wrap across multiple lines.
|
|
77
76
|
*/
|
|
78
77
|
showMarkdown(markdown: string, isUnicode: boolean, reverseEncodingMap: Map<string, number> | undefined, x: number, y: number, fontSize: number, multiline?: {
|
|
79
78
|
availableWidth: number;
|
|
@@ -110,7 +110,12 @@ export class PdfGraphics {
|
|
|
110
110
|
const chars = [];
|
|
111
111
|
for (const seg of segments) {
|
|
112
112
|
for (const char of seg.text) {
|
|
113
|
-
chars.push({
|
|
113
|
+
chars.push({
|
|
114
|
+
char,
|
|
115
|
+
bold: seg.bold,
|
|
116
|
+
italic: seg.italic,
|
|
117
|
+
strikethrough: seg.strikethrough,
|
|
118
|
+
});
|
|
114
119
|
}
|
|
115
120
|
}
|
|
116
121
|
const result = [];
|
|
@@ -125,23 +130,29 @@ export class PdfGraphics {
|
|
|
125
130
|
let curText = '';
|
|
126
131
|
let curBold = false;
|
|
127
132
|
let curItalic = false;
|
|
133
|
+
let curStrikethrough = false;
|
|
128
134
|
const lineLen = lines[lineIdx].replace(/\r/g, '').length;
|
|
129
135
|
for (let j = 0; j < lineLen && pos < chars.length; j++, pos++) {
|
|
130
|
-
const { char, bold, italic } = chars[pos];
|
|
136
|
+
const { char, bold, italic, strikethrough } = chars[pos];
|
|
131
137
|
if (curText === '') {
|
|
132
138
|
curText = char;
|
|
133
139
|
curBold = bold;
|
|
134
140
|
curItalic = italic;
|
|
141
|
+
curStrikethrough = strikethrough;
|
|
135
142
|
}
|
|
136
|
-
else if (bold !== curBold ||
|
|
143
|
+
else if (bold !== curBold ||
|
|
144
|
+
italic !== curItalic ||
|
|
145
|
+
strikethrough !== curStrikethrough) {
|
|
137
146
|
lineSegs.push({
|
|
138
147
|
text: curText,
|
|
139
148
|
bold: curBold,
|
|
140
149
|
italic: curItalic,
|
|
150
|
+
strikethrough: curStrikethrough,
|
|
141
151
|
});
|
|
142
152
|
curText = char;
|
|
143
153
|
curBold = bold;
|
|
144
154
|
curItalic = italic;
|
|
155
|
+
curStrikethrough = strikethrough;
|
|
145
156
|
}
|
|
146
157
|
else {
|
|
147
158
|
curText += char;
|
|
@@ -152,6 +163,7 @@ export class PdfGraphics {
|
|
|
152
163
|
text: curText,
|
|
153
164
|
bold: curBold,
|
|
154
165
|
italic: curItalic,
|
|
166
|
+
strikethrough: curStrikethrough,
|
|
155
167
|
});
|
|
156
168
|
result.push(lineSegs);
|
|
157
169
|
}
|
|
@@ -189,14 +201,13 @@ export class PdfGraphics {
|
|
|
189
201
|
}
|
|
190
202
|
/**
|
|
191
203
|
* Emits styled text segments into the current BT…ET block.
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
* no variant fonts are provided (backward compatible).
|
|
195
|
-
* Each segment is positioned with an absolute Tm so no prior Td is needed.
|
|
204
|
+
* Returns an array of rects for any strikethrough segments so the caller
|
|
205
|
+
* can draw the lines after closing the text object.
|
|
196
206
|
*/
|
|
197
207
|
showSegments(lineSegs, isUnicode, reverseEncodingMap, startX, startY, fontSize) {
|
|
198
208
|
const regularFontName = this.defaultAppearance.fontName;
|
|
199
209
|
let x = startX;
|
|
210
|
+
const strikethroughRects = [];
|
|
200
211
|
for (const seg of lineSegs) {
|
|
201
212
|
const variantName = this.resolveVariantFontName(seg.bold, seg.italic);
|
|
202
213
|
if (variantName) {
|
|
@@ -208,7 +219,11 @@ export class PdfGraphics {
|
|
|
208
219
|
this.raw(`/${variantName} ${fontSize} Tf`);
|
|
209
220
|
this.raw(`0 Tr`);
|
|
210
221
|
this.showText(seg.text, segIsUnicode, segEncMap);
|
|
211
|
-
|
|
222
|
+
const segWidth = this.measureTextWidthWithFont(seg.text, variantName, fontSize);
|
|
223
|
+
if (seg.strikethrough) {
|
|
224
|
+
strikethroughRects.push({ x, y: startY, width: segWidth });
|
|
225
|
+
}
|
|
226
|
+
x += segWidth;
|
|
212
227
|
}
|
|
213
228
|
else {
|
|
214
229
|
// Fallback simulation (no variant font provided)
|
|
@@ -224,30 +239,52 @@ export class PdfGraphics {
|
|
|
224
239
|
this.raw(`0 Tr`);
|
|
225
240
|
}
|
|
226
241
|
this.showText(seg.text, isUnicode, reverseEncodingMap);
|
|
227
|
-
|
|
242
|
+
const segWidth = this.measureTextWidth(seg.text, fontSize);
|
|
243
|
+
if (seg.strikethrough) {
|
|
244
|
+
strikethroughRects.push({ x, y: startY, width: segWidth });
|
|
245
|
+
}
|
|
246
|
+
x += segWidth;
|
|
228
247
|
}
|
|
229
248
|
}
|
|
230
249
|
// Restore regular font and fill-only rendering mode
|
|
231
250
|
this.raw(`/${regularFontName} ${fontSize} Tf`);
|
|
232
251
|
this.raw(`0 Tr`);
|
|
233
|
-
return
|
|
252
|
+
return strikethroughRects;
|
|
234
253
|
}
|
|
235
254
|
/**
|
|
236
|
-
* Parses a markdown string
|
|
237
|
-
*
|
|
255
|
+
* Parses a markdown string, renders the styled segments inside a BT…ET
|
|
256
|
+
* block, then draws strikethrough lines (if any) as path operations after
|
|
257
|
+
* the text object. Pass `multiline` to wrap across multiple lines.
|
|
238
258
|
*/
|
|
239
259
|
showMarkdown(markdown, isUnicode, reverseEncodingMap, x, y, fontSize, multiline) {
|
|
240
260
|
const segments = parseMarkdownSegments(markdown);
|
|
261
|
+
const allStrikethroughRects = [];
|
|
262
|
+
this.beginText();
|
|
241
263
|
if (multiline) {
|
|
242
264
|
const plainText = segments.map((s) => s.text).join('');
|
|
243
265
|
const lines = this.wrapTextToLines(plainText, multiline.availableWidth);
|
|
244
266
|
const styledLines = PdfGraphics.splitSegmentsToLines(segments, lines);
|
|
245
267
|
for (let i = 0; i < styledLines.length; i++) {
|
|
246
|
-
this.showSegments(styledLines[i], isUnicode, reverseEncodingMap, x, y - i * multiline.lineHeight, fontSize);
|
|
268
|
+
const rects = this.showSegments(styledLines[i], isUnicode, reverseEncodingMap, x, y - i * multiline.lineHeight, fontSize);
|
|
269
|
+
allStrikethroughRects.push(...rects);
|
|
247
270
|
}
|
|
248
271
|
}
|
|
249
272
|
else {
|
|
250
|
-
this.showSegments(segments, isUnicode, reverseEncodingMap, x, y, fontSize);
|
|
273
|
+
const rects = this.showSegments(segments, isUnicode, reverseEncodingMap, x, y, fontSize);
|
|
274
|
+
allStrikethroughRects.push(...rects);
|
|
275
|
+
}
|
|
276
|
+
this.endText();
|
|
277
|
+
// Draw strikethrough lines outside the text object
|
|
278
|
+
if (allStrikethroughRects.length > 0) {
|
|
279
|
+
const lineY = fontSize * 0.35;
|
|
280
|
+
const lineWidth = Math.max(0.5, fontSize * 0.06);
|
|
281
|
+
this.raw(`q`);
|
|
282
|
+
this.raw(`${lineWidth.toFixed(3)} w`);
|
|
283
|
+
for (const rect of allStrikethroughRects) {
|
|
284
|
+
const sy = (rect.y + lineY).toFixed(3);
|
|
285
|
+
this.raw(`${rect.x.toFixed(3)} ${sy} m ${(rect.x + rect.width).toFixed(3)} ${sy} l S`);
|
|
286
|
+
}
|
|
287
|
+
this.raw(`Q`);
|
|
251
288
|
}
|
|
252
289
|
return this;
|
|
253
290
|
}
|
|
@@ -100,7 +100,6 @@ export class PdfTextAppearanceStream extends PdfAppearanceStream {
|
|
|
100
100
|
lines = g.wrapTextToLines(value, availableWidth);
|
|
101
101
|
const renderLineHeight = finalFontSize * 1.2;
|
|
102
102
|
const startY = height - padding - finalFontSize;
|
|
103
|
-
g.beginText();
|
|
104
103
|
if (ctx.markdown) {
|
|
105
104
|
g.showMarkdown(ctx.markdown, isUnicode, reverseEncodingMap, padding, startY, finalFontSize, {
|
|
106
105
|
availableWidth,
|
|
@@ -108,14 +107,15 @@ export class PdfTextAppearanceStream extends PdfAppearanceStream {
|
|
|
108
107
|
});
|
|
109
108
|
}
|
|
110
109
|
else {
|
|
110
|
+
g.beginText();
|
|
111
111
|
g.moveTo(padding, startY);
|
|
112
112
|
for (let i = 0; i < lines.length; i++) {
|
|
113
113
|
if (i > 0)
|
|
114
114
|
g.moveTo(0, -renderLineHeight);
|
|
115
115
|
g.showText(lines[i].replace(/\r/g, ''), isUnicode, reverseEncodingMap);
|
|
116
116
|
}
|
|
117
|
+
g.endText();
|
|
117
118
|
}
|
|
118
|
-
g.endText();
|
|
119
119
|
}
|
|
120
120
|
else {
|
|
121
121
|
// Single line — for non-auto-size, shrink if text overflows
|
|
@@ -126,15 +126,15 @@ export class PdfTextAppearanceStream extends PdfAppearanceStream {
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
const textY = (height - finalFontSize) / 2 + finalFontSize * 0.2;
|
|
129
|
-
g.beginText();
|
|
130
129
|
if (ctx.markdown) {
|
|
131
130
|
g.showMarkdown(ctx.markdown, isUnicode, reverseEncodingMap, padding, textY, finalFontSize);
|
|
132
131
|
}
|
|
133
132
|
else {
|
|
133
|
+
g.beginText();
|
|
134
134
|
g.moveTo(padding, textY);
|
|
135
135
|
g.showText(value, isUnicode, reverseEncodingMap);
|
|
136
|
+
g.endText();
|
|
136
137
|
}
|
|
137
|
-
g.endText();
|
|
138
138
|
}
|
|
139
139
|
g.restore();
|
|
140
140
|
g.endMarkedContent();
|
|
@@ -62,7 +62,9 @@ export declare abstract class PdfFormField extends PdfWidgetAnnotation {
|
|
|
62
62
|
set onState(state: string);
|
|
63
63
|
get value(): string;
|
|
64
64
|
protected setRawValue(val: string | PdfString): void;
|
|
65
|
+
updateAppearance(cache?: Set<PdfIndirectObject>): void;
|
|
65
66
|
set value(val: string | PdfString);
|
|
67
|
+
get markdownValue(): string | undefined;
|
|
66
68
|
set markdownValue(val: string);
|
|
67
69
|
get fontSize(): number | null;
|
|
68
70
|
set fontSize(size: number);
|
|
@@ -83,11 +83,19 @@ export class PdfFormField extends PdfWidgetAnnotation {
|
|
|
83
83
|
const page = this.page;
|
|
84
84
|
if (page) {
|
|
85
85
|
const annots = page.annotations;
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
|
|
86
|
+
const widget = this;
|
|
87
|
+
const alreadyPresent = annots.items.some((r) => {
|
|
88
|
+
if (!(r instanceof PdfObjectReference))
|
|
89
|
+
return false;
|
|
90
|
+
try {
|
|
91
|
+
return r.resolve() === widget;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
89
97
|
if (!alreadyPresent) {
|
|
90
|
-
annots.items.push(
|
|
98
|
+
annots.items.push(this.reference);
|
|
91
99
|
}
|
|
92
100
|
}
|
|
93
101
|
}
|
|
@@ -111,7 +119,7 @@ export class PdfFormField extends PdfWidgetAnnotation {
|
|
|
111
119
|
}
|
|
112
120
|
}
|
|
113
121
|
get siblings() {
|
|
114
|
-
return this.parent?.children ?? [];
|
|
122
|
+
return (this.parent?.children ?? []).filter((sib) => sib !== this);
|
|
115
123
|
}
|
|
116
124
|
get font() {
|
|
117
125
|
const fontName = this.fontName;
|
|
@@ -320,35 +328,39 @@ export class PdfFormField extends PdfWidgetAnnotation {
|
|
|
320
328
|
target.content.set('V', pdfVal);
|
|
321
329
|
}
|
|
322
330
|
}
|
|
323
|
-
|
|
324
|
-
|
|
331
|
+
for (const child of this.children) {
|
|
332
|
+
if (child.content.has('V')) {
|
|
333
|
+
child.content.delete('V');
|
|
334
|
+
}
|
|
325
335
|
}
|
|
336
|
+
this._form?.xfa?.datasets?.updateField(this.name, this.value);
|
|
337
|
+
this.updateAppearance();
|
|
338
|
+
}
|
|
339
|
+
updateAppearance(cache = new Set()) {
|
|
340
|
+
if (cache.has(this))
|
|
341
|
+
return;
|
|
342
|
+
cache.add(this);
|
|
326
343
|
if (this.defaultGenerateAppearance) {
|
|
327
344
|
this.generateAppearance();
|
|
328
345
|
}
|
|
329
346
|
for (const sibling of this.siblings) {
|
|
330
|
-
|
|
331
|
-
sibling.generateAppearance();
|
|
332
|
-
}
|
|
347
|
+
sibling.updateAppearance(cache);
|
|
333
348
|
}
|
|
334
349
|
// Separated field/widget structure: field has no Rect but its Kids
|
|
335
350
|
// are widget annotations that do. Clear stale V entries on children
|
|
336
351
|
// so they inherit the parent's value, then generate appearances.
|
|
337
352
|
for (const child of this.children) {
|
|
338
|
-
if (
|
|
339
|
-
child.
|
|
340
|
-
|
|
341
|
-
if (child.defaultGenerateAppearance) {
|
|
342
|
-
if (this._form)
|
|
343
|
-
child.form = this._form;
|
|
344
|
-
child.generateAppearance();
|
|
345
|
-
}
|
|
353
|
+
if (this._form)
|
|
354
|
+
child.form = this._form;
|
|
355
|
+
child.updateAppearance(cache);
|
|
346
356
|
}
|
|
347
|
-
this._form?.xfa?.datasets?.updateField(this.name, this.value);
|
|
348
357
|
}
|
|
349
358
|
set value(val) {
|
|
350
359
|
this.setRawValue(val);
|
|
351
360
|
}
|
|
361
|
+
get markdownValue() {
|
|
362
|
+
return this._markdownValue ?? this.parent?._markdownValue;
|
|
363
|
+
}
|
|
352
364
|
set markdownValue(val) {
|
|
353
365
|
const plainText = parseMarkdownSegments(val)
|
|
354
366
|
.map((s) => s.text)
|
|
@@ -360,9 +372,7 @@ export class PdfFormField extends PdfWidgetAnnotation {
|
|
|
360
372
|
this.defaultGenerateAppearance = saved;
|
|
361
373
|
// setRawValue cleared _markdownValue; store the markdown string now
|
|
362
374
|
this._markdownValue = val;
|
|
363
|
-
|
|
364
|
-
this.generateAppearance();
|
|
365
|
-
}
|
|
375
|
+
this.updateAppearance();
|
|
366
376
|
}
|
|
367
377
|
get fontSize() {
|
|
368
378
|
const da = this.defaultAppearance || '';
|
|
@@ -119,11 +119,21 @@ export class PdfAcroForm extends PdfIndirectObject {
|
|
|
119
119
|
const page = field.page;
|
|
120
120
|
if (!page)
|
|
121
121
|
return;
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
const annots = page.annotations;
|
|
123
|
+
// Unregistered fields all share key "-1/0", so compare by object
|
|
124
|
+
// identity (via resolve()) rather than by key.
|
|
125
|
+
const alreadyPresent = annots.items.some((r) => {
|
|
126
|
+
if (!(r instanceof PdfObjectReference))
|
|
127
|
+
return false;
|
|
128
|
+
try {
|
|
129
|
+
return r.resolve() === field;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
125
135
|
if (!alreadyPresent) {
|
|
126
|
-
|
|
136
|
+
annots.items.push(field.reference);
|
|
127
137
|
}
|
|
128
138
|
}
|
|
129
139
|
set fields(newFields) {
|
|
@@ -2,11 +2,12 @@ export type StyledSegment = {
|
|
|
2
2
|
text: string;
|
|
3
3
|
bold: boolean;
|
|
4
4
|
italic: boolean;
|
|
5
|
+
strikethrough: boolean;
|
|
5
6
|
};
|
|
6
7
|
/**
|
|
7
|
-
* Parses a markdown string with **bold**, *italic*,
|
|
8
|
-
* syntax into an array of styled text segments.
|
|
8
|
+
* Parses a markdown string with **bold**, __bold__, *italic*, ***bold+italic***,
|
|
9
|
+
* and ~~strikethrough~~ syntax into an array of styled text segments.
|
|
9
10
|
*
|
|
10
|
-
* Unrecognized or unmatched
|
|
11
|
+
* Unrecognized or unmatched markers are emitted as plain text.
|
|
11
12
|
*/
|
|
12
13
|
export declare function parseMarkdownSegments(text: string): StyledSegment[];
|
|
@@ -1,26 +1,70 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Parses a markdown string with **bold**, *italic*,
|
|
3
|
-
* syntax into an array of styled text segments.
|
|
2
|
+
* Parses a markdown string with **bold**, __bold__, *italic*, ***bold+italic***,
|
|
3
|
+
* and ~~strikethrough~~ syntax into an array of styled text segments.
|
|
4
4
|
*
|
|
5
|
-
* Unrecognized or unmatched
|
|
5
|
+
* Unrecognized or unmatched markers are emitted as plain text.
|
|
6
6
|
*/
|
|
7
7
|
export function parseMarkdownSegments(text) {
|
|
8
8
|
const segments = [];
|
|
9
|
-
// Match
|
|
10
|
-
const re = /\*\*\*(.+?)\*\*\*|\*\*(.+?)
|
|
9
|
+
// Match longest tokens first: ***…***, **…**, __…__, ~~…~~, *…*, _…_
|
|
10
|
+
const re = /\*\*\*(.+?)\*\*\*|\*\*(.+?)\*\*|__(.+?)__|~~(.+?)~~|\*(.+?)\*|_(.+?)_|([^*_~]+|[*_~])/gs;
|
|
11
11
|
let match;
|
|
12
12
|
while ((match = re.exec(text)) !== null) {
|
|
13
13
|
if (match[1] !== undefined) {
|
|
14
|
-
segments.push({
|
|
14
|
+
segments.push({
|
|
15
|
+
text: match[1],
|
|
16
|
+
bold: true,
|
|
17
|
+
italic: true,
|
|
18
|
+
strikethrough: false,
|
|
19
|
+
});
|
|
15
20
|
}
|
|
16
21
|
else if (match[2] !== undefined) {
|
|
17
|
-
segments.push({
|
|
22
|
+
segments.push({
|
|
23
|
+
text: match[2],
|
|
24
|
+
bold: true,
|
|
25
|
+
italic: false,
|
|
26
|
+
strikethrough: false,
|
|
27
|
+
});
|
|
18
28
|
}
|
|
19
29
|
else if (match[3] !== undefined) {
|
|
20
|
-
segments.push({
|
|
30
|
+
segments.push({
|
|
31
|
+
text: match[3],
|
|
32
|
+
bold: true,
|
|
33
|
+
italic: false,
|
|
34
|
+
strikethrough: false,
|
|
35
|
+
});
|
|
21
36
|
}
|
|
22
|
-
else if (match[4] !== undefined
|
|
23
|
-
segments.push({
|
|
37
|
+
else if (match[4] !== undefined) {
|
|
38
|
+
segments.push({
|
|
39
|
+
text: match[4],
|
|
40
|
+
bold: false,
|
|
41
|
+
italic: false,
|
|
42
|
+
strikethrough: true,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
else if (match[5] !== undefined) {
|
|
46
|
+
segments.push({
|
|
47
|
+
text: match[5],
|
|
48
|
+
bold: false,
|
|
49
|
+
italic: true,
|
|
50
|
+
strikethrough: false,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
else if (match[6] !== undefined) {
|
|
54
|
+
segments.push({
|
|
55
|
+
text: match[6],
|
|
56
|
+
bold: false,
|
|
57
|
+
italic: true,
|
|
58
|
+
strikethrough: false,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else if (match[7] !== undefined && match[7].length > 0) {
|
|
62
|
+
segments.push({
|
|
63
|
+
text: match[7],
|
|
64
|
+
bold: false,
|
|
65
|
+
italic: false,
|
|
66
|
+
strikethrough: false,
|
|
67
|
+
});
|
|
24
68
|
}
|
|
25
69
|
}
|
|
26
70
|
return segments;
|