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