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
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
HEADING_RATIO_H2,
|
|
6
6
|
HEADING_RATIO_H3,
|
|
7
7
|
tidyScriptTags
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-TMJVD6FW.js";
|
|
9
9
|
import {
|
|
10
10
|
safeMax,
|
|
11
11
|
safeMin
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-F5YVCJVF.js";
|
|
13
13
|
|
|
14
14
|
// src/pdf/line-extract.ts
|
|
15
15
|
import { OPS } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
@@ -415,13 +415,13 @@ function classifyAndAdd(seg, lineWidth, horizontals, verticals, fromFill = false
|
|
|
415
415
|
verticals.push({ x1: x, y1, x2: x, y2, lineWidth, fromFill });
|
|
416
416
|
}
|
|
417
417
|
}
|
|
418
|
-
function preprocessLines(horizontals, verticals) {
|
|
418
|
+
function preprocessLines(horizontals, verticals, nonRules) {
|
|
419
419
|
let h = horizontals.filter((l) => l.lineWidth <= MAX_LINE_WIDTH);
|
|
420
420
|
let v = verticals.filter((l) => l.lineWidth <= MAX_LINE_WIDTH);
|
|
421
421
|
h = dropShadingStacks(h, "h");
|
|
422
422
|
v = dropShadingStacks(v, "v");
|
|
423
|
-
h = mergeParallelLines(h, "h");
|
|
424
|
-
v = mergeParallelLines(v, "v");
|
|
423
|
+
h = mergeParallelLines(h, "h", nonRules);
|
|
424
|
+
v = mergeParallelLines(v, "v", nonRules);
|
|
425
425
|
return { horizontals: h, verticals: v };
|
|
426
426
|
}
|
|
427
427
|
var STACK_GAP = 2;
|
|
@@ -581,15 +581,15 @@ function closeOpenTableEdges(horizontals, verticals) {
|
|
|
581
581
|
const hasInterior = verticals.some((v) => v.x1 > x1 + EDGE_INSET && v.x1 < x2 - EDGE_INSET && crossCount(v) >= 2);
|
|
582
582
|
if (!hasInterior) continue;
|
|
583
583
|
for (const edgeX of [x1, x2]) {
|
|
584
|
-
const
|
|
585
|
-
if (!
|
|
584
|
+
const closed2 = verticals.some((v) => Math.abs(v.x1 - edgeX) <= EDGE_NEAR && v.y1 <= yMax + EDGE_CONNECT_TOL && v.y2 >= yMin - EDGE_CONNECT_TOL);
|
|
585
|
+
if (!closed2) {
|
|
586
586
|
synthesized.push({ x1: edgeX, y1: yMin, x2: edgeX, y2: yMax, lineWidth: 0.5 });
|
|
587
587
|
}
|
|
588
588
|
}
|
|
589
589
|
}
|
|
590
590
|
return synthesized.length ? [...verticals, ...synthesized] : verticals;
|
|
591
591
|
}
|
|
592
|
-
function mergeParallelLines(lines, dir) {
|
|
592
|
+
function mergeParallelLines(lines, dir, nonRules) {
|
|
593
593
|
if (lines.length <= 1) return lines;
|
|
594
594
|
const sorted = [...lines].sort((a, b) => {
|
|
595
595
|
const posA = dir === "h" ? a.y1 : a.x1;
|
|
@@ -612,6 +612,7 @@ function mergeParallelLines(lines, dir) {
|
|
|
612
612
|
const overlap2 = Math.min(prevEnd, currEnd) - Math.max(prevStart, currStart);
|
|
613
613
|
const minLen = Math.min(prevEnd - prevStart, currEnd - currStart);
|
|
614
614
|
if (overlap2 > minLen * 0.3) {
|
|
615
|
+
if (nonRules?.has(prev) && !nonRules.has(curr)) nonRules.delete(prev);
|
|
615
616
|
if (dir === "h") {
|
|
616
617
|
prev.x1 = Math.min(prev.x1, curr.x1);
|
|
617
618
|
prev.x2 = Math.max(prev.x2, curr.x2);
|
|
@@ -4124,7 +4125,12 @@ function detectSpecialKoreanTables(blocks) {
|
|
|
4124
4125
|
flushKvTable();
|
|
4125
4126
|
return result;
|
|
4126
4127
|
}
|
|
4127
|
-
function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables = false) {
|
|
4128
|
+
function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables = false, context = []) {
|
|
4129
|
+
if (context.length && !tables) {
|
|
4130
|
+
const removed = removeHeaderFooterBlocks([...blocks, ...context], pageHeights, [], notes).filter((index) => index < blocks.length);
|
|
4131
|
+
if (removed.length) warnings.push({ message: `${removed.length}\uAC1C \uBA38\uB9AC\uAE00/\uBC14\uB2E5\uAE00 \uC694\uC18C \uC81C\uAC70\uB428`, code: "HIDDEN_TEXT_FILTERED" });
|
|
4132
|
+
return removed;
|
|
4133
|
+
}
|
|
4128
4134
|
const ZONE_RATIO = 0.12;
|
|
4129
4135
|
const MIN_REPEAT2 = 3;
|
|
4130
4136
|
const topEntries = [];
|
|
@@ -4204,6 +4210,7 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables =
|
|
|
4204
4210
|
|
|
4205
4211
|
// src/pdf/table-meta.ts
|
|
4206
4212
|
var CLIP_TABLES = /* @__PURE__ */ new WeakSet();
|
|
4213
|
+
var FRAME_TITLE_BLOCKS = /* @__PURE__ */ new WeakMap();
|
|
4207
4214
|
var TABLE_COLXS = /* @__PURE__ */ new WeakMap();
|
|
4208
4215
|
var TABLE_ROWYS = /* @__PURE__ */ new WeakMap();
|
|
4209
4216
|
var TABLE_TAIL = /* @__PURE__ */ new WeakMap();
|
|
@@ -4311,6 +4318,262 @@ function mergeSliverColumns(grid, colXs, maxWidth) {
|
|
|
4311
4318
|
return merged;
|
|
4312
4319
|
}
|
|
4313
4320
|
|
|
4321
|
+
// src/pdf/image-bullets.ts
|
|
4322
|
+
import { OPS as OPS3, ImageKind } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
4323
|
+
var multiply = (m, t) => [
|
|
4324
|
+
m[0] * t[0] + m[2] * t[1],
|
|
4325
|
+
m[1] * t[0] + m[3] * t[1],
|
|
4326
|
+
m[0] * t[2] + m[2] * t[3],
|
|
4327
|
+
m[1] * t[2] + m[3] * t[3],
|
|
4328
|
+
m[0] * t[4] + m[2] * t[5] + m[4],
|
|
4329
|
+
m[1] * t[4] + m[3] * t[5] + m[5]
|
|
4330
|
+
];
|
|
4331
|
+
function hollowCircle(image) {
|
|
4332
|
+
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;
|
|
4333
|
+
const stride = image.kind === ImageKind.RGB_24BPP ? 3 : image.kind === ImageKind.RGBA_32BPP ? 4 : 0;
|
|
4334
|
+
const { width, height, data } = image;
|
|
4335
|
+
if (!stride || data.length < width * height * stride) return false;
|
|
4336
|
+
const dark = [];
|
|
4337
|
+
let white = 0;
|
|
4338
|
+
for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) {
|
|
4339
|
+
const i = (y * width + x) * stride;
|
|
4340
|
+
if (stride === 4 && data[i + 3] < 240) return false;
|
|
4341
|
+
const min = Math.min(data[i], data[i + 1], data[i + 2]), max = Math.max(data[i], data[i + 1], data[i + 2]);
|
|
4342
|
+
if (max - min > 15) return false;
|
|
4343
|
+
if (min >= 235) white++;
|
|
4344
|
+
if (max < 180) dark.push({ x, y });
|
|
4345
|
+
}
|
|
4346
|
+
if (white < width * height * 0.65 || dark.length < width * height * 0.025 || dark.length > width * height * 0.3) return false;
|
|
4347
|
+
const x0 = Math.min(...dark.map((p) => p.x)), x1 = Math.max(...dark.map((p) => p.x));
|
|
4348
|
+
const y0 = Math.min(...dark.map((p) => p.y)), y1 = Math.max(...dark.map((p) => p.y));
|
|
4349
|
+
const w = x1 - x0 + 1, h = y1 - y0 + 1, radius = (w + h) / 4;
|
|
4350
|
+
const cx = (x0 + x1) / 2, cy = (y0 + y1) / 2;
|
|
4351
|
+
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;
|
|
4352
|
+
const sectors = /* @__PURE__ */ new Set();
|
|
4353
|
+
for (const point of dark) {
|
|
4354
|
+
const r = Math.hypot(point.x - cx, point.y - cy) / radius;
|
|
4355
|
+
if (r < 0.65 || r > 1.15) return false;
|
|
4356
|
+
sectors.add(Math.floor((Math.atan2(point.y - cy, point.x - cx) + Math.PI) / (Math.PI * 2) * 8) % 8);
|
|
4357
|
+
}
|
|
4358
|
+
return sectors.size === 8;
|
|
4359
|
+
}
|
|
4360
|
+
async function resolveImagePixels(page, id) {
|
|
4361
|
+
const objects = id.startsWith("g_") ? page.commonObjs : page.objs;
|
|
4362
|
+
return new Promise((resolve) => {
|
|
4363
|
+
const timer = setTimeout(() => resolve(null), 5e3);
|
|
4364
|
+
try {
|
|
4365
|
+
objects.get(id, (value) => {
|
|
4366
|
+
clearTimeout(timer);
|
|
4367
|
+
resolve(value ?? null);
|
|
4368
|
+
});
|
|
4369
|
+
} catch {
|
|
4370
|
+
clearTimeout(timer);
|
|
4371
|
+
resolve(null);
|
|
4372
|
+
}
|
|
4373
|
+
});
|
|
4374
|
+
}
|
|
4375
|
+
function smallVisibleImagePaints(fnArray, argsArray) {
|
|
4376
|
+
const paints = [];
|
|
4377
|
+
let ctm = [1, 0, 0, 1, 0, 0];
|
|
4378
|
+
let alpha = 1, clip = null, unknownClip = false;
|
|
4379
|
+
const stack = [];
|
|
4380
|
+
let pathRect, pendingClip = false;
|
|
4381
|
+
const intersectClip = (box) => {
|
|
4382
|
+
clip = clip ? {
|
|
4383
|
+
x1: Math.max(clip.x1, box.x1),
|
|
4384
|
+
y1: Math.max(clip.y1, box.y1),
|
|
4385
|
+
x2: Math.min(clip.x2, box.x2),
|
|
4386
|
+
y2: Math.min(clip.y2, box.y2)
|
|
4387
|
+
} : box;
|
|
4388
|
+
};
|
|
4389
|
+
const rectangle = (x, y, w, h) => extractImageRegions(
|
|
4390
|
+
[OPS3.transform, OPS3.transform, OPS3.paintImageXObject],
|
|
4391
|
+
[ctm, [w, 0, 0, h, x, y], ["bounds"]]
|
|
4392
|
+
)[0];
|
|
4393
|
+
for (let i = 0; i < fnArray.length; i++) {
|
|
4394
|
+
const op = fnArray[i], args = argsArray[i];
|
|
4395
|
+
if (op === OPS3.save || op === OPS3.paintFormXObjectBegin) {
|
|
4396
|
+
stack.push({ ctm, alpha, clip, unknownClip });
|
|
4397
|
+
const matrix = op === OPS3.paintFormXObjectBegin ? args?.[0] : void 0;
|
|
4398
|
+
if (Array.isArray(matrix) && matrix.length >= 6) ctm = multiply(ctm, matrix);
|
|
4399
|
+
const bounds = op === OPS3.paintFormXObjectBegin ? args?.[1] : void 0;
|
|
4400
|
+
if (Array.isArray(bounds) && bounds.length === 4) {
|
|
4401
|
+
const box = rectangle(bounds[0], bounds[1], bounds[2] - bounds[0], bounds[3] - bounds[1]);
|
|
4402
|
+
if (box && ctm[1] === 0 && ctm[2] === 0) intersectClip(box);
|
|
4403
|
+
else unknownClip = true;
|
|
4404
|
+
}
|
|
4405
|
+
} else if (op === OPS3.restore || op === OPS3.paintFormXObjectEnd) {
|
|
4406
|
+
const state = stack.pop();
|
|
4407
|
+
ctm = state?.ctm ?? [1, 0, 0, 1, 0, 0];
|
|
4408
|
+
alpha = state?.alpha ?? 1;
|
|
4409
|
+
clip = state?.clip ?? null;
|
|
4410
|
+
unknownClip = state?.unknownClip ?? false;
|
|
4411
|
+
} else if (op === OPS3.setGState) {
|
|
4412
|
+
for (const [key, value] of args?.[0] ?? []) {
|
|
4413
|
+
if (key === "ca") alpha = typeof value === "number" ? value : 0;
|
|
4414
|
+
}
|
|
4415
|
+
} else if (op === OPS3.constructPath) {
|
|
4416
|
+
const [operations, coordinates] = args;
|
|
4417
|
+
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;
|
|
4418
|
+
} else if (op === OPS3.clip || op === OPS3.eoClip) pendingClip = true;
|
|
4419
|
+
else if ([
|
|
4420
|
+
OPS3.endPath,
|
|
4421
|
+
OPS3.stroke,
|
|
4422
|
+
OPS3.closeStroke,
|
|
4423
|
+
OPS3.fill,
|
|
4424
|
+
OPS3.eoFill,
|
|
4425
|
+
OPS3.fillStroke,
|
|
4426
|
+
OPS3.eoFillStroke,
|
|
4427
|
+
OPS3.closeFillStroke,
|
|
4428
|
+
OPS3.closeEOFillStroke
|
|
4429
|
+
].includes(op)) {
|
|
4430
|
+
if (pendingClip) {
|
|
4431
|
+
if (pathRect) intersectClip(pathRect);
|
|
4432
|
+
else unknownClip = true;
|
|
4433
|
+
}
|
|
4434
|
+
pendingClip = false;
|
|
4435
|
+
pathRect = void 0;
|
|
4436
|
+
} else if (op === OPS3.transform && Array.isArray(args) && args.length >= 6) ctm = multiply(ctm, args);
|
|
4437
|
+
else if (op === OPS3.paintImageXObject && typeof args?.[0] === "string") {
|
|
4438
|
+
if (typeof args[1] !== "number" || typeof args[2] !== "number" || args[1] < 16 || args[1] > 128 || args[2] < 16 || args[2] > 128) continue;
|
|
4439
|
+
const box = extractImageRegions([OPS3.transform, OPS3.paintImageXObject], [ctm, args])[0];
|
|
4440
|
+
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;
|
|
4441
|
+
const width = box.x2 - box.x1, height = box.y2 - box.y1;
|
|
4442
|
+
if (width < 3 || width > 24 || height < 3 || height > 24 || width / height < 0.5 || width / height > 2) continue;
|
|
4443
|
+
paints.push({ id: args[0], box, mirrored: ctm[0] < 0 });
|
|
4444
|
+
}
|
|
4445
|
+
}
|
|
4446
|
+
return paints;
|
|
4447
|
+
}
|
|
4448
|
+
async function restoreImageBullets(items, page, fnArray, argsArray, shapes = /* @__PURE__ */ new Map()) {
|
|
4449
|
+
const candidates = [];
|
|
4450
|
+
for (const { id, box } of smallVisibleImagePaints(fnArray, argsArray)) {
|
|
4451
|
+
const width = box.x2 - box.x1, height = box.y2 - box.y1;
|
|
4452
|
+
if (Math.abs(width - height) > Math.min(width, height) * 0.1) continue;
|
|
4453
|
+
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];
|
|
4454
|
+
if (!line || /^[○●•◦□■∙]/.test(line.text.trim()) || !/\p{L}/u.test(line.text)) continue;
|
|
4455
|
+
const row = items.filter((item) => Math.abs(item.y - line.y) <= 2 && item.x >= line.x);
|
|
4456
|
+
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;
|
|
4457
|
+
candidates.push({ id, x: box.x1, width, line });
|
|
4458
|
+
}
|
|
4459
|
+
let restored = 0;
|
|
4460
|
+
const used = /* @__PURE__ */ new Set();
|
|
4461
|
+
for (const candidate of candidates) {
|
|
4462
|
+
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);
|
|
4463
|
+
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);
|
|
4464
|
+
const numberedList = numbered.some((item, index) => index > 0 && item.text.trim().charCodeAt(0) === numbered[index - 1].text.trim().charCodeAt(0) + 1);
|
|
4465
|
+
if (!same.length && !numberedList || used.has(candidate.line)) continue;
|
|
4466
|
+
if (!shapes.has(candidate.id)) shapes.set(candidate.id, hollowCircle(await resolveImagePixels(page, candidate.id)));
|
|
4467
|
+
if (!shapes.get(candidate.id)) continue;
|
|
4468
|
+
used.add(candidate.line);
|
|
4469
|
+
items.push({ ...candidate.line, text: "\u25CB", x: candidate.x, w: candidate.width, strike: false, underline: false, hasSpaceBefore: false, syntheticSpace: false });
|
|
4470
|
+
restored++;
|
|
4471
|
+
}
|
|
4472
|
+
return restored;
|
|
4473
|
+
}
|
|
4474
|
+
|
|
4475
|
+
// src/pdf/flow-boxes.ts
|
|
4476
|
+
import { ImageKind as ImageKind2 } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
4477
|
+
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;
|
|
4478
|
+
function closed(grid, hs, vs) {
|
|
4479
|
+
const b = grid.bbox;
|
|
4480
|
+
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));
|
|
4481
|
+
}
|
|
4482
|
+
function groupFlowBoxUnits(blocks, grids, hs, vs, images) {
|
|
4483
|
+
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));
|
|
4484
|
+
const bands = [], visited = /* @__PURE__ */ new Set();
|
|
4485
|
+
for (const first of candidates) {
|
|
4486
|
+
if (visited.has(first)) continue;
|
|
4487
|
+
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);
|
|
4488
|
+
row.forEach((g) => visited.add(g));
|
|
4489
|
+
if (row.length < 4 || row.filter((g) => g.rowYs.length === 2 && g.colXs.length === 2).length < 3) continue;
|
|
4490
|
+
const connectors = [];
|
|
4491
|
+
for (let i = 1; i < row.length; i++) {
|
|
4492
|
+
const left = row[i - 1].bbox, right = row[i].bbox, gap = right.x1 - left.x2;
|
|
4493
|
+
if (gap < 4 || gap > Math.min(left.x2 - left.x1, right.x2 - right.x1) * 0.6) break;
|
|
4494
|
+
const centerX = (left.x2 + right.x1) / 2, centerY = (left.y1 + left.y2) / 2;
|
|
4495
|
+
const connector = images.find((p) => {
|
|
4496
|
+
const w = p.x2 - p.x1, h = p.y2 - p.y1;
|
|
4497
|
+
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;
|
|
4498
|
+
});
|
|
4499
|
+
if (!connector) break;
|
|
4500
|
+
connectors.push(connector);
|
|
4501
|
+
}
|
|
4502
|
+
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;
|
|
4503
|
+
bands.push(row);
|
|
4504
|
+
}
|
|
4505
|
+
const members = /* @__PURE__ */ new Map();
|
|
4506
|
+
for (const band of bands) {
|
|
4507
|
+
const columns = band.map((g) => blocks.filter((b) => b.bbox && contains2(g.bbox, {
|
|
4508
|
+
x1: b.bbox.x,
|
|
4509
|
+
y1: b.bbox.y,
|
|
4510
|
+
x2: b.bbox.x + b.bbox.width,
|
|
4511
|
+
y2: b.bbox.y + b.bbox.height
|
|
4512
|
+
})).sort((a, b) => b.bbox.y + b.bbox.height - a.bbox.y - a.bbox.height || a.bbox.x - b.bbox.x));
|
|
4513
|
+
if (columns.some((column) => !column.length)) continue;
|
|
4514
|
+
const unit = columns.flat();
|
|
4515
|
+
for (const block of unit) members.set(block, unit);
|
|
4516
|
+
}
|
|
4517
|
+
const units = [], emitted = /* @__PURE__ */ new Set();
|
|
4518
|
+
for (const block of blocks) {
|
|
4519
|
+
const unit = members.get(block);
|
|
4520
|
+
if (!unit) units.push([block]);
|
|
4521
|
+
else if (!emitted.has(unit)) {
|
|
4522
|
+
units.push(unit);
|
|
4523
|
+
emitted.add(unit);
|
|
4524
|
+
}
|
|
4525
|
+
}
|
|
4526
|
+
return units;
|
|
4527
|
+
}
|
|
4528
|
+
function arrowDirection(image) {
|
|
4529
|
+
if (!image?.data || image.width < 16 || image.width > 128 || image.height < 16 || image.height > 128) return 0;
|
|
4530
|
+
const { width, height, data } = image;
|
|
4531
|
+
const stride = image.kind === ImageKind2.RGB_24BPP ? 3 : image.kind === ImageKind2.RGBA_32BPP ? 4 : 0;
|
|
4532
|
+
if (!stride || data.length < width * height * stride) return 0;
|
|
4533
|
+
const ink = [];
|
|
4534
|
+
let white = 0;
|
|
4535
|
+
for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) {
|
|
4536
|
+
const offset = (y * width + x) * stride;
|
|
4537
|
+
if (stride === 4 && data[offset + 3] < 240) return 0;
|
|
4538
|
+
const min = Math.min(data[offset], data[offset + 1], data[offset + 2]);
|
|
4539
|
+
if (min >= 235) white++;
|
|
4540
|
+
if (min < 230) ink.push({ x, y });
|
|
4541
|
+
}
|
|
4542
|
+
if (white < width * height * 0.55 || !ink.length) return 0;
|
|
4543
|
+
const x0 = Math.min(...ink.map((p) => p.x)), x1 = Math.max(...ink.map((p) => p.x));
|
|
4544
|
+
const y0 = Math.min(...ink.map((p) => p.y)), y1 = Math.max(...ink.map((p) => p.y));
|
|
4545
|
+
const w = x1 - x0 + 1, h = y1 - y0 + 1, centerY = (y0 + y1) / 2;
|
|
4546
|
+
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;
|
|
4547
|
+
const pointsRight = (mirror) => {
|
|
4548
|
+
const points = ink.map((p) => ({ x: mirror ? x0 + x1 - p.x : p.x, y: p.y }));
|
|
4549
|
+
const tail = points.filter((p) => p.x <= x0 + w * 0.25), tip = points.filter((p) => p.x >= x1 - w * 0.1);
|
|
4550
|
+
if (!tail.length || !tip.length) return false;
|
|
4551
|
+
const span = (points2) => Math.max(...points2.map((p) => p.y)) - Math.min(...points2.map((p) => p.y)) + 1;
|
|
4552
|
+
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;
|
|
4553
|
+
let head = 0;
|
|
4554
|
+
for (let x = Math.ceil(x0 + w * 0.45); x <= x0 + w * 0.75; x++) {
|
|
4555
|
+
const column = points.filter((p) => p.x === x);
|
|
4556
|
+
if (column.length) head = Math.max(head, span(column));
|
|
4557
|
+
}
|
|
4558
|
+
const middle = new Set(points.filter((p) => Math.abs(p.y - centerY) <= 1).map((p) => p.x));
|
|
4559
|
+
return head >= h * 0.8 && middle.size >= w * 0.9;
|
|
4560
|
+
};
|
|
4561
|
+
return pointsRight(false) ? 1 : pointsRight(true) ? -1 : 0;
|
|
4562
|
+
}
|
|
4563
|
+
async function detectRightArrowRegions(page, fnArray, argsArray, directions = /* @__PURE__ */ new Map()) {
|
|
4564
|
+
const regions = [];
|
|
4565
|
+
const paints = smallVisibleImagePaints(fnArray, argsArray);
|
|
4566
|
+
for (const paint of paints) {
|
|
4567
|
+
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);
|
|
4568
|
+
const positions = new Set(row.map((other) => Math.round(other.box.x1)));
|
|
4569
|
+
if (positions.size < 3) continue;
|
|
4570
|
+
if (!directions.has(paint.id)) directions.set(paint.id, arrowDirection(await resolveImagePixels(page, paint.id)));
|
|
4571
|
+
const direction = directions.get(paint.id) ?? 0;
|
|
4572
|
+
if (direction && (paint.mirrored ? -direction : direction) === 1) regions.push(paint.box);
|
|
4573
|
+
}
|
|
4574
|
+
return regions;
|
|
4575
|
+
}
|
|
4576
|
+
|
|
4314
4577
|
// src/pdf/side-tabs.ts
|
|
4315
4578
|
var BAND = 0.12;
|
|
4316
4579
|
var MAX_CHARS = 10;
|
|
@@ -4325,7 +4588,8 @@ function isSideTabTable(box, table, others, pageWidth, pageHeight) {
|
|
|
4325
4588
|
if (!side) return false;
|
|
4326
4589
|
const texts = table.cells.flat().map((c) => c.text.replace(/\s+/g, ""));
|
|
4327
4590
|
if (!texts.some(Boolean) || texts.some((t) => [...t].length > TAB_CELL_CHARS)) return false;
|
|
4328
|
-
|
|
4591
|
+
const overlap2 = others.filter((it) => it.y >= box.y1 && it.y <= box.y2);
|
|
4592
|
+
return overlap2.length > 0 && overlap2.every((it) => side === "R" ? it.x + it.w <= box.x1 + 1 : it.x >= box.x2 - 1);
|
|
4329
4593
|
}
|
|
4330
4594
|
function removeSideTabs(blocks, pageWidths) {
|
|
4331
4595
|
const edges = /* @__PURE__ */ new Map();
|
|
@@ -4354,7 +4618,7 @@ function removeSideTabs(blocks, pageWidths) {
|
|
|
4354
4618
|
}
|
|
4355
4619
|
if (!w || !area || !b.bbox || !text || [...text].length > MAX_CHARS) return null;
|
|
4356
4620
|
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;
|
|
4357
|
-
return side && text.replace(/\s+/g, "")
|
|
4621
|
+
return side && `${side}\0${text.replace(/\s+/g, "")}`;
|
|
4358
4622
|
};
|
|
4359
4623
|
const pages = /* @__PURE__ */ new Map();
|
|
4360
4624
|
for (const b of blocks) {
|
|
@@ -4561,16 +4825,42 @@ function sideTabGlyphs(items) {
|
|
|
4561
4825
|
if (c) c.push(it);
|
|
4562
4826
|
else cols.push([it]);
|
|
4563
4827
|
}
|
|
4828
|
+
const cands = [];
|
|
4564
4829
|
for (const col of cols) {
|
|
4565
|
-
if (col.length <
|
|
4830
|
+
if (col.length < 2) continue;
|
|
4831
|
+
if (col.filter((g) => /[\p{L}\p{N}]/u.test(g.text)).length < col.length * 0.8) continue;
|
|
4566
4832
|
col.sort((a, b) => b.y - a.y);
|
|
4567
4833
|
const fs = [...col.map((i) => i.fontSize)].sort((a, b) => a - b)[col.length >> 1];
|
|
4568
4834
|
if (col.slice(1).some((it, k) => col[k].y - it.y > fs * 3)) continue;
|
|
4835
|
+
cands.push({ col, fs });
|
|
4836
|
+
}
|
|
4837
|
+
const bands = [];
|
|
4838
|
+
for (const c of cands.sort((a, b) => a.col[0].x - b.col[0].x)) {
|
|
4839
|
+
const last = bands[bands.length - 1];
|
|
4840
|
+
if (last) {
|
|
4841
|
+
const lastRight = Math.max(...last.col.map((i) => i.x + i.w));
|
|
4842
|
+
const gap = Math.min(...c.col.map((i) => i.x)) - lastRight;
|
|
4843
|
+
const lTop = Math.max(...last.col.map((i) => i.y)), lBot = Math.min(...last.col.map((i) => i.y));
|
|
4844
|
+
const cTop = c.col[0].y, cBot = c.col[c.col.length - 1].y;
|
|
4845
|
+
if (gap <= Math.max(last.fs, c.fs) * 1.5 && Math.min(lTop, cTop) >= Math.max(lBot, cBot)) {
|
|
4846
|
+
last.col.push(...c.col);
|
|
4847
|
+
last.fs = Math.max(last.fs, c.fs);
|
|
4848
|
+
last.anchored ||= c.col.length >= SIDE_TAB_MIN;
|
|
4849
|
+
continue;
|
|
4850
|
+
}
|
|
4851
|
+
}
|
|
4852
|
+
bands.push({ col: [...c.col], fs: c.fs, anchored: c.col.length >= SIDE_TAB_MIN });
|
|
4853
|
+
}
|
|
4854
|
+
for (const { col, fs, anchored } of bands) {
|
|
4855
|
+
if (!anchored) continue;
|
|
4856
|
+
col.sort((a, b) => b.y - a.y);
|
|
4569
4857
|
const members = new Set(col);
|
|
4570
4858
|
const top = col[0].y + fs, bottom = col[col.length - 1].y - fs;
|
|
4571
|
-
const others = items.filter((i) => !members.has(i) && i.y <= top && i.y >= bottom);
|
|
4859
|
+
const others = items.filter((i) => !members.has(i) && i.text.trim() && i.y <= top && i.y >= bottom);
|
|
4860
|
+
if (!others.length) continue;
|
|
4572
4861
|
const left = Math.min(...col.map((i) => i.x)), right = Math.max(...col.map((i) => i.x + i.w));
|
|
4573
|
-
const
|
|
4862
|
+
const rest = items.filter((i) => !members.has(i) && i.text.trim());
|
|
4863
|
+
const outside = rest.every((i) => i.x >= right + fs) || rest.every((i) => i.x + i.w <= left - fs);
|
|
4574
4864
|
if (!outside) continue;
|
|
4575
4865
|
const alone = col.filter((g) => !others.some((i) => Math.abs(i.y - g.y) <= Y_TOL)).length;
|
|
4576
4866
|
if (alone < col.length * 0.4) continue;
|
|
@@ -5828,13 +6118,44 @@ var UNDER_SPAN_OVERLAP_RATIO = 0.8;
|
|
|
5828
6118
|
var UNDER_BOX_PAIR_MIN_EM = 0.5;
|
|
5829
6119
|
var UNDER_BOX_PAIR_MAX_EM = 2.2;
|
|
5830
6120
|
var UNDER_BOX_PAIR_OVERLAP = 0.8;
|
|
5831
|
-
function markUnderlineItems(items, horizontals, verticals) {
|
|
6121
|
+
function markUnderlineItems(items, horizontals, verticals, nonRules) {
|
|
5832
6122
|
const underlines = [];
|
|
6123
|
+
if (nonRules?.size) horizontals = horizontals.filter((line) => !nonRules.has(line));
|
|
5833
6124
|
if (items.length === 0 || horizontals.length === 0) return underlines;
|
|
6125
|
+
const tightOwners = /* @__PURE__ */ new Map();
|
|
6126
|
+
const tightlyOwned = (line) => {
|
|
6127
|
+
const cached = tightOwners.get(line);
|
|
6128
|
+
if (cached !== void 0) return cached;
|
|
6129
|
+
const owners = items.filter((item) => {
|
|
6130
|
+
const below = item.y - line.y1;
|
|
6131
|
+
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);
|
|
6132
|
+
}).sort((a, b) => a.x - b.x);
|
|
6133
|
+
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;
|
|
6134
|
+
for (let i = 1; owned && i < owners.length; i++) {
|
|
6135
|
+
const em = Math.max(owners[i].h, owners[i].fontSize, 1);
|
|
6136
|
+
if (owners[i].x - (owners[i - 1].x + owners[i - 1].w) > em * UNDER_COLUMN_GAP_EM) owned = false;
|
|
6137
|
+
}
|
|
6138
|
+
tightOwners.set(line, owned);
|
|
6139
|
+
return owned;
|
|
6140
|
+
};
|
|
6141
|
+
const paragraphUnderline = (line) => {
|
|
6142
|
+
if (!tightlyOwned(line)) return false;
|
|
6143
|
+
const width = line.x2 - line.x1;
|
|
6144
|
+
const ys = [];
|
|
6145
|
+
for (const other of horizontals) {
|
|
6146
|
+
const overlap2 = Math.min(line.x2, other.x2) - Math.max(line.x1, other.x1);
|
|
6147
|
+
if (other.lineWidth > UNDER_MAX_THICKNESS || overlap2 / Math.max(width, other.x2 - other.x1) < UNDER_SPAN_OVERLAP_RATIO || !tightlyOwned(other)) continue;
|
|
6148
|
+
if (!ys.some((y) => Math.abs(y - other.y1) < UNDER_GRID_EPS)) ys.push(other.y1);
|
|
6149
|
+
if (ys.length >= UNDER_REPEATED_SPAN_LEVELS) return true;
|
|
6150
|
+
}
|
|
6151
|
+
return false;
|
|
6152
|
+
};
|
|
5834
6153
|
for (const line of horizontals) {
|
|
5835
6154
|
if (line.lineWidth > UNDER_MAX_THICKNESS) continue;
|
|
5836
6155
|
const enclosed = insideTallCell(line, verticals, 0);
|
|
5837
|
-
|
|
6156
|
+
const repeated = isRepeatedSpanRule(line, horizontals);
|
|
6157
|
+
const textSeries = repeated && paragraphUnderline(line);
|
|
6158
|
+
if (!enclosed && (touchesVertical(line, verticals) || repeated && !textSeries)) continue;
|
|
5838
6159
|
const matches = [];
|
|
5839
6160
|
for (const item of items) {
|
|
5840
6161
|
const h = item.h > 0 ? item.h : item.fontSize;
|
|
@@ -5854,11 +6175,11 @@ function markUnderlineItems(items, horizontals, verticals) {
|
|
|
5854
6175
|
covered += m.w;
|
|
5855
6176
|
}
|
|
5856
6177
|
const inset = enclosed && insideTallCell(line, verticals, maxH);
|
|
5857
|
-
if (enclosed && !inset && (touchesVertical(line, verticals) ||
|
|
6178
|
+
if (enclosed && !inset && (touchesVertical(line, verticals) || repeated && !textSeries)) continue;
|
|
5858
6179
|
const pad = Math.max(maxH * UNDER_OWNER_PAD_EM, UNDER_OWNER_PAD_MIN_PT);
|
|
5859
6180
|
if (line.x1 < x1 - pad || line.x2 > x2 + pad) continue;
|
|
5860
6181
|
if (covered < (line.x2 - line.x1) * UNDER_MIN_COVERAGE) continue;
|
|
5861
|
-
if (hasBoxTopPair(line, maxH, horizontals, inset ? items : void 0)) continue;
|
|
6182
|
+
if (hasBoxTopPair(line, maxH, horizontals, inset || textSeries || tightlyOwned(line) ? items : void 0)) continue;
|
|
5862
6183
|
matches.sort((a, b) => a.x - b.x);
|
|
5863
6184
|
let hole = false;
|
|
5864
6185
|
for (let i = 1; i < matches.length; i++) {
|
|
@@ -5889,6 +6210,7 @@ function touchesVertical(line, verticals) {
|
|
|
5889
6210
|
for (const v of verticals) {
|
|
5890
6211
|
if (v.x1 < line.x1 - UNDER_GRID_EPS || v.x1 > line.x2 + UNDER_GRID_EPS) continue;
|
|
5891
6212
|
const lo = Math.min(v.y1, v.y2), hi = Math.max(v.y1, v.y2);
|
|
6213
|
+
if (hi - lo <= UNDER_GRID_EPS) continue;
|
|
5892
6214
|
if (lo <= line.y1 + UNDER_GRID_EPS && hi >= line.y1 - UNDER_GRID_EPS) return true;
|
|
5893
6215
|
}
|
|
5894
6216
|
return false;
|
|
@@ -6098,6 +6420,57 @@ function isPageFrameGrid(grid, cells, pageWidth, pageHeight, items = []) {
|
|
|
6098
6420
|
return inner.length === 0 || crossing >= 1 && crossing >= inBig.length * 0.01;
|
|
6099
6421
|
}
|
|
6100
6422
|
|
|
6423
|
+
// src/pdf/shaded-open-table.ts
|
|
6424
|
+
function closeShadedTableEdges(clipGrids, horizontals, verticals, fillRects) {
|
|
6425
|
+
const near = (a, b) => Math.abs(a - b) <= 1.5;
|
|
6426
|
+
let hs = horizontals, vs = verticals;
|
|
6427
|
+
const restored = [];
|
|
6428
|
+
for (const grid of clipGrids) {
|
|
6429
|
+
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;
|
|
6430
|
+
const { x1, x2, y1: mid, y2: top } = grid.bbox;
|
|
6431
|
+
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;
|
|
6432
|
+
const topRule = hs.find((h) => near(h.y1, top) && near(h.x1, x1) && near(h.x2, x2));
|
|
6433
|
+
if (!topRule) continue;
|
|
6434
|
+
const dividers = grid.colXs.slice(1, -1).map((x) => vs.find((v) => near(v.x1, x) && near(v.y2, top) && v.y1 <= mid - 6));
|
|
6435
|
+
if (dividers.some((v) => !v)) continue;
|
|
6436
|
+
const bottom = dividers[0].y1;
|
|
6437
|
+
if (!dividers.every((v) => near(v.y1, bottom))) continue;
|
|
6438
|
+
const bottomRule = hs.find((h) => near(h.y1, bottom) && near(h.x1, x1) && near(h.x2, x2));
|
|
6439
|
+
if (!bottomRule) continue;
|
|
6440
|
+
const missing = [x1, x2].filter((x) => !vs.some((v) => near(v.x1, x) && v.y1 <= bottom + 1.5 && v.y2 >= top - 1.5));
|
|
6441
|
+
if (!missing.length) continue;
|
|
6442
|
+
restored.push({ x1, x2, y1: bottom, y2: top });
|
|
6443
|
+
vs = vs.concat(missing.map((x) => ({ x1: x, x2: x, y1: bottom, y2: top, lineWidth: topRule.lineWidth })));
|
|
6444
|
+
if (!hs.some((h) => near(h.y1, mid) && near(h.x1, x1) && near(h.x2, x2))) {
|
|
6445
|
+
hs = hs.concat({ x1, x2, y1: mid, y2: mid, lineWidth: topRule.lineWidth });
|
|
6446
|
+
}
|
|
6447
|
+
}
|
|
6448
|
+
return { horizontals: hs, verticals: vs, restored };
|
|
6449
|
+
}
|
|
6450
|
+
function nestRestoredShadedGrids(grids, restored, horizontals, verticals) {
|
|
6451
|
+
const near = (a, b) => Math.abs(a - b) <= 1.5;
|
|
6452
|
+
if (restored.length === 0) return;
|
|
6453
|
+
const nested = /* @__PURE__ */ new Set();
|
|
6454
|
+
for (const grid of grids) {
|
|
6455
|
+
const b = grid.bbox;
|
|
6456
|
+
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;
|
|
6457
|
+
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)) {
|
|
6458
|
+
grid.lineNested = true;
|
|
6459
|
+
nested.add(grid);
|
|
6460
|
+
}
|
|
6461
|
+
}
|
|
6462
|
+
for (const frame of grids) {
|
|
6463
|
+
const b = frame.bbox;
|
|
6464
|
+
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;
|
|
6465
|
+
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);
|
|
6466
|
+
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;
|
|
6467
|
+
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);
|
|
6468
|
+
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;
|
|
6469
|
+
frame.colXs = [b.x1, b.x2];
|
|
6470
|
+
frame.rowYs = [b.y2, b.y1];
|
|
6471
|
+
}
|
|
6472
|
+
}
|
|
6473
|
+
|
|
6101
6474
|
// src/pdf/open-table-ends.ts
|
|
6102
6475
|
var ALIGN_TOL = 3;
|
|
6103
6476
|
var MIN_RULES = 3;
|
|
@@ -6433,6 +6806,140 @@ function detectTextBoxTables(boxes, items, pageNum) {
|
|
|
6433
6806
|
}];
|
|
6434
6807
|
}
|
|
6435
6808
|
|
|
6809
|
+
// src/pdf/frame-cell-blocks.ts
|
|
6810
|
+
var FRAME_READING_UNITS = /* @__PURE__ */ new WeakMap();
|
|
6811
|
+
var FRAME_SOURCE_BOUNDS = /* @__PURE__ */ new WeakMap();
|
|
6812
|
+
function recordFrameReadingUnit(blocks, bbox) {
|
|
6813
|
+
for (const block of blocks) FRAME_SOURCE_BOUNDS.set(block, bbox);
|
|
6814
|
+
if (blocks.length < 2) return;
|
|
6815
|
+
const unit = { blocks, bbox };
|
|
6816
|
+
for (const block of blocks) FRAME_READING_UNITS.set(block, unit);
|
|
6817
|
+
}
|
|
6818
|
+
function frameLayoutBoxes(blocks) {
|
|
6819
|
+
const boxes = [], seen2 = /* @__PURE__ */ new Set();
|
|
6820
|
+
for (const block of blocks) {
|
|
6821
|
+
const frame = FRAME_SOURCE_BOUNDS.get(block);
|
|
6822
|
+
if (frame) {
|
|
6823
|
+
if (!seen2.has(frame)) {
|
|
6824
|
+
boxes.push(frame);
|
|
6825
|
+
seen2.add(frame);
|
|
6826
|
+
}
|
|
6827
|
+
} else if (block.bbox) boxes.push(block.bbox);
|
|
6828
|
+
}
|
|
6829
|
+
return boxes;
|
|
6830
|
+
}
|
|
6831
|
+
function groupFrameParagraphUnits(units, frames) {
|
|
6832
|
+
const source = /* @__PURE__ */ new Map();
|
|
6833
|
+
for (const unit of units) for (const block of unit) source.set(block, unit);
|
|
6834
|
+
const members = /* @__PURE__ */ new Map(), emitted = /* @__PURE__ */ new Set();
|
|
6835
|
+
for (const frame of frames) {
|
|
6836
|
+
if (frame.length < 2 || frame.some((block) => block.type !== "paragraph" || source.get(block)?.length !== 1)) continue;
|
|
6837
|
+
for (const block of frame) members.set(block, frame);
|
|
6838
|
+
}
|
|
6839
|
+
const out = [];
|
|
6840
|
+
for (const unit of units) {
|
|
6841
|
+
const frame = unit.length === 1 ? members.get(unit[0]) : void 0;
|
|
6842
|
+
if (!frame) out.push(unit);
|
|
6843
|
+
else if (!emitted.has(frame)) {
|
|
6844
|
+
out.push(frame);
|
|
6845
|
+
emitted.add(frame);
|
|
6846
|
+
}
|
|
6847
|
+
}
|
|
6848
|
+
for (const unit of out) {
|
|
6849
|
+
if (unit.length < 2 || FRAME_READING_UNITS.get(unit[0])?.blocks === unit) continue;
|
|
6850
|
+
const bs = unit.map((b) => b.bbox).filter((b) => !!b);
|
|
6851
|
+
if (bs.length !== unit.length) continue;
|
|
6852
|
+
const x = Math.min(...bs.map((b) => b.x)), y = Math.min(...bs.map((b) => b.y));
|
|
6853
|
+
recordFrameReadingUnit(unit, {
|
|
6854
|
+
page: bs[0].page,
|
|
6855
|
+
x,
|
|
6856
|
+
y,
|
|
6857
|
+
width: Math.max(...bs.map((b) => b.x + b.width)) - x,
|
|
6858
|
+
height: Math.max(...bs.map((b) => b.y + b.height)) - y
|
|
6859
|
+
});
|
|
6860
|
+
}
|
|
6861
|
+
return out;
|
|
6862
|
+
}
|
|
6863
|
+
function recordFrameTitle(table, source, pageNum) {
|
|
6864
|
+
if (!CLIP_TABLES.has(table) || table.rows !== 1 || table.cols !== 3 || source.length < 2) return;
|
|
6865
|
+
const cells = table.cells[0];
|
|
6866
|
+
if (cells.length !== 3 || cells.some((c) => c.colSpan !== 1 || c.rowSpan !== 1 || c.blocks?.length || c.text.includes("\n"))) return;
|
|
6867
|
+
const [label, spacer, title] = cells;
|
|
6868
|
+
if (!/^(?:붙임|별첨|첨부|부록)\s*\d{1,3}$/.test(label.text.trim()) || spacer.text.trim() || !title.text.trim()) return;
|
|
6869
|
+
if (cells.some((c) => {
|
|
6870
|
+
const e = CELL_EDGES.get(c);
|
|
6871
|
+
return !e || e.t || e.b || e.l || e.r;
|
|
6872
|
+
})) return;
|
|
6873
|
+
const xs = TABLE_COLXS.get(table), style = dominantStyle(source), fs = style?.fontSize ?? 0;
|
|
6874
|
+
if (!xs || xs.length !== 4 || fs <= 0) return;
|
|
6875
|
+
const width = xs[3] - xs[0], gap = xs[2] - xs[1];
|
|
6876
|
+
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;
|
|
6877
|
+
if (source.some((i) => i.fontName !== source[0].fontName || Math.abs(i.fontSize - fs) > fs * 0.15)) return;
|
|
6878
|
+
if (groupByY([...source].sort((a, b) => b.y - a.y)).length !== 1) return;
|
|
6879
|
+
FRAME_TITLE_BLOCKS.set(table, {
|
|
6880
|
+
type: "paragraph",
|
|
6881
|
+
text: `${label.text.trim()} ${title.text.trim()}`,
|
|
6882
|
+
pageNumber: pageNum,
|
|
6883
|
+
bbox: computeBBox(source, pageNum),
|
|
6884
|
+
style
|
|
6885
|
+
});
|
|
6886
|
+
}
|
|
6887
|
+
var FRAME_RECT_TOL = 1.5;
|
|
6888
|
+
function takePendingNested(pending, cellBox, clipCell) {
|
|
6889
|
+
const out = [];
|
|
6890
|
+
for (let i = pending.length - 1; i >= 0; i--) {
|
|
6891
|
+
const p = pending[i].parent;
|
|
6892
|
+
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) {
|
|
6893
|
+
out.push(pending[i].block);
|
|
6894
|
+
pending.splice(i, 1);
|
|
6895
|
+
}
|
|
6896
|
+
}
|
|
6897
|
+
return out;
|
|
6898
|
+
}
|
|
6899
|
+
function buildFrameCellBlocks(cellItems, nested, pageNum, lex) {
|
|
6900
|
+
const tables = [...nested].sort((a, b) => b.bbox.y + b.bbox.height - (a.bbox.y + a.bbox.height));
|
|
6901
|
+
const blocks = [];
|
|
6902
|
+
let rest = [...cellItems];
|
|
6903
|
+
const pushParagraphs = (items) => {
|
|
6904
|
+
if (items.length === 0) return;
|
|
6905
|
+
const source = items.map((it) => ({ ...it, isHidden: false })).sort((a, b) => b.y - a.y || a.x - b.x);
|
|
6906
|
+
const paragraphs = [];
|
|
6907
|
+
pushLineParagraphs(paragraphs, mergeSuperscriptLines(groupByY(source)), pageNum, lex);
|
|
6908
|
+
for (const block of paragraphs) {
|
|
6909
|
+
block.text = cleanCellText(block.text ?? "");
|
|
6910
|
+
if (block.text) blocks.push(block);
|
|
6911
|
+
}
|
|
6912
|
+
};
|
|
6913
|
+
for (const tb of tables) {
|
|
6914
|
+
const bottom = tb.bbox.y;
|
|
6915
|
+
pushParagraphs(rest.filter((it) => it.y >= bottom));
|
|
6916
|
+
rest = rest.filter((it) => it.y < bottom);
|
|
6917
|
+
blocks.push(tb);
|
|
6918
|
+
}
|
|
6919
|
+
pushParagraphs(rest);
|
|
6920
|
+
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");
|
|
6921
|
+
return { blocks, text };
|
|
6922
|
+
}
|
|
6923
|
+
|
|
6924
|
+
// src/pdf/nested-shaded-headers.ts
|
|
6925
|
+
function extendNestedShadedHeaders(clipGrids, lineGrids, horizontals, verticals, fills) {
|
|
6926
|
+
const near = (a, b) => Math.abs(a - b) <= 1.5;
|
|
6927
|
+
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;
|
|
6928
|
+
const extended = [];
|
|
6929
|
+
for (let i = 0; i < clipGrids.length; i++) {
|
|
6930
|
+
const c = clipGrids[i], parent = c.clipParent;
|
|
6931
|
+
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;
|
|
6932
|
+
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;
|
|
6933
|
+
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;
|
|
6934
|
+
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)));
|
|
6935
|
+
if (!host) continue;
|
|
6936
|
+
const grid = { ...host, clipParent: parent, cells: extractCells(host, horizontals, verticals) };
|
|
6937
|
+
clipGrids[i] = grid;
|
|
6938
|
+
extended.push(grid);
|
|
6939
|
+
}
|
|
6940
|
+
return extended;
|
|
6941
|
+
}
|
|
6942
|
+
|
|
6436
6943
|
// src/pdf/page-regions.ts
|
|
6437
6944
|
function splitTwoColumnProse(items, cutX) {
|
|
6438
6945
|
const left = [];
|
|
@@ -6760,7 +7267,7 @@ function figureColumnBands(items, figures) {
|
|
|
6760
7267
|
}
|
|
6761
7268
|
|
|
6762
7269
|
// src/pdf/page-blocks.ts
|
|
6763
|
-
function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeight, extraLines, detectTables = true, carry, lexicon) {
|
|
7270
|
+
function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeight, extraLines, detectTables = true, carry, lexicon, verifiedRightArrows = []) {
|
|
6764
7271
|
if (items.length === 0) {
|
|
6765
7272
|
if (carry) carry.clip = void 0;
|
|
6766
7273
|
return [];
|
|
@@ -6768,7 +7275,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
6768
7275
|
const tab = sideTabGlyphs(items);
|
|
6769
7276
|
if (tab.size) {
|
|
6770
7277
|
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]) }));
|
|
6771
|
-
return [...glyphs, ...extractPageBlocksWithLines(items.filter((i) => !tab.has(i)), pageNum, opList, pageWidth, pageHeight, extraLines, detectTables, carry, lexicon)];
|
|
7278
|
+
return [...glyphs, ...extractPageBlocksWithLines(items.filter((i) => !tab.has(i)), pageNum, opList, pageWidth, pageHeight, extraLines, detectTables, carry, lexicon, verifiedRightArrows)];
|
|
6772
7279
|
}
|
|
6773
7280
|
const lex = lexicon ?? new WrapLexicon();
|
|
6774
7281
|
for (const line of streamLines(items)) lex.addLine(mergeLineSimple(line));
|
|
@@ -6796,19 +7303,28 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
6796
7303
|
}
|
|
6797
7304
|
;
|
|
6798
7305
|
({ horizontals, verticals } = filterPageBorderLines(horizontals, verticals, pageWidth, pageHeight));
|
|
6799
|
-
({ horizontals, verticals } = preprocessLines(horizontals, verticals));
|
|
7306
|
+
({ horizontals, verticals } = preprocessLines(horizontals, verticals, extracted.nonRules));
|
|
7307
|
+
markStrikethroughItems(items, horizontals);
|
|
7308
|
+
wrapStrikethroughRuns(items);
|
|
7309
|
+
const underlines = new Set(markUnderlineItems(items, horizontals, verticals, extracted.nonRules));
|
|
7310
|
+
if (underlines.size) horizontals = horizontals.filter((l) => !underlines.has(l));
|
|
7311
|
+
wrapUnderlineRuns(items);
|
|
6800
7312
|
horizontals = closeOpenTableEnds(horizontals, verticals, items.every((it) => it.seq !== void 0));
|
|
6801
7313
|
verticals = closeOpenTableEdges(horizontals, verticals);
|
|
6802
7314
|
verticals = bridgeSplitColumnVerticals(horizontals, verticals);
|
|
6803
7315
|
if (detectTables && clipGrids.length === 0) verticals = bridgeSkippedRowVerticals(horizontals, verticals, items);
|
|
6804
7316
|
if (detectTables && clipGrids.length === 0) ({ horizontals, verticals } = extendHeaderBoxRows(horizontals, verticals, items));
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
const underlines = new Set(markUnderlineItems(items, horizontals, verticals));
|
|
6808
|
-
if (underlines.size) horizontals = horizontals.filter((l) => !underlines.has(l));
|
|
6809
|
-
wrapUnderlineRuns(items);
|
|
7317
|
+
const shadedEdges = detectTables ? closeShadedTableEdges(clipGrids, horizontals, verticals, extracted.fillRects) : void 0;
|
|
7318
|
+
if (shadedEdges) ({ horizontals, verticals } = shadedEdges);
|
|
6810
7319
|
const lineGrids = detectTables ? buildTableGrids(horizontals, verticals) : [];
|
|
7320
|
+
if (shadedEdges) nestRestoredShadedGrids(lineGrids, shadedEdges.restored, horizontals, verticals);
|
|
6811
7321
|
const tableClipGrids = dropHeadBandClipGrids(dropInsetClipGrids(dropShadingClipGrids(clipGrids, lineGrids, extracted.fillRects, verticals), lineGrids), lineGrids);
|
|
7322
|
+
recordClipCellEdges(
|
|
7323
|
+
extendNestedShadedHeaders(tableClipGrids, lineGrids, horizontals, verticals, extracted.fillRects),
|
|
7324
|
+
extracted.horizontals.concat(extracted.shortH),
|
|
7325
|
+
extracted.verticals.concat(extracted.shortV),
|
|
7326
|
+
extracted.nonRules
|
|
7327
|
+
);
|
|
6812
7328
|
const grids = [...tableClipGrids, ...dropGridsInside(lineGrids, tableClipGrids, clipResult.containers)];
|
|
6813
7329
|
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 }));
|
|
6814
7330
|
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) {
|
|
@@ -6818,7 +7334,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
6818
7334
|
if (detectTables && clipGrids.length === 0 && ruled.length === 0 && lineGrids.length === 0) ruled.push(...detectTextBoxTables(extracted.hiddenBoxes, items, pageNum));
|
|
6819
7335
|
if (ruled.length > 0) {
|
|
6820
7336
|
const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray).filter((r) => r.x2 - r.x1 >= 8 && r.y2 - r.y1 >= 8);
|
|
6821
|
-
return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, ruled, rawRules);
|
|
7337
|
+
return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, ruled, rawRules, verifiedRightArrows);
|
|
6822
7338
|
}
|
|
6823
7339
|
if (detectTables && stackedTableBands(items)) {
|
|
6824
7340
|
return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures());
|
|
@@ -6829,7 +7345,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
6829
7345
|
}
|
|
6830
7346
|
if (grids.length > 0) {
|
|
6831
7347
|
const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray).filter((r) => r.x2 - r.x1 >= 8 && r.y2 - r.y1 >= 8);
|
|
6832
|
-
return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, [], rawRules);
|
|
7348
|
+
return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, [], rawRules, verifiedRightArrows);
|
|
6833
7349
|
}
|
|
6834
7350
|
return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures());
|
|
6835
7351
|
}
|
|
@@ -6934,42 +7450,10 @@ function isSparseProseGrid(table) {
|
|
|
6934
7450
|
const prose = filled.filter((t) => t.length >= 60 && /[.!?。]/.test(t)).reduce((n, t) => n + t.length, 0);
|
|
6935
7451
|
return prose >= chars * 0.6;
|
|
6936
7452
|
}
|
|
6937
|
-
|
|
6938
|
-
function takePendingNested(pending, cellBox, clipCell) {
|
|
6939
|
-
const out = [];
|
|
6940
|
-
for (let i = pending.length - 1; i >= 0; i--) {
|
|
6941
|
-
const p = pending[i].parent;
|
|
6942
|
-
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) {
|
|
6943
|
-
out.push(pending[i].block);
|
|
6944
|
-
pending.splice(i, 1);
|
|
6945
|
-
}
|
|
6946
|
-
}
|
|
6947
|
-
return out;
|
|
6948
|
-
}
|
|
6949
|
-
function buildFrameCellBlocks(cellItems, nested, pageNum, wrap) {
|
|
6950
|
-
const tables = [...nested].sort((a, b) => b.bbox.y + b.bbox.height - (a.bbox.y + a.bbox.height));
|
|
6951
|
-
const blocks = [];
|
|
6952
|
-
let rest = [...cellItems];
|
|
6953
|
-
const pushParagraphs = (items) => {
|
|
6954
|
-
if (items.length === 0) return;
|
|
6955
|
-
for (const line of cleanCellText(cellTextToString(items, wrap)).split("\n")) {
|
|
6956
|
-
const t = line.trim();
|
|
6957
|
-
if (t) blocks.push({ type: "paragraph", text: t, pageNumber: pageNum });
|
|
6958
|
-
}
|
|
6959
|
-
};
|
|
6960
|
-
for (const tb of tables) {
|
|
6961
|
-
const bottom = tb.bbox.y;
|
|
6962
|
-
pushParagraphs(rest.filter((it) => it.y >= bottom));
|
|
6963
|
-
rest = rest.filter((it) => it.y < bottom);
|
|
6964
|
-
blocks.push(tb);
|
|
6965
|
-
}
|
|
6966
|
-
pushParagraphs(rest);
|
|
6967
|
-
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");
|
|
6968
|
-
return { blocks, text };
|
|
6969
|
-
}
|
|
6970
|
-
function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions = [], lex, ruled = [], rawRules = horizontals) {
|
|
7453
|
+
function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions = [], lex, ruled = [], rawRules = horizontals, verifiedRightArrows = []) {
|
|
6971
7454
|
const ocrPage = items.length > 0 && items.every((i) => i.fontName === "ocr");
|
|
6972
7455
|
const blocks = [];
|
|
7456
|
+
const frameParagraphUnits = [];
|
|
6973
7457
|
const usedItems = /* @__PURE__ */ new Set();
|
|
6974
7458
|
for (const r of ruled) {
|
|
6975
7459
|
for (const it of r.items) usedItems.add(it);
|
|
@@ -7026,7 +7510,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7026
7510
|
const nested = pendingNested.length ? takePendingNested(pendingNested, cell.bbox, !!grid.cells) : [];
|
|
7027
7511
|
if (nested.length > 0) {
|
|
7028
7512
|
nestedAttached = true;
|
|
7029
|
-
const built = buildFrameCellBlocks(cellItems, nested, pageNum,
|
|
7513
|
+
const built = buildFrameCellBlocks(cellItems, nested, pageNum, lex);
|
|
7030
7514
|
irGrid[cell.row][cell.col] = { text: built.text, colSpan: cell.colSpan, rowSpan: cell.rowSpan, blocks: built.blocks };
|
|
7031
7515
|
if (cellItems.length) recordCellLines(irGrid[cell.row][cell.col], cellItems);
|
|
7032
7516
|
takeClipCellEdges(cell, irGrid[cell.row][cell.col]);
|
|
@@ -7037,6 +7521,9 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7037
7521
|
colSpan: cell.colSpan,
|
|
7038
7522
|
rowSpan: cell.rowSpan
|
|
7039
7523
|
};
|
|
7524
|
+
if (numRows === 1 && numCols === 1 && cellItems.length) {
|
|
7525
|
+
irGrid[cell.row][cell.col].blocks = buildFrameCellBlocks(cellItems, [], pageNum, lex).blocks;
|
|
7526
|
+
}
|
|
7040
7527
|
const b = cell.bbox;
|
|
7041
7528
|
const isBackdrop = (r) => r.x1 <= b.x1 + 1 && r.x2 >= b.x2 - 1 && r.y1 <= b.y1 + 1 && r.y2 >= b.y2 - 1;
|
|
7042
7529
|
if (imageRegions.some((r) => {
|
|
@@ -7072,7 +7559,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7072
7559
|
}
|
|
7073
7560
|
if (!rebuiltUsed && attachUnitRow(items, grid, finalGrid, numCols, usedItems)) finalRows++;
|
|
7074
7561
|
let semanticOneColumn = false;
|
|
7075
|
-
if (!grid.cells && numCols === 1 && numGridRows >= 2) {
|
|
7562
|
+
if (!grid.cells && !nestedAttached && numCols === 1 && numGridRows >= 2) {
|
|
7076
7563
|
const populatedRows = finalGrid.filter((row) => row[0]?.text.trim());
|
|
7077
7564
|
if (populatedRows.length >= 4) {
|
|
7078
7565
|
const fontSizes = tableItems.map((item) => item.fontSize).filter((size) => size > 0).sort((a, b) => a - b);
|
|
@@ -7125,13 +7612,15 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7125
7612
|
recordRowRules(irTable, grid.cells, grid.bbox, rawRules);
|
|
7126
7613
|
}
|
|
7127
7614
|
TABLE_COLXS.set(irTable, grid.colXs);
|
|
7615
|
+
if (grid.cells) recordFrameTitle(irTable, tableItems, pageNum);
|
|
7128
7616
|
if (grid.cells && finalRows === numRows) TABLE_ROWYS.set(irTable, grid.rowYs);
|
|
7129
7617
|
if (grid.continues) CONT_PARTS.set(irTable, grid.continues);
|
|
7130
7618
|
const hasContent = finalGrid.some((row) => row.some((cell) => cell.text.trim() !== ""));
|
|
7131
7619
|
const emptyPart = !hasContent && !!grid.cells && !grid.clipParent && !nestedAttached;
|
|
7132
7620
|
if (!hasContent && !emptyPart) continue;
|
|
7133
7621
|
if (emptyPart) EMPTY_PARTS.add(irTable);
|
|
7134
|
-
|
|
7622
|
+
const ownItems = numCols === 1 ? new Set(tableItems) : null;
|
|
7623
|
+
if (ownItems && isSideTabTable(grid.bbox, irTable, items.filter((it) => !ownItems.has(it)), pageWidth, pageHeight)) {
|
|
7135
7624
|
SIDE_TAB_TABLES.add(irTable);
|
|
7136
7625
|
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 } });
|
|
7137
7626
|
continue;
|
|
@@ -7175,7 +7664,14 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7175
7664
|
continue;
|
|
7176
7665
|
}
|
|
7177
7666
|
}
|
|
7178
|
-
if (!grid.cells && shouldDemoteTable(irTable)) {
|
|
7667
|
+
if (!grid.cells && !nestedAttached && shouldDemoteTable(irTable)) {
|
|
7668
|
+
const paragraphs = numRows === 1 && numCols === 1 ? irTable.cells[0]?.[0]?.blocks : void 0;
|
|
7669
|
+
if (paragraphs?.length) {
|
|
7670
|
+
blocks.push(...paragraphs);
|
|
7671
|
+
frameParagraphUnits.push(paragraphs);
|
|
7672
|
+
recordFrameReadingUnit(paragraphs, tableBbox);
|
|
7673
|
+
continue;
|
|
7674
|
+
}
|
|
7179
7675
|
const demoted = demoteTableToText(irTable);
|
|
7180
7676
|
if (demoted) {
|
|
7181
7677
|
const text = numGridRows === 1 ? "\n" + demoted + "\n" : demoted;
|
|
@@ -7229,9 +7725,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7229
7725
|
}
|
|
7230
7726
|
{
|
|
7231
7727
|
const rects = remaining.map((i) => ({ x: i.x, y: i.y, w: i.w, h: i.h > 0 ? i.h : i.fontSize }));
|
|
7232
|
-
for (const b of blocks) {
|
|
7233
|
-
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 });
|
|
7234
|
-
}
|
|
7728
|
+
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 });
|
|
7235
7729
|
gutterX = detectColumnGutter(rects) ?? findRuledColumnDivider(
|
|
7236
7730
|
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 })),
|
|
7237
7731
|
horizontals,
|
|
@@ -7278,7 +7772,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7278
7772
|
finalTextBlocks = detectListBlocks(textBlocks);
|
|
7279
7773
|
}
|
|
7280
7774
|
}
|
|
7281
|
-
const units =
|
|
7775
|
+
const units = groupFrameParagraphUnits(groupFlowBoxUnits(blocks, grids, horizontals, verticals, verifiedRightArrows), frameParagraphUnits);
|
|
7282
7776
|
let off = 0;
|
|
7283
7777
|
for (const size of groupSizes) {
|
|
7284
7778
|
const unit = finalTextBlocks.slice(off, off + size);
|
|
@@ -7417,7 +7911,7 @@ function mergeAdjacentTableBlocks(blocks) {
|
|
|
7417
7911
|
table: merged,
|
|
7418
7912
|
bbox: { ...pb, y: cb.y, height: pb.y + pb.height - cb.y }
|
|
7419
7913
|
};
|
|
7420
|
-
} 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)) {
|
|
7914
|
+
} 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)) {
|
|
7421
7915
|
const merged = {
|
|
7422
7916
|
rows: prev.table.rows + curr.table.rows,
|
|
7423
7917
|
cols: prev.table.cols,
|
|
@@ -7432,6 +7926,12 @@ function mergeAdjacentTableBlocks(blocks) {
|
|
|
7432
7926
|
}
|
|
7433
7927
|
return result;
|
|
7434
7928
|
}
|
|
7929
|
+
function separateRepeatedHeadings(upper, lower) {
|
|
7930
|
+
const u = upper.table, d = lower.table, ub = upper.bbox, db = lower.bbox;
|
|
7931
|
+
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;
|
|
7932
|
+
const a = u.cells[0], b = d.cells[0], norm = (text) => text.replace(/<\/?u>|~~|\s+/g, "");
|
|
7933
|
+
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));
|
|
7934
|
+
}
|
|
7435
7935
|
function streamLines(items) {
|
|
7436
7936
|
if (items.some((i) => i.seq === void 0)) return groupByY([...items].sort((a, b) => b.y - a.y || a.x - b.x));
|
|
7437
7937
|
const lines = [];
|
|
@@ -7609,7 +8109,11 @@ export {
|
|
|
7609
8109
|
extractImageRegions,
|
|
7610
8110
|
filterHiddenText,
|
|
7611
8111
|
collapseEvenSpacing,
|
|
8112
|
+
computeBBox,
|
|
8113
|
+
dominantStyle,
|
|
7612
8114
|
normalizeItems,
|
|
8115
|
+
groupByY,
|
|
8116
|
+
mergeLineSimple,
|
|
7613
8117
|
WrapLexicon,
|
|
7614
8118
|
startsNewItem,
|
|
7615
8119
|
wrapJoiner,
|
|
@@ -7630,6 +8134,7 @@ export {
|
|
|
7630
8134
|
detectKoreanListBlocks,
|
|
7631
8135
|
removeHeaderFooterBlocks,
|
|
7632
8136
|
CLIP_TABLES,
|
|
8137
|
+
FRAME_TITLE_BLOCKS,
|
|
7633
8138
|
TABLE_COLXS,
|
|
7634
8139
|
TABLE_ROWYS,
|
|
7635
8140
|
TABLE_TAIL,
|
|
@@ -7643,7 +8148,11 @@ export {
|
|
|
7643
8148
|
trimTrailingEmptyTableCols,
|
|
7644
8149
|
NO_EDGES,
|
|
7645
8150
|
joinCellEdges,
|
|
8151
|
+
FRAME_READING_UNITS,
|
|
8152
|
+
recordFrameReadingUnit,
|
|
8153
|
+
restoreImageBullets,
|
|
8154
|
+
detectRightArrowRegions,
|
|
7646
8155
|
removeSideTabs,
|
|
7647
8156
|
extractPageBlocksWithLines
|
|
7648
8157
|
};
|
|
7649
|
-
//# sourceMappingURL=chunk-
|
|
8158
|
+
//# sourceMappingURL=chunk-KUUSP6OS.js.map
|