kordoc 4.18.2 → 4.18.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/dist/{-I3CP33G4.js → -DDAVBMHD.js} +11 -11
- package/dist/{chunk-O2DI4GHD.js → chunk-274ZPMHK.js} +2 -2
- package/dist/{chunk-QGFZU3JE.cjs → chunk-3WLZOJIE.cjs} +10 -8
- package/dist/chunk-3WLZOJIE.cjs.map +1 -0
- package/dist/{chunk-UZGZRGYM.cjs → chunk-3XSP7V5P.cjs} +10 -5
- package/dist/chunk-3XSP7V5P.cjs.map +1 -0
- package/dist/{chunk-GM7XIZF2.js → chunk-4IBY5LTJ.js} +2 -2
- package/dist/chunk-6H25SXDI.js +11 -0
- package/dist/chunk-6H25SXDI.js.map +1 -0
- package/dist/{chunk-N5DQFA7L.js → chunk-7GR2GCJF.js} +10 -5
- package/dist/chunk-7GR2GCJF.js.map +1 -0
- package/dist/{chunk-YNLW6EGU.cjs → chunk-AVIZ55NQ.cjs} +3 -3
- package/dist/chunk-AVIZ55NQ.cjs.map +1 -0
- package/dist/chunk-DC6CTQTK.js +9 -0
- package/dist/chunk-DC6CTQTK.js.map +1 -0
- package/dist/{chunk-L5RLJPI3.js → chunk-DUV7Y6IQ.js} +3 -3
- package/dist/{chunk-KDMAYOWH.cjs → chunk-E2644XCO.cjs} +698 -189
- package/dist/chunk-E2644XCO.cjs.map +1 -0
- package/dist/{chunk-LSOD2A6N.js → chunk-ELOPDQES.js} +2 -2
- package/dist/{chunk-M4P7YS2N.js → chunk-F2GDLA45.js} +81 -61
- package/dist/chunk-F2GDLA45.js.map +1 -0
- package/dist/{chunk-OBILAVWC.js → chunk-F5YVCJVF.js} +10 -5
- package/dist/chunk-F5YVCJVF.js.map +1 -0
- package/dist/chunk-GS7T56RP.cjs.map +1 -1
- package/dist/{chunk-4B2EXELH.js → chunk-HRJJDNRD.js} +2 -2
- package/dist/{chunk-CKUIFTXJ.js → chunk-IAXGGQGD.js} +2 -2
- package/dist/{chunk-BL7KRE6X.js → chunk-IBQCK4F3.js} +7 -3
- package/dist/chunk-IBQCK4F3.js.map +1 -0
- package/dist/chunk-J55UQC5H.cjs.map +1 -1
- package/dist/{chunk-OGAYGUJF.js → chunk-KUUSP6OS.js} +581 -72
- package/dist/chunk-KUUSP6OS.js.map +1 -0
- package/dist/{chunk-LACO375L.js → chunk-LGF2IO66.js} +4 -3
- package/dist/chunk-LGF2IO66.js.map +1 -0
- package/dist/{chunk-L64QRUMK.js → chunk-MXA6YW2W.js} +582 -73
- package/dist/chunk-MXA6YW2W.js.map +1 -0
- package/dist/{chunk-OI5ZSSIC.cjs → chunk-OIUSF2VA.cjs} +16 -12
- package/dist/chunk-OIUSF2VA.cjs.map +1 -0
- package/dist/{chunk-6OKBTY72.js → chunk-QVCHFCT2.js} +2 -2
- package/dist/{chunk-C2CVOC5K.js → chunk-RCI7LY4N.js} +8 -4
- package/dist/chunk-RCI7LY4N.js.map +1 -0
- package/dist/{chunk-W2YYBPW5.cjs → chunk-SVNBZEL6.cjs} +3 -3
- package/dist/chunk-SVNBZEL6.cjs.map +1 -0
- package/dist/{chunk-VSY5PAJ5.js → chunk-T2BJPT6D.js} +3 -3
- package/dist/{chunk-VSY5PAJ5.js.map → chunk-T2BJPT6D.js.map} +1 -1
- package/dist/chunk-TK3FDAEE.cjs +9 -0
- package/dist/chunk-TK3FDAEE.cjs.map +1 -0
- package/dist/{chunk-F5HING4Y.js → chunk-TMJVD6FW.js} +5 -4
- package/dist/chunk-TMJVD6FW.js.map +1 -0
- package/dist/{chunk-T4MXCSBP.js → chunk-V5X4LLVM.js} +71 -47
- package/dist/chunk-V5X4LLVM.js.map +1 -0
- package/dist/{chunk-IA3UKDHA.js → chunk-VTVK2JMI.js} +3 -2
- package/dist/{chunk-IA3UKDHA.js.map → chunk-VTVK2JMI.js.map} +1 -1
- package/dist/{chunk-B2E6C2LH.js → chunk-XG4SYOZL.js} +6 -4
- package/dist/chunk-XG4SYOZL.js.map +1 -0
- package/dist/{chunk-QP7IXF7R.js → chunk-YCY2R4FM.js} +2 -2
- package/dist/{chunk-NZM2SSI4.js → chunk-Z2PPDQK2.js} +2 -2
- package/dist/chunks-5QTTAT5T.js +10 -0
- package/dist/cli.js +179 -119
- package/dist/cli.js.map +1 -1
- package/dist/{formula-E3N7KDDG.js → formula-7ZOZ5QJ6.js} +8 -4
- package/dist/{formula-E3N7KDDG.js.map → formula-7ZOZ5QJ6.js.map} +1 -1
- package/dist/{formula-AQZODKZF.js → formula-HQFZEXFF.js} +7 -3
- package/dist/{formula-AQZODKZF.js.map → formula-HQFZEXFF.js.map} +1 -1
- package/dist/{formula-VY4ITOMN.cjs → formula-YYJQBKEN.cjs} +13 -9
- package/dist/formula-YYJQBKEN.cjs.map +1 -0
- package/dist/{image-ocr-IMYXOHHV.js → image-ocr-4BGX2EJJ.js} +7 -6
- package/dist/{image-ocr-IMYXOHHV.js.map → image-ocr-4BGX2EJJ.js.map} +1 -1
- package/dist/{image-ocr-6LYEBMVR.cjs → image-ocr-CC26Q5KG.cjs} +16 -15
- package/dist/image-ocr-CC26Q5KG.cjs.map +1 -0
- package/dist/{image-ocr-LN3GSQPW.js → image-ocr-RK3HJVCI.js} +10 -9
- package/dist/{image-ocr-LN3GSQPW.js.map → image-ocr-RK3HJVCI.js.map} +1 -1
- package/dist/index.cjs +860 -817
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +141 -98
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +26 -26
- package/dist/mcp.js.map +1 -1
- package/dist/{model-bundle-IHKNDLOT.js → model-bundle-VHRXG63R.js} +5 -5
- package/dist/{models-YXITRAMR.js → models-G3WA24SY.js} +5 -5
- package/dist/page-range-QHHFTL7X.cjs.map +1 -1
- package/dist/{parser-7KECZTTP.cjs → parser-BGORCLIU.cjs} +461 -243
- package/dist/parser-BGORCLIU.cjs.map +1 -0
- package/dist/{parser-M3T2EWUN.js → parser-GFDGAVLV.js} +255 -37
- package/dist/parser-GFDGAVLV.js.map +1 -0
- package/dist/{parser-KB4BYQBZ.js → parser-SOWTUOMK.js} +258 -40
- package/dist/parser-SOWTUOMK.js.map +1 -0
- package/dist/pdf-ocr-7IOOVR2I.js +20 -0
- package/dist/pdf-ocr-EJ2HNZN6.cjs +17 -0
- package/dist/pdf-ocr-EJ2HNZN6.cjs.map +1 -0
- package/dist/pdf-ocr-RACAZU3N.js +16 -0
- package/dist/{profile-io-GQWQR7YQ.js → profile-io-Q2T47RVH.js} +3 -3
- package/dist/{rasterize-Y6TVFQ3M.js → rasterize-OAVMUTE6.js} +3 -3
- package/dist/{redact-doc-TRPZ3HNW.js → redact-doc-ECFOVR4X.js} +11 -11
- package/dist/{render-GHT5HKBO.js → render-NSKWZVTD.js} +7 -7
- package/dist/seal-A4MG7MPQ.js +10 -0
- package/dist/{setup-AGSCEHDB.js → setup-REH2KZP2.js} +3 -3
- package/dist/visual-B56WQAGW.js +20 -0
- package/dist/{watch-ALSEW4GB.js → watch-JXDUZYBY.js} +13 -13
- package/dist/watch-JXDUZYBY.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-B2E6C2LH.js.map +0 -1
- package/dist/chunk-BL7KRE6X.js.map +0 -1
- package/dist/chunk-C2CVOC5K.js.map +0 -1
- package/dist/chunk-F5HING4Y.js.map +0 -1
- package/dist/chunk-KDMAYOWH.cjs.map +0 -1
- package/dist/chunk-L64QRUMK.js.map +0 -1
- package/dist/chunk-LACO375L.js.map +0 -1
- package/dist/chunk-M4P7YS2N.js.map +0 -1
- package/dist/chunk-N5DQFA7L.js.map +0 -1
- package/dist/chunk-OBILAVWC.js.map +0 -1
- package/dist/chunk-OGAYGUJF.js.map +0 -1
- package/dist/chunk-OI5ZSSIC.cjs.map +0 -1
- package/dist/chunk-QGFZU3JE.cjs.map +0 -1
- package/dist/chunk-T4MXCSBP.js.map +0 -1
- package/dist/chunk-UZGZRGYM.cjs.map +0 -1
- package/dist/chunk-W2YYBPW5.cjs.map +0 -1
- package/dist/chunk-YNLW6EGU.cjs.map +0 -1
- package/dist/chunks-IFFRC5IQ.js +0 -10
- package/dist/formula-VY4ITOMN.cjs.map +0 -1
- package/dist/image-ocr-6LYEBMVR.cjs.map +0 -1
- package/dist/parser-7KECZTTP.cjs.map +0 -1
- package/dist/parser-KB4BYQBZ.js.map +0 -1
- package/dist/parser-M3T2EWUN.js.map +0 -1
- package/dist/pdf-ocr-4S2OAHUX.js +0 -15
- package/dist/pdf-ocr-IGYCZ7G2.cjs +0 -16
- package/dist/pdf-ocr-IGYCZ7G2.cjs.map +0 -1
- package/dist/pdf-ocr-YEBFWU2K.js +0 -19
- package/dist/seal-3YTXSABW.js +0 -10
- package/dist/visual-R3E35Q2K.js +0 -20
- package/dist/watch-ALSEW4GB.js.map +0 -1
- /package/dist/{-I3CP33G4.js.map → -DDAVBMHD.js.map} +0 -0
- /package/dist/{chunk-O2DI4GHD.js.map → chunk-274ZPMHK.js.map} +0 -0
- /package/dist/{chunk-GM7XIZF2.js.map → chunk-4IBY5LTJ.js.map} +0 -0
- /package/dist/{chunk-L5RLJPI3.js.map → chunk-DUV7Y6IQ.js.map} +0 -0
- /package/dist/{chunk-LSOD2A6N.js.map → chunk-ELOPDQES.js.map} +0 -0
- /package/dist/{chunk-4B2EXELH.js.map → chunk-HRJJDNRD.js.map} +0 -0
- /package/dist/{chunk-CKUIFTXJ.js.map → chunk-IAXGGQGD.js.map} +0 -0
- /package/dist/{chunk-6OKBTY72.js.map → chunk-QVCHFCT2.js.map} +0 -0
- /package/dist/{chunk-QP7IXF7R.js.map → chunk-YCY2R4FM.js.map} +0 -0
- /package/dist/{chunk-NZM2SSI4.js.map → chunk-Z2PPDQK2.js.map} +0 -0
- /package/dist/{chunks-IFFRC5IQ.js.map → chunks-5QTTAT5T.js.map} +0 -0
- /package/dist/{model-bundle-IHKNDLOT.js.map → model-bundle-VHRXG63R.js.map} +0 -0
- /package/dist/{models-YXITRAMR.js.map → models-G3WA24SY.js.map} +0 -0
- /package/dist/{pdf-ocr-4S2OAHUX.js.map → pdf-ocr-7IOOVR2I.js.map} +0 -0
- /package/dist/{pdf-ocr-YEBFWU2K.js.map → pdf-ocr-RACAZU3N.js.map} +0 -0
- /package/dist/{profile-io-GQWQR7YQ.js.map → profile-io-Q2T47RVH.js.map} +0 -0
- /package/dist/{rasterize-Y6TVFQ3M.js.map → rasterize-OAVMUTE6.js.map} +0 -0
- /package/dist/{redact-doc-TRPZ3HNW.js.map → redact-doc-ECFOVR4X.js.map} +0 -0
- /package/dist/{render-GHT5HKBO.js.map → render-NSKWZVTD.js.map} +0 -0
- /package/dist/{seal-3YTXSABW.js.map → seal-A4MG7MPQ.js.map} +0 -0
- /package/dist/{setup-AGSCEHDB.js.map → setup-REH2KZP2.js.map} +0 -0
- /package/dist/{visual-R3E35Q2K.js.map → visual-B56WQAGW.js.map} +0 -0
|
@@ -4,15 +4,15 @@ import {
|
|
|
4
4
|
HEADING_RATIO_H2,
|
|
5
5
|
HEADING_RATIO_H3,
|
|
6
6
|
tidyScriptTags
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XG4SYOZL.js";
|
|
8
8
|
import {
|
|
9
9
|
ensureModelsIn,
|
|
10
10
|
getModelsDir
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-ELOPDQES.js";
|
|
12
12
|
import {
|
|
13
13
|
safeMax,
|
|
14
14
|
safeMin
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-7GR2GCJF.js";
|
|
16
16
|
|
|
17
17
|
// src/ocr/models.ts
|
|
18
18
|
import { join } from "path";
|
|
@@ -488,13 +488,13 @@ function classifyAndAdd(seg, lineWidth, horizontals, verticals, fromFill = false
|
|
|
488
488
|
verticals.push({ x1: x, y1, x2: x, y2, lineWidth, fromFill });
|
|
489
489
|
}
|
|
490
490
|
}
|
|
491
|
-
function preprocessLines(horizontals, verticals) {
|
|
491
|
+
function preprocessLines(horizontals, verticals, nonRules) {
|
|
492
492
|
let h = horizontals.filter((l) => l.lineWidth <= MAX_LINE_WIDTH);
|
|
493
493
|
let v = verticals.filter((l) => l.lineWidth <= MAX_LINE_WIDTH);
|
|
494
494
|
h = dropShadingStacks(h, "h");
|
|
495
495
|
v = dropShadingStacks(v, "v");
|
|
496
|
-
h = mergeParallelLines(h, "h");
|
|
497
|
-
v = mergeParallelLines(v, "v");
|
|
496
|
+
h = mergeParallelLines(h, "h", nonRules);
|
|
497
|
+
v = mergeParallelLines(v, "v", nonRules);
|
|
498
498
|
return { horizontals: h, verticals: v };
|
|
499
499
|
}
|
|
500
500
|
var STACK_GAP = 2;
|
|
@@ -654,15 +654,15 @@ function closeOpenTableEdges(horizontals, verticals) {
|
|
|
654
654
|
const hasInterior = verticals.some((v) => v.x1 > x1 + EDGE_INSET && v.x1 < x2 - EDGE_INSET && crossCount(v) >= 2);
|
|
655
655
|
if (!hasInterior) continue;
|
|
656
656
|
for (const edgeX of [x1, x2]) {
|
|
657
|
-
const
|
|
658
|
-
if (!
|
|
657
|
+
const closed2 = verticals.some((v) => Math.abs(v.x1 - edgeX) <= EDGE_NEAR && v.y1 <= yMax + EDGE_CONNECT_TOL && v.y2 >= yMin - EDGE_CONNECT_TOL);
|
|
658
|
+
if (!closed2) {
|
|
659
659
|
synthesized.push({ x1: edgeX, y1: yMin, x2: edgeX, y2: yMax, lineWidth: 0.5 });
|
|
660
660
|
}
|
|
661
661
|
}
|
|
662
662
|
}
|
|
663
663
|
return synthesized.length ? [...verticals, ...synthesized] : verticals;
|
|
664
664
|
}
|
|
665
|
-
function mergeParallelLines(lines, dir) {
|
|
665
|
+
function mergeParallelLines(lines, dir, nonRules) {
|
|
666
666
|
if (lines.length <= 1) return lines;
|
|
667
667
|
const sorted = [...lines].sort((a, b) => {
|
|
668
668
|
const posA = dir === "h" ? a.y1 : a.x1;
|
|
@@ -685,6 +685,7 @@ function mergeParallelLines(lines, dir) {
|
|
|
685
685
|
const overlap2 = Math.min(prevEnd, currEnd) - Math.max(prevStart, currStart);
|
|
686
686
|
const minLen = Math.min(prevEnd - prevStart, currEnd - currStart);
|
|
687
687
|
if (overlap2 > minLen * 0.3) {
|
|
688
|
+
if (nonRules?.has(prev) && !nonRules.has(curr)) nonRules.delete(prev);
|
|
688
689
|
if (dir === "h") {
|
|
689
690
|
prev.x1 = Math.min(prev.x1, curr.x1);
|
|
690
691
|
prev.x2 = Math.max(prev.x2, curr.x2);
|
|
@@ -4197,7 +4198,12 @@ function detectSpecialKoreanTables(blocks) {
|
|
|
4197
4198
|
flushKvTable();
|
|
4198
4199
|
return result;
|
|
4199
4200
|
}
|
|
4200
|
-
function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables = false) {
|
|
4201
|
+
function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables = false, context = []) {
|
|
4202
|
+
if (context.length && !tables) {
|
|
4203
|
+
const removed = removeHeaderFooterBlocks([...blocks, ...context], pageHeights, [], notes).filter((index) => index < blocks.length);
|
|
4204
|
+
if (removed.length) warnings.push({ message: `${removed.length}\uAC1C \uBA38\uB9AC\uAE00/\uBC14\uB2E5\uAE00 \uC694\uC18C \uC81C\uAC70\uB428`, code: "HIDDEN_TEXT_FILTERED" });
|
|
4205
|
+
return removed;
|
|
4206
|
+
}
|
|
4201
4207
|
const ZONE_RATIO = 0.12;
|
|
4202
4208
|
const MIN_REPEAT2 = 3;
|
|
4203
4209
|
const topEntries = [];
|
|
@@ -4277,6 +4283,7 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables =
|
|
|
4277
4283
|
|
|
4278
4284
|
// src/pdf/table-meta.ts
|
|
4279
4285
|
var CLIP_TABLES = /* @__PURE__ */ new WeakSet();
|
|
4286
|
+
var FRAME_TITLE_BLOCKS = /* @__PURE__ */ new WeakMap();
|
|
4280
4287
|
var TABLE_COLXS = /* @__PURE__ */ new WeakMap();
|
|
4281
4288
|
var TABLE_ROWYS = /* @__PURE__ */ new WeakMap();
|
|
4282
4289
|
var TABLE_TAIL = /* @__PURE__ */ new WeakMap();
|
|
@@ -4384,6 +4391,262 @@ function mergeSliverColumns(grid, colXs, maxWidth) {
|
|
|
4384
4391
|
return merged;
|
|
4385
4392
|
}
|
|
4386
4393
|
|
|
4394
|
+
// src/pdf/image-bullets.ts
|
|
4395
|
+
import { OPS as OPS3, ImageKind } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
4396
|
+
var multiply = (m, t) => [
|
|
4397
|
+
m[0] * t[0] + m[2] * t[1],
|
|
4398
|
+
m[1] * t[0] + m[3] * t[1],
|
|
4399
|
+
m[0] * t[2] + m[2] * t[3],
|
|
4400
|
+
m[1] * t[2] + m[3] * t[3],
|
|
4401
|
+
m[0] * t[4] + m[2] * t[5] + m[4],
|
|
4402
|
+
m[1] * t[4] + m[3] * t[5] + m[5]
|
|
4403
|
+
];
|
|
4404
|
+
function hollowCircle(image) {
|
|
4405
|
+
if (!image?.data || image.width < 16 || image.width > 128 || image.height < 16 || image.height > 128 || Math.abs(image.width - image.height) > Math.min(image.width, image.height) * 0.1) return false;
|
|
4406
|
+
const stride = image.kind === ImageKind.RGB_24BPP ? 3 : image.kind === ImageKind.RGBA_32BPP ? 4 : 0;
|
|
4407
|
+
const { width, height, data } = image;
|
|
4408
|
+
if (!stride || data.length < width * height * stride) return false;
|
|
4409
|
+
const dark = [];
|
|
4410
|
+
let white = 0;
|
|
4411
|
+
for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) {
|
|
4412
|
+
const i = (y * width + x) * stride;
|
|
4413
|
+
if (stride === 4 && data[i + 3] < 240) return false;
|
|
4414
|
+
const min = Math.min(data[i], data[i + 1], data[i + 2]), max = Math.max(data[i], data[i + 1], data[i + 2]);
|
|
4415
|
+
if (max - min > 15) return false;
|
|
4416
|
+
if (min >= 235) white++;
|
|
4417
|
+
if (max < 180) dark.push({ x, y });
|
|
4418
|
+
}
|
|
4419
|
+
if (white < width * height * 0.65 || dark.length < width * height * 0.025 || dark.length > width * height * 0.3) return false;
|
|
4420
|
+
const x0 = Math.min(...dark.map((p) => p.x)), x1 = Math.max(...dark.map((p) => p.x));
|
|
4421
|
+
const y0 = Math.min(...dark.map((p) => p.y)), y1 = Math.max(...dark.map((p) => p.y));
|
|
4422
|
+
const w = x1 - x0 + 1, h = y1 - y0 + 1, radius = (w + h) / 4;
|
|
4423
|
+
const cx = (x0 + x1) / 2, cy = (y0 + y1) / 2;
|
|
4424
|
+
if (Math.abs(w - h) > Math.min(w, h) * 0.15 || w < width * 0.4 || w > width * 0.85 || h < height * 0.4 || h > height * 0.85 || x0 < width * 0.04 || y0 < height * 0.04 || x1 >= width * 0.96 || y1 >= height * 0.96 || Math.abs(cx - width / 2) > width * 0.15 || Math.abs(cy - height / 2) > height * 0.15) return false;
|
|
4425
|
+
const sectors = /* @__PURE__ */ new Set();
|
|
4426
|
+
for (const point of dark) {
|
|
4427
|
+
const r = Math.hypot(point.x - cx, point.y - cy) / radius;
|
|
4428
|
+
if (r < 0.65 || r > 1.15) return false;
|
|
4429
|
+
sectors.add(Math.floor((Math.atan2(point.y - cy, point.x - cx) + Math.PI) / (Math.PI * 2) * 8) % 8);
|
|
4430
|
+
}
|
|
4431
|
+
return sectors.size === 8;
|
|
4432
|
+
}
|
|
4433
|
+
async function resolveImagePixels(page, id) {
|
|
4434
|
+
const objects = id.startsWith("g_") ? page.commonObjs : page.objs;
|
|
4435
|
+
return new Promise((resolve) => {
|
|
4436
|
+
const timer = setTimeout(() => resolve(null), 5e3);
|
|
4437
|
+
try {
|
|
4438
|
+
objects.get(id, (value) => {
|
|
4439
|
+
clearTimeout(timer);
|
|
4440
|
+
resolve(value ?? null);
|
|
4441
|
+
});
|
|
4442
|
+
} catch {
|
|
4443
|
+
clearTimeout(timer);
|
|
4444
|
+
resolve(null);
|
|
4445
|
+
}
|
|
4446
|
+
});
|
|
4447
|
+
}
|
|
4448
|
+
function smallVisibleImagePaints(fnArray, argsArray) {
|
|
4449
|
+
const paints = [];
|
|
4450
|
+
let ctm = [1, 0, 0, 1, 0, 0];
|
|
4451
|
+
let alpha = 1, clip = null, unknownClip = false;
|
|
4452
|
+
const stack = [];
|
|
4453
|
+
let pathRect, pendingClip = false;
|
|
4454
|
+
const intersectClip = (box) => {
|
|
4455
|
+
clip = clip ? {
|
|
4456
|
+
x1: Math.max(clip.x1, box.x1),
|
|
4457
|
+
y1: Math.max(clip.y1, box.y1),
|
|
4458
|
+
x2: Math.min(clip.x2, box.x2),
|
|
4459
|
+
y2: Math.min(clip.y2, box.y2)
|
|
4460
|
+
} : box;
|
|
4461
|
+
};
|
|
4462
|
+
const rectangle = (x, y, w, h) => extractImageRegions(
|
|
4463
|
+
[OPS3.transform, OPS3.transform, OPS3.paintImageXObject],
|
|
4464
|
+
[ctm, [w, 0, 0, h, x, y], ["bounds"]]
|
|
4465
|
+
)[0];
|
|
4466
|
+
for (let i = 0; i < fnArray.length; i++) {
|
|
4467
|
+
const op = fnArray[i], args = argsArray[i];
|
|
4468
|
+
if (op === OPS3.save || op === OPS3.paintFormXObjectBegin) {
|
|
4469
|
+
stack.push({ ctm, alpha, clip, unknownClip });
|
|
4470
|
+
const matrix = op === OPS3.paintFormXObjectBegin ? args?.[0] : void 0;
|
|
4471
|
+
if (Array.isArray(matrix) && matrix.length >= 6) ctm = multiply(ctm, matrix);
|
|
4472
|
+
const bounds = op === OPS3.paintFormXObjectBegin ? args?.[1] : void 0;
|
|
4473
|
+
if (Array.isArray(bounds) && bounds.length === 4) {
|
|
4474
|
+
const box = rectangle(bounds[0], bounds[1], bounds[2] - bounds[0], bounds[3] - bounds[1]);
|
|
4475
|
+
if (box && ctm[1] === 0 && ctm[2] === 0) intersectClip(box);
|
|
4476
|
+
else unknownClip = true;
|
|
4477
|
+
}
|
|
4478
|
+
} else if (op === OPS3.restore || op === OPS3.paintFormXObjectEnd) {
|
|
4479
|
+
const state = stack.pop();
|
|
4480
|
+
ctm = state?.ctm ?? [1, 0, 0, 1, 0, 0];
|
|
4481
|
+
alpha = state?.alpha ?? 1;
|
|
4482
|
+
clip = state?.clip ?? null;
|
|
4483
|
+
unknownClip = state?.unknownClip ?? false;
|
|
4484
|
+
} else if (op === OPS3.setGState) {
|
|
4485
|
+
for (const [key, value] of args?.[0] ?? []) {
|
|
4486
|
+
if (key === "ca") alpha = typeof value === "number" ? value : 0;
|
|
4487
|
+
}
|
|
4488
|
+
} else if (op === OPS3.constructPath) {
|
|
4489
|
+
const [operations, coordinates] = args;
|
|
4490
|
+
pathRect = pathRect === void 0 && operations?.length === 1 && operations[0] === OPS3.rectangle && coordinates?.length >= 4 && ctm[1] === 0 && ctm[2] === 0 ? rectangle(coordinates[0], coordinates[1], coordinates[2], coordinates[3]) : null;
|
|
4491
|
+
} else if (op === OPS3.clip || op === OPS3.eoClip) pendingClip = true;
|
|
4492
|
+
else if ([
|
|
4493
|
+
OPS3.endPath,
|
|
4494
|
+
OPS3.stroke,
|
|
4495
|
+
OPS3.closeStroke,
|
|
4496
|
+
OPS3.fill,
|
|
4497
|
+
OPS3.eoFill,
|
|
4498
|
+
OPS3.fillStroke,
|
|
4499
|
+
OPS3.eoFillStroke,
|
|
4500
|
+
OPS3.closeFillStroke,
|
|
4501
|
+
OPS3.closeEOFillStroke
|
|
4502
|
+
].includes(op)) {
|
|
4503
|
+
if (pendingClip) {
|
|
4504
|
+
if (pathRect) intersectClip(pathRect);
|
|
4505
|
+
else unknownClip = true;
|
|
4506
|
+
}
|
|
4507
|
+
pendingClip = false;
|
|
4508
|
+
pathRect = void 0;
|
|
4509
|
+
} else if (op === OPS3.transform && Array.isArray(args) && args.length >= 6) ctm = multiply(ctm, args);
|
|
4510
|
+
else if (op === OPS3.paintImageXObject && typeof args?.[0] === "string") {
|
|
4511
|
+
if (typeof args[1] !== "number" || typeof args[2] !== "number" || args[1] < 16 || args[1] > 128 || args[2] < 16 || args[2] > 128) continue;
|
|
4512
|
+
const box = extractImageRegions([OPS3.transform, OPS3.paintImageXObject], [ctm, args])[0];
|
|
4513
|
+
if (!box || ctm[1] !== 0 || ctm[2] !== 0 || alpha < 0.99 || unknownClip || clip && (box.x1 + (box.x2 - box.x1) * 0.03 < clip.x1 || box.y1 + (box.y2 - box.y1) * 0.03 < clip.y1 || box.x2 - (box.x2 - box.x1) * 0.03 > clip.x2 || box.y2 - (box.y2 - box.y1) * 0.03 > clip.y2)) continue;
|
|
4514
|
+
const width = box.x2 - box.x1, height = box.y2 - box.y1;
|
|
4515
|
+
if (width < 3 || width > 24 || height < 3 || height > 24 || width / height < 0.5 || width / height > 2) continue;
|
|
4516
|
+
paints.push({ id: args[0], box, mirrored: ctm[0] < 0 });
|
|
4517
|
+
}
|
|
4518
|
+
}
|
|
4519
|
+
return paints;
|
|
4520
|
+
}
|
|
4521
|
+
async function restoreImageBullets(items, page, fnArray, argsArray, shapes = /* @__PURE__ */ new Map()) {
|
|
4522
|
+
const candidates = [];
|
|
4523
|
+
for (const { id, box } of smallVisibleImagePaints(fnArray, argsArray)) {
|
|
4524
|
+
const width = box.x2 - box.x1, height = box.y2 - box.y1;
|
|
4525
|
+
if (Math.abs(width - height) > Math.min(width, height) * 0.1) continue;
|
|
4526
|
+
const line = items.filter((item) => !item.isHidden && item.fontSize > 0 && item.x >= box.x2 && item.x - box.x2 <= item.fontSize * 0.7 && Math.abs(item.y + item.h / 2 - (box.y1 + box.y2) / 2) <= item.fontSize * 0.4 && height >= item.fontSize * 0.5 && height <= item.fontSize * 1.2).sort((a, b) => a.x - b.x)[0];
|
|
4527
|
+
if (!line || /^[○●•◦□■∙]/.test(line.text.trim()) || !/\p{L}/u.test(line.text)) continue;
|
|
4528
|
+
const row = items.filter((item) => Math.abs(item.y - line.y) <= 2 && item.x >= line.x);
|
|
4529
|
+
if (row.reduce((n, item) => n + (item.text.match(/\p{L}/gu)?.length ?? 0), 0) < 12 || items.some((item) => item !== line && Math.abs(item.y - line.y) <= 2 && item.x < line.x)) continue;
|
|
4530
|
+
candidates.push({ id, x: box.x1, width, line });
|
|
4531
|
+
}
|
|
4532
|
+
let restored = 0;
|
|
4533
|
+
const used = /* @__PURE__ */ new Set();
|
|
4534
|
+
for (const candidate of candidates) {
|
|
4535
|
+
const same = candidates.filter((other) => other.id === candidate.id && other.line !== candidate.line && Math.abs(other.line.x - candidate.line.x) <= 1 && Math.abs(other.x - candidate.x) <= 1 && Math.abs(other.width - candidate.width) <= 1 && other.line.fontSize === candidate.line.fontSize && Math.abs(other.line.y - candidate.line.y) >= candidate.line.fontSize * 2);
|
|
4536
|
+
const numbered = items.filter((item) => !item.isHidden && /^[①-⑮]\s*/.test(item.text.trim()) && item.fontName === candidate.line.fontName && item.fontSize === candidate.line.fontSize && Math.abs(item.x - candidate.x) <= 1 && (item.text.match(/\p{L}/gu)?.length ?? 0) >= 12).sort((a, b) => b.y - a.y);
|
|
4537
|
+
const numberedList = numbered.some((item, index) => index > 0 && item.text.trim().charCodeAt(0) === numbered[index - 1].text.trim().charCodeAt(0) + 1);
|
|
4538
|
+
if (!same.length && !numberedList || used.has(candidate.line)) continue;
|
|
4539
|
+
if (!shapes.has(candidate.id)) shapes.set(candidate.id, hollowCircle(await resolveImagePixels(page, candidate.id)));
|
|
4540
|
+
if (!shapes.get(candidate.id)) continue;
|
|
4541
|
+
used.add(candidate.line);
|
|
4542
|
+
items.push({ ...candidate.line, text: "\u25CB", x: candidate.x, w: candidate.width, strike: false, underline: false, hasSpaceBefore: false, syntheticSpace: false });
|
|
4543
|
+
restored++;
|
|
4544
|
+
}
|
|
4545
|
+
return restored;
|
|
4546
|
+
}
|
|
4547
|
+
|
|
4548
|
+
// src/pdf/flow-boxes.ts
|
|
4549
|
+
import { ImageKind as ImageKind2 } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
4550
|
+
var contains2 = (outer, inner, tolerance = 1) => inner.x1 >= outer.x1 - tolerance && inner.x2 <= outer.x2 + tolerance && inner.y1 >= outer.y1 - tolerance && inner.y2 <= outer.y2 + tolerance;
|
|
4551
|
+
function closed(grid, hs, vs) {
|
|
4552
|
+
const b = grid.bbox;
|
|
4553
|
+
return [b.y1, b.y2].every((y) => hs.some((h) => Math.abs(h.y1 - y) <= 1 && h.x1 <= b.x1 + 1 && h.x2 >= b.x2 - 1)) && [b.x1, b.x2].every((x) => vs.some((v) => Math.abs(v.x1 - x) <= 1 && v.y1 <= b.y1 + 1 && v.y2 >= b.y2 - 1));
|
|
4554
|
+
}
|
|
4555
|
+
function groupFlowBoxUnits(blocks, grids, hs, vs, images) {
|
|
4556
|
+
const candidates = grids.filter((g) => g.bbox.y2 - g.bbox.y1 >= 30 && closed(g, hs, vs) && !grids.some((other) => other !== g && contains2(other.bbox, g.bbox, 0) && (other.bbox.x2 - other.bbox.x1) * (other.bbox.y2 - other.bbox.y1) > (g.bbox.x2 - g.bbox.x1) * (g.bbox.y2 - g.bbox.y1) + 1));
|
|
4557
|
+
const bands = [], visited = /* @__PURE__ */ new Set();
|
|
4558
|
+
for (const first of candidates) {
|
|
4559
|
+
if (visited.has(first)) continue;
|
|
4560
|
+
const row = candidates.filter((g) => Math.abs(g.bbox.y1 - first.bbox.y1) <= 1 && Math.abs(g.bbox.y2 - first.bbox.y2) <= 1).sort((a, b) => a.bbox.x1 - b.bbox.x1);
|
|
4561
|
+
row.forEach((g) => visited.add(g));
|
|
4562
|
+
if (row.length < 4 || row.filter((g) => g.rowYs.length === 2 && g.colXs.length === 2).length < 3) continue;
|
|
4563
|
+
const connectors = [];
|
|
4564
|
+
for (let i = 1; i < row.length; i++) {
|
|
4565
|
+
const left = row[i - 1].bbox, right = row[i].bbox, gap = right.x1 - left.x2;
|
|
4566
|
+
if (gap < 4 || gap > Math.min(left.x2 - left.x1, right.x2 - right.x1) * 0.6) break;
|
|
4567
|
+
const centerX = (left.x2 + right.x1) / 2, centerY = (left.y1 + left.y2) / 2;
|
|
4568
|
+
const connector = images.find((p) => {
|
|
4569
|
+
const w = p.x2 - p.x1, h = p.y2 - p.y1;
|
|
4570
|
+
return p.x1 >= left.x2 && p.x2 <= right.x1 && w >= gap * 0.4 && w <= gap * 0.9 && h >= 3 && h <= (left.y2 - left.y1) * 0.2 && w / h >= 0.8 && w / h <= 1.6 && Math.abs((p.x1 + p.x2) / 2 - centerX) <= gap * 0.15 && Math.abs((p.y1 + p.y2) / 2 - centerY) <= (left.y2 - left.y1) * 0.1;
|
|
4571
|
+
});
|
|
4572
|
+
if (!connector) break;
|
|
4573
|
+
connectors.push(connector);
|
|
4574
|
+
}
|
|
4575
|
+
if (connectors.length !== row.length - 1 || connectors.some((p) => Math.abs(p.x2 - p.x1 - (connectors[0].x2 - connectors[0].x1)) > (connectors[0].x2 - connectors[0].x1) * 0.2 || Math.abs(p.y2 - p.y1 - (connectors[0].y2 - connectors[0].y1)) > (connectors[0].y2 - connectors[0].y1) * 0.2)) continue;
|
|
4576
|
+
bands.push(row);
|
|
4577
|
+
}
|
|
4578
|
+
const members = /* @__PURE__ */ new Map();
|
|
4579
|
+
for (const band of bands) {
|
|
4580
|
+
const columns = band.map((g) => blocks.filter((b) => b.bbox && contains2(g.bbox, {
|
|
4581
|
+
x1: b.bbox.x,
|
|
4582
|
+
y1: b.bbox.y,
|
|
4583
|
+
x2: b.bbox.x + b.bbox.width,
|
|
4584
|
+
y2: b.bbox.y + b.bbox.height
|
|
4585
|
+
})).sort((a, b) => b.bbox.y + b.bbox.height - a.bbox.y - a.bbox.height || a.bbox.x - b.bbox.x));
|
|
4586
|
+
if (columns.some((column) => !column.length)) continue;
|
|
4587
|
+
const unit = columns.flat();
|
|
4588
|
+
for (const block of unit) members.set(block, unit);
|
|
4589
|
+
}
|
|
4590
|
+
const units = [], emitted = /* @__PURE__ */ new Set();
|
|
4591
|
+
for (const block of blocks) {
|
|
4592
|
+
const unit = members.get(block);
|
|
4593
|
+
if (!unit) units.push([block]);
|
|
4594
|
+
else if (!emitted.has(unit)) {
|
|
4595
|
+
units.push(unit);
|
|
4596
|
+
emitted.add(unit);
|
|
4597
|
+
}
|
|
4598
|
+
}
|
|
4599
|
+
return units;
|
|
4600
|
+
}
|
|
4601
|
+
function arrowDirection(image) {
|
|
4602
|
+
if (!image?.data || image.width < 16 || image.width > 128 || image.height < 16 || image.height > 128) return 0;
|
|
4603
|
+
const { width, height, data } = image;
|
|
4604
|
+
const stride = image.kind === ImageKind2.RGB_24BPP ? 3 : image.kind === ImageKind2.RGBA_32BPP ? 4 : 0;
|
|
4605
|
+
if (!stride || data.length < width * height * stride) return 0;
|
|
4606
|
+
const ink = [];
|
|
4607
|
+
let white = 0;
|
|
4608
|
+
for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) {
|
|
4609
|
+
const offset = (y * width + x) * stride;
|
|
4610
|
+
if (stride === 4 && data[offset + 3] < 240) return 0;
|
|
4611
|
+
const min = Math.min(data[offset], data[offset + 1], data[offset + 2]);
|
|
4612
|
+
if (min >= 235) white++;
|
|
4613
|
+
if (min < 230) ink.push({ x, y });
|
|
4614
|
+
}
|
|
4615
|
+
if (white < width * height * 0.55 || !ink.length) return 0;
|
|
4616
|
+
const x0 = Math.min(...ink.map((p) => p.x)), x1 = Math.max(...ink.map((p) => p.x));
|
|
4617
|
+
const y0 = Math.min(...ink.map((p) => p.y)), y1 = Math.max(...ink.map((p) => p.y));
|
|
4618
|
+
const w = x1 - x0 + 1, h = y1 - y0 + 1, centerY = (y0 + y1) / 2;
|
|
4619
|
+
if (w < width * 0.5 || h < height * 0.5 || x0 < width * 0.04 || y0 < height * 0.04 || x1 >= width * 0.96 || y1 >= height * 0.96) return 0;
|
|
4620
|
+
const pointsRight = (mirror) => {
|
|
4621
|
+
const points = ink.map((p) => ({ x: mirror ? x0 + x1 - p.x : p.x, y: p.y }));
|
|
4622
|
+
const tail = points.filter((p) => p.x <= x0 + w * 0.25), tip = points.filter((p) => p.x >= x1 - w * 0.1);
|
|
4623
|
+
if (!tail.length || !tip.length) return false;
|
|
4624
|
+
const span = (points2) => Math.max(...points2.map((p) => p.y)) - Math.min(...points2.map((p) => p.y)) + 1;
|
|
4625
|
+
if (span(tail) > h * 0.4 || span(tip) > h * 0.45 || Math.abs((Math.max(...tail.map((p) => p.y)) + Math.min(...tail.map((p) => p.y))) / 2 - centerY) > h * 0.1 || Math.abs((Math.max(...tip.map((p) => p.y)) + Math.min(...tip.map((p) => p.y))) / 2 - centerY) > h * 0.1) return false;
|
|
4626
|
+
let head = 0;
|
|
4627
|
+
for (let x = Math.ceil(x0 + w * 0.45); x <= x0 + w * 0.75; x++) {
|
|
4628
|
+
const column = points.filter((p) => p.x === x);
|
|
4629
|
+
if (column.length) head = Math.max(head, span(column));
|
|
4630
|
+
}
|
|
4631
|
+
const middle = new Set(points.filter((p) => Math.abs(p.y - centerY) <= 1).map((p) => p.x));
|
|
4632
|
+
return head >= h * 0.8 && middle.size >= w * 0.9;
|
|
4633
|
+
};
|
|
4634
|
+
return pointsRight(false) ? 1 : pointsRight(true) ? -1 : 0;
|
|
4635
|
+
}
|
|
4636
|
+
async function detectRightArrowRegions(page, fnArray, argsArray, directions = /* @__PURE__ */ new Map()) {
|
|
4637
|
+
const regions = [];
|
|
4638
|
+
const paints = smallVisibleImagePaints(fnArray, argsArray);
|
|
4639
|
+
for (const paint of paints) {
|
|
4640
|
+
const row = paints.filter((other) => other.id === paint.id && Math.abs(other.box.y1 - paint.box.y1) <= 1 && Math.abs(other.box.y2 - paint.box.y2) <= 1 && Math.abs(other.box.x2 - other.box.x1 - (paint.box.x2 - paint.box.x1)) <= 1);
|
|
4641
|
+
const positions = new Set(row.map((other) => Math.round(other.box.x1)));
|
|
4642
|
+
if (positions.size < 3) continue;
|
|
4643
|
+
if (!directions.has(paint.id)) directions.set(paint.id, arrowDirection(await resolveImagePixels(page, paint.id)));
|
|
4644
|
+
const direction = directions.get(paint.id) ?? 0;
|
|
4645
|
+
if (direction && (paint.mirrored ? -direction : direction) === 1) regions.push(paint.box);
|
|
4646
|
+
}
|
|
4647
|
+
return regions;
|
|
4648
|
+
}
|
|
4649
|
+
|
|
4387
4650
|
// src/pdf/side-tabs.ts
|
|
4388
4651
|
var BAND = 0.12;
|
|
4389
4652
|
var MAX_CHARS = 10;
|
|
@@ -4398,7 +4661,8 @@ function isSideTabTable(box, table, others, pageWidth, pageHeight) {
|
|
|
4398
4661
|
if (!side) return false;
|
|
4399
4662
|
const texts = table.cells.flat().map((c) => c.text.replace(/\s+/g, ""));
|
|
4400
4663
|
if (!texts.some(Boolean) || texts.some((t) => [...t].length > TAB_CELL_CHARS)) return false;
|
|
4401
|
-
|
|
4664
|
+
const overlap2 = others.filter((it) => it.y >= box.y1 && it.y <= box.y2);
|
|
4665
|
+
return overlap2.length > 0 && overlap2.every((it) => side === "R" ? it.x + it.w <= box.x1 + 1 : it.x >= box.x2 - 1);
|
|
4402
4666
|
}
|
|
4403
4667
|
function removeSideTabs(blocks, pageWidths) {
|
|
4404
4668
|
const edges = /* @__PURE__ */ new Map();
|
|
@@ -4427,7 +4691,7 @@ function removeSideTabs(blocks, pageWidths) {
|
|
|
4427
4691
|
}
|
|
4428
4692
|
if (!w || !area || !b.bbox || !text || [...text].length > MAX_CHARS) return null;
|
|
4429
4693
|
const side = b.bbox.x + b.bbox.width <= Math.min(w * BAND, area.left - 1) ? "L" : b.bbox.x >= Math.max(w * (1 - BAND), area.right + 1) ? "R" : null;
|
|
4430
|
-
return side && text.replace(/\s+/g, "")
|
|
4694
|
+
return side && `${side}\0${text.replace(/\s+/g, "")}`;
|
|
4431
4695
|
};
|
|
4432
4696
|
const pages = /* @__PURE__ */ new Map();
|
|
4433
4697
|
for (const b of blocks) {
|
|
@@ -4634,16 +4898,42 @@ function sideTabGlyphs(items) {
|
|
|
4634
4898
|
if (c) c.push(it);
|
|
4635
4899
|
else cols.push([it]);
|
|
4636
4900
|
}
|
|
4901
|
+
const cands = [];
|
|
4637
4902
|
for (const col of cols) {
|
|
4638
|
-
if (col.length <
|
|
4903
|
+
if (col.length < 2) continue;
|
|
4904
|
+
if (col.filter((g) => /[\p{L}\p{N}]/u.test(g.text)).length < col.length * 0.8) continue;
|
|
4639
4905
|
col.sort((a, b) => b.y - a.y);
|
|
4640
4906
|
const fs = [...col.map((i) => i.fontSize)].sort((a, b) => a - b)[col.length >> 1];
|
|
4641
4907
|
if (col.slice(1).some((it, k) => col[k].y - it.y > fs * 3)) continue;
|
|
4908
|
+
cands.push({ col, fs });
|
|
4909
|
+
}
|
|
4910
|
+
const bands = [];
|
|
4911
|
+
for (const c of cands.sort((a, b) => a.col[0].x - b.col[0].x)) {
|
|
4912
|
+
const last = bands[bands.length - 1];
|
|
4913
|
+
if (last) {
|
|
4914
|
+
const lastRight = Math.max(...last.col.map((i) => i.x + i.w));
|
|
4915
|
+
const gap = Math.min(...c.col.map((i) => i.x)) - lastRight;
|
|
4916
|
+
const lTop = Math.max(...last.col.map((i) => i.y)), lBot = Math.min(...last.col.map((i) => i.y));
|
|
4917
|
+
const cTop = c.col[0].y, cBot = c.col[c.col.length - 1].y;
|
|
4918
|
+
if (gap <= Math.max(last.fs, c.fs) * 1.5 && Math.min(lTop, cTop) >= Math.max(lBot, cBot)) {
|
|
4919
|
+
last.col.push(...c.col);
|
|
4920
|
+
last.fs = Math.max(last.fs, c.fs);
|
|
4921
|
+
last.anchored ||= c.col.length >= SIDE_TAB_MIN;
|
|
4922
|
+
continue;
|
|
4923
|
+
}
|
|
4924
|
+
}
|
|
4925
|
+
bands.push({ col: [...c.col], fs: c.fs, anchored: c.col.length >= SIDE_TAB_MIN });
|
|
4926
|
+
}
|
|
4927
|
+
for (const { col, fs, anchored } of bands) {
|
|
4928
|
+
if (!anchored) continue;
|
|
4929
|
+
col.sort((a, b) => b.y - a.y);
|
|
4642
4930
|
const members = new Set(col);
|
|
4643
4931
|
const top = col[0].y + fs, bottom = col[col.length - 1].y - fs;
|
|
4644
|
-
const others = items.filter((i) => !members.has(i) && i.y <= top && i.y >= bottom);
|
|
4932
|
+
const others = items.filter((i) => !members.has(i) && i.text.trim() && i.y <= top && i.y >= bottom);
|
|
4933
|
+
if (!others.length) continue;
|
|
4645
4934
|
const left = Math.min(...col.map((i) => i.x)), right = Math.max(...col.map((i) => i.x + i.w));
|
|
4646
|
-
const
|
|
4935
|
+
const rest = items.filter((i) => !members.has(i) && i.text.trim());
|
|
4936
|
+
const outside = rest.every((i) => i.x >= right + fs) || rest.every((i) => i.x + i.w <= left - fs);
|
|
4647
4937
|
if (!outside) continue;
|
|
4648
4938
|
const alone = col.filter((g) => !others.some((i) => Math.abs(i.y - g.y) <= Y_TOL)).length;
|
|
4649
4939
|
if (alone < col.length * 0.4) continue;
|
|
@@ -5901,13 +6191,44 @@ var UNDER_SPAN_OVERLAP_RATIO = 0.8;
|
|
|
5901
6191
|
var UNDER_BOX_PAIR_MIN_EM = 0.5;
|
|
5902
6192
|
var UNDER_BOX_PAIR_MAX_EM = 2.2;
|
|
5903
6193
|
var UNDER_BOX_PAIR_OVERLAP = 0.8;
|
|
5904
|
-
function markUnderlineItems(items, horizontals, verticals) {
|
|
6194
|
+
function markUnderlineItems(items, horizontals, verticals, nonRules) {
|
|
5905
6195
|
const underlines = [];
|
|
6196
|
+
if (nonRules?.size) horizontals = horizontals.filter((line) => !nonRules.has(line));
|
|
5906
6197
|
if (items.length === 0 || horizontals.length === 0) return underlines;
|
|
6198
|
+
const tightOwners = /* @__PURE__ */ new Map();
|
|
6199
|
+
const tightlyOwned = (line) => {
|
|
6200
|
+
const cached = tightOwners.get(line);
|
|
6201
|
+
if (cached !== void 0) return cached;
|
|
6202
|
+
const owners = items.filter((item) => {
|
|
6203
|
+
const below = item.y - line.y1;
|
|
6204
|
+
return item.w > 0 && item.text.trim() && below >= 0.5 && below <= 3 && Math.min(line.x2, item.x + item.w) > Math.max(line.x1, item.x);
|
|
6205
|
+
}).sort((a, b) => a.x - b.x);
|
|
6206
|
+
let owned = owners.length > 0 && (Math.abs(owners[0].x - line.x1) <= UNDER_GRID_EPS || owners.length === 1 && line.x1 > owners[0].x && line.x1 - owners[0].x <= Math.max(owners[0].h, owners[0].fontSize, 1) * 3) && Math.abs(owners[owners.length - 1].x + owners[owners.length - 1].w - line.x2) <= UNDER_GRID_EPS;
|
|
6207
|
+
for (let i = 1; owned && i < owners.length; i++) {
|
|
6208
|
+
const em = Math.max(owners[i].h, owners[i].fontSize, 1);
|
|
6209
|
+
if (owners[i].x - (owners[i - 1].x + owners[i - 1].w) > em * UNDER_COLUMN_GAP_EM) owned = false;
|
|
6210
|
+
}
|
|
6211
|
+
tightOwners.set(line, owned);
|
|
6212
|
+
return owned;
|
|
6213
|
+
};
|
|
6214
|
+
const paragraphUnderline = (line) => {
|
|
6215
|
+
if (!tightlyOwned(line)) return false;
|
|
6216
|
+
const width = line.x2 - line.x1;
|
|
6217
|
+
const ys = [];
|
|
6218
|
+
for (const other of horizontals) {
|
|
6219
|
+
const overlap2 = Math.min(line.x2, other.x2) - Math.max(line.x1, other.x1);
|
|
6220
|
+
if (other.lineWidth > UNDER_MAX_THICKNESS || overlap2 / Math.max(width, other.x2 - other.x1) < UNDER_SPAN_OVERLAP_RATIO || !tightlyOwned(other)) continue;
|
|
6221
|
+
if (!ys.some((y) => Math.abs(y - other.y1) < UNDER_GRID_EPS)) ys.push(other.y1);
|
|
6222
|
+
if (ys.length >= UNDER_REPEATED_SPAN_LEVELS) return true;
|
|
6223
|
+
}
|
|
6224
|
+
return false;
|
|
6225
|
+
};
|
|
5907
6226
|
for (const line of horizontals) {
|
|
5908
6227
|
if (line.lineWidth > UNDER_MAX_THICKNESS) continue;
|
|
5909
6228
|
const enclosed = insideTallCell(line, verticals, 0);
|
|
5910
|
-
|
|
6229
|
+
const repeated = isRepeatedSpanRule(line, horizontals);
|
|
6230
|
+
const textSeries = repeated && paragraphUnderline(line);
|
|
6231
|
+
if (!enclosed && (touchesVertical(line, verticals) || repeated && !textSeries)) continue;
|
|
5911
6232
|
const matches = [];
|
|
5912
6233
|
for (const item of items) {
|
|
5913
6234
|
const h = item.h > 0 ? item.h : item.fontSize;
|
|
@@ -5927,11 +6248,11 @@ function markUnderlineItems(items, horizontals, verticals) {
|
|
|
5927
6248
|
covered += m.w;
|
|
5928
6249
|
}
|
|
5929
6250
|
const inset = enclosed && insideTallCell(line, verticals, maxH);
|
|
5930
|
-
if (enclosed && !inset && (touchesVertical(line, verticals) ||
|
|
6251
|
+
if (enclosed && !inset && (touchesVertical(line, verticals) || repeated && !textSeries)) continue;
|
|
5931
6252
|
const pad = Math.max(maxH * UNDER_OWNER_PAD_EM, UNDER_OWNER_PAD_MIN_PT);
|
|
5932
6253
|
if (line.x1 < x1 - pad || line.x2 > x2 + pad) continue;
|
|
5933
6254
|
if (covered < (line.x2 - line.x1) * UNDER_MIN_COVERAGE) continue;
|
|
5934
|
-
if (hasBoxTopPair(line, maxH, horizontals, inset ? items : void 0)) continue;
|
|
6255
|
+
if (hasBoxTopPair(line, maxH, horizontals, inset || textSeries || tightlyOwned(line) ? items : void 0)) continue;
|
|
5935
6256
|
matches.sort((a, b) => a.x - b.x);
|
|
5936
6257
|
let hole = false;
|
|
5937
6258
|
for (let i = 1; i < matches.length; i++) {
|
|
@@ -5962,6 +6283,7 @@ function touchesVertical(line, verticals) {
|
|
|
5962
6283
|
for (const v of verticals) {
|
|
5963
6284
|
if (v.x1 < line.x1 - UNDER_GRID_EPS || v.x1 > line.x2 + UNDER_GRID_EPS) continue;
|
|
5964
6285
|
const lo = Math.min(v.y1, v.y2), hi = Math.max(v.y1, v.y2);
|
|
6286
|
+
if (hi - lo <= UNDER_GRID_EPS) continue;
|
|
5965
6287
|
if (lo <= line.y1 + UNDER_GRID_EPS && hi >= line.y1 - UNDER_GRID_EPS) return true;
|
|
5966
6288
|
}
|
|
5967
6289
|
return false;
|
|
@@ -6171,6 +6493,57 @@ function isPageFrameGrid(grid, cells, pageWidth, pageHeight, items = []) {
|
|
|
6171
6493
|
return inner.length === 0 || crossing >= 1 && crossing >= inBig.length * 0.01;
|
|
6172
6494
|
}
|
|
6173
6495
|
|
|
6496
|
+
// src/pdf/shaded-open-table.ts
|
|
6497
|
+
function closeShadedTableEdges(clipGrids, horizontals, verticals, fillRects) {
|
|
6498
|
+
const near = (a, b) => Math.abs(a - b) <= 1.5;
|
|
6499
|
+
let hs = horizontals, vs = verticals;
|
|
6500
|
+
const restored = [];
|
|
6501
|
+
for (const grid of clipGrids) {
|
|
6502
|
+
if (grid.clipParent || grid.rowYs.length !== 2 || grid.colXs.length < 3 || !grid.cells?.length || grid.cells.some((c) => c.filler || c.rowSpan !== 1 || c.colSpan !== 1)) continue;
|
|
6503
|
+
const { x1, x2, y1: mid, y2: top } = grid.bbox;
|
|
6504
|
+
if (!grid.cells.every((c) => fillRects.some((f) => near(f.x1, c.bbox.x1) && near(f.x2, c.bbox.x2) && near(f.y1, c.bbox.y1) && near(f.y2, c.bbox.y2)))) continue;
|
|
6505
|
+
const topRule = hs.find((h) => near(h.y1, top) && near(h.x1, x1) && near(h.x2, x2));
|
|
6506
|
+
if (!topRule) continue;
|
|
6507
|
+
const dividers = grid.colXs.slice(1, -1).map((x) => vs.find((v) => near(v.x1, x) && near(v.y2, top) && v.y1 <= mid - 6));
|
|
6508
|
+
if (dividers.some((v) => !v)) continue;
|
|
6509
|
+
const bottom = dividers[0].y1;
|
|
6510
|
+
if (!dividers.every((v) => near(v.y1, bottom))) continue;
|
|
6511
|
+
const bottomRule = hs.find((h) => near(h.y1, bottom) && near(h.x1, x1) && near(h.x2, x2));
|
|
6512
|
+
if (!bottomRule) continue;
|
|
6513
|
+
const missing = [x1, x2].filter((x) => !vs.some((v) => near(v.x1, x) && v.y1 <= bottom + 1.5 && v.y2 >= top - 1.5));
|
|
6514
|
+
if (!missing.length) continue;
|
|
6515
|
+
restored.push({ x1, x2, y1: bottom, y2: top });
|
|
6516
|
+
vs = vs.concat(missing.map((x) => ({ x1: x, x2: x, y1: bottom, y2: top, lineWidth: topRule.lineWidth })));
|
|
6517
|
+
if (!hs.some((h) => near(h.y1, mid) && near(h.x1, x1) && near(h.x2, x2))) {
|
|
6518
|
+
hs = hs.concat({ x1, x2, y1: mid, y2: mid, lineWidth: topRule.lineWidth });
|
|
6519
|
+
}
|
|
6520
|
+
}
|
|
6521
|
+
return { horizontals: hs, verticals: vs, restored };
|
|
6522
|
+
}
|
|
6523
|
+
function nestRestoredShadedGrids(grids, restored, horizontals, verticals) {
|
|
6524
|
+
const near = (a, b) => Math.abs(a - b) <= 1.5;
|
|
6525
|
+
if (restored.length === 0) return;
|
|
6526
|
+
const nested = /* @__PURE__ */ new Set();
|
|
6527
|
+
for (const grid of grids) {
|
|
6528
|
+
const b = grid.bbox;
|
|
6529
|
+
if (!restored.some((r) => near(r.x1, b.x1) && near(r.x2, b.x2) && near(r.y1, b.y1) && near(r.y2, b.y2))) continue;
|
|
6530
|
+
if (grids.some((g) => g !== grid && b.x1 - g.bbox.x1 >= 0.8 && g.bbox.x2 - b.x2 >= 0.8 && b.y1 - g.bbox.y1 >= 0.8 && g.bbox.y2 - b.y2 >= 0.8)) {
|
|
6531
|
+
grid.lineNested = true;
|
|
6532
|
+
nested.add(grid);
|
|
6533
|
+
}
|
|
6534
|
+
}
|
|
6535
|
+
for (const frame of grids) {
|
|
6536
|
+
const b = frame.bbox;
|
|
6537
|
+
if (frame.lineNested || ![...nested].some((g) => g.bbox.x1 > b.x1 && g.bbox.x2 < b.x2 && g.bbox.y1 > b.y1 && g.bbox.y2 < b.y2)) continue;
|
|
6538
|
+
const fullH = horizontals.filter((h) => near(h.x1, b.x1) && near(h.x2, b.x2) && h.y1 >= b.y1 - 1.5 && h.y1 <= b.y2 + 1.5);
|
|
6539
|
+
if (!fullH.some((h) => near(h.y1, b.y1)) || !fullH.some((h) => near(h.y1, b.y2)) || fullH.some((h) => h.y1 > b.y1 + 1.5 && h.y1 < b.y2 - 1.5)) continue;
|
|
6540
|
+
const fullV = verticals.filter((v) => v.y1 <= b.y1 + 1.5 && v.y2 >= b.y2 - 1.5 && v.x1 >= b.x1 - 1.5 && v.x1 <= b.x2 + 1.5);
|
|
6541
|
+
if (!fullV.some((v) => near(v.x1, b.x1)) || !fullV.some((v) => near(v.x1, b.x2)) || fullV.some((v) => v.x1 > b.x1 + 1.5 && v.x1 < b.x2 - 1.5)) continue;
|
|
6542
|
+
frame.colXs = [b.x1, b.x2];
|
|
6543
|
+
frame.rowYs = [b.y2, b.y1];
|
|
6544
|
+
}
|
|
6545
|
+
}
|
|
6546
|
+
|
|
6174
6547
|
// src/pdf/open-table-ends.ts
|
|
6175
6548
|
var ALIGN_TOL = 3;
|
|
6176
6549
|
var MIN_RULES = 3;
|
|
@@ -6506,6 +6879,140 @@ function detectTextBoxTables(boxes, items, pageNum) {
|
|
|
6506
6879
|
}];
|
|
6507
6880
|
}
|
|
6508
6881
|
|
|
6882
|
+
// src/pdf/frame-cell-blocks.ts
|
|
6883
|
+
var FRAME_READING_UNITS = /* @__PURE__ */ new WeakMap();
|
|
6884
|
+
var FRAME_SOURCE_BOUNDS = /* @__PURE__ */ new WeakMap();
|
|
6885
|
+
function recordFrameReadingUnit(blocks, bbox) {
|
|
6886
|
+
for (const block of blocks) FRAME_SOURCE_BOUNDS.set(block, bbox);
|
|
6887
|
+
if (blocks.length < 2) return;
|
|
6888
|
+
const unit = { blocks, bbox };
|
|
6889
|
+
for (const block of blocks) FRAME_READING_UNITS.set(block, unit);
|
|
6890
|
+
}
|
|
6891
|
+
function frameLayoutBoxes(blocks) {
|
|
6892
|
+
const boxes = [], seen2 = /* @__PURE__ */ new Set();
|
|
6893
|
+
for (const block of blocks) {
|
|
6894
|
+
const frame = FRAME_SOURCE_BOUNDS.get(block);
|
|
6895
|
+
if (frame) {
|
|
6896
|
+
if (!seen2.has(frame)) {
|
|
6897
|
+
boxes.push(frame);
|
|
6898
|
+
seen2.add(frame);
|
|
6899
|
+
}
|
|
6900
|
+
} else if (block.bbox) boxes.push(block.bbox);
|
|
6901
|
+
}
|
|
6902
|
+
return boxes;
|
|
6903
|
+
}
|
|
6904
|
+
function groupFrameParagraphUnits(units, frames) {
|
|
6905
|
+
const source = /* @__PURE__ */ new Map();
|
|
6906
|
+
for (const unit of units) for (const block of unit) source.set(block, unit);
|
|
6907
|
+
const members = /* @__PURE__ */ new Map(), emitted = /* @__PURE__ */ new Set();
|
|
6908
|
+
for (const frame of frames) {
|
|
6909
|
+
if (frame.length < 2 || frame.some((block) => block.type !== "paragraph" || source.get(block)?.length !== 1)) continue;
|
|
6910
|
+
for (const block of frame) members.set(block, frame);
|
|
6911
|
+
}
|
|
6912
|
+
const out = [];
|
|
6913
|
+
for (const unit of units) {
|
|
6914
|
+
const frame = unit.length === 1 ? members.get(unit[0]) : void 0;
|
|
6915
|
+
if (!frame) out.push(unit);
|
|
6916
|
+
else if (!emitted.has(frame)) {
|
|
6917
|
+
out.push(frame);
|
|
6918
|
+
emitted.add(frame);
|
|
6919
|
+
}
|
|
6920
|
+
}
|
|
6921
|
+
for (const unit of out) {
|
|
6922
|
+
if (unit.length < 2 || FRAME_READING_UNITS.get(unit[0])?.blocks === unit) continue;
|
|
6923
|
+
const bs = unit.map((b) => b.bbox).filter((b) => !!b);
|
|
6924
|
+
if (bs.length !== unit.length) continue;
|
|
6925
|
+
const x = Math.min(...bs.map((b) => b.x)), y = Math.min(...bs.map((b) => b.y));
|
|
6926
|
+
recordFrameReadingUnit(unit, {
|
|
6927
|
+
page: bs[0].page,
|
|
6928
|
+
x,
|
|
6929
|
+
y,
|
|
6930
|
+
width: Math.max(...bs.map((b) => b.x + b.width)) - x,
|
|
6931
|
+
height: Math.max(...bs.map((b) => b.y + b.height)) - y
|
|
6932
|
+
});
|
|
6933
|
+
}
|
|
6934
|
+
return out;
|
|
6935
|
+
}
|
|
6936
|
+
function recordFrameTitle(table, source, pageNum) {
|
|
6937
|
+
if (!CLIP_TABLES.has(table) || table.rows !== 1 || table.cols !== 3 || source.length < 2) return;
|
|
6938
|
+
const cells = table.cells[0];
|
|
6939
|
+
if (cells.length !== 3 || cells.some((c) => c.colSpan !== 1 || c.rowSpan !== 1 || c.blocks?.length || c.text.includes("\n"))) return;
|
|
6940
|
+
const [label, spacer, title] = cells;
|
|
6941
|
+
if (!/^(?:붙임|별첨|첨부|부록)\s*\d{1,3}$/.test(label.text.trim()) || spacer.text.trim() || !title.text.trim()) return;
|
|
6942
|
+
if (cells.some((c) => {
|
|
6943
|
+
const e = CELL_EDGES.get(c);
|
|
6944
|
+
return !e || e.t || e.b || e.l || e.r;
|
|
6945
|
+
})) return;
|
|
6946
|
+
const xs = TABLE_COLXS.get(table), style = dominantStyle(source), fs = style?.fontSize ?? 0;
|
|
6947
|
+
if (!xs || xs.length !== 4 || fs <= 0) return;
|
|
6948
|
+
const width = xs[3] - xs[0], gap = xs[2] - xs[1];
|
|
6949
|
+
if (width < fs * 12 || gap <= 0 || gap > fs * 1.5 || xs[1] - xs[0] > width * 0.25 || xs[3] - xs[2] < width * 0.6) return;
|
|
6950
|
+
if (source.some((i) => i.fontName !== source[0].fontName || Math.abs(i.fontSize - fs) > fs * 0.15)) return;
|
|
6951
|
+
if (groupByY([...source].sort((a, b) => b.y - a.y)).length !== 1) return;
|
|
6952
|
+
FRAME_TITLE_BLOCKS.set(table, {
|
|
6953
|
+
type: "paragraph",
|
|
6954
|
+
text: `${label.text.trim()} ${title.text.trim()}`,
|
|
6955
|
+
pageNumber: pageNum,
|
|
6956
|
+
bbox: computeBBox(source, pageNum),
|
|
6957
|
+
style
|
|
6958
|
+
});
|
|
6959
|
+
}
|
|
6960
|
+
var FRAME_RECT_TOL = 1.5;
|
|
6961
|
+
function takePendingNested(pending, cellBox, clipCell) {
|
|
6962
|
+
const out = [];
|
|
6963
|
+
for (let i = pending.length - 1; i >= 0; i--) {
|
|
6964
|
+
const p = pending[i].parent;
|
|
6965
|
+
if (pending[i].contained ? p.x1 >= cellBox.x1 - FRAME_RECT_TOL && p.x2 <= cellBox.x2 + FRAME_RECT_TOL && p.y1 >= cellBox.y1 - FRAME_RECT_TOL && p.y2 <= cellBox.y2 + FRAME_RECT_TOL : clipCell && Math.abs(p.x1 - cellBox.x1) <= FRAME_RECT_TOL && Math.abs(p.x2 - cellBox.x2) <= FRAME_RECT_TOL && Math.abs(p.y1 - cellBox.y1) <= FRAME_RECT_TOL && Math.abs(p.y2 - cellBox.y2) <= FRAME_RECT_TOL) {
|
|
6966
|
+
out.push(pending[i].block);
|
|
6967
|
+
pending.splice(i, 1);
|
|
6968
|
+
}
|
|
6969
|
+
}
|
|
6970
|
+
return out;
|
|
6971
|
+
}
|
|
6972
|
+
function buildFrameCellBlocks(cellItems, nested, pageNum, lex) {
|
|
6973
|
+
const tables = [...nested].sort((a, b) => b.bbox.y + b.bbox.height - (a.bbox.y + a.bbox.height));
|
|
6974
|
+
const blocks = [];
|
|
6975
|
+
let rest = [...cellItems];
|
|
6976
|
+
const pushParagraphs = (items) => {
|
|
6977
|
+
if (items.length === 0) return;
|
|
6978
|
+
const source = items.map((it) => ({ ...it, isHidden: false })).sort((a, b) => b.y - a.y || a.x - b.x);
|
|
6979
|
+
const paragraphs = [];
|
|
6980
|
+
pushLineParagraphs(paragraphs, mergeSuperscriptLines(groupByY(source)), pageNum, lex);
|
|
6981
|
+
for (const block of paragraphs) {
|
|
6982
|
+
block.text = cleanCellText(block.text ?? "");
|
|
6983
|
+
if (block.text) blocks.push(block);
|
|
6984
|
+
}
|
|
6985
|
+
};
|
|
6986
|
+
for (const tb of tables) {
|
|
6987
|
+
const bottom = tb.bbox.y;
|
|
6988
|
+
pushParagraphs(rest.filter((it) => it.y >= bottom));
|
|
6989
|
+
rest = rest.filter((it) => it.y < bottom);
|
|
6990
|
+
blocks.push(tb);
|
|
6991
|
+
}
|
|
6992
|
+
pushParagraphs(rest);
|
|
6993
|
+
const text = blocks.map((b) => b.type === "table" && b.table ? b.table.cells.flat().map((c) => c.text).filter(Boolean).join("\n") : b.text ?? "").filter(Boolean).join("\n");
|
|
6994
|
+
return { blocks, text };
|
|
6995
|
+
}
|
|
6996
|
+
|
|
6997
|
+
// src/pdf/nested-shaded-headers.ts
|
|
6998
|
+
function extendNestedShadedHeaders(clipGrids, lineGrids, horizontals, verticals, fills) {
|
|
6999
|
+
const near = (a, b) => Math.abs(a - b) <= 1.5;
|
|
7000
|
+
const contains3 = (a, b) => b.x1 >= a.x1 - 1.5 && b.x2 <= a.x2 + 1.5 && b.y1 >= a.y1 - 1.5 && b.y2 <= a.y2 + 1.5;
|
|
7001
|
+
const extended = [];
|
|
7002
|
+
for (let i = 0; i < clipGrids.length; i++) {
|
|
7003
|
+
const c = clipGrids[i], parent = c.clipParent;
|
|
7004
|
+
if (!parent || c.rowYs.length !== 2 || c.colXs.length < 3 || !c.cells?.length || c.cells.some((cell) => cell.filler || cell.rowSpan !== 1 || cell.colSpan !== 1)) continue;
|
|
7005
|
+
if (!clipGrids.some((g) => g.rowYs.length === 2 && g.colXs.length === 2 && near(g.bbox.x1, parent.x1) && near(g.bbox.x2, parent.x2) && near(g.bbox.y1, parent.y1) && near(g.bbox.y2, parent.y2))) continue;
|
|
7006
|
+
if (!c.cells.every((cell) => fills.some((f) => near(f.x1, cell.bbox.x1) && near(f.x2, cell.bbox.x2) && near(f.y1, cell.bbox.y1) && near(f.y2, cell.bbox.y2)))) continue;
|
|
7007
|
+
const host = lineGrids.find((l) => l.rowYs.length > 2 && l.colXs.length === c.colXs.length && c.colXs.every((x, k) => near(x, l.colXs[k])) && c.rowYs.every((y, k) => near(y, l.rowYs[k])) && contains3(parent, l.bbox) && l.rowYs.every((y) => horizontals.some((h) => near(h.y1, y) && near(h.x1, l.bbox.x1) && near(h.x2, l.bbox.x2))) && l.colXs.every((x) => verticals.some((v) => near(v.x1, x) && v.y1 <= l.bbox.y1 + 1.5 && v.y2 >= l.bbox.y2 - 1.5)) && !clipGrids.some((o) => o !== c && !contains3(o.bbox, l.bbox) && Math.min(o.bbox.x2, l.bbox.x2) > Math.max(o.bbox.x1, l.bbox.x1) && Math.min(o.bbox.y2, l.bbox.y2) > Math.max(o.bbox.y1, l.bbox.y1)));
|
|
7008
|
+
if (!host) continue;
|
|
7009
|
+
const grid = { ...host, clipParent: parent, cells: extractCells(host, horizontals, verticals) };
|
|
7010
|
+
clipGrids[i] = grid;
|
|
7011
|
+
extended.push(grid);
|
|
7012
|
+
}
|
|
7013
|
+
return extended;
|
|
7014
|
+
}
|
|
7015
|
+
|
|
6509
7016
|
// src/pdf/page-regions.ts
|
|
6510
7017
|
function splitTwoColumnProse(items, cutX) {
|
|
6511
7018
|
const left = [];
|
|
@@ -6833,7 +7340,7 @@ function figureColumnBands(items, figures) {
|
|
|
6833
7340
|
}
|
|
6834
7341
|
|
|
6835
7342
|
// src/pdf/page-blocks.ts
|
|
6836
|
-
function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeight, extraLines, detectTables = true, carry, lexicon) {
|
|
7343
|
+
function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeight, extraLines, detectTables = true, carry, lexicon, verifiedRightArrows = []) {
|
|
6837
7344
|
if (items.length === 0) {
|
|
6838
7345
|
if (carry) carry.clip = void 0;
|
|
6839
7346
|
return [];
|
|
@@ -6841,7 +7348,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
6841
7348
|
const tab = sideTabGlyphs(items);
|
|
6842
7349
|
if (tab.size) {
|
|
6843
7350
|
const glyphs = [...tab].sort((a, b) => b.y - a.y).map((g) => ({ type: "paragraph", text: g.text.trim(), pageNumber: pageNum, bbox: computeBBox([g], pageNum), style: dominantStyle([g]) }));
|
|
6844
|
-
return [...glyphs, ...extractPageBlocksWithLines(items.filter((i) => !tab.has(i)), pageNum, opList, pageWidth, pageHeight, extraLines, detectTables, carry, lexicon)];
|
|
7351
|
+
return [...glyphs, ...extractPageBlocksWithLines(items.filter((i) => !tab.has(i)), pageNum, opList, pageWidth, pageHeight, extraLines, detectTables, carry, lexicon, verifiedRightArrows)];
|
|
6845
7352
|
}
|
|
6846
7353
|
const lex = lexicon ?? new WrapLexicon();
|
|
6847
7354
|
for (const line of streamLines(items)) lex.addLine(mergeLineSimple(line));
|
|
@@ -6869,19 +7376,28 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
6869
7376
|
}
|
|
6870
7377
|
;
|
|
6871
7378
|
({ horizontals, verticals } = filterPageBorderLines(horizontals, verticals, pageWidth, pageHeight));
|
|
6872
|
-
({ horizontals, verticals } = preprocessLines(horizontals, verticals));
|
|
7379
|
+
({ horizontals, verticals } = preprocessLines(horizontals, verticals, extracted.nonRules));
|
|
7380
|
+
markStrikethroughItems(items, horizontals);
|
|
7381
|
+
wrapStrikethroughRuns(items);
|
|
7382
|
+
const underlines = new Set(markUnderlineItems(items, horizontals, verticals, extracted.nonRules));
|
|
7383
|
+
if (underlines.size) horizontals = horizontals.filter((l) => !underlines.has(l));
|
|
7384
|
+
wrapUnderlineRuns(items);
|
|
6873
7385
|
horizontals = closeOpenTableEnds(horizontals, verticals, items.every((it) => it.seq !== void 0));
|
|
6874
7386
|
verticals = closeOpenTableEdges(horizontals, verticals);
|
|
6875
7387
|
verticals = bridgeSplitColumnVerticals(horizontals, verticals);
|
|
6876
7388
|
if (detectTables && clipGrids.length === 0) verticals = bridgeSkippedRowVerticals(horizontals, verticals, items);
|
|
6877
7389
|
if (detectTables && clipGrids.length === 0) ({ horizontals, verticals } = extendHeaderBoxRows(horizontals, verticals, items));
|
|
6878
|
-
|
|
6879
|
-
|
|
6880
|
-
const underlines = new Set(markUnderlineItems(items, horizontals, verticals));
|
|
6881
|
-
if (underlines.size) horizontals = horizontals.filter((l) => !underlines.has(l));
|
|
6882
|
-
wrapUnderlineRuns(items);
|
|
7390
|
+
const shadedEdges = detectTables ? closeShadedTableEdges(clipGrids, horizontals, verticals, extracted.fillRects) : void 0;
|
|
7391
|
+
if (shadedEdges) ({ horizontals, verticals } = shadedEdges);
|
|
6883
7392
|
const lineGrids = detectTables ? buildTableGrids(horizontals, verticals) : [];
|
|
7393
|
+
if (shadedEdges) nestRestoredShadedGrids(lineGrids, shadedEdges.restored, horizontals, verticals);
|
|
6884
7394
|
const tableClipGrids = dropHeadBandClipGrids(dropInsetClipGrids(dropShadingClipGrids(clipGrids, lineGrids, extracted.fillRects, verticals), lineGrids), lineGrids);
|
|
7395
|
+
recordClipCellEdges(
|
|
7396
|
+
extendNestedShadedHeaders(tableClipGrids, lineGrids, horizontals, verticals, extracted.fillRects),
|
|
7397
|
+
extracted.horizontals.concat(extracted.shortH),
|
|
7398
|
+
extracted.verticals.concat(extracted.shortV),
|
|
7399
|
+
extracted.nonRules
|
|
7400
|
+
);
|
|
6885
7401
|
const grids = [...tableClipGrids, ...dropGridsInside(lineGrids, tableClipGrids, clipResult.containers)];
|
|
6886
7402
|
const figures = () => extractImageRegions(opList.fnArray, opList.argsArray, true).filter((r) => r.x2 - r.x1 >= 40 && r.y2 - r.y1 >= 40).map((r) => ({ x: r.x1, y: r.y1, w: r.x2 - r.x1, h: r.y2 - r.y1 }));
|
|
6887
7403
|
if (grids.length === 1 && grids[0].rowYs.length === 2 && grids[0].colXs.length === 2 && grids[0].bbox.x2 - grids[0].bbox.x1 > pageWidth * 1.2 && grids[0].bbox.y2 - grids[0].bbox.y1 > pageHeight * 1.2) {
|
|
@@ -6891,7 +7407,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
6891
7407
|
if (detectTables && clipGrids.length === 0 && ruled.length === 0 && lineGrids.length === 0) ruled.push(...detectTextBoxTables(extracted.hiddenBoxes, items, pageNum));
|
|
6892
7408
|
if (ruled.length > 0) {
|
|
6893
7409
|
const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray).filter((r) => r.x2 - r.x1 >= 8 && r.y2 - r.y1 >= 8);
|
|
6894
|
-
return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, ruled, rawRules);
|
|
7410
|
+
return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, ruled, rawRules, verifiedRightArrows);
|
|
6895
7411
|
}
|
|
6896
7412
|
if (detectTables && stackedTableBands(items)) {
|
|
6897
7413
|
return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures());
|
|
@@ -6902,7 +7418,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
6902
7418
|
}
|
|
6903
7419
|
if (grids.length > 0) {
|
|
6904
7420
|
const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray).filter((r) => r.x2 - r.x1 >= 8 && r.y2 - r.y1 >= 8);
|
|
6905
|
-
return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, [], rawRules);
|
|
7421
|
+
return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, [], rawRules, verifiedRightArrows);
|
|
6906
7422
|
}
|
|
6907
7423
|
return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures());
|
|
6908
7424
|
}
|
|
@@ -7007,42 +7523,10 @@ function isSparseProseGrid(table) {
|
|
|
7007
7523
|
const prose = filled.filter((t) => t.length >= 60 && /[.!?。]/.test(t)).reduce((n, t) => n + t.length, 0);
|
|
7008
7524
|
return prose >= chars * 0.6;
|
|
7009
7525
|
}
|
|
7010
|
-
|
|
7011
|
-
function takePendingNested(pending, cellBox, clipCell) {
|
|
7012
|
-
const out = [];
|
|
7013
|
-
for (let i = pending.length - 1; i >= 0; i--) {
|
|
7014
|
-
const p = pending[i].parent;
|
|
7015
|
-
if (pending[i].contained ? p.x1 >= cellBox.x1 - FRAME_RECT_TOL && p.x2 <= cellBox.x2 + FRAME_RECT_TOL && p.y1 >= cellBox.y1 - FRAME_RECT_TOL && p.y2 <= cellBox.y2 + FRAME_RECT_TOL : clipCell && Math.abs(p.x1 - cellBox.x1) <= FRAME_RECT_TOL && Math.abs(p.x2 - cellBox.x2) <= FRAME_RECT_TOL && Math.abs(p.y1 - cellBox.y1) <= FRAME_RECT_TOL && Math.abs(p.y2 - cellBox.y2) <= FRAME_RECT_TOL) {
|
|
7016
|
-
out.push(pending[i].block);
|
|
7017
|
-
pending.splice(i, 1);
|
|
7018
|
-
}
|
|
7019
|
-
}
|
|
7020
|
-
return out;
|
|
7021
|
-
}
|
|
7022
|
-
function buildFrameCellBlocks(cellItems, nested, pageNum, wrap) {
|
|
7023
|
-
const tables = [...nested].sort((a, b) => b.bbox.y + b.bbox.height - (a.bbox.y + a.bbox.height));
|
|
7024
|
-
const blocks = [];
|
|
7025
|
-
let rest = [...cellItems];
|
|
7026
|
-
const pushParagraphs = (items) => {
|
|
7027
|
-
if (items.length === 0) return;
|
|
7028
|
-
for (const line of cleanCellText(cellTextToString(items, wrap)).split("\n")) {
|
|
7029
|
-
const t = line.trim();
|
|
7030
|
-
if (t) blocks.push({ type: "paragraph", text: t, pageNumber: pageNum });
|
|
7031
|
-
}
|
|
7032
|
-
};
|
|
7033
|
-
for (const tb of tables) {
|
|
7034
|
-
const bottom = tb.bbox.y;
|
|
7035
|
-
pushParagraphs(rest.filter((it) => it.y >= bottom));
|
|
7036
|
-
rest = rest.filter((it) => it.y < bottom);
|
|
7037
|
-
blocks.push(tb);
|
|
7038
|
-
}
|
|
7039
|
-
pushParagraphs(rest);
|
|
7040
|
-
const text = blocks.map((b) => b.type === "table" && b.table ? b.table.cells.flat().map((c) => c.text).filter(Boolean).join("\n") : b.text ?? "").filter(Boolean).join("\n");
|
|
7041
|
-
return { blocks, text };
|
|
7042
|
-
}
|
|
7043
|
-
function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions = [], lex, ruled = [], rawRules = horizontals) {
|
|
7526
|
+
function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions = [], lex, ruled = [], rawRules = horizontals, verifiedRightArrows = []) {
|
|
7044
7527
|
const ocrPage = items.length > 0 && items.every((i) => i.fontName === "ocr");
|
|
7045
7528
|
const blocks = [];
|
|
7529
|
+
const frameParagraphUnits = [];
|
|
7046
7530
|
const usedItems = /* @__PURE__ */ new Set();
|
|
7047
7531
|
for (const r of ruled) {
|
|
7048
7532
|
for (const it of r.items) usedItems.add(it);
|
|
@@ -7099,7 +7583,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7099
7583
|
const nested = pendingNested.length ? takePendingNested(pendingNested, cell.bbox, !!grid.cells) : [];
|
|
7100
7584
|
if (nested.length > 0) {
|
|
7101
7585
|
nestedAttached = true;
|
|
7102
|
-
const built = buildFrameCellBlocks(cellItems, nested, pageNum,
|
|
7586
|
+
const built = buildFrameCellBlocks(cellItems, nested, pageNum, lex);
|
|
7103
7587
|
irGrid[cell.row][cell.col] = { text: built.text, colSpan: cell.colSpan, rowSpan: cell.rowSpan, blocks: built.blocks };
|
|
7104
7588
|
if (cellItems.length) recordCellLines(irGrid[cell.row][cell.col], cellItems);
|
|
7105
7589
|
takeClipCellEdges(cell, irGrid[cell.row][cell.col]);
|
|
@@ -7110,6 +7594,9 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7110
7594
|
colSpan: cell.colSpan,
|
|
7111
7595
|
rowSpan: cell.rowSpan
|
|
7112
7596
|
};
|
|
7597
|
+
if (numRows === 1 && numCols === 1 && cellItems.length) {
|
|
7598
|
+
irGrid[cell.row][cell.col].blocks = buildFrameCellBlocks(cellItems, [], pageNum, lex).blocks;
|
|
7599
|
+
}
|
|
7113
7600
|
const b = cell.bbox;
|
|
7114
7601
|
const isBackdrop = (r) => r.x1 <= b.x1 + 1 && r.x2 >= b.x2 - 1 && r.y1 <= b.y1 + 1 && r.y2 >= b.y2 - 1;
|
|
7115
7602
|
if (imageRegions.some((r) => {
|
|
@@ -7145,7 +7632,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7145
7632
|
}
|
|
7146
7633
|
if (!rebuiltUsed && attachUnitRow(items, grid, finalGrid, numCols, usedItems)) finalRows++;
|
|
7147
7634
|
let semanticOneColumn = false;
|
|
7148
|
-
if (!grid.cells && numCols === 1 && numGridRows >= 2) {
|
|
7635
|
+
if (!grid.cells && !nestedAttached && numCols === 1 && numGridRows >= 2) {
|
|
7149
7636
|
const populatedRows = finalGrid.filter((row) => row[0]?.text.trim());
|
|
7150
7637
|
if (populatedRows.length >= 4) {
|
|
7151
7638
|
const fontSizes = tableItems.map((item) => item.fontSize).filter((size) => size > 0).sort((a, b) => a - b);
|
|
@@ -7198,13 +7685,15 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7198
7685
|
recordRowRules(irTable, grid.cells, grid.bbox, rawRules);
|
|
7199
7686
|
}
|
|
7200
7687
|
TABLE_COLXS.set(irTable, grid.colXs);
|
|
7688
|
+
if (grid.cells) recordFrameTitle(irTable, tableItems, pageNum);
|
|
7201
7689
|
if (grid.cells && finalRows === numRows) TABLE_ROWYS.set(irTable, grid.rowYs);
|
|
7202
7690
|
if (grid.continues) CONT_PARTS.set(irTable, grid.continues);
|
|
7203
7691
|
const hasContent = finalGrid.some((row) => row.some((cell) => cell.text.trim() !== ""));
|
|
7204
7692
|
const emptyPart = !hasContent && !!grid.cells && !grid.clipParent && !nestedAttached;
|
|
7205
7693
|
if (!hasContent && !emptyPart) continue;
|
|
7206
7694
|
if (emptyPart) EMPTY_PARTS.add(irTable);
|
|
7207
|
-
|
|
7695
|
+
const ownItems = numCols === 1 ? new Set(tableItems) : null;
|
|
7696
|
+
if (ownItems && isSideTabTable(grid.bbox, irTable, items.filter((it) => !ownItems.has(it)), pageWidth, pageHeight)) {
|
|
7208
7697
|
SIDE_TAB_TABLES.add(irTable);
|
|
7209
7698
|
blocks.push({ type: "table", table: irTable, pageNumber: pageNum, bbox: { page: pageNum, x: grid.bbox.x1, y: grid.bbox.y1, width: gridW, height: grid.bbox.y2 - grid.bbox.y1 } });
|
|
7210
7699
|
continue;
|
|
@@ -7248,7 +7737,14 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7248
7737
|
continue;
|
|
7249
7738
|
}
|
|
7250
7739
|
}
|
|
7251
|
-
if (!grid.cells && shouldDemoteTable(irTable)) {
|
|
7740
|
+
if (!grid.cells && !nestedAttached && shouldDemoteTable(irTable)) {
|
|
7741
|
+
const paragraphs = numRows === 1 && numCols === 1 ? irTable.cells[0]?.[0]?.blocks : void 0;
|
|
7742
|
+
if (paragraphs?.length) {
|
|
7743
|
+
blocks.push(...paragraphs);
|
|
7744
|
+
frameParagraphUnits.push(paragraphs);
|
|
7745
|
+
recordFrameReadingUnit(paragraphs, tableBbox);
|
|
7746
|
+
continue;
|
|
7747
|
+
}
|
|
7252
7748
|
const demoted = demoteTableToText(irTable);
|
|
7253
7749
|
if (demoted) {
|
|
7254
7750
|
const text = numGridRows === 1 ? "\n" + demoted + "\n" : demoted;
|
|
@@ -7302,9 +7798,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7302
7798
|
}
|
|
7303
7799
|
{
|
|
7304
7800
|
const rects = remaining.map((i) => ({ x: i.x, y: i.y, w: i.w, h: i.h > 0 ? i.h : i.fontSize }));
|
|
7305
|
-
for (const b of blocks) {
|
|
7306
|
-
if (b.bbox && !(b.table && EMPTY_PARTS.has(b.table))) rects.push({ x: b.bbox.x, y: b.bbox.y, w: b.bbox.width, h: b.bbox.height });
|
|
7307
|
-
}
|
|
7801
|
+
for (const b of frameLayoutBoxes(blocks.filter((b2) => !(b2.table && EMPTY_PARTS.has(b2.table))))) rects.push({ x: b.x, y: b.y, w: b.width, h: b.height });
|
|
7308
7802
|
gutterX = detectColumnGutter(rects) ?? findRuledColumnDivider(
|
|
7309
7803
|
blocks.filter((b) => b.type === "table" && b.bbox && b.table && !EMPTY_PARTS.has(b.table)).map((b) => ({ x: b.bbox.x, y: b.bbox.y, w: b.bbox.width, h: b.bbox.height })),
|
|
7310
7804
|
horizontals,
|
|
@@ -7351,7 +7845,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7351
7845
|
finalTextBlocks = detectListBlocks(textBlocks);
|
|
7352
7846
|
}
|
|
7353
7847
|
}
|
|
7354
|
-
const units =
|
|
7848
|
+
const units = groupFrameParagraphUnits(groupFlowBoxUnits(blocks, grids, horizontals, verticals, verifiedRightArrows), frameParagraphUnits);
|
|
7355
7849
|
let off = 0;
|
|
7356
7850
|
for (const size of groupSizes) {
|
|
7357
7851
|
const unit = finalTextBlocks.slice(off, off + size);
|
|
@@ -7490,7 +7984,7 @@ function mergeAdjacentTableBlocks(blocks) {
|
|
|
7490
7984
|
table: merged,
|
|
7491
7985
|
bbox: { ...pb, y: cb.y, height: pb.y + pb.height - cb.y }
|
|
7492
7986
|
};
|
|
7493
|
-
} else if (prev.type === "table" && curr.type === "table" && prev.table && curr.table && prev.table.cols === curr.table.cols && prev.table.renderAsTable === curr.table.renderAsTable && !CLIP_TABLES.has(prev.table) && !CLIP_TABLES.has(curr.table)) {
|
|
7987
|
+
} else if (prev.type === "table" && curr.type === "table" && prev.table && curr.table && prev.table.cols === curr.table.cols && prev.table.renderAsTable === curr.table.renderAsTable && !CLIP_TABLES.has(prev.table) && !CLIP_TABLES.has(curr.table) && !separateRepeatedHeadings(prev, curr)) {
|
|
7494
7988
|
const merged = {
|
|
7495
7989
|
rows: prev.table.rows + curr.table.rows,
|
|
7496
7990
|
cols: prev.table.cols,
|
|
@@ -7505,6 +7999,12 @@ function mergeAdjacentTableBlocks(blocks) {
|
|
|
7505
7999
|
}
|
|
7506
8000
|
return result;
|
|
7507
8001
|
}
|
|
8002
|
+
function separateRepeatedHeadings(upper, lower) {
|
|
8003
|
+
const u = upper.table, d = lower.table, ub = upper.bbox, db = lower.bbox;
|
|
8004
|
+
if (!ub || !db || ub.page !== db.page || u.rows < 2 || d.rows < 2 || !u.hasHeader || !d.hasHeader || ub.y - (db.y + db.height) <= 1 || Math.abs(ub.x - db.x) > 1 || Math.abs(ub.width - db.width) > 1) return false;
|
|
8005
|
+
const a = u.cells[0], b = d.cells[0], norm = (text) => text.replace(/<\/?u>|~~|\s+/g, "");
|
|
8006
|
+
return a.filter((cell) => norm(cell.text)).length >= 2 && a.length === b.length && a.every((cell, c) => cell.colSpan === b[c].colSpan && cell.rowSpan === b[c].rowSpan && norm(cell.text) === norm(b[c].text));
|
|
8007
|
+
}
|
|
7508
8008
|
function streamLines(items) {
|
|
7509
8009
|
if (items.some((i) => i.seq === void 0)) return groupByY([...items].sort((a, b) => b.y - a.y || a.x - b.x));
|
|
7510
8010
|
const lines = [];
|
|
@@ -7689,7 +8189,11 @@ export {
|
|
|
7689
8189
|
extractImageRegions,
|
|
7690
8190
|
filterHiddenText,
|
|
7691
8191
|
collapseEvenSpacing,
|
|
8192
|
+
computeBBox,
|
|
8193
|
+
dominantStyle,
|
|
7692
8194
|
normalizeItems,
|
|
8195
|
+
groupByY,
|
|
8196
|
+
mergeLineSimple,
|
|
7693
8197
|
WrapLexicon,
|
|
7694
8198
|
startsNewItem,
|
|
7695
8199
|
wrapJoiner,
|
|
@@ -7710,6 +8214,7 @@ export {
|
|
|
7710
8214
|
detectKoreanListBlocks,
|
|
7711
8215
|
removeHeaderFooterBlocks,
|
|
7712
8216
|
CLIP_TABLES,
|
|
8217
|
+
FRAME_TITLE_BLOCKS,
|
|
7713
8218
|
TABLE_COLXS,
|
|
7714
8219
|
TABLE_ROWYS,
|
|
7715
8220
|
TABLE_TAIL,
|
|
@@ -7723,7 +8228,11 @@ export {
|
|
|
7723
8228
|
trimTrailingEmptyTableCols,
|
|
7724
8229
|
NO_EDGES,
|
|
7725
8230
|
joinCellEdges,
|
|
8231
|
+
FRAME_READING_UNITS,
|
|
8232
|
+
recordFrameReadingUnit,
|
|
8233
|
+
restoreImageBullets,
|
|
8234
|
+
detectRightArrowRegions,
|
|
7726
8235
|
removeSideTabs,
|
|
7727
8236
|
extractPageBlocksWithLines
|
|
7728
8237
|
};
|
|
7729
|
-
//# sourceMappingURL=chunk-
|
|
8238
|
+
//# sourceMappingURL=chunk-MXA6YW2W.js.map
|