kordoc 4.14.2 → 4.14.4
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 +51 -6
- package/dist/{-AQKXLFIM.js → -Z4TJ3QGK.js} +13 -11
- package/dist/{chunk-QOMNEWCQ.cjs → chunk-5LAZQCUJ.cjs} +305 -31
- package/dist/chunk-5LAZQCUJ.cjs.map +1 -0
- package/dist/{chunk-7IAQ4HOK.js → chunk-6BWU6SQX.js} +1 -1
- package/dist/chunk-6BWU6SQX.js.map +1 -0
- package/dist/{chunk-FOJZNMMK.js → chunk-6CUIXJOC.js} +1 -1
- package/dist/chunk-6CUIXJOC.js.map +1 -0
- package/dist/{chunk-ZWD734EY.js → chunk-7SE4EZ45.js} +2 -2
- package/dist/{chunk-TSFS5VKD.js → chunk-D4U2TXDC.js} +332 -141
- package/dist/chunk-D4U2TXDC.js.map +1 -0
- package/dist/chunk-DPWWXUOG.js +2222 -0
- package/dist/chunk-DPWWXUOG.js.map +1 -0
- package/dist/{chunk-GDW4YP7K.js → chunk-GLSBEEZJ.js} +2 -2
- package/dist/{chunk-JQEFP45L.js → chunk-GUJ4Q73I.js} +2 -2
- package/dist/{chunk-ZWOFQRIB.js → chunk-HIJUKZHM.js} +3 -3
- package/dist/chunk-IMAAFSAX.cjs +1352 -0
- package/dist/chunk-IMAAFSAX.cjs.map +1 -0
- package/dist/{chunk-TNCKOL2O.js → chunk-LCW7SEPG.js} +2 -2
- package/dist/chunk-LFSQAMSM.js +1352 -0
- package/dist/chunk-LFSQAMSM.js.map +1 -0
- package/dist/chunk-MG6DJEX4.js +1299 -0
- package/dist/chunk-MG6DJEX4.js.map +1 -0
- package/dist/{chunk-QC5T6D4J.js → chunk-NLU6LBLY.js} +299 -25
- package/dist/chunk-NLU6LBLY.js.map +1 -0
- package/dist/{chunk-EQZI77PP.cjs → chunk-QEJUY6SK.cjs} +3 -3
- package/dist/{chunk-EQZI77PP.cjs.map → chunk-QEJUY6SK.cjs.map} +1 -1
- package/dist/{chunk-VQ5W4MYO.js → chunk-QIF2VXBQ.js} +298 -24
- package/dist/chunk-QIF2VXBQ.js.map +1 -0
- package/dist/{chunk-UET462HB.js → chunk-TITDJWVZ.js} +2 -2
- package/dist/{chunk-247ANM72.cjs → chunk-USHQCF5T.cjs} +870 -147
- package/dist/chunk-USHQCF5T.cjs.map +1 -0
- package/dist/{chunk-C7FQBSON.js → chunk-V3DX4DUF.js} +2 -2
- package/dist/{chunk-DOGPOY4B.js → chunk-VDN7LMPL.js} +2 -2
- package/dist/{chunk-EDNJLUSE.js → chunk-VJIL6PIL.js} +2 -2
- package/dist/{chunk-L7DMSMAG.cjs → chunk-VWUYVEFN.cjs} +1 -1
- package/dist/chunk-VWUYVEFN.cjs.map +1 -0
- package/dist/{chunk-HR2XNERB.cjs → chunk-WJHAU73B.cjs} +2 -2
- package/dist/{chunk-HR2XNERB.cjs.map → chunk-WJHAU73B.cjs.map} +1 -1
- package/dist/{chunk-NS55SM7A.js → chunk-WJJGW5PL.js} +2 -2
- package/dist/{chunk-EISO3POT.js → chunk-XVXHXQIO.js} +788 -194
- package/dist/chunk-XVXHXQIO.js.map +1 -0
- package/dist/{chunk-ILU76UF3.js → chunk-YAKC46HZ.js} +2 -2
- package/dist/chunk-YAKC46HZ.js.map +1 -0
- package/dist/{chunk-3DUADAY2.js → chunk-YAVHVFRY.js} +851 -128
- package/dist/chunk-YAVHVFRY.js.map +1 -0
- package/dist/{chunk-A7QC2ZVP.js → chunk-YT3GC62E.js} +851 -128
- package/dist/chunk-YT3GC62E.js.map +1 -0
- package/dist/chunks-CCMRL4MJ.js +10 -0
- package/dist/cli.js +228 -97
- package/dist/cli.js.map +1 -1
- package/dist/{formula-PJJ6S3Z2.cjs → formula-5LOVHAKE.cjs} +9 -9
- package/dist/{formula-PJJ6S3Z2.cjs.map → formula-5LOVHAKE.cjs.map} +1 -1
- package/dist/{formula-JGFTXWYT.js → formula-7RANCW5L.js} +3 -3
- package/dist/{formula-5S7WWXGH.js → formula-7UYJOVTB.js} +4 -4
- package/dist/{image-ocr-WCAYXLOA.js → image-ocr-I6JOCATS.js} +34 -16
- package/dist/image-ocr-I6JOCATS.js.map +1 -0
- package/dist/{image-ocr-ZTYAGV3W.cjs → image-ocr-NYBJEOH2.cjs} +36 -18
- package/dist/image-ocr-NYBJEOH2.cjs.map +1 -0
- package/dist/{image-ocr-FLIL7MGN.js → image-ocr-ZV6PDBUQ.js} +32 -14
- package/dist/image-ocr-ZV6PDBUQ.js.map +1 -0
- package/dist/index.cjs +4048 -1216
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -28
- package/dist/index.d.ts +66 -28
- package/dist/index.js +3487 -655
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +74 -53
- package/dist/mcp.js.map +1 -1
- package/dist/{model-bundle-FSPZZ2EM.js → model-bundle-2C5IYDLE.js} +5 -5
- package/dist/{models-CJPAQK5R.js → models-SEQZHZFT.js} +5 -5
- package/dist/{parser-SCUTZAIJ.js → parser-3FNXEP6T.js} +708 -250
- package/dist/parser-3FNXEP6T.js.map +1 -0
- package/dist/{parser-A4TMPJAM.js → parser-FJBJXRJK.js} +708 -250
- package/dist/parser-FJBJXRJK.js.map +1 -0
- package/dist/{parser-VCXE4I5A.cjs → parser-HVEKF73B.cjs} +733 -275
- package/dist/parser-HVEKF73B.cjs.map +1 -0
- package/dist/pdf-ocr-JRDBJ6TA.cjs +14 -0
- package/dist/{pdf-ocr-MBZZ57LD.cjs.map → pdf-ocr-JRDBJ6TA.cjs.map} +1 -1
- package/dist/pdf-ocr-UUBWBEHL.js +16 -0
- package/dist/pdf-ocr-VJSF2SQC.js +13 -0
- package/dist/{profile-io-LBM263K7.js → profile-io-RUFZOZO6.js} +3 -3
- package/dist/{rasterize-46RG4ZF6.js → rasterize-IOYXR5SI.js} +3 -3
- package/dist/redact-NMIKVHMP.js +18 -0
- package/dist/redact-doc-QBHNJ2BU.js +1284 -0
- package/dist/redact-doc-QBHNJ2BU.js.map +1 -0
- package/dist/{render-NGP5T24S.js → render-YZ2TEC3N.js} +7 -7
- package/dist/seal-ECV44TUH.js +10 -0
- package/dist/{setup-AU4OCHNH.js → setup-MPIEP6XT.js} +3 -3
- package/dist/visual-ICMOWUCR.js +19 -0
- package/dist/{watch-MKPUCPXM.js → watch-RYO7MN5B.js} +12 -12
- package/package.json +2 -2
- package/dist/chunk-247ANM72.cjs.map +0 -1
- package/dist/chunk-3DUADAY2.js.map +0 -1
- package/dist/chunk-422427XJ.cjs +0 -571
- package/dist/chunk-422427XJ.cjs.map +0 -1
- package/dist/chunk-7IAQ4HOK.js.map +0 -1
- package/dist/chunk-A7QC2ZVP.js.map +0 -1
- package/dist/chunk-DZIXKL7E.js +0 -145
- package/dist/chunk-DZIXKL7E.js.map +0 -1
- package/dist/chunk-EISO3POT.js.map +0 -1
- package/dist/chunk-EP7KOI2V.js +0 -571
- package/dist/chunk-EP7KOI2V.js.map +0 -1
- package/dist/chunk-FOJZNMMK.js.map +0 -1
- package/dist/chunk-ILU76UF3.js.map +0 -1
- package/dist/chunk-KVWV4ULP.js +0 -516
- package/dist/chunk-KVWV4ULP.js.map +0 -1
- package/dist/chunk-L7DMSMAG.cjs.map +0 -1
- package/dist/chunk-QC5T6D4J.js.map +0 -1
- package/dist/chunk-QOMNEWCQ.cjs.map +0 -1
- package/dist/chunk-TSFS5VKD.js.map +0 -1
- package/dist/chunk-VQ5W4MYO.js.map +0 -1
- package/dist/chunks-SX77P5CV.js +0 -10
- package/dist/image-ocr-FLIL7MGN.js.map +0 -1
- package/dist/image-ocr-WCAYXLOA.js.map +0 -1
- package/dist/image-ocr-ZTYAGV3W.cjs.map +0 -1
- package/dist/parser-A4TMPJAM.js.map +0 -1
- package/dist/parser-SCUTZAIJ.js.map +0 -1
- package/dist/parser-VCXE4I5A.cjs.map +0 -1
- package/dist/pdf-ocr-76SAUXMZ.js +0 -13
- package/dist/pdf-ocr-CPU55CVF.js +0 -16
- package/dist/pdf-ocr-MBZZ57LD.cjs +0 -14
- package/dist/redact-7ILEAUTS.js +0 -12
- package/dist/seal-RGUPOLXD.js +0 -10
- package/dist/visual-NZLYIYEM.js +0 -19
- /package/dist/{-AQKXLFIM.js.map → -Z4TJ3QGK.js.map} +0 -0
- /package/dist/{chunk-ZWD734EY.js.map → chunk-7SE4EZ45.js.map} +0 -0
- /package/dist/{chunk-GDW4YP7K.js.map → chunk-GLSBEEZJ.js.map} +0 -0
- /package/dist/{chunk-JQEFP45L.js.map → chunk-GUJ4Q73I.js.map} +0 -0
- /package/dist/{chunk-ZWOFQRIB.js.map → chunk-HIJUKZHM.js.map} +0 -0
- /package/dist/{chunk-TNCKOL2O.js.map → chunk-LCW7SEPG.js.map} +0 -0
- /package/dist/{chunk-UET462HB.js.map → chunk-TITDJWVZ.js.map} +0 -0
- /package/dist/{chunk-C7FQBSON.js.map → chunk-V3DX4DUF.js.map} +0 -0
- /package/dist/{chunk-DOGPOY4B.js.map → chunk-VDN7LMPL.js.map} +0 -0
- /package/dist/{chunk-EDNJLUSE.js.map → chunk-VJIL6PIL.js.map} +0 -0
- /package/dist/{chunk-NS55SM7A.js.map → chunk-WJJGW5PL.js.map} +0 -0
- /package/dist/{chunks-SX77P5CV.js.map → chunks-CCMRL4MJ.js.map} +0 -0
- /package/dist/{formula-JGFTXWYT.js.map → formula-7RANCW5L.js.map} +0 -0
- /package/dist/{formula-5S7WWXGH.js.map → formula-7UYJOVTB.js.map} +0 -0
- /package/dist/{model-bundle-FSPZZ2EM.js.map → model-bundle-2C5IYDLE.js.map} +0 -0
- /package/dist/{models-CJPAQK5R.js.map → models-SEQZHZFT.js.map} +0 -0
- /package/dist/{pdf-ocr-76SAUXMZ.js.map → pdf-ocr-UUBWBEHL.js.map} +0 -0
- /package/dist/{pdf-ocr-CPU55CVF.js.map → pdf-ocr-VJSF2SQC.js.map} +0 -0
- /package/dist/{profile-io-LBM263K7.js.map → profile-io-RUFZOZO6.js.map} +0 -0
- /package/dist/{rasterize-46RG4ZF6.js.map → rasterize-IOYXR5SI.js.map} +0 -0
- /package/dist/{redact-7ILEAUTS.js.map → redact-NMIKVHMP.js.map} +0 -0
- /package/dist/{render-NGP5T24S.js.map → render-YZ2TEC3N.js.map} +0 -0
- /package/dist/{seal-RGUPOLXD.js.map → seal-ECV44TUH.js.map} +0 -0
- /package/dist/{setup-AU4OCHNH.js.map → setup-MPIEP6XT.js.map} +0 -0
- /package/dist/{visual-NZLYIYEM.js.map → visual-ICMOWUCR.js.map} +0 -0
- /package/dist/{watch-MKPUCPXM.js.map → watch-RYO7MN5B.js.map} +0 -0
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
CELL_LINES,
|
|
4
|
+
CLIP_TABLES,
|
|
5
|
+
CONT_PARTS,
|
|
6
|
+
EMPTY_PARTS,
|
|
7
|
+
FILLER_CELLS,
|
|
8
|
+
IMAGE_CELLS,
|
|
9
|
+
TABLE_COLXS,
|
|
10
|
+
WrapLexicon,
|
|
3
11
|
collapseEvenSpacing,
|
|
4
12
|
computeMedianFontSizeFromFreq,
|
|
5
13
|
detectHeadings,
|
|
@@ -9,24 +17,27 @@ import {
|
|
|
9
17
|
extractImageRegions,
|
|
10
18
|
extractPageBlocksWithLines,
|
|
11
19
|
filterHiddenText,
|
|
12
|
-
|
|
20
|
+
joinPageBreakWraps,
|
|
13
21
|
normalizeItems,
|
|
14
|
-
removeHeaderFooterBlocks
|
|
15
|
-
|
|
22
|
+
removeHeaderFooterBlocks,
|
|
23
|
+
trimTrailingEmptyTableCols
|
|
24
|
+
} from "./chunk-YAVHVFRY.js";
|
|
16
25
|
import {
|
|
17
26
|
encodePng
|
|
18
27
|
} from "./chunk-7FCNOKOR.js";
|
|
19
|
-
import "./chunk-
|
|
28
|
+
import "./chunk-6BWU6SQX.js";
|
|
20
29
|
import {
|
|
21
30
|
parsePageRange
|
|
22
31
|
} from "./chunk-MOL7MDBG.js";
|
|
23
32
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
33
|
+
WINGDINGS,
|
|
34
|
+
blocksToMarkdown,
|
|
35
|
+
escapeLiteralDollar
|
|
36
|
+
} from "./chunk-NLU6LBLY.js";
|
|
26
37
|
import {
|
|
27
38
|
KordocError,
|
|
28
39
|
sanitizeHref
|
|
29
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-TITDJWVZ.js";
|
|
30
41
|
|
|
31
42
|
// src/pdf/image-extract.ts
|
|
32
43
|
import { OPS, ImageKind } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
@@ -110,7 +121,7 @@ function toRgba(img) {
|
|
|
110
121
|
}
|
|
111
122
|
return null;
|
|
112
123
|
}
|
|
113
|
-
async function extractPageImages(page, fnArray, argsArray, pageNumber, state, warnings) {
|
|
124
|
+
async function extractPageImages(page, fnArray, argsArray, pageNumber, state, warnings, withBytes = true) {
|
|
114
125
|
const blocks = [];
|
|
115
126
|
const images = [];
|
|
116
127
|
const pageSeenIds = /* @__PURE__ */ new Set();
|
|
@@ -149,12 +160,14 @@ async function extractPageImages(page, fnArray, argsArray, pageNumber, state, wa
|
|
|
149
160
|
if (state.seen.has(hash)) continue;
|
|
150
161
|
const rgba = toRgba(imgData);
|
|
151
162
|
if (!rgba) continue;
|
|
152
|
-
const png = encodePng(w, h, rgba);
|
|
153
163
|
state.imageIndex++;
|
|
154
|
-
state.totalBytes += png.length;
|
|
155
164
|
const filename = `image_${String(state.imageIndex).padStart(3, "0")}.png`;
|
|
156
165
|
state.seen.set(hash, filename);
|
|
157
|
-
|
|
166
|
+
if (withBytes) {
|
|
167
|
+
const png = encodePng(w, h, rgba);
|
|
168
|
+
state.totalBytes += png.length;
|
|
169
|
+
images.push({ filename, data: png, mimeType: "image/png" });
|
|
170
|
+
}
|
|
158
171
|
blocks.push({ type: "image", text: filename, pageNumber });
|
|
159
172
|
}
|
|
160
173
|
return { blocks, images };
|
|
@@ -199,7 +212,9 @@ var RARE_JONG = /* @__PURE__ */ new Set([3, 5, 6, 9, 10, 11, 12, 13, 14, 15, 18,
|
|
|
199
212
|
var MOJIBAKE_MIN_HANGUL = 30;
|
|
200
213
|
var MOJIBAKE_MAX_NOBATCHIM = 0.15;
|
|
201
214
|
var MOJIBAKE_MIN_RAREBATCHIM = 0.25;
|
|
202
|
-
|
|
215
|
+
var VECTOR_TEXT_MIN_GLYPHS = 40;
|
|
216
|
+
var VECTOR_TEXT_MIN_SHARE = 0.25;
|
|
217
|
+
function computePageQuality(page, text, vectorGlyphs = 0) {
|
|
203
218
|
let total = 0;
|
|
204
219
|
let hangul = 0;
|
|
205
220
|
let hangulNoBatchim = 0;
|
|
@@ -240,7 +255,10 @@ function computePageQuality(page, text) {
|
|
|
240
255
|
const garbledHangul = hangul >= MOJIBAKE_MIN_HANGUL && hangulNoBatchimRatio < MOJIBAKE_MAX_NOBATCHIM && hangulRareBatchimRatio >= MOJIBAKE_MIN_RAREBATCHIM;
|
|
241
256
|
let needsOcr = false;
|
|
242
257
|
let ocrReason;
|
|
243
|
-
if (total
|
|
258
|
+
if (vectorGlyphs >= VECTOR_TEXT_MIN_GLYPHS && vectorGlyphs >= (vectorGlyphs + total) * VECTOR_TEXT_MIN_SHARE) {
|
|
259
|
+
needsOcr = true;
|
|
260
|
+
ocrReason = "vector_text";
|
|
261
|
+
} else if (total < LOW_TEXT_THRESHOLD) {
|
|
244
262
|
needsOcr = true;
|
|
245
263
|
ocrReason = "low_text";
|
|
246
264
|
} else if (puaRatio >= HIGH_PUA_THRESHOLD) {
|
|
@@ -325,232 +343,657 @@ function summarizeDocumentQuality(pages) {
|
|
|
325
343
|
};
|
|
326
344
|
}
|
|
327
345
|
|
|
328
|
-
// src/pdf/
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
"\u{1F5CF}",
|
|
349
|
-
"\u{1F5D0}",
|
|
350
|
-
"\u{1F5C4}",
|
|
351
|
-
"\u231B",
|
|
352
|
-
"\u{1F5AE}",
|
|
353
|
-
"\u{1F5B0}",
|
|
354
|
-
"\u{1F5B2}",
|
|
355
|
-
"\u{1F5B3}",
|
|
356
|
-
"\u{1F5B4}",
|
|
357
|
-
"\u{1F5AB}",
|
|
358
|
-
"\u{1F5AC}",
|
|
359
|
-
"\u2707",
|
|
360
|
-
"\u270D",
|
|
361
|
-
"\u{1F58E}",
|
|
362
|
-
"\u270C",
|
|
363
|
-
"\u{1F44C}",
|
|
364
|
-
"\u{1F44D}",
|
|
365
|
-
"\u{1F44E}",
|
|
366
|
-
"\u261C",
|
|
367
|
-
"\u261E",
|
|
368
|
-
"\u261D",
|
|
369
|
-
"\u261F",
|
|
370
|
-
"\u{1F590}",
|
|
371
|
-
"\u263A",
|
|
372
|
-
"\u{1F610}",
|
|
373
|
-
"\u2639",
|
|
374
|
-
"\u{1F4A3}",
|
|
375
|
-
"\u2620",
|
|
376
|
-
"\u{1F3F3}",
|
|
377
|
-
"\u{1F3F1}",
|
|
378
|
-
"\u2708",
|
|
379
|
-
"\u263C",
|
|
380
|
-
"\u{1F4A7}",
|
|
381
|
-
"\u2744",
|
|
382
|
-
"\u{1F546}",
|
|
383
|
-
"\u271E",
|
|
384
|
-
"\u{1F548}",
|
|
385
|
-
"\u2720",
|
|
386
|
-
"\u2721",
|
|
387
|
-
"\u262A",
|
|
388
|
-
"\u262F",
|
|
389
|
-
"\u0950",
|
|
390
|
-
"\u2638",
|
|
391
|
-
"\u2648",
|
|
392
|
-
"\u2649",
|
|
393
|
-
"\u264A",
|
|
394
|
-
"\u264B",
|
|
395
|
-
"\u264C",
|
|
396
|
-
"\u264D",
|
|
397
|
-
"\u264E",
|
|
398
|
-
"\u264F",
|
|
399
|
-
"\u2650",
|
|
400
|
-
"\u2651",
|
|
401
|
-
"\u2652",
|
|
402
|
-
"\u2653",
|
|
403
|
-
"\u{1F670}",
|
|
404
|
-
"\u{1F675}",
|
|
405
|
-
"\u25CF",
|
|
406
|
-
"\u25CB",
|
|
407
|
-
"\u25A0",
|
|
408
|
-
"\u25A1",
|
|
409
|
-
"\u25A1",
|
|
410
|
-
"\u2751",
|
|
411
|
-
"\u2752",
|
|
412
|
-
"\u2B27",
|
|
413
|
-
"\u29EB",
|
|
414
|
-
"\u25C6",
|
|
415
|
-
"\u2756",
|
|
416
|
-
"\u2B25",
|
|
417
|
-
"\u2327",
|
|
418
|
-
"\u2BB9",
|
|
419
|
-
"\u2318",
|
|
420
|
-
"\u{1F3F5}",
|
|
421
|
-
"\u{1F3F6}",
|
|
422
|
-
"\u{1F676}",
|
|
423
|
-
"\u{1F677}",
|
|
424
|
-
"",
|
|
425
|
-
"\u24EA",
|
|
426
|
-
"\u2460",
|
|
427
|
-
"\u2461",
|
|
428
|
-
"\u2462",
|
|
429
|
-
"\u2463",
|
|
430
|
-
"\u2464",
|
|
431
|
-
"\u2465",
|
|
432
|
-
"\u2466",
|
|
433
|
-
"\u2467",
|
|
434
|
-
"\u2468",
|
|
435
|
-
"\u2469",
|
|
436
|
-
"\u24FF",
|
|
437
|
-
"\u2776",
|
|
438
|
-
"\u2777",
|
|
439
|
-
"\u2778",
|
|
440
|
-
"\u2779",
|
|
441
|
-
"\u277A",
|
|
442
|
-
"\u277B",
|
|
443
|
-
"\u277C",
|
|
444
|
-
"\u277D",
|
|
445
|
-
"\u277E",
|
|
446
|
-
"\u277F",
|
|
447
|
-
"\u{1F662}",
|
|
448
|
-
"\u{1F660}",
|
|
449
|
-
"\u{1F661}",
|
|
450
|
-
"\u{1F663}",
|
|
451
|
-
"\u{1F65E}",
|
|
452
|
-
"\u{1F65C}",
|
|
453
|
-
"\u{1F65D}",
|
|
454
|
-
"\u{1F65F}",
|
|
455
|
-
"\xB7",
|
|
456
|
-
"\u2022",
|
|
457
|
-
"\u25AA",
|
|
458
|
-
"\u26AA",
|
|
459
|
-
"\u25CB",
|
|
460
|
-
"\u25EF",
|
|
461
|
-
"\u25C9",
|
|
462
|
-
"\u25CE",
|
|
463
|
-
"\u{1F53F}",
|
|
464
|
-
"\u25AA",
|
|
465
|
-
"\u25FB",
|
|
466
|
-
"\u{1F7C2}",
|
|
467
|
-
"\u2726",
|
|
468
|
-
"\u2605",
|
|
469
|
-
"\u2736",
|
|
470
|
-
"\u2734",
|
|
471
|
-
"\u2739",
|
|
472
|
-
"\u2735",
|
|
473
|
-
"\u2BD0",
|
|
474
|
-
"\u2316",
|
|
475
|
-
"\u27E1",
|
|
476
|
-
"\u2311",
|
|
477
|
-
"\u2BD1",
|
|
478
|
-
"\u272A",
|
|
479
|
-
"\u2730",
|
|
480
|
-
"\u{1F550}",
|
|
481
|
-
"\u{1F551}",
|
|
482
|
-
"\u{1F552}",
|
|
483
|
-
"\u{1F553}",
|
|
484
|
-
"\u{1F554}",
|
|
485
|
-
"\u{1F555}",
|
|
486
|
-
"\u{1F556}",
|
|
487
|
-
"\u{1F557}",
|
|
488
|
-
"\u{1F558}",
|
|
489
|
-
"\u{1F559}",
|
|
490
|
-
"\u{1F55A}",
|
|
491
|
-
"\u{1F55B}",
|
|
492
|
-
"\u2BB0",
|
|
493
|
-
"\u2BB1",
|
|
494
|
-
"\u2BB2",
|
|
495
|
-
"\u2BB3",
|
|
496
|
-
"\u2BB4",
|
|
497
|
-
"\u2BB5",
|
|
498
|
-
"\u2BB6",
|
|
499
|
-
"\u2BB7",
|
|
500
|
-
"\u{1F66A}",
|
|
501
|
-
"\u{1F66B}",
|
|
502
|
-
"\u{1F655}",
|
|
503
|
-
"\u{1F654}",
|
|
504
|
-
"\u{1F657}",
|
|
505
|
-
"\u{1F656}",
|
|
506
|
-
"\u{1F650}",
|
|
507
|
-
"\u{1F651}",
|
|
508
|
-
"\u{1F652}",
|
|
509
|
-
"\u{1F653}",
|
|
510
|
-
"\u232B",
|
|
511
|
-
"\u2326",
|
|
512
|
-
"\u2B98",
|
|
513
|
-
"\u2B9A",
|
|
514
|
-
"\u2B99",
|
|
515
|
-
"\u2B9B",
|
|
516
|
-
"\u2B88",
|
|
517
|
-
"\u2B8A",
|
|
518
|
-
"\u2B89",
|
|
519
|
-
"\u2B8B",
|
|
520
|
-
"\u2190",
|
|
521
|
-
"\u2192",
|
|
522
|
-
"\u2191",
|
|
523
|
-
"\u2193",
|
|
524
|
-
"\u2196",
|
|
525
|
-
"\u2197",
|
|
526
|
-
"\u2199",
|
|
527
|
-
"\u2198",
|
|
528
|
-
"\u2B05",
|
|
529
|
-
"\u2794",
|
|
530
|
-
"\u2B06",
|
|
531
|
-
"\u2B07",
|
|
532
|
-
"\u2B09",
|
|
533
|
-
"\u2B08",
|
|
534
|
-
"\u2B0B",
|
|
535
|
-
"\u2B0A",
|
|
536
|
-
"\u21E6",
|
|
537
|
-
"\u21E8",
|
|
538
|
-
"\u21E7",
|
|
539
|
-
"\u21E9",
|
|
540
|
-
"\u2B04",
|
|
541
|
-
"\u21F3",
|
|
542
|
-
"\u2B00",
|
|
543
|
-
"\u2B01",
|
|
544
|
-
"\u2B03",
|
|
545
|
-
"\u2B02",
|
|
546
|
-
"\u{1F8AC}",
|
|
547
|
-
"\u{1F8AD}",
|
|
548
|
-
"\u2717",
|
|
549
|
-
"\u2714",
|
|
550
|
-
"\u2612",
|
|
551
|
-
"\u2611",
|
|
552
|
-
""
|
|
346
|
+
// src/pdf/vector-glyphs.ts
|
|
347
|
+
import { OPS as OPS2 } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
348
|
+
var GLYPH_MIN_H = 3;
|
|
349
|
+
var GLYPH_MAX_H = 40;
|
|
350
|
+
var GLYPH_MAX_ASPECT = 2;
|
|
351
|
+
var GLYPH_MIN_SEGS = 8;
|
|
352
|
+
var GLYPH_MIN_SUBS = 2;
|
|
353
|
+
var RUN_GAP_EM = 1.5;
|
|
354
|
+
var RUN_MIN = 3;
|
|
355
|
+
var RUN_ALIGN_EM = 0.05;
|
|
356
|
+
var RUN_MAX_OVERLAP = 0.2;
|
|
357
|
+
var RUN_MIN_COLOR = 0.9;
|
|
358
|
+
var RUN_MIN_SHAPES = 0.5;
|
|
359
|
+
var mul = (m, t) => [
|
|
360
|
+
m[0] * t[0] + m[2] * t[1],
|
|
361
|
+
m[1] * t[0] + m[3] * t[1],
|
|
362
|
+
m[0] * t[2] + m[2] * t[3],
|
|
363
|
+
m[1] * t[2] + m[3] * t[3],
|
|
364
|
+
m[0] * t[4] + m[2] * t[5] + m[4],
|
|
365
|
+
m[1] * t[4] + m[3] * t[5] + m[5]
|
|
553
366
|
];
|
|
367
|
+
function collectGlyphPaths(fnArray, argsArray) {
|
|
368
|
+
const out = [];
|
|
369
|
+
let ctm = [1, 0, 0, 1, 0, 0];
|
|
370
|
+
let color = 0;
|
|
371
|
+
const stack = [];
|
|
372
|
+
let x1 = Infinity, y1 = Infinity, x2 = -Infinity, y2 = -Infinity;
|
|
373
|
+
let segs = 0, subs = 0, rects = 0;
|
|
374
|
+
let ops = [];
|
|
375
|
+
const add = (x, y) => {
|
|
376
|
+
const tx = ctm[0] * x + ctm[2] * y + ctm[4], ty = ctm[1] * x + ctm[3] * y + ctm[5];
|
|
377
|
+
if (tx < x1) x1 = tx;
|
|
378
|
+
if (tx > x2) x2 = tx;
|
|
379
|
+
if (ty < y1) y1 = ty;
|
|
380
|
+
if (ty > y2) y2 = ty;
|
|
381
|
+
};
|
|
382
|
+
const reset = () => {
|
|
383
|
+
x1 = Infinity;
|
|
384
|
+
y1 = Infinity;
|
|
385
|
+
x2 = -Infinity;
|
|
386
|
+
y2 = -Infinity;
|
|
387
|
+
segs = 0;
|
|
388
|
+
subs = 0;
|
|
389
|
+
rects = 0;
|
|
390
|
+
ops = [];
|
|
391
|
+
};
|
|
392
|
+
for (let i = 0; i < fnArray.length; i++) {
|
|
393
|
+
const op = fnArray[i];
|
|
394
|
+
const args = argsArray[i];
|
|
395
|
+
switch (op) {
|
|
396
|
+
case OPS2.save:
|
|
397
|
+
stack.push([ctm, color]);
|
|
398
|
+
break;
|
|
399
|
+
case OPS2.restore:
|
|
400
|
+
[ctm, color] = stack.pop() ?? [[1, 0, 0, 1, 0, 0], 0];
|
|
401
|
+
break;
|
|
402
|
+
case OPS2.transform:
|
|
403
|
+
ctm = mul(ctm, args);
|
|
404
|
+
break;
|
|
405
|
+
case OPS2.paintFormXObjectBegin: {
|
|
406
|
+
stack.push([ctm, color]);
|
|
407
|
+
const m = args[0];
|
|
408
|
+
if (Array.isArray(m) && m.length >= 6) ctm = mul(ctm, m);
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
case OPS2.paintFormXObjectEnd:
|
|
412
|
+
[ctm, color] = stack.pop() ?? [[1, 0, 0, 1, 0, 0], 0];
|
|
413
|
+
break;
|
|
414
|
+
case OPS2.setFillRGBColor: {
|
|
415
|
+
const c = args;
|
|
416
|
+
color = c[0] << 16 | c[1] << 8 | c[2];
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
case OPS2.constructPath: {
|
|
420
|
+
const [subOps, coords] = args;
|
|
421
|
+
if (!Array.isArray(subOps) || !Array.isArray(coords)) break;
|
|
422
|
+
ops.push(i);
|
|
423
|
+
let ci = 0;
|
|
424
|
+
for (const s of subOps) {
|
|
425
|
+
if (s === OPS2.moveTo) {
|
|
426
|
+
add(coords[ci], coords[ci + 1]);
|
|
427
|
+
ci += 2;
|
|
428
|
+
subs++;
|
|
429
|
+
} else if (s === OPS2.lineTo) {
|
|
430
|
+
add(coords[ci], coords[ci + 1]);
|
|
431
|
+
ci += 2;
|
|
432
|
+
segs++;
|
|
433
|
+
} else if (s === OPS2.curveTo) {
|
|
434
|
+
add(coords[ci], coords[ci + 1]);
|
|
435
|
+
add(coords[ci + 2], coords[ci + 3]);
|
|
436
|
+
add(coords[ci + 4], coords[ci + 5]);
|
|
437
|
+
ci += 6;
|
|
438
|
+
segs++;
|
|
439
|
+
} else if (s === OPS2.curveTo2 || s === OPS2.curveTo3) {
|
|
440
|
+
add(coords[ci], coords[ci + 1]);
|
|
441
|
+
add(coords[ci + 2], coords[ci + 3]);
|
|
442
|
+
ci += 4;
|
|
443
|
+
segs++;
|
|
444
|
+
} else if (s === OPS2.rectangle) {
|
|
445
|
+
const rx = coords[ci], ry = coords[ci + 1], rw = coords[ci + 2], rh = coords[ci + 3];
|
|
446
|
+
add(rx, ry);
|
|
447
|
+
add(rx + rw, ry + rh);
|
|
448
|
+
add(rx, ry + rh);
|
|
449
|
+
add(rx + rw, ry);
|
|
450
|
+
ci += 4;
|
|
451
|
+
rects++;
|
|
452
|
+
subs++;
|
|
453
|
+
segs += 4;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
case OPS2.fill:
|
|
459
|
+
case OPS2.eoFill:
|
|
460
|
+
case OPS2.fillStroke:
|
|
461
|
+
case OPS2.eoFillStroke:
|
|
462
|
+
case OPS2.closeFillStroke:
|
|
463
|
+
case OPS2.closeEOFillStroke: {
|
|
464
|
+
const w = x2 - x1, h = y2 - y1;
|
|
465
|
+
if (segs > rects * 4 && h >= GLYPH_MIN_H && h <= GLYPH_MAX_H && w <= h * GLYPH_MAX_ASPECT && segs >= GLYPH_MIN_SEGS && subs >= GLYPH_MIN_SUBS) {
|
|
466
|
+
out.push({ x1, y1, x2, y2, segs, subs, color, ops: [...ops, i] });
|
|
467
|
+
}
|
|
468
|
+
reset();
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
case OPS2.stroke:
|
|
472
|
+
case OPS2.closeStroke:
|
|
473
|
+
case OPS2.endPath:
|
|
474
|
+
reset();
|
|
475
|
+
break;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return out;
|
|
479
|
+
}
|
|
480
|
+
function coveredByText(b, texts) {
|
|
481
|
+
const cx = (b.x1 + b.x2) / 2, cy = (b.y1 + b.y2) / 2;
|
|
482
|
+
for (const t of texts) {
|
|
483
|
+
if (cx >= t.x - 1 && cx <= t.x + t.w + 1 && cy >= t.y - t.h * 0.3 - 1 && cy <= t.y + t.h + 1 && t.text.trim()) return true;
|
|
484
|
+
}
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
var median = (a) => {
|
|
488
|
+
const s = a.slice().sort((x, y) => x - y);
|
|
489
|
+
return s[s.length >> 1];
|
|
490
|
+
};
|
|
491
|
+
var spread = (a) => {
|
|
492
|
+
const c = median(a);
|
|
493
|
+
return median(a.map((v) => Math.abs(v - c)));
|
|
494
|
+
};
|
|
495
|
+
function isTextRun(m, em) {
|
|
496
|
+
if (m.length < RUN_MIN) return false;
|
|
497
|
+
if (Math.min(spread(m.map((b) => b.y2)), spread(m.map((b) => b.y1))) > em * RUN_ALIGN_EM) return false;
|
|
498
|
+
let overlaps = 0;
|
|
499
|
+
for (let i = 1; i < m.length; i++) if (m[i].x1 < m[i - 1].x2 - em * 0.1) overlaps++;
|
|
500
|
+
if (overlaps > (m.length - 1) * RUN_MAX_OVERLAP) return false;
|
|
501
|
+
const colors = /* @__PURE__ */ new Map();
|
|
502
|
+
for (const b of m) colors.set(b.color, (colors.get(b.color) ?? 0) + 1);
|
|
503
|
+
if (Math.max(...colors.values()) < m.length * RUN_MIN_COLOR) return false;
|
|
504
|
+
const shapes = new Set(m.map((b) => `${Math.round((b.x2 - b.x1) * 2)}:${Math.round((b.y2 - b.y1) * 2)}:${b.segs}`));
|
|
505
|
+
return shapes.size >= m.length * RUN_MIN_SHAPES;
|
|
506
|
+
}
|
|
507
|
+
function scanVectorGlyphs(fnArray, argsArray, texts) {
|
|
508
|
+
const paths = collectGlyphPaths(fnArray, argsArray);
|
|
509
|
+
if (paths.length < RUN_MIN) return { glyphs: 0, paths };
|
|
510
|
+
const free = paths.filter((b) => !coveredByText(b, texts));
|
|
511
|
+
const sorted = free.slice().sort((a, b) => a.y1 + a.y2 - (b.y1 + b.y2));
|
|
512
|
+
let glyphs = 0;
|
|
513
|
+
let row = [];
|
|
514
|
+
let rowCy = 0, rowH = 0;
|
|
515
|
+
const flushRow = () => {
|
|
516
|
+
if (row.length < RUN_MIN) return;
|
|
517
|
+
row.sort((a, b) => a.x1 - b.x1);
|
|
518
|
+
const em = median(row.map((b) => b.y2 - b.y1));
|
|
519
|
+
let start = 0, maxX = row[0].x2;
|
|
520
|
+
for (let i = 1; i <= row.length; i++) {
|
|
521
|
+
if (i < row.length && row[i].x1 - maxX <= em * RUN_GAP_EM) {
|
|
522
|
+
if (row[i].x2 > maxX) maxX = row[i].x2;
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
const run = row.slice(start, i);
|
|
526
|
+
if (isTextRun(run, em)) glyphs += run.length;
|
|
527
|
+
if (i < row.length) {
|
|
528
|
+
start = i;
|
|
529
|
+
maxX = row[i].x2;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
for (const b of sorted) {
|
|
534
|
+
const cy = (b.y1 + b.y2) / 2, h = b.y2 - b.y1;
|
|
535
|
+
if (row.length && Math.abs(cy - rowCy) <= Math.max(h, rowH) * 0.5) {
|
|
536
|
+
row.push(b);
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
flushRow();
|
|
540
|
+
row = [b];
|
|
541
|
+
rowCy = cy;
|
|
542
|
+
rowH = h;
|
|
543
|
+
}
|
|
544
|
+
flushRow();
|
|
545
|
+
return { glyphs, paths };
|
|
546
|
+
}
|
|
547
|
+
function ocrVectorOps(opList, paths) {
|
|
548
|
+
const drop = /* @__PURE__ */ new Set();
|
|
549
|
+
for (const p of paths) for (const i of p.ops) drop.add(i);
|
|
550
|
+
const fnArray = [];
|
|
551
|
+
const argsArray = [];
|
|
552
|
+
for (let i = 0; i < opList.fnArray.length; i++) {
|
|
553
|
+
const op = opList.fnArray[i];
|
|
554
|
+
if (drop.has(i) || op === OPS2.clip || op === OPS2.eoClip) continue;
|
|
555
|
+
fnArray.push(op);
|
|
556
|
+
argsArray.push(opList.argsArray[i]);
|
|
557
|
+
}
|
|
558
|
+
return { fnArray, argsArray };
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// src/pdf/table-parts.ts
|
|
562
|
+
var PART_COL_TOL = 1;
|
|
563
|
+
function anchorsOf(table) {
|
|
564
|
+
const out = [];
|
|
565
|
+
const covered = /* @__PURE__ */ new Set();
|
|
566
|
+
for (let r = 0; r < table.rows; r++) {
|
|
567
|
+
for (let c = 0; c < table.cols; c++) {
|
|
568
|
+
if (covered.has(r * 1e5 + c)) continue;
|
|
569
|
+
const cell = table.cells[r]?.[c];
|
|
570
|
+
if (!cell) continue;
|
|
571
|
+
out.push({ r, c, rs: cell.rowSpan, cs: cell.colSpan, cell });
|
|
572
|
+
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
573
|
+
for (let dc = 0; dc < cell.colSpan; dc++) if (dr || dc) covered.add((r + dr) * 1e5 + (c + dc));
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return out;
|
|
578
|
+
}
|
|
579
|
+
function unionCoords(a, b) {
|
|
580
|
+
const out = [...a];
|
|
581
|
+
for (const v of b) if (!a.some((x) => Math.abs(x - v) <= PART_COL_TOL)) out.push(v);
|
|
582
|
+
return out.sort((x, y) => x - y);
|
|
583
|
+
}
|
|
584
|
+
var indexOf = (coords, x) => {
|
|
585
|
+
let best = -1, bestD = Infinity;
|
|
586
|
+
for (let i = 0; i < coords.length; i++) {
|
|
587
|
+
const d = Math.abs(coords[i] - x);
|
|
588
|
+
if (d < bestD) {
|
|
589
|
+
bestD = d;
|
|
590
|
+
best = i;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return bestD <= PART_COL_TOL ? best : -1;
|
|
594
|
+
};
|
|
595
|
+
var rowText = (anchors, r) => anchors.filter((a) => a.r === r).map((a) => a.cell.text.replace(/\s+/g, "")).join("|");
|
|
596
|
+
var hasText = (t) => t.replace(/\|/g, "") !== "";
|
|
597
|
+
function joinSplitParts(prev, pcx, curr, ccx, dx = 0, prevBottom) {
|
|
598
|
+
if (pcx.length !== prev.cols + 1 || ccx.length !== curr.cols + 1) return null;
|
|
599
|
+
const U = unionCoords(pcx, ccx);
|
|
600
|
+
const cols = U.length - 1;
|
|
601
|
+
if (cols < 1) return null;
|
|
602
|
+
const pa = anchorsOf(prev), ca = anchorsOf(curr);
|
|
603
|
+
let skip = 0;
|
|
604
|
+
while (skip < Math.min(3, curr.rows - 1, prev.rows) && rowText(ca, skip) !== "" && rowText(ca, skip) === rowText(pa, skip)) skip++;
|
|
605
|
+
for (let h = 1; h <= 2 && !skip; h++) {
|
|
606
|
+
while (skip < Math.min(3, curr.rows - 1, prev.rows - h) && hasText(rowText(ca, skip)) && rowText(ca, skip) === rowText(pa, h + skip)) skip++;
|
|
607
|
+
}
|
|
608
|
+
const rows = prev.rows + curr.rows - skip;
|
|
609
|
+
const grid = Array.from({ length: rows }, () => Array.from({ length: cols }, () => ({ text: "", colSpan: 1, rowSpan: 1 })));
|
|
610
|
+
const owner = Array.from({ length: rows }, () => new Array(cols).fill(null));
|
|
611
|
+
const place = (a, x, rowOff, shift = 0) => {
|
|
612
|
+
const c1 = indexOf(U, x[a.c]), c2 = indexOf(U, x[a.c + a.cs]);
|
|
613
|
+
if (c1 < 0 || c2 <= c1) return false;
|
|
614
|
+
const r = a.r + rowOff;
|
|
615
|
+
const placed = { r, c: c1, rs: a.rs, cs: c2 - c1, cell: a.cell };
|
|
616
|
+
for (let dr = 0; dr < a.rs; dr++) for (let dc = c1; dc < c2; dc++) {
|
|
617
|
+
if (r + dr < rows) owner[r + dr][dc] = placed;
|
|
618
|
+
}
|
|
619
|
+
grid[r][c1] = { ...a.cell, colSpan: c2 - c1, rowSpan: a.rs };
|
|
620
|
+
const lines = CELL_LINES.get(a.cell);
|
|
621
|
+
if (lines) CELL_LINES.set(grid[r][c1], shift ? lines.map((l) => ({ ...l, l: l.l + shift, r: l.r + shift })) : lines);
|
|
622
|
+
if (IMAGE_CELLS.has(a.cell)) IMAGE_CELLS.add(grid[r][c1]);
|
|
623
|
+
return true;
|
|
624
|
+
};
|
|
625
|
+
for (const a of pa) if (!FILLER_CELLS.has(a.cell) && !place(a, pcx, 0)) return null;
|
|
626
|
+
for (const a of ca) {
|
|
627
|
+
if (a.r < skip || FILLER_CELLS.has(a.cell)) continue;
|
|
628
|
+
if (!place(a, ccx, prev.rows - skip, dx)) return null;
|
|
629
|
+
}
|
|
630
|
+
const first = prev.rows;
|
|
631
|
+
for (let c = 0; c < cols; c++) {
|
|
632
|
+
const above = owner[first - 1]?.[c];
|
|
633
|
+
if (!above) continue;
|
|
634
|
+
let r = first;
|
|
635
|
+
while (r < rows && owner[r][c] === null) r++;
|
|
636
|
+
if (r === first) continue;
|
|
637
|
+
const span = r - first;
|
|
638
|
+
let ok = true;
|
|
639
|
+
for (let dc = above.c; dc < above.c + above.cs && ok; dc++) {
|
|
640
|
+
for (let rr = first; rr < first + span; rr++) if (owner[rr][dc] !== null) {
|
|
641
|
+
ok = false;
|
|
642
|
+
break;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (!ok) continue;
|
|
646
|
+
const newRs = above.rs + span;
|
|
647
|
+
grid[above.r][above.c].rowSpan = newRs;
|
|
648
|
+
const grown = { ...above, rs: newRs };
|
|
649
|
+
for (let rr = above.r; rr < above.r + newRs; rr++) for (let dc = above.c; dc < above.c + above.cs; dc++) owner[rr][dc] = grown;
|
|
650
|
+
}
|
|
651
|
+
for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) if (owner[r][c] === null) FILLER_CELLS.add(grid[r][c]);
|
|
652
|
+
const table = { rows, cols, cells: grid, hasHeader: prev.hasHeader, ...prev.caption ? { caption: prev.caption } : {} };
|
|
653
|
+
const split = rows > prev.rows && mergeSplitRow(table, owner, prev.rows, U);
|
|
654
|
+
if (rows > prev.rows && !split && prevBottom !== void 0) mergeStraddlingCells(table, owner, prev.rows, prevBottom);
|
|
655
|
+
return { table, colXs: U, split, header: ca.filter((a) => a.r < skip && a.cell.text.trim()).length >= 2 };
|
|
656
|
+
}
|
|
657
|
+
function mergeStraddlingCells(table, owner, first, prevBottom) {
|
|
658
|
+
const last = first - 1;
|
|
659
|
+
if (!owner[first].some((o, c) => o !== null && o === owner[last][c])) return;
|
|
660
|
+
for (let c = 0; c < table.cols; ) {
|
|
661
|
+
const u = owner[last][c], d = owner[first][c];
|
|
662
|
+
if (!u) {
|
|
663
|
+
c++;
|
|
664
|
+
continue;
|
|
665
|
+
}
|
|
666
|
+
c = u.c + u.cs;
|
|
667
|
+
if (!d || d === u || u.r >= last || u.r + u.rs - 1 !== last || d.r !== first || d.c !== u.c || d.cs !== u.cs) continue;
|
|
668
|
+
const a = table.cells[u.r][u.c], b = table.cells[first][d.c];
|
|
669
|
+
const U = CELL_LINES.get(a);
|
|
670
|
+
if (!U?.length || U.length > STRADDLE_MAX_LINES || !hasContent(b)) continue;
|
|
671
|
+
const lu = U[U.length - 1];
|
|
672
|
+
if (lu.y - prevBottom > STRADDLE_BOTTOM * (lu.h || 10)) continue;
|
|
673
|
+
appendCell(a, b);
|
|
674
|
+
a.rowSpan = first + d.rs - u.r;
|
|
675
|
+
table.cells[first][d.c] = { text: "", colSpan: 1, rowSpan: 1 };
|
|
676
|
+
const grown = { ...u, rs: a.rowSpan };
|
|
677
|
+
for (let rr = u.r; rr < u.r + grown.rs; rr++) for (let dc = u.c; dc < u.c + u.cs; dc++) owner[rr][dc] = grown;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
var FULL_LINE_TOL = 1;
|
|
681
|
+
var FULL_LINE_MIN_FRAC = 0.5;
|
|
682
|
+
var FULL_LINE_EDGE_MIN = 12;
|
|
683
|
+
var SINGLE_LINE_WORD_GAP = 3.5;
|
|
684
|
+
var SHORT_LINE_GAP = 1.5;
|
|
685
|
+
var STRADDLE_MAX_LINES = 3;
|
|
686
|
+
var STRADDLE_BOTTOM = 1.2;
|
|
687
|
+
var CARRIED_MIN_COL_W = 4;
|
|
688
|
+
var LABEL_ROOM = 1.5;
|
|
689
|
+
var HANGING_MIN = 0.5;
|
|
690
|
+
var HANGING_TOL = 1;
|
|
691
|
+
function continuesAcross(u, d, x1, x2) {
|
|
692
|
+
const U = CELL_LINES.get(u), D = CELL_LINES.get(d);
|
|
693
|
+
if (!U?.length || !D?.length) return false;
|
|
694
|
+
const last = U[U.length - 1];
|
|
695
|
+
const fs = last.h || 10;
|
|
696
|
+
let minL = Infinity, maxR = -Infinity;
|
|
697
|
+
for (const l of U) {
|
|
698
|
+
minL = Math.min(minL, l.l);
|
|
699
|
+
maxR = Math.max(maxR, l.r);
|
|
700
|
+
}
|
|
701
|
+
for (const l of D) {
|
|
702
|
+
minL = Math.min(minL, l.l);
|
|
703
|
+
maxR = Math.max(maxR, l.r);
|
|
704
|
+
}
|
|
705
|
+
maxR = Math.max(maxR, x2 - (minL - x1));
|
|
706
|
+
if (maxR - last.r > FULL_LINE_TOL * fs) return false;
|
|
707
|
+
if (U.length === 1 && x2 - last.r > Math.max(FULL_LINE_EDGE_MIN, SINGLE_LINE_WORD_GAP * fs)) return false;
|
|
708
|
+
if (last.r - last.l < FULL_LINE_MIN_FRAC * (x2 - x1)) return false;
|
|
709
|
+
const leftAligned = (l) => l.l - minL <= fs && maxR - l.r > SHORT_LINE_GAP * fs;
|
|
710
|
+
const hanging = U.length >= 2 && U.every((l) => maxR - l.r <= FULL_LINE_TOL * fs) && last.l - minL >= HANGING_MIN * fs && Math.abs(D[0].l - last.l) <= HANGING_TOL;
|
|
711
|
+
return U.some(leftAligned) || D.some(leftAligned) || hanging;
|
|
712
|
+
}
|
|
713
|
+
function lineEnded(c, x1, x2) {
|
|
714
|
+
const L = CELL_LINES.get(c);
|
|
715
|
+
if (!L || L.length !== 1) return false;
|
|
716
|
+
const l = L[0];
|
|
717
|
+
return x2 - l.r - (l.l - x1) >= LABEL_ROOM * (l.h || 10);
|
|
718
|
+
}
|
|
719
|
+
function appendCell(a, b) {
|
|
720
|
+
if (a.blocks?.length || b.blocks?.length) {
|
|
721
|
+
const asBlocks = (c) => c.blocks?.length ? c.blocks : c.text.split("\n").map((l) => l.trim()).filter(Boolean).map((text) => ({ type: "paragraph", text }));
|
|
722
|
+
a.blocks = [...asBlocks(a), ...asBlocks(b)];
|
|
723
|
+
}
|
|
724
|
+
if (b.text.trim()) a.text = a.text.trim() ? a.text + "\n" + b.text : b.text;
|
|
725
|
+
}
|
|
726
|
+
var hasContent = (cell) => !!cell.text.trim() || !!cell.blocks?.length || IMAGE_CELLS.has(cell);
|
|
727
|
+
function mergeSplitRow(table, owner, first, colXs) {
|
|
728
|
+
const last = first - 1;
|
|
729
|
+
const pairs = [];
|
|
730
|
+
let carried = false;
|
|
731
|
+
for (let c = 0; c < table.cols; ) {
|
|
732
|
+
const a = owner[last][c], b = owner[first][c];
|
|
733
|
+
if (!a && !b) {
|
|
734
|
+
if (colXs[c + 1] - colXs[c] >= CARRIED_MIN_COL_W) carried = true;
|
|
735
|
+
c++;
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
if (!a || !b) return false;
|
|
739
|
+
if (a !== b) {
|
|
740
|
+
if (a.c !== b.c || a.cs !== b.cs || a.r + a.rs - 1 !== last || b.r !== first || b.rs !== 1) return false;
|
|
741
|
+
pairs.push([a, b]);
|
|
742
|
+
} else if (a.r === last && a.rs === 2) carried = true;
|
|
743
|
+
c = a.c + a.cs;
|
|
744
|
+
}
|
|
745
|
+
const carriedSplit = carried && pairs.filter(([u, d]) => hasContent(u.cell) && hasContent(d.cell)).length <= 1 && !pairs.some(([u, d]) => !hasContent(u.cell) && hasContent(d.cell));
|
|
746
|
+
const cell = (a) => table.cells[a.r][a.c];
|
|
747
|
+
if (!carriedSplit) {
|
|
748
|
+
const norm = (c) => c.text.replace(/\s+/g, "");
|
|
749
|
+
if (pairs.some(([u, d]) => hasContent(d.cell) && norm(cell(d)) !== norm(cell(u)) && lineEnded(cell(u), colXs[u.c], colXs[u.c + u.cs]))) return false;
|
|
750
|
+
if (!pairs.some(([u, d]) => continuesAcross(cell(u), cell(d), colXs[u.c], colXs[u.c + u.cs]))) return false;
|
|
751
|
+
}
|
|
752
|
+
for (const [u, d] of pairs) appendCell(table.cells[u.r][u.c], table.cells[d.r][d.c]);
|
|
753
|
+
for (let r = 0; r < first; r++) for (let c = 0; c < table.cols; c++) {
|
|
754
|
+
const o = owner[r][c];
|
|
755
|
+
if (o && o.r === r && o.c === c && r + table.cells[r][c].rowSpan > first) table.cells[r][c].rowSpan--;
|
|
756
|
+
}
|
|
757
|
+
table.cells.splice(first, 1);
|
|
758
|
+
table.rows--;
|
|
759
|
+
return true;
|
|
760
|
+
}
|
|
761
|
+
var NEIGHBOR_TABLE_EPSILON = 0.2;
|
|
762
|
+
function besideOwn(b, p, c) {
|
|
763
|
+
if (!b.bbox) return false;
|
|
764
|
+
if (b.type === "table") return leftColumnOf(b, p);
|
|
765
|
+
const t = (b.pageNumber === p.pageNumber ? p : c).bbox;
|
|
766
|
+
const bx1 = b.bbox.x, bx2 = b.bbox.x + b.bbox.width;
|
|
767
|
+
return bx2 <= t.x + 1 || bx1 >= t.x + t.width - 1;
|
|
768
|
+
}
|
|
769
|
+
function leftColumnOf(b, t) {
|
|
770
|
+
return !!b.bbox && b.pageNumber === t.pageNumber && b.bbox.x + b.bbox.width <= t.bbox.x + 1;
|
|
771
|
+
}
|
|
772
|
+
function placeJoined(blocks, i, j, table) {
|
|
773
|
+
const prev = blocks[i];
|
|
774
|
+
blocks[i] = { ...prev, table };
|
|
775
|
+
blocks.splice(j, 1);
|
|
776
|
+
let k = j - 1;
|
|
777
|
+
while (k > i && !leftColumnOf(blocks[k], prev)) k--;
|
|
778
|
+
if (k > i) blocks.splice(k, 0, blocks.splice(i, 1)[0]);
|
|
779
|
+
}
|
|
780
|
+
function insideTable(b, t) {
|
|
781
|
+
if (!b.bbox || b.pageNumber !== t.pageNumber) return false;
|
|
782
|
+
const o = t.bbox;
|
|
783
|
+
return b.bbox.x >= o.x - 1 && b.bbox.x + b.bbox.width <= o.x + o.width + 1 && b.bbox.y >= o.y - 1 && b.bbox.y + b.bbox.height <= o.y + o.height + 1;
|
|
784
|
+
}
|
|
785
|
+
function mergeCrossPageTables(blocks, pageHeights) {
|
|
786
|
+
mergeColumnFlow(blocks, pageHeights);
|
|
787
|
+
for (let i = blocks.length - 2; i >= 0; i--) {
|
|
788
|
+
const prev = blocks[i];
|
|
789
|
+
if (prev.type !== "table" || !prev.table || !prev.bbox || !prev.pageNumber) continue;
|
|
790
|
+
let j = i + 1;
|
|
791
|
+
while (j < blocks.length && (blocks[j].type !== "table" || insideTable(blocks[j], prev) || leftColumnOf(blocks[j], prev)) && (blocks[j].pageNumber ?? 0) <= prev.pageNumber + 1) j++;
|
|
792
|
+
const curr = blocks[j];
|
|
793
|
+
if (!curr || curr.type !== "table" || !curr.table || !curr.bbox || curr.pageNumber !== prev.pageNumber + 1) continue;
|
|
794
|
+
const joined = j === i + 1 || blocks.slice(i + 1, j).every((b) => besideOwn(b, prev, curr) || insideTable(b, prev)) ? looksContinued(prev, curr, pageHeights) && !restartsTable(blocks, i, curr.table, pageHeights) ? joinClipParts(prev, curr, pageHeights) ?? false : null : null;
|
|
795
|
+
if (joined) {
|
|
796
|
+
placeJoined(blocks, i, j, joined);
|
|
797
|
+
continue;
|
|
798
|
+
}
|
|
799
|
+
if (EMPTY_PARTS.has(curr.table)) {
|
|
800
|
+
blocks.splice(j, 1);
|
|
801
|
+
i++;
|
|
802
|
+
continue;
|
|
803
|
+
}
|
|
804
|
+
if (joined === null) continue;
|
|
805
|
+
if (prev.table.cols !== curr.table.cols || EMPTY_PARTS.has(prev.table)) continue;
|
|
806
|
+
const width = Math.max(prev.bbox.width, curr.bbox.width, 1);
|
|
807
|
+
const leftDiff = Math.abs(prev.bbox.x - curr.bbox.x);
|
|
808
|
+
const rightDiff = Math.abs(prev.bbox.x + prev.bbox.width - (curr.bbox.x + curr.bbox.width));
|
|
809
|
+
if (leftDiff > width * NEIGHBOR_TABLE_EPSILON || rightDiff > width * NEIGHBOR_TABLE_EPSILON) continue;
|
|
810
|
+
const px = TABLE_COLXS.get(prev.table), cx = TABLE_COLXS.get(curr.table);
|
|
811
|
+
if (px && cx && !shiftedSame(px, cx, !CLIP_TABLES.has(prev.table) && !CLIP_TABLES.has(curr.table))) continue;
|
|
812
|
+
let currCells = curr.table.cells;
|
|
813
|
+
if (currCells.length > 1 && prev.table.cells.length > 0 && rowTextsEqual(prev.table.cells[0], currCells[0])) {
|
|
814
|
+
currCells = currCells.slice(1);
|
|
815
|
+
}
|
|
816
|
+
if (currCells.length === 0) {
|
|
817
|
+
blocks.splice(j, 1);
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
const merged = {
|
|
821
|
+
rows: prev.table.rows + currCells.length,
|
|
822
|
+
cols: prev.table.cols,
|
|
823
|
+
cells: [...prev.table.cells, ...currCells],
|
|
824
|
+
hasHeader: prev.table.hasHeader,
|
|
825
|
+
caption: prev.table.caption
|
|
826
|
+
};
|
|
827
|
+
if (px ?? cx) TABLE_COLXS.set(merged, px ?? cx);
|
|
828
|
+
if (CLIP_TABLES.has(prev.table) || CLIP_TABLES.has(curr.table)) CLIP_TABLES.add(merged);
|
|
829
|
+
placeJoined(blocks, i, j, merged);
|
|
830
|
+
}
|
|
831
|
+
for (let i = blocks.length - 1; i >= 0; i--) {
|
|
832
|
+
const t = blocks[i].table;
|
|
833
|
+
if (blocks[i].type === "table" && t && EMPTY_PARTS.has(t)) blocks.splice(i, 1);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
function mergeColumnFlow(blocks, pageHeights) {
|
|
837
|
+
if (!pageHeights) return;
|
|
838
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
839
|
+
const L = blocks[i];
|
|
840
|
+
if (L.type !== "table" || !L.table || !L.bbox || !L.pageNumber || !CLIP_TABLES.has(L.table) || EMPTY_PARTS.has(L.table)) continue;
|
|
841
|
+
const ph = pageHeights.get(L.pageNumber);
|
|
842
|
+
if (!ph || L.bbox.y > ph * PAGE_EDGE_BAND) continue;
|
|
843
|
+
let s0 = i, s1 = i;
|
|
844
|
+
while (s0 > 0 && blocks[s0 - 1].pageNumber === L.pageNumber) s0--;
|
|
845
|
+
while (s1 + 1 < blocks.length && blocks[s1 + 1].pageNumber === L.pageNumber) s1++;
|
|
846
|
+
let k = -1;
|
|
847
|
+
for (let q = s0; q <= s1; q++) {
|
|
848
|
+
const R2 = blocks[q];
|
|
849
|
+
if (q === i || R2.type !== "table" || !R2.table || !R2.bbox || !leftColumnOf(L, R2)) continue;
|
|
850
|
+
const top2 = R2.bbox.y + R2.bbox.height;
|
|
851
|
+
if (top2 < ph * (1 - PAGE_EDGE_BAND)) continue;
|
|
852
|
+
if (k < 0 || top2 > blocks[k].bbox.y + blocks[k].bbox.height) k = q;
|
|
853
|
+
}
|
|
854
|
+
if (k < 0) continue;
|
|
855
|
+
const R = blocks[k];
|
|
856
|
+
if (Math.abs(R.bbox.width - L.bbox.width) > Math.max(R.bbox.width, L.bbox.width) * NEIGHBOR_TABLE_EPSILON) continue;
|
|
857
|
+
if (!looksContinued(L, R) || restartsTable(blocks, i, R.table, pageHeights)) continue;
|
|
858
|
+
const joined = joinClipParts(L, R, pageHeights);
|
|
859
|
+
if (!joined) continue;
|
|
860
|
+
const top = L.bbox.y + L.bbox.height;
|
|
861
|
+
const at = Math.min(i, k);
|
|
862
|
+
blocks[at] = { ...L, table: joined, bbox: { ...L.bbox, y: R.bbox.y, height: Math.max(0, top - R.bbox.y) } };
|
|
863
|
+
blocks.splice(Math.max(i, k), 1);
|
|
864
|
+
i = at - 1;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
function joinClipParts(prev, curr, pageHeights) {
|
|
868
|
+
const pt = prev.table, ct = curr.table;
|
|
869
|
+
if (!CLIP_TABLES.has(pt) || !CLIP_TABLES.has(ct)) return null;
|
|
870
|
+
const px = TABLE_COLXS.get(pt), cx = TABLE_COLXS.get(ct);
|
|
871
|
+
if (!px || !cx) return null;
|
|
872
|
+
let xs = cx, shifted = false, dx = 0;
|
|
873
|
+
if (!shiftedSame(px, cx, false)) {
|
|
874
|
+
if (!pageHeights?.get(prev.pageNumber) || !pageHeights?.get(curr.pageNumber)) return null;
|
|
875
|
+
dx = px[px.length - 1] - cx[cx.length - 1];
|
|
876
|
+
if (Math.abs(dx) > CONTINUATION_COL_TOL) {
|
|
877
|
+
xs = cx.map((x) => x + dx);
|
|
878
|
+
shifted = true;
|
|
879
|
+
} else dx = 0;
|
|
880
|
+
if (!px.some((x) => Math.abs(x - xs[0]) <= CONTINUATION_COL_TOL)) return null;
|
|
881
|
+
}
|
|
882
|
+
const res = joinSplitParts(pt, px, ct, xs, dx, prev.bbox?.y);
|
|
883
|
+
if (!res || shifted && !res.split && !res.header) return null;
|
|
884
|
+
TABLE_COLXS.set(res.table, res.colXs);
|
|
885
|
+
CLIP_TABLES.add(res.table);
|
|
886
|
+
return res.table;
|
|
887
|
+
}
|
|
888
|
+
var ANNEX_HEAD_RE = /^\s*[<\[(【]?\s*(?:붙\s*임|참\s*고|별\s*첨|별\s*지|별\s*표|첨\s*부|부\s*록)(?:\s*\d|\s*$|\s*[>\])】])|^\s*■/;
|
|
889
|
+
function looksContinued(prev, curr, pageHeights) {
|
|
890
|
+
const ph = pageHeights?.get(prev.pageNumber), ch = pageHeights?.get(curr.pageNumber);
|
|
891
|
+
if (ph && ch && (prev.bbox.y > ph * PAGE_EDGE_BAND || curr.bbox.y + curr.bbox.height < ch * (1 - PAGE_EDGE_BAND))) return false;
|
|
892
|
+
const firstText = curr.table.cells[0]?.find((c) => c.text.trim())?.text ?? "";
|
|
893
|
+
return !ANNEX_HEAD_RE.test(firstText);
|
|
894
|
+
}
|
|
895
|
+
function firstRowSig(t) {
|
|
896
|
+
const x = TABLE_COLXS.get(t);
|
|
897
|
+
if (!x || x.length !== t.cols + 1) return null;
|
|
898
|
+
return anchorsOf(t).filter((a) => a.r === 0).map((a) => ({ x1: x[a.c], x2: x[a.c + a.cs], t: a.cell.text.replace(/\s+/g, "") }));
|
|
899
|
+
}
|
|
900
|
+
function restartsTable(blocks, i, curr, pageHeights) {
|
|
901
|
+
const cs = firstRowSig(curr);
|
|
902
|
+
if (!cs || cs.length < RESTART_MIN_ANCHORS) return false;
|
|
903
|
+
const hs = firstRowSig(blocks[chainHead(blocks, i, pageHeights)].table);
|
|
904
|
+
if (!hs || hs.length !== cs.length) return false;
|
|
905
|
+
const dx = hs[hs.length - 1].x2 - cs[cs.length - 1].x2;
|
|
906
|
+
if (!hs.every((h, n) => Math.abs(h.x1 - cs[n].x1 - dx) <= CONTINUATION_COL_TOL && Math.abs(h.x2 - cs[n].x2 - dx) <= CONTINUATION_COL_TOL)) return false;
|
|
907
|
+
let same = 0, diff = 0;
|
|
908
|
+
for (let n = 0; n < hs.length; n++) {
|
|
909
|
+
if (!hs[n].t && !cs[n].t) continue;
|
|
910
|
+
if (hs[n].t === cs[n].t) same++;
|
|
911
|
+
else diff++;
|
|
912
|
+
}
|
|
913
|
+
return same >= 2 && diff >= 1;
|
|
914
|
+
}
|
|
915
|
+
function chainHead(blocks, i, pageHeights) {
|
|
916
|
+
let k = i;
|
|
917
|
+
for (let steps = 0; steps < RESTART_LOOKBACK_PAGES; steps++) {
|
|
918
|
+
const cur = blocks[k];
|
|
919
|
+
let p = k - 1;
|
|
920
|
+
while (p >= 0 && blocks[p].type !== "table" && (blocks[p].pageNumber ?? 0) >= (cur.pageNumber ?? 0) - 1) p--;
|
|
921
|
+
if (p < 0 || blocks[p].type !== "table" || !blocks[p].table || !blocks[p].bbox) break;
|
|
922
|
+
for (let q = p - 1; q >= 0 && blocks[q].pageNumber === blocks[p].pageNumber; q--) {
|
|
923
|
+
if (blocks[q].type === "table" && blocks[q].bbox && insideTable(blocks[p], blocks[q])) {
|
|
924
|
+
p = q;
|
|
925
|
+
break;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
const pb = blocks[p];
|
|
929
|
+
if (pb.pageNumber !== (cur.pageNumber ?? 0) - 1) break;
|
|
930
|
+
if (!blocks.slice(p + 1, k).every((b) => besideOwn(b, pb, cur) || insideTable(b, pb))) break;
|
|
931
|
+
if (!looksContinued(pb, cur, pageHeights)) break;
|
|
932
|
+
const px = TABLE_COLXS.get(pb.table), cx = TABLE_COLXS.get(cur.table);
|
|
933
|
+
if (!px || !cx) break;
|
|
934
|
+
const dx = px[px.length - 1] - cx[cx.length - 1];
|
|
935
|
+
if (!shiftedSame(px, cx) && !px.some((x) => Math.abs(x - (cx[0] + dx)) <= CONTINUATION_COL_TOL)) break;
|
|
936
|
+
k = p;
|
|
937
|
+
}
|
|
938
|
+
return k;
|
|
939
|
+
}
|
|
940
|
+
function rowTextsEqual(a, b) {
|
|
941
|
+
if (a.length !== b.length) return false;
|
|
942
|
+
const norm = (t) => t.replace(/\s+/g, "");
|
|
943
|
+
for (let i = 0; i < a.length; i++) {
|
|
944
|
+
if (norm(a[i].text) !== norm(b[i].text)) return false;
|
|
945
|
+
}
|
|
946
|
+
return a.some((c) => c.text.trim() !== "");
|
|
947
|
+
}
|
|
948
|
+
var CONTINUATION_COL_TOL = 2;
|
|
949
|
+
function shiftedSame(px, cx, allowShift = true) {
|
|
950
|
+
if (px.length !== cx.length) return false;
|
|
951
|
+
const dx = allowShift ? px[px.length - 1] - cx[cx.length - 1] : 0;
|
|
952
|
+
return px.every((x, k) => Math.abs(x - cx[k] - dx) <= CONTINUATION_COL_TOL);
|
|
953
|
+
}
|
|
954
|
+
var PAGE_EDGE_BAND = 0.16;
|
|
955
|
+
var RESTART_MIN_ANCHORS = 3;
|
|
956
|
+
var RESTART_LOOKBACK_PAGES = 5;
|
|
957
|
+
|
|
958
|
+
// src/pdf/cell-continuation.ts
|
|
959
|
+
var COL_MATCH_TOL = 0.5;
|
|
960
|
+
function lastRowCell(t, x1, x2) {
|
|
961
|
+
const xs = TABLE_COLXS.get(t);
|
|
962
|
+
const covered = /* @__PURE__ */ new Set();
|
|
963
|
+
for (let r = 0; r < t.rows; r++) {
|
|
964
|
+
for (let c = 0; c < t.cols; c++) {
|
|
965
|
+
if (covered.has(r * 1e5 + c)) continue;
|
|
966
|
+
const cell = t.cells[r]?.[c];
|
|
967
|
+
if (!cell) continue;
|
|
968
|
+
for (let dr = 0; dr < cell.rowSpan; dr++) for (let dc = 0; dc < cell.colSpan; dc++) covered.add((r + dr) * 1e5 + c + dc);
|
|
969
|
+
if (r + cell.rowSpan !== t.rows) continue;
|
|
970
|
+
if (xs ? Math.abs(xs[c] - x1) <= COL_MATCH_TOL && Math.abs(xs[c + cell.colSpan] - x2) <= COL_MATCH_TOL : t.cols === 1) return cell;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
return void 0;
|
|
974
|
+
}
|
|
975
|
+
var cellBlocks = (cell, pageNumber) => cell.blocks ?? cell.text.split("\n").map((t) => t.trim()).filter(Boolean).map((text) => ({ type: "paragraph", text, pageNumber }));
|
|
976
|
+
function mergeContinuedCells(blocks, pageHeights) {
|
|
977
|
+
for (let j = blocks.length - 1; j > 0; j--) {
|
|
978
|
+
const part = blocks[j];
|
|
979
|
+
const from = part.table ? CONT_PARTS.get(part.table) : void 0;
|
|
980
|
+
if (!from || !part.table) continue;
|
|
981
|
+
let i = j - 1;
|
|
982
|
+
while (i >= 0 && blocks[i].type !== "table") i--;
|
|
983
|
+
const prev = blocks[i];
|
|
984
|
+
if (i < 0 || !prev.table || prev.pageNumber !== (part.pageNumber ?? 0) - 1) continue;
|
|
985
|
+
const cell = lastRowCell(prev.table, from.x1, from.x2);
|
|
986
|
+
const add = part.table.cells[0]?.[0];
|
|
987
|
+
if (!cell || !add) continue;
|
|
988
|
+
if (cell.blocks || add.blocks) cell.blocks = [...cellBlocks(cell, prev.pageNumber), ...cellBlocks(add, part.pageNumber)];
|
|
989
|
+
cell.text = [cell.text, add.text].filter((s) => s.trim()).join("\n");
|
|
990
|
+
if (cell.text.trim() || cell.blocks?.length) EMPTY_PARTS.delete(prev.table);
|
|
991
|
+
blocks.splice(j, 1);
|
|
992
|
+
if (cell.blocks) mergeCrossPageTables(cell.blocks, pageHeights);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// src/pdf/symbol-fonts.ts
|
|
554
997
|
var WINANSI_REVERSE = {
|
|
555
998
|
8364: 128,
|
|
556
999
|
8218: 130,
|
|
@@ -623,7 +1066,8 @@ function remapSymbolFontItems(items, resolveFontName) {
|
|
|
623
1066
|
function normalizeAraea(text) {
|
|
624
1067
|
return text.replace(/(?<![\u1100-\u115F])\u119E/g, "\u318D");
|
|
625
1068
|
}
|
|
626
|
-
var
|
|
1069
|
+
var stripNoUnicodeGlyph = (text) => text.includes("\uF000") ? text.replace(/\uF000/g, "") : text;
|
|
1070
|
+
var cleanChars = (text) => normalizeAraea(stripNoUnicodeGlyph(stripControlChars(text)));
|
|
627
1071
|
function sanitizeBlockControlChars(blocks) {
|
|
628
1072
|
for (const b of blocks) {
|
|
629
1073
|
if (b.text) b.text = cleanChars(b.text);
|
|
@@ -658,7 +1102,8 @@ function cleanPdfText(text) {
|
|
|
658
1102
|
normalizeAraea(stripControlChars(text)).replace(/^\d{1,4}\n/, "").replace(/^[\s]*[-–—]\s*[-–—]?\d+[-–—]?[\s]*[-–—]?[\s]*$/gm, "").replace(/^\s*\d+\s*\/\s*\d+\s*$/gm, "").replace(/\n\d{1,4}\n/g, "\n").replace(/\n\d{1,4}$/, "").replace(/^#{1,6}\s*\d{1,4}\s*$/gm, "")
|
|
659
1103
|
).replace(/^(?!\| ---).*$/gm, (line) => {
|
|
660
1104
|
if (/^\s*\${1,2}.+\${1,2}\s*$/.test(line)) return line;
|
|
661
|
-
|
|
1105
|
+
const mark = /^(?:#{1,6}|-) /.exec(line)?.[0] ?? "";
|
|
1106
|
+
return mark + collapseEvenSpacing(line.slice(mark.length));
|
|
662
1107
|
}).replace(/([□■◆○●▶ㅇ])\s+([가-힣])\s+([가-힣])/g, "$1 $2$3").replace(/\\~\\~/g, "~~").replace(/~~~~/g, "").replace(/<u>\s*<\/u>/g, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
663
1108
|
}
|
|
664
1109
|
function startsWithMarker(line) {
|
|
@@ -737,7 +1182,7 @@ function applyLinkAnnotations(items, annots) {
|
|
|
737
1182
|
|
|
738
1183
|
// src/pdf/formula-ocr.ts
|
|
739
1184
|
async function applyFormulaOcr(buffer, blocks, pageFilter, effectivePageCount, warnings, _onProgress) {
|
|
740
|
-
const formulaMod = await import("./formula-
|
|
1185
|
+
const formulaMod = await import("./formula-7UYJOVTB.js");
|
|
741
1186
|
const { FormulaPipeline, ensureFormulaModels } = formulaMod;
|
|
742
1187
|
await ensureFormulaModels((p) => {
|
|
743
1188
|
if (p.phase === "download" && p.total) {
|
|
@@ -937,6 +1382,9 @@ async function parsePdfDocument(buffer, options) {
|
|
|
937
1382
|
const imageState = createPdfImageState();
|
|
938
1383
|
const extractedImages = [];
|
|
939
1384
|
const pageImageBlocks = /* @__PURE__ */ new Map();
|
|
1385
|
+
const carry = {};
|
|
1386
|
+
const vectorPageOps = /* @__PURE__ */ new Map();
|
|
1387
|
+
const wrapLexicon = new WrapLexicon();
|
|
940
1388
|
let parsedPages = 0;
|
|
941
1389
|
for (let i = 1; i <= effectivePageCount; i++) {
|
|
942
1390
|
if (pageFilter && !pageFilter.has(i)) continue;
|
|
@@ -967,6 +1415,7 @@ async function parsePdfDocument(buffer, options) {
|
|
|
967
1415
|
return void 0;
|
|
968
1416
|
}
|
|
969
1417
|
});
|
|
1418
|
+
for (const it of visible) if (it.text.includes("$")) it.text = escapeLiteralDollar(it.text);
|
|
970
1419
|
const pageArea = viewport.width * viewport.height;
|
|
971
1420
|
if (pageArea > 0) {
|
|
972
1421
|
const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray);
|
|
@@ -975,19 +1424,19 @@ async function parsePdfDocument(buffer, options) {
|
|
|
975
1424
|
const area = (r.x2 - r.x1) * (r.y2 - r.y1);
|
|
976
1425
|
if (area < pageArea * 0.05) continue;
|
|
977
1426
|
pagesWithLargeImage.add(i);
|
|
978
|
-
const
|
|
1427
|
+
const hasText2 = visible.some((it) => {
|
|
979
1428
|
const cx = it.x + it.w / 2;
|
|
980
1429
|
const cy = it.y + (it.h || it.fontSize) / 2;
|
|
981
1430
|
return cx >= r.x1 && cx <= r.x2 && cy >= r.y1 && cy <= r.y2;
|
|
982
1431
|
});
|
|
983
|
-
if (!
|
|
1432
|
+
if (!hasText2) uncovered++;
|
|
984
1433
|
}
|
|
985
1434
|
if (uncovered > 0) skippedImagePages.set(i, uncovered);
|
|
986
1435
|
}
|
|
987
|
-
const pageBlocks = extractPageBlocksWithLines(visible, i, opList, viewport.width, viewport.height, void 0, options?.tables !== false);
|
|
1436
|
+
const pageBlocks = extractPageBlocksWithLines(visible, i, opList, viewport.width, viewport.height, void 0, options?.tables !== false, carry, wrapLexicon);
|
|
988
1437
|
for (const b of pageBlocks) blocks.push(b);
|
|
989
1438
|
try {
|
|
990
|
-
const { blocks: imgBlocks, images: pageImages } = await extractPageImages(page, opList.fnArray, opList.argsArray, i, imageState, warnings);
|
|
1439
|
+
const { blocks: imgBlocks, images: pageImages } = await extractPageImages(page, opList.fnArray, opList.argsArray, i, imageState, warnings, options?.images !== false);
|
|
991
1440
|
if (imgBlocks.length > 0) pageImageBlocks.set(i, imgBlocks);
|
|
992
1441
|
extractedImages.push(...pageImages);
|
|
993
1442
|
} catch {
|
|
@@ -1003,7 +1452,12 @@ async function parsePdfDocument(buffer, options) {
|
|
|
1003
1452
|
totalTextBytes += t.length * 2;
|
|
1004
1453
|
pageText += pageText ? "\n" + t : t;
|
|
1005
1454
|
}
|
|
1006
|
-
|
|
1455
|
+
const vector = scanVectorGlyphs(opList.fnArray, opList.argsArray, visible);
|
|
1456
|
+
const quality = computePageQuality(i, pageText, vector.glyphs);
|
|
1457
|
+
pageQuality.push(quality);
|
|
1458
|
+
if (options?.ocr && quality.ocrReason === "vector_text" && page.rotate % 360 === 0 && page.view[0] === 0 && page.view[1] === 0) {
|
|
1459
|
+
vectorPageOps.set(i, ocrVectorOps(opList, vector.paths));
|
|
1460
|
+
}
|
|
1007
1461
|
if (totalTextBytes > MAX_TOTAL_TEXT) throw new KordocError("\uD14D\uC2A4\uD2B8 \uCD94\uCD9C \uD06C\uAE30 \uCD08\uACFC");
|
|
1008
1462
|
parsedPages++;
|
|
1009
1463
|
options?.onProgress?.(parsedPages, totalTarget);
|
|
@@ -1029,9 +1483,9 @@ async function parsePdfDocument(buffer, options) {
|
|
|
1029
1483
|
}
|
|
1030
1484
|
if (targets.size > 0) {
|
|
1031
1485
|
try {
|
|
1032
|
-
const { runPdfOcr } = await import("./pdf-ocr-
|
|
1486
|
+
const { runPdfOcr } = await import("./pdf-ocr-UUBWBEHL.js");
|
|
1033
1487
|
const mode = typeof options.ocr === "function" ? options.ocr : "builtin";
|
|
1034
|
-
const ocrPageBlocks = await runPdfOcr(ocrBuffer, targets, mode, warnings, options.onProgress, options.tables !== false);
|
|
1488
|
+
const ocrPageBlocks = await runPdfOcr(ocrBuffer, targets, mode, warnings, options.onProgress, options.tables !== false, vectorPageOps);
|
|
1035
1489
|
if (ocrPageBlocks.size > 0) {
|
|
1036
1490
|
for (const p of ocrPageBlocks.keys()) ocrDone.add(p);
|
|
1037
1491
|
const merged = blocks.filter((b) => !(b.pageNumber && ocrDone.has(b.pageNumber)));
|
|
@@ -1061,6 +1515,7 @@ async function parsePdfDocument(buffer, options) {
|
|
|
1061
1515
|
}
|
|
1062
1516
|
if (!isImageBased) {
|
|
1063
1517
|
const OCR_REASON_MESSAGES = {
|
|
1518
|
+
vector_text: "\uAE00\uC790\uB97C \uACE1\uC120(\uBCA1\uD130 \uACBD\uB85C)\uC73C\uB85C \uADF8\uB9B0 \uD398\uC774\uC9C0 (\uD14D\uC2A4\uD2B8\uCE35\uC5D0 \uAE00\uC790 \uC5C6\uC74C)",
|
|
1064
1519
|
low_text: "\uD14D\uC2A4\uD2B8\uAC00 \uAC70\uC758 \uC5C6\uB294 \uD398\uC774\uC9C0 (\uC2A4\uCE94/\uC774\uBBF8\uC9C0 \uCD94\uC815)",
|
|
1065
1520
|
high_pua: "\uAE00\uAF34 \uB9E4\uD551 \uC2E4\uD328 (PUA \uBE44\uC728 \uB192\uC74C) \u2014 \uCD94\uCD9C \uD14D\uC2A4\uD2B8 \uC2E0\uB8B0 \uBD88\uAC00",
|
|
1066
1521
|
high_control: "\uC81C\uC5B4\uBB38\uC790 \uBE44\uC728 \uB192\uC74C \u2014 \uCD94\uCD9C \uD14D\uC2A4\uD2B8 \uC2E0\uB8B0 \uBD88\uAC00",
|
|
@@ -1084,7 +1539,10 @@ async function parsePdfDocument(buffer, options) {
|
|
|
1084
1539
|
blocks.splice(removed[ri], 1);
|
|
1085
1540
|
}
|
|
1086
1541
|
}
|
|
1087
|
-
|
|
1542
|
+
mergeContinuedCells(blocks, pageHeights);
|
|
1543
|
+
mergeCrossPageTables(blocks, pageHeights);
|
|
1544
|
+
if (!options?.keepTrailingEmptyCols) trimTrailingEmptyTableCols(blocks);
|
|
1545
|
+
joinPageBreakWraps(blocks, wrapLexicon);
|
|
1088
1546
|
injectPageImageBlocks(blocks, pageImageBlocks);
|
|
1089
1547
|
if (options?.formulaOcr && formulaBuffer) {
|
|
1090
1548
|
try {
|
|
@@ -1166,4 +1624,4 @@ export {
|
|
|
1166
1624
|
parsePdfDocument,
|
|
1167
1625
|
removeHeaderFooterBlocks
|
|
1168
1626
|
};
|
|
1169
|
-
//# sourceMappingURL=parser-
|
|
1627
|
+
//# sourceMappingURL=parser-3FNXEP6T.js.map
|