@bendyline/squisq-formats 2.0.1 → 2.2.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.
- package/LICENSE +21 -0
- package/NOTICE.md +20 -0
- package/README.md +1 -1
- package/dist/{chunk-CRAVSMPZ.js → chunk-26ISNJ7Y.js} +356 -114
- package/dist/{chunk-NKAJPJ4G.js → chunk-2JJ5RFDZ.js} +0 -1
- package/dist/{chunk-HTW2M27H.js → chunk-3NKXBZSR.js} +193 -42
- package/dist/{chunk-U32AG3G3.js → chunk-4V3KCHAP.js} +3 -4
- package/dist/{chunk-MLX2BOJC.js → chunk-6RQOV3B3.js} +1 -2
- package/dist/{chunk-QRVN6A6E.js → chunk-6S6GU3ZG.js} +5 -6
- package/dist/{chunk-FE6OJV6O.js → chunk-7AWFHP5U.js} +1 -1
- package/dist/{chunk-RFAPOKHJ.js → chunk-AD2WT564.js} +59 -9
- package/dist/{chunk-O3GVVND4.js → chunk-AONELFLA.js} +0 -1
- package/dist/{chunk-XKUMNGBW.js → chunk-EJTNGKEA.js} +5 -8
- package/dist/chunk-GX7RAUME.js +121 -0
- package/dist/{chunk-SSUPBUF5.js → chunk-IIQYS2YH.js} +0 -1
- package/dist/{chunk-ABVI556T.js → chunk-IPN56VLW.js} +83 -58
- package/dist/{chunk-LXYLOOST.js → chunk-JE6LSIHE.js} +83 -22
- package/dist/{chunk-U4MRIFKL.js → chunk-JU2RHXUB.js} +0 -1
- package/dist/{chunk-4VUWTSGM.js → chunk-K6XRMVPW.js} +64 -31
- package/dist/{chunk-ODL3SSPT.js → chunk-KXOZMWBS.js} +0 -1
- package/dist/chunk-OGS5VCGJ.js +446 -0
- package/dist/{chunk-GVS2XXV6.js → chunk-PJXJI2LY.js} +449 -57
- package/dist/{chunk-2KPARF2P.js → chunk-PU7REGWV.js} +5 -8
- package/dist/{chunk-PN52A5AA.js → chunk-SBUW7NHR.js} +0 -1
- package/dist/{chunk-VSYHZECT.js → chunk-TAAENIRB.js} +5 -8
- package/dist/{chunk-WC7WULGV.js → chunk-X2DEAXNK.js} +62 -2
- package/dist/container/index.js +1 -2
- package/dist/csv/index.d.ts +27 -2
- package/dist/csv/index.js +1 -2
- package/dist/docx/index.d.ts +5 -1
- package/dist/docx/index.js +9 -10
- package/dist/epub/index.d.ts +2 -0
- package/dist/epub/index.js +5 -6
- package/dist/{export-D2NkylDT.d.ts → export-D9msROJS.d.ts} +18 -6
- package/dist/extract-MN7LA3NL.js +13 -0
- package/dist/html/index.d.ts +11 -4
- package/dist/html/index.js +3 -4
- package/dist/images-ESPQKVTW.js +6 -0
- package/dist/{import-K8mfc0fz.d.ts → import-C3htUTss.d.ts} +5 -1
- package/dist/{import-DTkDxHmZ.d.ts → import-C8whCC7_.d.ts} +6 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.js +28 -26
- package/dist/infer/index.d.ts +3 -3
- package/dist/infer/index.js +7 -9
- package/dist/{layouts-BHrgZ5FS.d.ts → layouts-CTdPlB-u.d.ts} +1 -1
- package/dist/layouts-DRWZGSPD.js +10 -0
- package/dist/{mapTheme-IR27S6IV.js → mapTheme-4TWH25FT.js} +1 -2
- package/dist/ooxml/index.d.ts +3 -3
- package/dist/ooxml/index.js +14 -13
- package/dist/pdf/index.d.ts +18 -0
- package/dist/pdf/index.js +2 -3
- package/dist/pptx/index.d.ts +4 -4
- package/dist/pptx/index.js +11 -13
- package/dist/{reader-B9L8Ucbj.d.ts → reader-B_m1aKZC.d.ts} +30 -1
- package/dist/registry/index.d.ts +21 -5
- package/dist/registry/index.js +9 -6
- package/dist/{themeReader-DJKErl_j.d.ts → themeReader-DCtwC83Q.d.ts} +1 -1
- package/dist/xlsx/index.d.ts +3 -3
- package/dist/xlsx/index.js +6 -7
- package/package.json +6 -3
- package/dist/chunk-2KPARF2P.js.map +0 -1
- package/dist/chunk-4VUWTSGM.js.map +0 -1
- package/dist/chunk-6M7Z25LA.js +0 -46
- package/dist/chunk-6M7Z25LA.js.map +0 -1
- package/dist/chunk-ABVI556T.js.map +0 -1
- package/dist/chunk-CRAVSMPZ.js.map +0 -1
- package/dist/chunk-FE6OJV6O.js.map +0 -1
- package/dist/chunk-GVS2XXV6.js.map +0 -1
- package/dist/chunk-HTW2M27H.js.map +0 -1
- package/dist/chunk-LXYLOOST.js.map +0 -1
- package/dist/chunk-MLX2BOJC.js.map +0 -1
- package/dist/chunk-NKAJPJ4G.js.map +0 -1
- package/dist/chunk-O3GVVND4.js.map +0 -1
- package/dist/chunk-ODL3SSPT.js.map +0 -1
- package/dist/chunk-PN52A5AA.js.map +0 -1
- package/dist/chunk-QRVN6A6E.js.map +0 -1
- package/dist/chunk-RFAPOKHJ.js.map +0 -1
- package/dist/chunk-SSUPBUF5.js.map +0 -1
- package/dist/chunk-U32AG3G3.js.map +0 -1
- package/dist/chunk-U4MRIFKL.js.map +0 -1
- package/dist/chunk-VJJM2SSH.js +0 -275
- package/dist/chunk-VJJM2SSH.js.map +0 -1
- package/dist/chunk-VSYHZECT.js.map +0 -1
- package/dist/chunk-WC7WULGV.js.map +0 -1
- package/dist/chunk-XKUMNGBW.js.map +0 -1
- package/dist/chunk-YRT7GQ5Y.js +0 -28
- package/dist/chunk-YRT7GQ5Y.js.map +0 -1
- package/dist/container/index.js.map +0 -1
- package/dist/csv/index.js.map +0 -1
- package/dist/docx/index.js.map +0 -1
- package/dist/epub/index.js.map +0 -1
- package/dist/extract-H6RXJMHP.js +0 -15
- package/dist/extract-H6RXJMHP.js.map +0 -1
- package/dist/html/index.js.map +0 -1
- package/dist/images-7FBWPKE3.js +0 -7
- package/dist/images-7FBWPKE3.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/infer/index.js.map +0 -1
- package/dist/layouts-QVPK3ZCU.js +0 -12
- package/dist/layouts-QVPK3ZCU.js.map +0 -1
- package/dist/mapTheme-IR27S6IV.js.map +0 -1
- package/dist/ooxml/index.js.map +0 -1
- package/dist/pdf/index.js.map +0 -1
- package/dist/pptx/index.js.map +0 -1
- package/dist/registry/index.js.map +0 -1
- package/dist/xlsx/index.js.map +0 -1
- package/src/__tests__/container.test.ts +0 -230
- package/src/__tests__/convert.test.ts +0 -495
- package/src/__tests__/csvImport.test.ts +0 -84
- package/src/__tests__/docxExport.test.ts +0 -457
- package/src/__tests__/docxImport.test.ts +0 -410
- package/src/__tests__/epub.test.ts +0 -649
- package/src/__tests__/exportThemeReconciliation.test.ts +0 -87
- package/src/__tests__/formatRegistry.test.ts +0 -174
- package/src/__tests__/html.test.ts +0 -435
- package/src/__tests__/htmlImport.test.ts +0 -57
- package/src/__tests__/inferTheme.test.ts +0 -135
- package/src/__tests__/lossyWarnings.test.ts +0 -146
- package/src/__tests__/ooxml.test.ts +0 -271
- package/src/__tests__/ooxmlCancellation.test.ts +0 -113
- package/src/__tests__/ooxmlThemeReader.test.ts +0 -92
- package/src/__tests__/pdfExport.test.ts +0 -322
- package/src/__tests__/pdfImport.test.ts +0 -384
- package/src/__tests__/plainHtml.test.ts +0 -417
- package/src/__tests__/plainHtmlBundle.test.ts +0 -253
- package/src/__tests__/pptxExport.test.ts +0 -138
- package/src/__tests__/pptxImport.test.ts +0 -145
- package/src/__tests__/pptxInferFixtures.ts +0 -314
- package/src/__tests__/pptxLayoutInfer.test.ts +0 -395
- package/src/__tests__/roundTrip.test.ts +0 -201
- package/src/__tests__/roundTripAssets.test.ts +0 -50
- package/src/__tests__/roundTripMatrix.fixtures.ts +0 -86
- package/src/__tests__/roundTripMatrix.helpers.ts +0 -154
- package/src/__tests__/roundTripMatrix.test.ts +0 -142
- package/src/__tests__/sharedContainer.test.ts +0 -41
- package/src/__tests__/sharedImages.test.ts +0 -61
- package/src/__tests__/xlsxExport.test.ts +0 -164
- package/src/__tests__/xlsxImport.test.ts +0 -80
- package/src/__tests__/zipSafety.test.ts +0 -317
- package/src/container/index.ts +0 -94
- package/src/csv/index.ts +0 -188
- package/src/docx/export.ts +0 -1267
- package/src/docx/import.ts +0 -995
- package/src/docx/index.ts +0 -26
- package/src/docx/styles.ts +0 -145
- package/src/epub/export.ts +0 -968
- package/src/epub/index.ts +0 -20
- package/src/html/docsHtmlBundle.ts +0 -373
- package/src/html/htmlTemplate.ts +0 -385
- package/src/html/imageUtils.ts +0 -61
- package/src/html/import.ts +0 -297
- package/src/html/index.ts +0 -212
- package/src/html/plainHtml.ts +0 -790
- package/src/html/plainHtmlBundle.ts +0 -421
- package/src/index.ts +0 -109
- package/src/infer/extract.ts +0 -127
- package/src/infer/index.ts +0 -199
- package/src/infer/mapTheme.ts +0 -176
- package/src/infer/types.ts +0 -27
- package/src/ooxml/index.ts +0 -111
- package/src/ooxml/namespaces.ts +0 -196
- package/src/ooxml/readUtils.ts +0 -44
- package/src/ooxml/reader.ts +0 -318
- package/src/ooxml/themeReader.ts +0 -197
- package/src/ooxml/types.ts +0 -103
- package/src/ooxml/writer.ts +0 -339
- package/src/ooxml/xmlUtils.ts +0 -123
- package/src/pdf/export.ts +0 -1084
- package/src/pdf/import.ts +0 -1164
- package/src/pdf/index.ts +0 -29
- package/src/pdf/styles.ts +0 -180
- package/src/pptx/export.ts +0 -1184
- package/src/pptx/import.ts +0 -455
- package/src/pptx/index.ts +0 -52
- package/src/pptx/layouts.ts +0 -1222
- package/src/pptx/styles.ts +0 -96
- package/src/pptx/templates.ts +0 -187
- package/src/registry/convert.ts +0 -433
- package/src/registry/defaultFormats.ts +0 -413
- package/src/registry/errors.ts +0 -46
- package/src/registry/index.ts +0 -43
- package/src/registry/registry.ts +0 -48
- package/src/registry/types.ts +0 -170
- package/src/shared/boundedZipArchive.ts +0 -383
- package/src/shared/container.ts +0 -28
- package/src/shared/fidelity.ts +0 -130
- package/src/shared/images.ts +0 -44
- package/src/shared/inlineRuns.ts +0 -99
- package/src/shared/text.ts +0 -41
- package/src/shared/zipEntryCount.ts +0 -151
- package/src/shared/zipLimits.ts +0 -296
- package/src/shared/zipSafety.ts +0 -19
- package/src/xlsx/export.ts +0 -253
- package/src/xlsx/import.ts +0 -160
- package/src/xlsx/index.ts +0 -35
|
@@ -1,11 +1,314 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildContainer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IIQYS2YH.js";
|
|
4
4
|
|
|
5
5
|
// src/pdf/export.ts
|
|
6
|
-
import { PDFDocument, StandardFonts, rgb } from "pdf-lib";
|
|
6
|
+
import { PDFDocument, StandardFonts, rgb, PDFString } from "pdf-lib";
|
|
7
7
|
import { docToMarkdown, resolveThemeForDoc } from "@bendyline/squisq/doc";
|
|
8
|
-
import { readFrontmatterThemeId } from "@bendyline/squisq/markdown";
|
|
8
|
+
import { readFrontmatterThemeId, sanitizeUrl } from "@bendyline/squisq/markdown";
|
|
9
|
+
|
|
10
|
+
// src/pdf/winAnsi.ts
|
|
11
|
+
var CP1252_HIGH_SPECIALS = /* @__PURE__ */ new Set([
|
|
12
|
+
8364,
|
|
13
|
+
// euro sign
|
|
14
|
+
8218,
|
|
15
|
+
// single low-9 quotation mark
|
|
16
|
+
402,
|
|
17
|
+
// latin small letter f with hook
|
|
18
|
+
8222,
|
|
19
|
+
// double low-9 quotation mark
|
|
20
|
+
8230,
|
|
21
|
+
// horizontal ellipsis
|
|
22
|
+
8224,
|
|
23
|
+
// dagger
|
|
24
|
+
8225,
|
|
25
|
+
// double dagger
|
|
26
|
+
710,
|
|
27
|
+
// modifier letter circumflex accent
|
|
28
|
+
8240,
|
|
29
|
+
// per mille sign
|
|
30
|
+
352,
|
|
31
|
+
// latin capital letter S with caron
|
|
32
|
+
8249,
|
|
33
|
+
// single left-pointing angle quotation mark
|
|
34
|
+
338,
|
|
35
|
+
// latin capital ligature OE
|
|
36
|
+
381,
|
|
37
|
+
// latin capital letter Z with caron
|
|
38
|
+
8216,
|
|
39
|
+
// left single quotation mark
|
|
40
|
+
8217,
|
|
41
|
+
// right single quotation mark
|
|
42
|
+
8220,
|
|
43
|
+
// left double quotation mark
|
|
44
|
+
8221,
|
|
45
|
+
// right double quotation mark
|
|
46
|
+
8226,
|
|
47
|
+
// bullet
|
|
48
|
+
8211,
|
|
49
|
+
// en dash
|
|
50
|
+
8212,
|
|
51
|
+
// em dash
|
|
52
|
+
732,
|
|
53
|
+
// small tilde
|
|
54
|
+
8482,
|
|
55
|
+
// trade mark sign
|
|
56
|
+
353,
|
|
57
|
+
// latin small letter s with caron
|
|
58
|
+
8250,
|
|
59
|
+
// single right-pointing angle quotation mark
|
|
60
|
+
339,
|
|
61
|
+
// latin small ligature oe
|
|
62
|
+
382,
|
|
63
|
+
// latin small letter z with caron
|
|
64
|
+
376
|
|
65
|
+
// latin capital letter Y with diaeresis
|
|
66
|
+
]);
|
|
67
|
+
function isWinAnsiEncodable(codePoint) {
|
|
68
|
+
if (codePoint >= 32 && codePoint <= 126) return true;
|
|
69
|
+
if (codePoint >= 160 && codePoint <= 255) return true;
|
|
70
|
+
return CP1252_HIGH_SPECIALS.has(codePoint);
|
|
71
|
+
}
|
|
72
|
+
var WINANSI_REPLACEMENT = "?";
|
|
73
|
+
var TRANSLITERATIONS = /* @__PURE__ */ new Map([
|
|
74
|
+
// ── Whitespace & invisibles ──
|
|
75
|
+
// A tab keeps its visual width (code fences are the common case); every
|
|
76
|
+
// other control/format character collapses to a space or disappears.
|
|
77
|
+
[9, " "],
|
|
78
|
+
// tab
|
|
79
|
+
[10, " "],
|
|
80
|
+
// line feed
|
|
81
|
+
[11, " "],
|
|
82
|
+
// vertical tab
|
|
83
|
+
[12, " "],
|
|
84
|
+
// form feed
|
|
85
|
+
[13, " "],
|
|
86
|
+
// carriage return
|
|
87
|
+
[133, " "],
|
|
88
|
+
// next line
|
|
89
|
+
[8232, " "],
|
|
90
|
+
// line separator
|
|
91
|
+
[8233, " "],
|
|
92
|
+
// paragraph separator
|
|
93
|
+
[8192, " "],
|
|
94
|
+
// en quad
|
|
95
|
+
[8193, " "],
|
|
96
|
+
// em quad
|
|
97
|
+
[8194, " "],
|
|
98
|
+
// en space
|
|
99
|
+
[8195, " "],
|
|
100
|
+
// em space
|
|
101
|
+
[8196, " "],
|
|
102
|
+
// three-per-em space
|
|
103
|
+
[8197, " "],
|
|
104
|
+
// four-per-em space
|
|
105
|
+
[8198, " "],
|
|
106
|
+
// six-per-em space
|
|
107
|
+
[8199, " "],
|
|
108
|
+
// figure space
|
|
109
|
+
[8200, " "],
|
|
110
|
+
// punctuation space
|
|
111
|
+
[8201, " "],
|
|
112
|
+
// thin space
|
|
113
|
+
[8202, " "],
|
|
114
|
+
// hair space
|
|
115
|
+
[8239, " "],
|
|
116
|
+
// narrow no-break space
|
|
117
|
+
[8287, " "],
|
|
118
|
+
// medium mathematical space
|
|
119
|
+
[12288, " "],
|
|
120
|
+
// ideographic space
|
|
121
|
+
[8203, ""],
|
|
122
|
+
// zero-width space
|
|
123
|
+
[8204, ""],
|
|
124
|
+
// zero-width non-joiner
|
|
125
|
+
[8205, ""],
|
|
126
|
+
// zero-width joiner
|
|
127
|
+
[8288, ""],
|
|
128
|
+
// word joiner
|
|
129
|
+
[65279, ""],
|
|
130
|
+
// zero-width no-break space / BOM
|
|
131
|
+
// ── Dashes & hyphens (en/em dash ARE encodable and stay verbatim) ──
|
|
132
|
+
[8208, "-"],
|
|
133
|
+
// hyphen
|
|
134
|
+
[8209, "-"],
|
|
135
|
+
// non-breaking hyphen
|
|
136
|
+
[8210, "-"],
|
|
137
|
+
// figure dash
|
|
138
|
+
[8213, "--"],
|
|
139
|
+
// horizontal bar
|
|
140
|
+
[8722, "-"],
|
|
141
|
+
// minus sign
|
|
142
|
+
// ── Quotes & primes (curly quotes ARE encodable and stay verbatim) ──
|
|
143
|
+
[8242, "'"],
|
|
144
|
+
// prime
|
|
145
|
+
[8243, '"'],
|
|
146
|
+
// double prime
|
|
147
|
+
[8245, "'"],
|
|
148
|
+
// reversed prime
|
|
149
|
+
[8246, '"'],
|
|
150
|
+
// reversed double prime
|
|
151
|
+
// ── Arrows ──
|
|
152
|
+
[8592, "<-"],
|
|
153
|
+
// leftwards arrow
|
|
154
|
+
[8593, "^"],
|
|
155
|
+
// upwards arrow
|
|
156
|
+
[8594, "->"],
|
|
157
|
+
// rightwards arrow
|
|
158
|
+
[8595, "v"],
|
|
159
|
+
// downwards arrow
|
|
160
|
+
[8596, "<->"],
|
|
161
|
+
// left right arrow
|
|
162
|
+
[8656, "<="],
|
|
163
|
+
// leftwards double arrow
|
|
164
|
+
[8658, "=>"],
|
|
165
|
+
// rightwards double arrow
|
|
166
|
+
[8660, "<=>"],
|
|
167
|
+
// left right double arrow
|
|
168
|
+
// ── Math & comparison ──
|
|
169
|
+
[8800, "!="],
|
|
170
|
+
// not equal to
|
|
171
|
+
[8804, "<="],
|
|
172
|
+
// less-than or equal to
|
|
173
|
+
[8805, ">="],
|
|
174
|
+
// greater-than or equal to
|
|
175
|
+
[8776, "~="],
|
|
176
|
+
// almost equal to
|
|
177
|
+
[8801, "=="],
|
|
178
|
+
// identical to
|
|
179
|
+
[8734, "inf"],
|
|
180
|
+
// infinity
|
|
181
|
+
[8730, "sqrt"],
|
|
182
|
+
// square root
|
|
183
|
+
[8721, "sum"],
|
|
184
|
+
// n-ary summation
|
|
185
|
+
[8719, "prod"],
|
|
186
|
+
// n-ary product
|
|
187
|
+
[8260, "/"],
|
|
188
|
+
// fraction slash
|
|
189
|
+
// ── Bullets & marks (U+2022 bullet IS encodable) ──
|
|
190
|
+
[8227, "*"],
|
|
191
|
+
// triangular bullet
|
|
192
|
+
[8259, "-"],
|
|
193
|
+
// hyphen bullet
|
|
194
|
+
[8729, "*"],
|
|
195
|
+
// bullet operator
|
|
196
|
+
[9642, "*"],
|
|
197
|
+
// black small square
|
|
198
|
+
[9643, "*"],
|
|
199
|
+
// white small square
|
|
200
|
+
[9675, "o"],
|
|
201
|
+
// white circle
|
|
202
|
+
[9679, "*"],
|
|
203
|
+
// black circle
|
|
204
|
+
[9702, "o"],
|
|
205
|
+
// white bullet
|
|
206
|
+
[10003, "v"],
|
|
207
|
+
// check mark
|
|
208
|
+
[10004, "v"],
|
|
209
|
+
// heavy check mark
|
|
210
|
+
[10007, "x"],
|
|
211
|
+
// ballot x
|
|
212
|
+
[10008, "x"],
|
|
213
|
+
// heavy ballot x
|
|
214
|
+
// ── Ellipsis variants (U+2026 itself IS encodable) ──
|
|
215
|
+
[8229, ".."],
|
|
216
|
+
// two dot leader
|
|
217
|
+
[8943, "..."],
|
|
218
|
+
// midline horizontal ellipsis
|
|
219
|
+
// ── Ligatures ──
|
|
220
|
+
[64256, "ff"],
|
|
221
|
+
[64257, "fi"],
|
|
222
|
+
[64258, "fl"],
|
|
223
|
+
[64259, "ffi"],
|
|
224
|
+
[64260, "ffl"]
|
|
225
|
+
]);
|
|
226
|
+
var WHITESPACE_LIKE = /* @__PURE__ */ new Set([
|
|
227
|
+
9,
|
|
228
|
+
10,
|
|
229
|
+
11,
|
|
230
|
+
12,
|
|
231
|
+
13,
|
|
232
|
+
133,
|
|
233
|
+
8232,
|
|
234
|
+
8233,
|
|
235
|
+
8192,
|
|
236
|
+
8193,
|
|
237
|
+
8194,
|
|
238
|
+
8195,
|
|
239
|
+
8196,
|
|
240
|
+
8197,
|
|
241
|
+
8198,
|
|
242
|
+
8199,
|
|
243
|
+
8200,
|
|
244
|
+
8201,
|
|
245
|
+
8202,
|
|
246
|
+
8239,
|
|
247
|
+
8287,
|
|
248
|
+
12288,
|
|
249
|
+
8203,
|
|
250
|
+
8204,
|
|
251
|
+
8205,
|
|
252
|
+
8288,
|
|
253
|
+
65279
|
|
254
|
+
]);
|
|
255
|
+
var MAX_SAMPLES = 5;
|
|
256
|
+
var ASCII_ONLY = /^[\x20-\x7e]*$/;
|
|
257
|
+
var COMBINING_MARKS = /[̀-ͯ]/g;
|
|
258
|
+
function stripDiacritics(ch) {
|
|
259
|
+
const decomposed = ch.normalize("NFKD").replace(COMBINING_MARKS, "");
|
|
260
|
+
if (!decomposed) return void 0;
|
|
261
|
+
for (const c of decomposed) {
|
|
262
|
+
if (!isWinAnsiEncodable(c.codePointAt(0))) return void 0;
|
|
263
|
+
}
|
|
264
|
+
return decomposed;
|
|
265
|
+
}
|
|
266
|
+
function sanitizeWinAnsi(input) {
|
|
267
|
+
if (ASCII_ONLY.test(input)) return { text: input, substitutions: 0, samples: [] };
|
|
268
|
+
const text = input.normalize("NFC");
|
|
269
|
+
let out = "";
|
|
270
|
+
let substitutions = 0;
|
|
271
|
+
const samples = [];
|
|
272
|
+
for (const ch of text) {
|
|
273
|
+
const cp = ch.codePointAt(0);
|
|
274
|
+
if (isWinAnsiEncodable(cp)) {
|
|
275
|
+
out += ch;
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
const mapped = TRANSLITERATIONS.get(cp) ?? stripDiacritics(ch) ?? WINANSI_REPLACEMENT;
|
|
279
|
+
out += mapped;
|
|
280
|
+
if (WHITESPACE_LIKE.has(cp)) continue;
|
|
281
|
+
substitutions++;
|
|
282
|
+
const sample = `"${ch}" -> "${mapped}"`;
|
|
283
|
+
if (samples.length < MAX_SAMPLES && !samples.includes(sample)) samples.push(sample);
|
|
284
|
+
}
|
|
285
|
+
return { text: out, substitutions, samples };
|
|
286
|
+
}
|
|
287
|
+
var WinAnsiTracker = class {
|
|
288
|
+
constructor() {
|
|
289
|
+
this.count = 0;
|
|
290
|
+
this.samples = [];
|
|
291
|
+
}
|
|
292
|
+
/** Sanitize `text` for pdf-lib and record any substitutions. */
|
|
293
|
+
clean(text) {
|
|
294
|
+
const result = sanitizeWinAnsi(text);
|
|
295
|
+
this.count += result.substitutions;
|
|
296
|
+
for (const sample of result.samples) {
|
|
297
|
+
if (this.samples.length >= MAX_SAMPLES) break;
|
|
298
|
+
if (!this.samples.includes(sample)) this.samples.push(sample);
|
|
299
|
+
}
|
|
300
|
+
return result.text;
|
|
301
|
+
}
|
|
302
|
+
/** Total substituted characters across the export. */
|
|
303
|
+
get substitutions() {
|
|
304
|
+
return this.count;
|
|
305
|
+
}
|
|
306
|
+
/** One-shot summary for the export, or undefined when nothing was lost. */
|
|
307
|
+
warning() {
|
|
308
|
+
if (this.count === 0) return void 0;
|
|
309
|
+
return `PDF export replaced ${this.count} character(s) that the standard PDF fonts cannot encode (${this.samples.join(", ")}). Scripts such as emoji, CJK and Cyrillic require an embedded Unicode font.`;
|
|
310
|
+
}
|
|
311
|
+
};
|
|
9
312
|
|
|
10
313
|
// src/pdf/styles.ts
|
|
11
314
|
var PAGE_WIDTH_LETTER = 612;
|
|
@@ -72,6 +375,7 @@ var IMPORT_URL_PATTERN = /https?:\/\/[^\s)>\]]+/g;
|
|
|
72
375
|
|
|
73
376
|
// src/pdf/export.ts
|
|
74
377
|
async function markdownDocToPdf(doc, options = {}) {
|
|
378
|
+
options.signal?.throwIfAborted();
|
|
75
379
|
const pdfDoc = await PDFDocument.create();
|
|
76
380
|
if (options.title) pdfDoc.setTitle(options.title);
|
|
77
381
|
if (options.author) pdfDoc.setAuthor(options.author);
|
|
@@ -79,6 +383,11 @@ async function markdownDocToPdf(doc, options = {}) {
|
|
|
79
383
|
pdfDoc.setModificationDate(/* @__PURE__ */ new Date());
|
|
80
384
|
const ctx = await createExportContext(pdfDoc, options, doc);
|
|
81
385
|
renderBlocks(doc.children, ctx, 0);
|
|
386
|
+
const warning = ctx.text.warning();
|
|
387
|
+
if (warning) {
|
|
388
|
+
if (options.onWarning) options.onWarning(warning);
|
|
389
|
+
else console.warn(warning);
|
|
390
|
+
}
|
|
82
391
|
const bytes = await pdfDoc.save();
|
|
83
392
|
return bytes.buffer;
|
|
84
393
|
}
|
|
@@ -124,7 +433,9 @@ async function createExportContext(pdfDoc, options, doc) {
|
|
|
124
433
|
y: pageHeight - margin,
|
|
125
434
|
contentWidth: pageWidth - 2 * margin,
|
|
126
435
|
bottomY: margin,
|
|
127
|
-
colors: { text: colorText, heading: colorHeading, link: colorLink }
|
|
436
|
+
colors: { text: colorText, heading: colorHeading, link: colorLink },
|
|
437
|
+
text: new WinAnsiTracker(),
|
|
438
|
+
signal: options.signal
|
|
128
439
|
};
|
|
129
440
|
}
|
|
130
441
|
function ensureSpace(ctx, needed) {
|
|
@@ -144,7 +455,7 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
144
455
|
case "text": {
|
|
145
456
|
const font = state.code ? state.bold ? ctx.fonts.monoBold : ctx.fonts.mono : pickFont(ctx, state.bold, state.italic);
|
|
146
457
|
spans.push({
|
|
147
|
-
text: node.value,
|
|
458
|
+
text: ctx.text.clean(node.value),
|
|
148
459
|
font,
|
|
149
460
|
fontSize: state.code ? CODE_FONT_SIZE : ctx.fontSize,
|
|
150
461
|
color: state.code ? COLOR_CODE_TEXT : state.color ?? ctx.colors.text,
|
|
@@ -173,7 +484,7 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
173
484
|
break;
|
|
174
485
|
case "inlineCode": {
|
|
175
486
|
spans.push({
|
|
176
|
-
text: node.value,
|
|
487
|
+
text: ctx.text.clean(node.value),
|
|
177
488
|
font: ctx.fonts.mono,
|
|
178
489
|
fontSize: CODE_FONT_SIZE,
|
|
179
490
|
color: COLOR_CODE_TEXT,
|
|
@@ -183,11 +494,12 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
183
494
|
}
|
|
184
495
|
case "link": {
|
|
185
496
|
const linkNode = node;
|
|
497
|
+
const safeLink = sanitizeUrl(linkNode.url, "link") ?? void 0;
|
|
186
498
|
spans.push(
|
|
187
499
|
...flattenInlines(linkNode.children, ctx, {
|
|
188
500
|
...state,
|
|
189
|
-
link:
|
|
190
|
-
color: ctx.colors.link
|
|
501
|
+
link: safeLink,
|
|
502
|
+
color: safeLink ? ctx.colors.link : state.color
|
|
191
503
|
})
|
|
192
504
|
);
|
|
193
505
|
break;
|
|
@@ -195,7 +507,7 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
195
507
|
case "image": {
|
|
196
508
|
const imgNode = node;
|
|
197
509
|
spans.push({
|
|
198
|
-
text: imgNode.alt ? `[Image: ${imgNode.alt}]` : "[Image]",
|
|
510
|
+
text: ctx.text.clean(imgNode.alt ? `[Image: ${imgNode.alt}]` : "[Image]"),
|
|
199
511
|
font: ctx.fonts.italic,
|
|
200
512
|
fontSize: ctx.fontSize,
|
|
201
513
|
color: COLOR_BLOCKQUOTE_TEXT
|
|
@@ -214,7 +526,7 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
214
526
|
const html = node.rawHtml;
|
|
215
527
|
if (html) {
|
|
216
528
|
spans.push({
|
|
217
|
-
text: html,
|
|
529
|
+
text: ctx.text.clean(html),
|
|
218
530
|
font: ctx.fonts.mono,
|
|
219
531
|
fontSize: CODE_FONT_SIZE,
|
|
220
532
|
color: COLOR_CODE_TEXT
|
|
@@ -224,7 +536,7 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
224
536
|
}
|
|
225
537
|
case "inlineMath":
|
|
226
538
|
spans.push({
|
|
227
|
-
text: node.value,
|
|
539
|
+
text: ctx.text.clean(node.value),
|
|
228
540
|
font: ctx.fonts.mono,
|
|
229
541
|
fontSize: CODE_FONT_SIZE,
|
|
230
542
|
color: COLOR_CODE_TEXT
|
|
@@ -233,7 +545,7 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
233
545
|
case "footnoteReference": {
|
|
234
546
|
const ref = node;
|
|
235
547
|
spans.push({
|
|
236
|
-
text: `[${ref.identifier}]
|
|
548
|
+
text: ctx.text.clean(`[${ref.identifier}]`),
|
|
237
549
|
font: ctx.fonts.regular,
|
|
238
550
|
fontSize: ctx.fontSize * 0.75,
|
|
239
551
|
color: ctx.colors.link
|
|
@@ -247,7 +559,7 @@ function flattenInlines(nodes, ctx, state) {
|
|
|
247
559
|
spans.push(...flattenInlines(fallback.children, ctx, state));
|
|
248
560
|
} else if (fallback.value) {
|
|
249
561
|
spans.push({
|
|
250
|
-
text: fallback.value,
|
|
562
|
+
text: ctx.text.clean(fallback.value),
|
|
251
563
|
font: pickFont(ctx, state.bold, state.italic),
|
|
252
564
|
fontSize: ctx.fontSize,
|
|
253
565
|
color: state.color ?? ctx.colors.text
|
|
@@ -283,12 +595,27 @@ function drawSpans(spans, ctx, availableWidth, x0) {
|
|
|
283
595
|
});
|
|
284
596
|
const textWidth = span.font.widthOfTextAtSize(span.text, span.fontSize);
|
|
285
597
|
if (span.link) {
|
|
598
|
+
const baseline = ctx.y - span.fontSize;
|
|
286
599
|
ctx.page.drawLine({
|
|
287
|
-
start: { x, y:
|
|
288
|
-
end: { x: x + textWidth, y:
|
|
600
|
+
start: { x, y: baseline - 1 },
|
|
601
|
+
end: { x: x + textWidth, y: baseline - 1 },
|
|
289
602
|
thickness: 0.5,
|
|
290
603
|
color: rgb(span.color.r, span.color.g, span.color.b)
|
|
291
604
|
});
|
|
605
|
+
const annotation = ctx.pdfDoc.context.register(
|
|
606
|
+
ctx.pdfDoc.context.obj({
|
|
607
|
+
Type: "Annot",
|
|
608
|
+
Subtype: "Link",
|
|
609
|
+
Rect: [x, baseline - 2, x + textWidth, baseline + span.fontSize + 2],
|
|
610
|
+
Border: [0, 0, 0],
|
|
611
|
+
A: {
|
|
612
|
+
Type: "Action",
|
|
613
|
+
S: "URI",
|
|
614
|
+
URI: PDFString.of(span.link)
|
|
615
|
+
}
|
|
616
|
+
})
|
|
617
|
+
);
|
|
618
|
+
ctx.page.node.addAnnot(annotation);
|
|
292
619
|
}
|
|
293
620
|
if (span.strikethrough) {
|
|
294
621
|
const midY = ctx.y - span.fontSize * 0.6;
|
|
@@ -360,7 +687,9 @@ function getLineHeight(line) {
|
|
|
360
687
|
return (maxSize || DEFAULT_FONT_SIZE) * LINE_HEIGHT_FACTOR;
|
|
361
688
|
}
|
|
362
689
|
function renderBlocks(nodes, ctx, extraIndent) {
|
|
363
|
-
for (
|
|
690
|
+
for (let index = 0; index < nodes.length; index++) {
|
|
691
|
+
if ((index & 255) === 0) ctx.signal?.throwIfAborted();
|
|
692
|
+
const node = nodes[index];
|
|
364
693
|
renderBlock(node, ctx, extraIndent);
|
|
365
694
|
}
|
|
366
695
|
}
|
|
@@ -499,7 +828,7 @@ function renderListItem(item, ctx, extraIndent, depth, ordered, counter) {
|
|
|
499
828
|
function renderCodeBlock(node, ctx, extraIndent) {
|
|
500
829
|
const x0 = ctx.margin + extraIndent;
|
|
501
830
|
const _w = ctx.contentWidth - extraIndent;
|
|
502
|
-
const lines = node.value.split("\n");
|
|
831
|
+
const lines = node.value.split("\n").map((line) => ctx.text.clean(line));
|
|
503
832
|
const lineH = CODE_FONT_SIZE * LINE_HEIGHT_FACTOR;
|
|
504
833
|
const totalHeight = lines.length * lineH + 12;
|
|
505
834
|
ensureSpace(ctx, Math.min(totalHeight, ctx.y - ctx.bottomY));
|
|
@@ -615,7 +944,7 @@ function renderThematicBreak(ctx, extraIndent) {
|
|
|
615
944
|
}
|
|
616
945
|
function renderHtmlBlock(node, ctx, extraIndent) {
|
|
617
946
|
if (!node.rawHtml) return;
|
|
618
|
-
const lines = node.rawHtml.split("\n");
|
|
947
|
+
const lines = node.rawHtml.split("\n").map((line) => ctx.text.clean(line));
|
|
619
948
|
const x0 = ctx.margin + extraIndent;
|
|
620
949
|
for (const line of lines) {
|
|
621
950
|
if (line.trim().length === 0) continue;
|
|
@@ -633,7 +962,7 @@ function renderHtmlBlock(node, ctx, extraIndent) {
|
|
|
633
962
|
ctx.y -= PARAGRAPH_SPACING;
|
|
634
963
|
}
|
|
635
964
|
function renderMathBlock(node, ctx, extraIndent) {
|
|
636
|
-
const lines = node.value.split("\n");
|
|
965
|
+
const lines = node.value.split("\n").map((line) => ctx.text.clean(line));
|
|
637
966
|
const x0 = ctx.margin + extraIndent;
|
|
638
967
|
for (const line of lines) {
|
|
639
968
|
const lineH = CODE_FONT_SIZE * LINE_HEIGHT_FACTOR;
|
|
@@ -652,7 +981,7 @@ function renderMathBlock(node, ctx, extraIndent) {
|
|
|
652
981
|
ctx.y -= PARAGRAPH_SPACING;
|
|
653
982
|
}
|
|
654
983
|
function renderFootnoteDefinition(node, ctx, extraIndent) {
|
|
655
|
-
const label = `[${node.identifier}]
|
|
984
|
+
const label = ctx.text.clean(`[${node.identifier}]`);
|
|
656
985
|
const lineH = ctx.fontSize * LINE_HEIGHT_FACTOR;
|
|
657
986
|
ensureSpace(ctx, lineH);
|
|
658
987
|
ctx.page.drawText(label, {
|
|
@@ -694,7 +1023,7 @@ function renderFallbackBlock(node, ctx, extraIndent) {
|
|
|
694
1023
|
} else if (fallback.value && typeof fallback.value === "string") {
|
|
695
1024
|
const lineH = ctx.fontSize * LINE_HEIGHT_FACTOR;
|
|
696
1025
|
ensureSpace(ctx, lineH);
|
|
697
|
-
ctx.page.drawText(fallback.value, {
|
|
1026
|
+
ctx.page.drawText(ctx.text.clean(fallback.value), {
|
|
698
1027
|
x: ctx.margin + extraIndent,
|
|
699
1028
|
y: ctx.y - ctx.fontSize,
|
|
700
1029
|
size: ctx.fontSize,
|
|
@@ -717,11 +1046,13 @@ function hexToRgb(hex) {
|
|
|
717
1046
|
// src/pdf/import.ts
|
|
718
1047
|
import { markdownToDoc } from "@bendyline/squisq/doc";
|
|
719
1048
|
import { stringifyMarkdown } from "@bendyline/squisq/markdown";
|
|
1049
|
+
import UPNG from "@pdf-lib/upng";
|
|
720
1050
|
async function pdfToMarkdownDoc(data, options = {}) {
|
|
1051
|
+
options.signal?.throwIfAborted();
|
|
721
1052
|
const bytes = data instanceof Blob ? new Uint8Array(await data.arrayBuffer()) : data instanceof ArrayBuffer ? new Uint8Array(data) : data;
|
|
722
|
-
const loaded = await loadPdfDocument(bytes);
|
|
1053
|
+
const loaded = await loadPdfDocument(bytes, options.signal);
|
|
723
1054
|
try {
|
|
724
|
-
const textLines = await extractTextLines(loaded.pdf);
|
|
1055
|
+
const textLines = await extractTextLines(loaded.pdf, options);
|
|
725
1056
|
if (textLines.length === 0) {
|
|
726
1057
|
return { type: "document", children: [] };
|
|
727
1058
|
}
|
|
@@ -737,12 +1068,16 @@ async function pdfToDoc(data, options = {}) {
|
|
|
737
1068
|
return markdownToDoc(markdownDoc);
|
|
738
1069
|
}
|
|
739
1070
|
async function pdfToContainer(data, options = {}) {
|
|
1071
|
+
options.signal?.throwIfAborted();
|
|
740
1072
|
const bytes = data instanceof Blob ? new Uint8Array(await data.arrayBuffer()) : data instanceof ArrayBuffer ? new Uint8Array(data) : data;
|
|
741
|
-
const loaded = await loadPdfDocument(bytes);
|
|
1073
|
+
const loaded = await loadPdfDocument(bytes, options.signal);
|
|
742
1074
|
let textLines;
|
|
743
1075
|
let images;
|
|
744
1076
|
try {
|
|
745
|
-
[textLines, images] = await Promise.all([
|
|
1077
|
+
[textLines, images] = await Promise.all([
|
|
1078
|
+
extractTextLines(loaded.pdf, options),
|
|
1079
|
+
extractImages(loaded, options)
|
|
1080
|
+
]);
|
|
746
1081
|
} finally {
|
|
747
1082
|
await loaded.pdf.destroy?.();
|
|
748
1083
|
}
|
|
@@ -758,25 +1093,48 @@ async function pdfToContainer(data, options = {}) {
|
|
|
758
1093
|
images.map((img) => [img.path, { data: img.data, mimeType: "image/png" }])
|
|
759
1094
|
);
|
|
760
1095
|
}
|
|
761
|
-
async function extractImages(loaded) {
|
|
762
|
-
if (typeof document === "undefined") return [];
|
|
1096
|
+
async function extractImages(loaded, options) {
|
|
763
1097
|
const { pdfjsLib, pdf } = loaded;
|
|
764
1098
|
const OPS_paintImageXObject = pdfjsLib.OPS?.paintImageXObject ?? 85;
|
|
1099
|
+
const OPS_paintInlineImageXObject = pdfjsLib.OPS?.paintInlineImageXObject ?? 86;
|
|
765
1100
|
const images = [];
|
|
766
1101
|
let counter = 0;
|
|
1102
|
+
let totalPixels = 0;
|
|
1103
|
+
const maxPages = safetyLimit("maxPages", options.maxPages ?? 5e3);
|
|
1104
|
+
const maxImagePixels = safetyLimit("maxImagePixels", options.maxImagePixels ?? 1e8);
|
|
1105
|
+
if (pdf.numPages > maxPages)
|
|
1106
|
+
throw new RangeError(`PDF exceeds the ${maxPages}-page safety limit`);
|
|
767
1107
|
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
|
|
1108
|
+
options.signal?.throwIfAborted();
|
|
768
1109
|
const page = await pdf.getPage(pageNum);
|
|
769
1110
|
if (!page.getOperatorList) continue;
|
|
770
1111
|
const opList = await page.getOperatorList();
|
|
771
1112
|
const seen = /* @__PURE__ */ new Set();
|
|
772
1113
|
for (let i = 0; i < opList.fnArray.length; i++) {
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
1114
|
+
const operation = opList.fnArray[i];
|
|
1115
|
+
if (operation !== OPS_paintImageXObject && operation !== OPS_paintInlineImageXObject)
|
|
1116
|
+
continue;
|
|
1117
|
+
const operand = opList.argsArray[i]?.[0];
|
|
1118
|
+
let imgData = null;
|
|
1119
|
+
if (operation === OPS_paintImageXObject) {
|
|
1120
|
+
if (!operand || typeof operand !== "string" || seen.has(operand)) continue;
|
|
1121
|
+
seen.add(operand);
|
|
1122
|
+
try {
|
|
1123
|
+
imgData = await getPdfImageObject(page.objs, operand, options.signal);
|
|
1124
|
+
} catch {
|
|
1125
|
+
continue;
|
|
1126
|
+
}
|
|
1127
|
+
} else if (operand && typeof operand === "object") {
|
|
1128
|
+
imgData = operand;
|
|
1129
|
+
}
|
|
777
1130
|
try {
|
|
778
|
-
const imgData = page.objs?.get(imgName);
|
|
779
1131
|
if (!imgData?.data || !imgData.width || !imgData.height) continue;
|
|
1132
|
+
totalPixels += imgData.width * imgData.height;
|
|
1133
|
+
if (totalPixels > maxImagePixels) {
|
|
1134
|
+
throw new RangeError(
|
|
1135
|
+
`PDF decoded images exceed the ${maxImagePixels}-pixel safety limit`
|
|
1136
|
+
);
|
|
1137
|
+
}
|
|
780
1138
|
const pngData = imageDataToPng(imgData);
|
|
781
1139
|
if (!pngData) continue;
|
|
782
1140
|
counter++;
|
|
@@ -786,52 +1144,69 @@ async function extractImages(loaded) {
|
|
|
786
1144
|
page: pageNum - 1,
|
|
787
1145
|
y: 0
|
|
788
1146
|
});
|
|
789
|
-
} catch {
|
|
1147
|
+
} catch (error) {
|
|
1148
|
+
if (error instanceof RangeError) throw error;
|
|
790
1149
|
}
|
|
791
1150
|
}
|
|
792
1151
|
}
|
|
793
1152
|
return images;
|
|
794
1153
|
}
|
|
1154
|
+
function getPdfImageObject(objects, name, signal) {
|
|
1155
|
+
if (!objects) return Promise.resolve(null);
|
|
1156
|
+
return new Promise((resolve, reject) => {
|
|
1157
|
+
let settled = false;
|
|
1158
|
+
const finish = (value) => {
|
|
1159
|
+
if (settled) return;
|
|
1160
|
+
settled = true;
|
|
1161
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1162
|
+
resolve(value);
|
|
1163
|
+
};
|
|
1164
|
+
const onAbort = () => {
|
|
1165
|
+
if (settled) return;
|
|
1166
|
+
settled = true;
|
|
1167
|
+
reject(signal?.reason ?? new DOMException("PDF image extraction cancelled", "AbortError"));
|
|
1168
|
+
};
|
|
1169
|
+
if (signal?.aborted) {
|
|
1170
|
+
onAbort();
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1174
|
+
try {
|
|
1175
|
+
const immediate = objects.get(name, finish);
|
|
1176
|
+
if (immediate !== void 0 && immediate !== null) finish(immediate);
|
|
1177
|
+
} catch (error) {
|
|
1178
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1179
|
+
reject(error);
|
|
1180
|
+
}
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
795
1183
|
function imageDataToPng(img) {
|
|
796
1184
|
try {
|
|
797
|
-
|
|
798
|
-
canvas.width = img.width;
|
|
799
|
-
canvas.height = img.height;
|
|
800
|
-
const ctx = canvas.getContext("2d");
|
|
801
|
-
if (!ctx) return null;
|
|
802
|
-
let imageData;
|
|
1185
|
+
let rgba;
|
|
803
1186
|
if (img.kind === 3 || img.data.length === img.width * img.height * 4) {
|
|
804
|
-
|
|
1187
|
+
rgba = new Uint8ClampedArray(img.data);
|
|
805
1188
|
} else if (img.kind === 2 || img.data.length === img.width * img.height * 3) {
|
|
806
|
-
|
|
1189
|
+
rgba = new Uint8ClampedArray(img.width * img.height * 4);
|
|
807
1190
|
for (let j = 0, k = 0; j < img.data.length; j += 3, k += 4) {
|
|
808
1191
|
rgba[k] = img.data[j];
|
|
809
1192
|
rgba[k + 1] = img.data[j + 1];
|
|
810
1193
|
rgba[k + 2] = img.data[j + 2];
|
|
811
1194
|
rgba[k + 3] = 255;
|
|
812
1195
|
}
|
|
813
|
-
imageData = new ImageData(rgba, img.width, img.height);
|
|
814
1196
|
} else if (img.kind === 1 || img.data.length === img.width * img.height) {
|
|
815
|
-
|
|
1197
|
+
rgba = new Uint8ClampedArray(img.width * img.height * 4);
|
|
816
1198
|
for (let j = 0, k = 0; j < img.data.length; j++, k += 4) {
|
|
817
1199
|
rgba[k] = img.data[j];
|
|
818
1200
|
rgba[k + 1] = img.data[j];
|
|
819
1201
|
rgba[k + 2] = img.data[j];
|
|
820
1202
|
rgba[k + 3] = 255;
|
|
821
1203
|
}
|
|
822
|
-
imageData = new ImageData(rgba, img.width, img.height);
|
|
823
1204
|
} else {
|
|
824
1205
|
return null;
|
|
825
1206
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
const binaryStr = atob(base64);
|
|
830
|
-
const bytes = new Uint8Array(binaryStr.length);
|
|
831
|
-
for (let i = 0; i < binaryStr.length; i++) {
|
|
832
|
-
bytes[i] = binaryStr.charCodeAt(i);
|
|
833
|
-
}
|
|
834
|
-
return bytes.buffer;
|
|
1207
|
+
const owned = new Uint8Array(rgba.byteLength);
|
|
1208
|
+
owned.set(rgba);
|
|
1209
|
+
return UPNG.encode([owned.buffer], img.width, img.height, 0);
|
|
835
1210
|
} catch {
|
|
836
1211
|
return null;
|
|
837
1212
|
}
|
|
@@ -891,7 +1266,8 @@ async function applyWorkerConfig(pdfjsLib) {
|
|
|
891
1266
|
pdfjsLib.GlobalWorkerOptions.workerSrc = _workerSrc;
|
|
892
1267
|
}
|
|
893
1268
|
}
|
|
894
|
-
async function loadPdfDocument(data) {
|
|
1269
|
+
async function loadPdfDocument(data, signal) {
|
|
1270
|
+
signal?.throwIfAborted();
|
|
895
1271
|
let pdfjsLib;
|
|
896
1272
|
try {
|
|
897
1273
|
pdfjsLib = await import("pdfjs-dist/legacy/build/pdf.mjs");
|
|
@@ -904,16 +1280,27 @@ async function loadPdfDocument(data) {
|
|
|
904
1280
|
isEvalSupported: false,
|
|
905
1281
|
useSystemFonts: true
|
|
906
1282
|
});
|
|
907
|
-
|
|
1283
|
+
const pdf = await loadingTask.promise;
|
|
1284
|
+
signal?.throwIfAborted();
|
|
1285
|
+
return { pdfjsLib, pdf };
|
|
908
1286
|
}
|
|
909
|
-
async function extractTextLines(pdf) {
|
|
1287
|
+
async function extractTextLines(pdf, options) {
|
|
910
1288
|
const allLines = [];
|
|
1289
|
+
const maxPages = safetyLimit("maxPages", options.maxPages ?? 5e3);
|
|
1290
|
+
const maxTextItems = safetyLimit("maxTextItems", options.maxTextItems ?? 1e6);
|
|
1291
|
+
let textItemCount = 0;
|
|
1292
|
+
if (pdf.numPages > maxPages)
|
|
1293
|
+
throw new RangeError(`PDF exceeds the ${maxPages}-page safety limit`);
|
|
911
1294
|
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
|
|
1295
|
+
options.signal?.throwIfAborted();
|
|
912
1296
|
const page = await pdf.getPage(pageNum);
|
|
913
1297
|
const content = await page.getTextContent();
|
|
914
1298
|
const styleMap = content.styles || {};
|
|
915
1299
|
const items = [];
|
|
916
1300
|
for (const item of content.items) {
|
|
1301
|
+
if (++textItemCount > maxTextItems) {
|
|
1302
|
+
throw new RangeError(`PDF exceeds the ${maxTextItems}-text-item safety limit`);
|
|
1303
|
+
}
|
|
917
1304
|
if (!item.str || item.str.trim().length === 0) continue;
|
|
918
1305
|
const transform = item.transform || [1, 0, 0, 1, 0, 0];
|
|
919
1306
|
const x = transform[4];
|
|
@@ -965,6 +1352,12 @@ async function extractTextLines(pdf) {
|
|
|
965
1352
|
}
|
|
966
1353
|
return allLines;
|
|
967
1354
|
}
|
|
1355
|
+
function safetyLimit(name, value) {
|
|
1356
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
1357
|
+
throw new RangeError(`${name} must be a non-negative safe integer`);
|
|
1358
|
+
}
|
|
1359
|
+
return value;
|
|
1360
|
+
}
|
|
968
1361
|
function detectBodyFontSize(lines) {
|
|
969
1362
|
const sizes = lines.map((l) => Math.round(l.fontSize * 2) / 2);
|
|
970
1363
|
return mode(sizes) || DEFAULT_FONT_SIZE;
|
|
@@ -1329,4 +1722,3 @@ export {
|
|
|
1329
1722
|
pdfToContainer,
|
|
1330
1723
|
configurePdfWorker
|
|
1331
1724
|
};
|
|
1332
|
-
//# sourceMappingURL=chunk-GVS2XXV6.js.map
|