kordoc 4.18.3 → 4.18.5
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/{-WOKB25R2.js → -3HZVXMPX.js} +11 -11
- package/dist/{chunk-3FZGL3IL.js → chunk-235UD74F.js} +2 -2
- package/dist/{chunk-BJ6RYYXV.js → chunk-2CRD4Q76.js} +633 -77
- package/dist/chunk-2CRD4Q76.js.map +1 -0
- package/dist/{chunk-ZD5WNQNC.cjs → chunk-2UY3FG26.cjs} +16 -12
- package/dist/chunk-2UY3FG26.cjs.map +1 -0
- package/dist/{chunk-RSDUH4XF.js → chunk-33YID2RV.js} +2 -2
- package/dist/{chunk-W7P4GPOV.js → chunk-5SWBC7HH.js} +8 -4
- package/dist/chunk-5SWBC7HH.js.map +1 -0
- package/dist/chunk-6H25SXDI.js +11 -0
- package/dist/chunk-6H25SXDI.js.map +1 -0
- package/dist/{chunk-RDBTOE5X.js → chunk-BFFAHFG5.js} +2 -2
- package/dist/{chunk-AZQWESRH.js → chunk-BXSMPCT5.js} +2 -2
- package/dist/chunk-DC6CTQTK.js +9 -0
- package/dist/chunk-DC6CTQTK.js.map +1 -0
- package/dist/{chunk-NES5U4JK.js → chunk-DV7DQEYU.js} +3 -3
- package/dist/{chunk-SHRRD2TD.cjs → chunk-EFVBB45E.cjs} +2 -2
- package/dist/chunk-EFVBB45E.cjs.map +1 -0
- package/dist/{chunk-V4BKT65D.cjs → chunk-FBY574Q5.cjs} +3 -3
- package/dist/chunk-FBY574Q5.cjs.map +1 -0
- package/dist/{chunk-IXX3WHIE.js → chunk-FYJDRO4B.js} +7 -3
- package/dist/chunk-FYJDRO4B.js.map +1 -0
- package/dist/chunk-GS7T56RP.cjs.map +1 -1
- package/dist/{chunk-6GLTGOP6.js → chunk-GYUV53LM.js} +2 -2
- package/dist/{chunk-HZV52V2X.cjs → chunk-H4NV5KRM.cjs} +3 -3
- package/dist/chunk-H4NV5KRM.cjs.map +1 -0
- package/dist/chunk-J55UQC5H.cjs.map +1 -1
- package/dist/{chunk-ZN3LHNJG.js → chunk-KDKPSX4V.js} +28 -27
- package/dist/chunk-KDKPSX4V.js.map +1 -0
- package/dist/{chunk-KSJ7GKNQ.js → chunk-L2K45SOK.js} +2 -2
- package/dist/{chunk-2ZBLQVAS.cjs → chunk-MU7XW5KO.cjs} +6 -6
- package/dist/chunk-MU7XW5KO.cjs.map +1 -0
- package/dist/{chunk-BGOR5GCF.js → chunk-N7GNBY2F.js} +2 -2
- package/dist/{chunk-OOX2GZZ4.js → chunk-OFSMOXS4.js} +3 -3
- package/dist/{chunk-OOX2GZZ4.js.map → chunk-OFSMOXS4.js.map} +1 -1
- package/dist/{chunk-UVUKT3IQ.js → chunk-OLCBIT3I.js} +2 -2
- package/dist/{chunk-PSJLB3SZ.js → chunk-PQ2ER3VQ.js} +2 -2
- package/dist/{chunk-VGDTONTB.js → chunk-QAE2NVVO.js} +2 -2
- package/dist/chunk-TK3FDAEE.cjs +9 -0
- package/dist/chunk-TK3FDAEE.cjs.map +1 -0
- package/dist/{chunk-RRURZDEK.js → chunk-U4SBX3B5.js} +2 -2
- package/dist/{chunk-WN5YLP7H.cjs → chunk-XGIUYCXI.cjs} +749 -193
- package/dist/chunk-XGIUYCXI.cjs.map +1 -0
- package/dist/{chunk-2I2RTJJ5.js → chunk-XNIVXYIZ.js} +25 -35
- package/dist/chunk-XNIVXYIZ.js.map +1 -0
- package/dist/{chunk-W3RADOLO.js → chunk-XSCQQ74A.js} +2 -2
- package/dist/{chunk-5X7XWYR2.js → chunk-XTB2IERG.js} +2 -2
- package/dist/{chunk-J2A46VCA.js → chunk-YON3IOC3.js} +632 -76
- package/dist/chunk-YON3IOC3.js.map +1 -0
- package/dist/{chunk-CAN5P6N6.js → chunk-ZH5Y3JT6.js} +2 -2
- package/dist/chunks-ONP3Z3Z2.js +10 -0
- package/dist/cli.js +161 -116
- package/dist/cli.js.map +1 -1
- package/dist/{formula-BQ5RW5XD.cjs → formula-DTPPV22Y.cjs} +13 -9
- package/dist/formula-DTPPV22Y.cjs.map +1 -0
- package/dist/{formula-GPCOJJXN.js → formula-EJQ6SI4B.js} +7 -3
- package/dist/{formula-GPCOJJXN.js.map → formula-EJQ6SI4B.js.map} +1 -1
- package/dist/{formula-QZAOKPBX.js → formula-FFC3PUFZ.js} +8 -4
- package/dist/{formula-QZAOKPBX.js.map → formula-FFC3PUFZ.js.map} +1 -1
- package/dist/{image-ocr-VKIUBLBX.cjs → image-ocr-6JWCKPMH.cjs} +16 -15
- package/dist/image-ocr-6JWCKPMH.cjs.map +1 -0
- package/dist/{image-ocr-TWNNVTZS.js → image-ocr-7KNVEPI5.js} +10 -9
- package/dist/{image-ocr-TWNNVTZS.js.map → image-ocr-7KNVEPI5.js.map} +1 -1
- package/dist/{image-ocr-POCME5I4.js → image-ocr-RCNFR4ET.js} +7 -6
- package/dist/{image-ocr-POCME5I4.js.map → image-ocr-RCNFR4ET.js.map} +1 -1
- package/dist/index.cjs +338 -347
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +42 -51
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +22 -22
- package/dist/{model-bundle-THYUL7GG.js → model-bundle-NULKJLSH.js} +5 -5
- package/dist/{models-U22N4RXX.js → models-3TJW4OTW.js} +5 -5
- package/dist/page-range-QHHFTL7X.cjs.map +1 -1
- package/dist/{parser-SCXRLOW7.js → parser-2YBNBFSA.js} +242 -37
- package/dist/parser-2YBNBFSA.js.map +1 -0
- package/dist/{parser-JOMFOZLH.cjs → parser-NDX6SCHX.cjs} +449 -244
- package/dist/parser-NDX6SCHX.cjs.map +1 -0
- package/dist/{parser-NKP2NCSV.js → parser-UL67LFWP.js} +245 -40
- package/dist/parser-UL67LFWP.js.map +1 -0
- package/dist/pdf-ocr-E5MEIMJO.cjs +17 -0
- package/dist/pdf-ocr-E5MEIMJO.cjs.map +1 -0
- package/dist/pdf-ocr-QPBJBELT.js +20 -0
- package/dist/pdf-ocr-RQ6FN3GA.js +16 -0
- package/dist/{profile-io-UI3TZBYH.js → profile-io-YVU5YX57.js} +3 -3
- package/dist/{rasterize-XMBV5H2I.js → rasterize-JLMPBFFB.js} +3 -3
- package/dist/{redact-doc-7ZZMHDBO.js → redact-doc-PH37VIKN.js} +11 -11
- package/dist/{render-SWRTUDAV.js → render-E6K2EZZZ.js} +7 -7
- package/dist/seal-TJOKACHN.js +10 -0
- package/dist/{setup-43JJEEU7.js → setup-MRNDUCQQ.js} +3 -3
- package/dist/visual-T2YKRHW3.js +20 -0
- package/dist/{watch-NRATQ472.js → watch-ZGBBBTBH.js} +12 -12
- package/package.json +1 -1
- package/dist/chunk-2I2RTJJ5.js.map +0 -1
- package/dist/chunk-2ZBLQVAS.cjs.map +0 -1
- package/dist/chunk-BJ6RYYXV.js.map +0 -1
- package/dist/chunk-HZV52V2X.cjs.map +0 -1
- package/dist/chunk-IXX3WHIE.js.map +0 -1
- package/dist/chunk-J2A46VCA.js.map +0 -1
- package/dist/chunk-SHRRD2TD.cjs.map +0 -1
- package/dist/chunk-V4BKT65D.cjs.map +0 -1
- package/dist/chunk-W7P4GPOV.js.map +0 -1
- package/dist/chunk-WN5YLP7H.cjs.map +0 -1
- package/dist/chunk-ZD5WNQNC.cjs.map +0 -1
- package/dist/chunk-ZN3LHNJG.js.map +0 -1
- package/dist/chunks-OQDRDICD.js +0 -10
- package/dist/formula-BQ5RW5XD.cjs.map +0 -1
- package/dist/image-ocr-VKIUBLBX.cjs.map +0 -1
- package/dist/parser-JOMFOZLH.cjs.map +0 -1
- package/dist/parser-NKP2NCSV.js.map +0 -1
- package/dist/parser-SCXRLOW7.js.map +0 -1
- package/dist/pdf-ocr-NF4AY5MI.cjs +0 -16
- package/dist/pdf-ocr-NF4AY5MI.cjs.map +0 -1
- package/dist/pdf-ocr-OLII3WAG.js +0 -15
- package/dist/pdf-ocr-VJL7ON2Q.js +0 -19
- package/dist/seal-UKKJZHKE.js +0 -10
- package/dist/visual-D2563HCJ.js +0 -20
- /package/dist/{-WOKB25R2.js.map → -3HZVXMPX.js.map} +0 -0
- /package/dist/{chunk-3FZGL3IL.js.map → chunk-235UD74F.js.map} +0 -0
- /package/dist/{chunk-RSDUH4XF.js.map → chunk-33YID2RV.js.map} +0 -0
- /package/dist/{chunk-RDBTOE5X.js.map → chunk-BFFAHFG5.js.map} +0 -0
- /package/dist/{chunk-AZQWESRH.js.map → chunk-BXSMPCT5.js.map} +0 -0
- /package/dist/{chunk-NES5U4JK.js.map → chunk-DV7DQEYU.js.map} +0 -0
- /package/dist/{chunk-6GLTGOP6.js.map → chunk-GYUV53LM.js.map} +0 -0
- /package/dist/{chunk-KSJ7GKNQ.js.map → chunk-L2K45SOK.js.map} +0 -0
- /package/dist/{chunk-BGOR5GCF.js.map → chunk-N7GNBY2F.js.map} +0 -0
- /package/dist/{chunk-UVUKT3IQ.js.map → chunk-OLCBIT3I.js.map} +0 -0
- /package/dist/{chunk-PSJLB3SZ.js.map → chunk-PQ2ER3VQ.js.map} +0 -0
- /package/dist/{chunk-VGDTONTB.js.map → chunk-QAE2NVVO.js.map} +0 -0
- /package/dist/{chunk-RRURZDEK.js.map → chunk-U4SBX3B5.js.map} +0 -0
- /package/dist/{chunk-W3RADOLO.js.map → chunk-XSCQQ74A.js.map} +0 -0
- /package/dist/{chunk-5X7XWYR2.js.map → chunk-XTB2IERG.js.map} +0 -0
- /package/dist/{chunk-CAN5P6N6.js.map → chunk-ZH5Y3JT6.js.map} +0 -0
- /package/dist/{chunks-OQDRDICD.js.map → chunks-ONP3Z3Z2.js.map} +0 -0
- /package/dist/{model-bundle-THYUL7GG.js.map → model-bundle-NULKJLSH.js.map} +0 -0
- /package/dist/{models-U22N4RXX.js.map → models-3TJW4OTW.js.map} +0 -0
- /package/dist/{pdf-ocr-OLII3WAG.js.map → pdf-ocr-QPBJBELT.js.map} +0 -0
- /package/dist/{pdf-ocr-VJL7ON2Q.js.map → pdf-ocr-RQ6FN3GA.js.map} +0 -0
- /package/dist/{profile-io-UI3TZBYH.js.map → profile-io-YVU5YX57.js.map} +0 -0
- /package/dist/{rasterize-XMBV5H2I.js.map → rasterize-JLMPBFFB.js.map} +0 -0
- /package/dist/{redact-doc-7ZZMHDBO.js.map → redact-doc-PH37VIKN.js.map} +0 -0
- /package/dist/{render-SWRTUDAV.js.map → render-E6K2EZZZ.js.map} +0 -0
- /package/dist/{seal-UKKJZHKE.js.map → seal-TJOKACHN.js.map} +0 -0
- /package/dist/{setup-43JJEEU7.js.map → setup-MRNDUCQQ.js.map} +0 -0
- /package/dist/{visual-D2563HCJ.js.map → visual-T2YKRHW3.js.map} +0 -0
- /package/dist/{watch-NRATQ472.js.map → watch-ZGBBBTBH.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-PQ2ER3VQ.js";
|
|
8
8
|
import {
|
|
9
9
|
ensureModelsIn,
|
|
10
10
|
getModelsDir
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-235UD74F.js";
|
|
12
12
|
import {
|
|
13
13
|
safeMax,
|
|
14
14
|
safeMin
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-ZH5Y3JT6.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,15 +4898,39 @@ 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;
|
|
4639
4904
|
if (col.filter((g) => /[\p{L}\p{N}]/u.test(g.text)).length < col.length * 0.8) continue;
|
|
4640
4905
|
col.sort((a, b) => b.y - a.y);
|
|
4641
4906
|
const fs = [...col.map((i) => i.fontSize)].sort((a, b) => a - b)[col.length >> 1];
|
|
4642
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);
|
|
4643
4930
|
const members = new Set(col);
|
|
4644
4931
|
const top = col[0].y + fs, bottom = col[col.length - 1].y - fs;
|
|
4645
|
-
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;
|
|
4646
4934
|
const left = Math.min(...col.map((i) => i.x)), right = Math.max(...col.map((i) => i.x + i.w));
|
|
4647
4935
|
const rest = items.filter((i) => !members.has(i) && i.text.trim());
|
|
4648
4936
|
const outside = rest.every((i) => i.x >= right + fs) || rest.every((i) => i.x + i.w <= left - fs);
|
|
@@ -5903,13 +6191,44 @@ var UNDER_SPAN_OVERLAP_RATIO = 0.8;
|
|
|
5903
6191
|
var UNDER_BOX_PAIR_MIN_EM = 0.5;
|
|
5904
6192
|
var UNDER_BOX_PAIR_MAX_EM = 2.2;
|
|
5905
6193
|
var UNDER_BOX_PAIR_OVERLAP = 0.8;
|
|
5906
|
-
function markUnderlineItems(items, horizontals, verticals) {
|
|
6194
|
+
function markUnderlineItems(items, horizontals, verticals, nonRules) {
|
|
5907
6195
|
const underlines = [];
|
|
6196
|
+
if (nonRules?.size) horizontals = horizontals.filter((line) => !nonRules.has(line));
|
|
5908
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
|
+
};
|
|
5909
6226
|
for (const line of horizontals) {
|
|
5910
6227
|
if (line.lineWidth > UNDER_MAX_THICKNESS) continue;
|
|
5911
6228
|
const enclosed = insideTallCell(line, verticals, 0);
|
|
5912
|
-
|
|
6229
|
+
const repeated = isRepeatedSpanRule(line, horizontals);
|
|
6230
|
+
const textSeries = repeated && paragraphUnderline(line);
|
|
6231
|
+
if (!enclosed && (touchesVertical(line, verticals) || repeated && !textSeries)) continue;
|
|
5913
6232
|
const matches = [];
|
|
5914
6233
|
for (const item of items) {
|
|
5915
6234
|
const h = item.h > 0 ? item.h : item.fontSize;
|
|
@@ -5929,11 +6248,11 @@ function markUnderlineItems(items, horizontals, verticals) {
|
|
|
5929
6248
|
covered += m.w;
|
|
5930
6249
|
}
|
|
5931
6250
|
const inset = enclosed && insideTallCell(line, verticals, maxH);
|
|
5932
|
-
if (enclosed && !inset && (touchesVertical(line, verticals) ||
|
|
6251
|
+
if (enclosed && !inset && (touchesVertical(line, verticals) || repeated && !textSeries)) continue;
|
|
5933
6252
|
const pad = Math.max(maxH * UNDER_OWNER_PAD_EM, UNDER_OWNER_PAD_MIN_PT);
|
|
5934
6253
|
if (line.x1 < x1 - pad || line.x2 > x2 + pad) continue;
|
|
5935
6254
|
if (covered < (line.x2 - line.x1) * UNDER_MIN_COVERAGE) continue;
|
|
5936
|
-
if (hasBoxTopPair(line, maxH, horizontals, inset ? items : void 0)) continue;
|
|
6255
|
+
if (hasBoxTopPair(line, maxH, horizontals, inset || textSeries || tightlyOwned(line) ? items : void 0)) continue;
|
|
5937
6256
|
matches.sort((a, b) => a.x - b.x);
|
|
5938
6257
|
let hole = false;
|
|
5939
6258
|
for (let i = 1; i < matches.length; i++) {
|
|
@@ -5964,6 +6283,7 @@ function touchesVertical(line, verticals) {
|
|
|
5964
6283
|
for (const v of verticals) {
|
|
5965
6284
|
if (v.x1 < line.x1 - UNDER_GRID_EPS || v.x1 > line.x2 + UNDER_GRID_EPS) continue;
|
|
5966
6285
|
const lo = Math.min(v.y1, v.y2), hi = Math.max(v.y1, v.y2);
|
|
6286
|
+
if (hi - lo <= UNDER_GRID_EPS) continue;
|
|
5967
6287
|
if (lo <= line.y1 + UNDER_GRID_EPS && hi >= line.y1 - UNDER_GRID_EPS) return true;
|
|
5968
6288
|
}
|
|
5969
6289
|
return false;
|
|
@@ -6173,6 +6493,57 @@ function isPageFrameGrid(grid, cells, pageWidth, pageHeight, items = []) {
|
|
|
6173
6493
|
return inner.length === 0 || crossing >= 1 && crossing >= inBig.length * 0.01;
|
|
6174
6494
|
}
|
|
6175
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
|
+
|
|
6176
6547
|
// src/pdf/open-table-ends.ts
|
|
6177
6548
|
var ALIGN_TOL = 3;
|
|
6178
6549
|
var MIN_RULES = 3;
|
|
@@ -6508,6 +6879,189 @@ function detectTextBoxTables(boxes, items, pageNum) {
|
|
|
6508
6879
|
}];
|
|
6509
6880
|
}
|
|
6510
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 takeFrameSpanningText(items, cutX, pageNum, lex) {
|
|
6905
|
+
let minX = Infinity, maxR = -Infinity;
|
|
6906
|
+
for (const item of items) {
|
|
6907
|
+
minX = Math.min(minX, item.x);
|
|
6908
|
+
maxR = Math.max(maxR, item.x + item.w);
|
|
6909
|
+
}
|
|
6910
|
+
const span = maxR - minX;
|
|
6911
|
+
const rows = groupByY([...items].sort((a, b) => b.y - a.y || a.x - b.x)).map((line) => {
|
|
6912
|
+
const runs = [];
|
|
6913
|
+
for (const item of [...line].sort((a, b) => a.x - b.x)) {
|
|
6914
|
+
const run = runs[runs.length - 1], prev = run?.[run.length - 1];
|
|
6915
|
+
if (prev && item.x - (prev.x + prev.w) <= Math.max(prev.fontSize, item.fontSize) * 0.6) run.push(item);
|
|
6916
|
+
else runs.push([item]);
|
|
6917
|
+
}
|
|
6918
|
+
return runs;
|
|
6919
|
+
});
|
|
6920
|
+
const taken = /* @__PURE__ */ new Set(), blocks = [];
|
|
6921
|
+
for (let r = 0; r < rows.length; r++) for (const run of rows[r]) {
|
|
6922
|
+
if (taken.has(run[0]) || run[0].x >= cutX || Math.max(...run.map((i) => i.x + i.w)) <= cutX) continue;
|
|
6923
|
+
const lines = [run], fs = Math.max(...run.map((i) => i.fontSize));
|
|
6924
|
+
const left = run[0].x, right = Math.max(...run.map((i) => i.x + i.w));
|
|
6925
|
+
if (right - left < span * 0.75) continue;
|
|
6926
|
+
let prevY = run[0].y;
|
|
6927
|
+
for (let next = r + 1; next < rows.length && rows[next].length === 1; next++) {
|
|
6928
|
+
const tail = rows[next][0], y = tail[0].y;
|
|
6929
|
+
if (taken.has(tail[0]) || prevY - y > fs * 1.8 || tail[0].x < left - 1 || tail[0].x > left + fs * 2 || tail.some((i) => Math.abs(i.fontSize - fs) > fs * 0.15) || Math.max(...tail.map((i) => i.x + i.w)) > right + 1) break;
|
|
6930
|
+
lines.push(tail);
|
|
6931
|
+
prevY = y;
|
|
6932
|
+
}
|
|
6933
|
+
for (const line of lines) for (const item of line) taken.add(item);
|
|
6934
|
+
pushLineParagraphs(blocks, mergeSuperscriptLines(lines), pageNum, lex);
|
|
6935
|
+
}
|
|
6936
|
+
let keep = 0;
|
|
6937
|
+
for (const item of items) if (!taken.has(item)) items[keep++] = item;
|
|
6938
|
+
items.length = keep;
|
|
6939
|
+
return blocks;
|
|
6940
|
+
}
|
|
6941
|
+
function frameColumnTextBands(items, spanning, cutX) {
|
|
6942
|
+
const tops = spanning.filter((b) => b.bbox).map((b) => b.bbox.y + b.bbox.height).sort((a, b) => b - a);
|
|
6943
|
+
const bands = /* @__PURE__ */ new Map();
|
|
6944
|
+
for (const item of items) {
|
|
6945
|
+
let band = 0;
|
|
6946
|
+
while (band < tops.length && tops[band] > item.y + item.h) band++;
|
|
6947
|
+
const sides = bands.get(band) ?? [[], [], []];
|
|
6948
|
+
sides[item.x + item.w <= cutX ? 0 : item.x >= cutX ? 2 : 1].push(item);
|
|
6949
|
+
bands.set(band, sides);
|
|
6950
|
+
}
|
|
6951
|
+
return [...bands].sort((a, b) => a[0] - b[0]).flatMap(([, sides]) => sides.filter((side) => side.length));
|
|
6952
|
+
}
|
|
6953
|
+
function groupFrameParagraphUnits(units, frames) {
|
|
6954
|
+
const source = /* @__PURE__ */ new Map();
|
|
6955
|
+
for (const unit of units) for (const block of unit) source.set(block, unit);
|
|
6956
|
+
const members = /* @__PURE__ */ new Map(), emitted = /* @__PURE__ */ new Set();
|
|
6957
|
+
for (const frame of frames) {
|
|
6958
|
+
if (frame.length < 2 || frame.some((block) => block.type !== "paragraph" || source.get(block)?.length !== 1)) continue;
|
|
6959
|
+
for (const block of frame) members.set(block, frame);
|
|
6960
|
+
}
|
|
6961
|
+
const out = [];
|
|
6962
|
+
for (const unit of units) {
|
|
6963
|
+
const frame = unit.length === 1 ? members.get(unit[0]) : void 0;
|
|
6964
|
+
if (!frame) out.push(unit);
|
|
6965
|
+
else if (!emitted.has(frame)) {
|
|
6966
|
+
out.push(frame);
|
|
6967
|
+
emitted.add(frame);
|
|
6968
|
+
}
|
|
6969
|
+
}
|
|
6970
|
+
for (const unit of out) {
|
|
6971
|
+
if (unit.length < 2 || FRAME_READING_UNITS.get(unit[0])?.blocks === unit) continue;
|
|
6972
|
+
const bs = unit.map((b) => b.bbox).filter((b) => !!b);
|
|
6973
|
+
if (bs.length !== unit.length) continue;
|
|
6974
|
+
const x = Math.min(...bs.map((b) => b.x)), y = Math.min(...bs.map((b) => b.y));
|
|
6975
|
+
recordFrameReadingUnit(unit, {
|
|
6976
|
+
page: bs[0].page,
|
|
6977
|
+
x,
|
|
6978
|
+
y,
|
|
6979
|
+
width: Math.max(...bs.map((b) => b.x + b.width)) - x,
|
|
6980
|
+
height: Math.max(...bs.map((b) => b.y + b.height)) - y
|
|
6981
|
+
});
|
|
6982
|
+
}
|
|
6983
|
+
return out;
|
|
6984
|
+
}
|
|
6985
|
+
function recordFrameTitle(table, source, pageNum) {
|
|
6986
|
+
if (!CLIP_TABLES.has(table) || table.rows !== 1 || table.cols !== 3 || source.length < 2) return;
|
|
6987
|
+
const cells = table.cells[0];
|
|
6988
|
+
if (cells.length !== 3 || cells.some((c) => c.colSpan !== 1 || c.rowSpan !== 1 || c.blocks?.length || c.text.includes("\n"))) return;
|
|
6989
|
+
const [label, spacer, title] = cells;
|
|
6990
|
+
if (!/^(?:붙임|별첨|첨부|부록)\s*\d{1,3}$/.test(label.text.trim()) || spacer.text.trim() || !title.text.trim()) return;
|
|
6991
|
+
if (cells.some((c) => {
|
|
6992
|
+
const e = CELL_EDGES.get(c);
|
|
6993
|
+
return !e || e.t || e.b || e.l || e.r;
|
|
6994
|
+
})) return;
|
|
6995
|
+
const xs = TABLE_COLXS.get(table), style = dominantStyle(source), fs = style?.fontSize ?? 0;
|
|
6996
|
+
if (!xs || xs.length !== 4 || fs <= 0) return;
|
|
6997
|
+
const width = xs[3] - xs[0], gap = xs[2] - xs[1];
|
|
6998
|
+
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;
|
|
6999
|
+
if (source.some((i) => i.fontName !== source[0].fontName || Math.abs(i.fontSize - fs) > fs * 0.15)) return;
|
|
7000
|
+
if (groupByY([...source].sort((a, b) => b.y - a.y)).length !== 1) return;
|
|
7001
|
+
FRAME_TITLE_BLOCKS.set(table, {
|
|
7002
|
+
type: "paragraph",
|
|
7003
|
+
text: `${label.text.trim()} ${title.text.trim()}`,
|
|
7004
|
+
pageNumber: pageNum,
|
|
7005
|
+
bbox: computeBBox(source, pageNum),
|
|
7006
|
+
style
|
|
7007
|
+
});
|
|
7008
|
+
}
|
|
7009
|
+
var FRAME_RECT_TOL = 1.5;
|
|
7010
|
+
function takePendingNested(pending, cellBox, clipCell) {
|
|
7011
|
+
const out = [];
|
|
7012
|
+
for (let i = pending.length - 1; i >= 0; i--) {
|
|
7013
|
+
const p = pending[i].parent;
|
|
7014
|
+
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) {
|
|
7015
|
+
out.push(pending[i].block);
|
|
7016
|
+
pending.splice(i, 1);
|
|
7017
|
+
}
|
|
7018
|
+
}
|
|
7019
|
+
return out;
|
|
7020
|
+
}
|
|
7021
|
+
function buildFrameCellBlocks(cellItems, nested, pageNum, lex) {
|
|
7022
|
+
const tables = [...nested].sort((a, b) => b.bbox.y + b.bbox.height - (a.bbox.y + a.bbox.height));
|
|
7023
|
+
const blocks = [];
|
|
7024
|
+
let rest = [...cellItems];
|
|
7025
|
+
const pushParagraphs = (items) => {
|
|
7026
|
+
if (items.length === 0) return;
|
|
7027
|
+
const source = items.map((it) => ({ ...it, isHidden: false })).sort((a, b) => b.y - a.y || a.x - b.x);
|
|
7028
|
+
const paragraphs = [];
|
|
7029
|
+
pushLineParagraphs(paragraphs, mergeSuperscriptLines(groupByY(source)), pageNum, lex);
|
|
7030
|
+
for (const block of paragraphs) {
|
|
7031
|
+
block.text = cleanCellText(block.text ?? "");
|
|
7032
|
+
if (block.text) blocks.push(block);
|
|
7033
|
+
}
|
|
7034
|
+
};
|
|
7035
|
+
for (const tb of tables) {
|
|
7036
|
+
const bottom = tb.bbox.y;
|
|
7037
|
+
pushParagraphs(rest.filter((it) => it.y >= bottom));
|
|
7038
|
+
rest = rest.filter((it) => it.y < bottom);
|
|
7039
|
+
blocks.push(tb);
|
|
7040
|
+
}
|
|
7041
|
+
pushParagraphs(rest);
|
|
7042
|
+
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");
|
|
7043
|
+
return { blocks, text };
|
|
7044
|
+
}
|
|
7045
|
+
|
|
7046
|
+
// src/pdf/nested-shaded-headers.ts
|
|
7047
|
+
function extendNestedShadedHeaders(clipGrids, lineGrids, horizontals, verticals, fills) {
|
|
7048
|
+
const near = (a, b) => Math.abs(a - b) <= 1.5;
|
|
7049
|
+
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;
|
|
7050
|
+
const extended = [];
|
|
7051
|
+
for (let i = 0; i < clipGrids.length; i++) {
|
|
7052
|
+
const c = clipGrids[i], parent = c.clipParent;
|
|
7053
|
+
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;
|
|
7054
|
+
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;
|
|
7055
|
+
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;
|
|
7056
|
+
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)));
|
|
7057
|
+
if (!host) continue;
|
|
7058
|
+
const grid = { ...host, clipParent: parent, cells: extractCells(host, horizontals, verticals) };
|
|
7059
|
+
clipGrids[i] = grid;
|
|
7060
|
+
extended.push(grid);
|
|
7061
|
+
}
|
|
7062
|
+
return extended;
|
|
7063
|
+
}
|
|
7064
|
+
|
|
6511
7065
|
// src/pdf/page-regions.ts
|
|
6512
7066
|
function splitTwoColumnProse(items, cutX) {
|
|
6513
7067
|
const left = [];
|
|
@@ -6835,7 +7389,7 @@ function figureColumnBands(items, figures) {
|
|
|
6835
7389
|
}
|
|
6836
7390
|
|
|
6837
7391
|
// src/pdf/page-blocks.ts
|
|
6838
|
-
function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeight, extraLines, detectTables = true, carry, lexicon) {
|
|
7392
|
+
function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeight, extraLines, detectTables = true, carry, lexicon, verifiedRightArrows = []) {
|
|
6839
7393
|
if (items.length === 0) {
|
|
6840
7394
|
if (carry) carry.clip = void 0;
|
|
6841
7395
|
return [];
|
|
@@ -6843,7 +7397,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
6843
7397
|
const tab = sideTabGlyphs(items);
|
|
6844
7398
|
if (tab.size) {
|
|
6845
7399
|
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]) }));
|
|
6846
|
-
return [...glyphs, ...extractPageBlocksWithLines(items.filter((i) => !tab.has(i)), pageNum, opList, pageWidth, pageHeight, extraLines, detectTables, carry, lexicon)];
|
|
7400
|
+
return [...glyphs, ...extractPageBlocksWithLines(items.filter((i) => !tab.has(i)), pageNum, opList, pageWidth, pageHeight, extraLines, detectTables, carry, lexicon, verifiedRightArrows)];
|
|
6847
7401
|
}
|
|
6848
7402
|
const lex = lexicon ?? new WrapLexicon();
|
|
6849
7403
|
for (const line of streamLines(items)) lex.addLine(mergeLineSimple(line));
|
|
@@ -6871,19 +7425,28 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
6871
7425
|
}
|
|
6872
7426
|
;
|
|
6873
7427
|
({ horizontals, verticals } = filterPageBorderLines(horizontals, verticals, pageWidth, pageHeight));
|
|
6874
|
-
({ horizontals, verticals } = preprocessLines(horizontals, verticals));
|
|
7428
|
+
({ horizontals, verticals } = preprocessLines(horizontals, verticals, extracted.nonRules));
|
|
7429
|
+
markStrikethroughItems(items, horizontals);
|
|
7430
|
+
wrapStrikethroughRuns(items);
|
|
7431
|
+
const underlines = new Set(markUnderlineItems(items, horizontals, verticals, extracted.nonRules));
|
|
7432
|
+
if (underlines.size) horizontals = horizontals.filter((l) => !underlines.has(l));
|
|
7433
|
+
wrapUnderlineRuns(items);
|
|
6875
7434
|
horizontals = closeOpenTableEnds(horizontals, verticals, items.every((it) => it.seq !== void 0));
|
|
6876
7435
|
verticals = closeOpenTableEdges(horizontals, verticals);
|
|
6877
7436
|
verticals = bridgeSplitColumnVerticals(horizontals, verticals);
|
|
6878
7437
|
if (detectTables && clipGrids.length === 0) verticals = bridgeSkippedRowVerticals(horizontals, verticals, items);
|
|
6879
7438
|
if (detectTables && clipGrids.length === 0) ({ horizontals, verticals } = extendHeaderBoxRows(horizontals, verticals, items));
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
const underlines = new Set(markUnderlineItems(items, horizontals, verticals));
|
|
6883
|
-
if (underlines.size) horizontals = horizontals.filter((l) => !underlines.has(l));
|
|
6884
|
-
wrapUnderlineRuns(items);
|
|
7439
|
+
const shadedEdges = detectTables ? closeShadedTableEdges(clipGrids, horizontals, verticals, extracted.fillRects) : void 0;
|
|
7440
|
+
if (shadedEdges) ({ horizontals, verticals } = shadedEdges);
|
|
6885
7441
|
const lineGrids = detectTables ? buildTableGrids(horizontals, verticals) : [];
|
|
7442
|
+
if (shadedEdges) nestRestoredShadedGrids(lineGrids, shadedEdges.restored, horizontals, verticals);
|
|
6886
7443
|
const tableClipGrids = dropHeadBandClipGrids(dropInsetClipGrids(dropShadingClipGrids(clipGrids, lineGrids, extracted.fillRects, verticals), lineGrids), lineGrids);
|
|
7444
|
+
recordClipCellEdges(
|
|
7445
|
+
extendNestedShadedHeaders(tableClipGrids, lineGrids, horizontals, verticals, extracted.fillRects),
|
|
7446
|
+
extracted.horizontals.concat(extracted.shortH),
|
|
7447
|
+
extracted.verticals.concat(extracted.shortV),
|
|
7448
|
+
extracted.nonRules
|
|
7449
|
+
);
|
|
6887
7450
|
const grids = [...tableClipGrids, ...dropGridsInside(lineGrids, tableClipGrids, clipResult.containers)];
|
|
6888
7451
|
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 }));
|
|
6889
7452
|
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) {
|
|
@@ -6893,7 +7456,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
6893
7456
|
if (detectTables && clipGrids.length === 0 && ruled.length === 0 && lineGrids.length === 0) ruled.push(...detectTextBoxTables(extracted.hiddenBoxes, items, pageNum));
|
|
6894
7457
|
if (ruled.length > 0) {
|
|
6895
7458
|
const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray).filter((r) => r.x2 - r.x1 >= 8 && r.y2 - r.y1 >= 8);
|
|
6896
|
-
return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, ruled, rawRules);
|
|
7459
|
+
return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, ruled, rawRules, verifiedRightArrows);
|
|
6897
7460
|
}
|
|
6898
7461
|
if (detectTables && stackedTableBands(items)) {
|
|
6899
7462
|
return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures());
|
|
@@ -6904,7 +7467,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
6904
7467
|
}
|
|
6905
7468
|
if (grids.length > 0) {
|
|
6906
7469
|
const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray).filter((r) => r.x2 - r.x1 >= 8 && r.y2 - r.y1 >= 8);
|
|
6907
|
-
return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, [], rawRules);
|
|
7470
|
+
return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, [], rawRules, verifiedRightArrows);
|
|
6908
7471
|
}
|
|
6909
7472
|
return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures());
|
|
6910
7473
|
}
|
|
@@ -7009,42 +7572,10 @@ function isSparseProseGrid(table) {
|
|
|
7009
7572
|
const prose = filled.filter((t) => t.length >= 60 && /[.!?。]/.test(t)).reduce((n, t) => n + t.length, 0);
|
|
7010
7573
|
return prose >= chars * 0.6;
|
|
7011
7574
|
}
|
|
7012
|
-
|
|
7013
|
-
function takePendingNested(pending, cellBox, clipCell) {
|
|
7014
|
-
const out = [];
|
|
7015
|
-
for (let i = pending.length - 1; i >= 0; i--) {
|
|
7016
|
-
const p = pending[i].parent;
|
|
7017
|
-
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) {
|
|
7018
|
-
out.push(pending[i].block);
|
|
7019
|
-
pending.splice(i, 1);
|
|
7020
|
-
}
|
|
7021
|
-
}
|
|
7022
|
-
return out;
|
|
7023
|
-
}
|
|
7024
|
-
function buildFrameCellBlocks(cellItems, nested, pageNum, wrap) {
|
|
7025
|
-
const tables = [...nested].sort((a, b) => b.bbox.y + b.bbox.height - (a.bbox.y + a.bbox.height));
|
|
7026
|
-
const blocks = [];
|
|
7027
|
-
let rest = [...cellItems];
|
|
7028
|
-
const pushParagraphs = (items) => {
|
|
7029
|
-
if (items.length === 0) return;
|
|
7030
|
-
for (const line of cleanCellText(cellTextToString(items, wrap)).split("\n")) {
|
|
7031
|
-
const t = line.trim();
|
|
7032
|
-
if (t) blocks.push({ type: "paragraph", text: t, pageNumber: pageNum });
|
|
7033
|
-
}
|
|
7034
|
-
};
|
|
7035
|
-
for (const tb of tables) {
|
|
7036
|
-
const bottom = tb.bbox.y;
|
|
7037
|
-
pushParagraphs(rest.filter((it) => it.y >= bottom));
|
|
7038
|
-
rest = rest.filter((it) => it.y < bottom);
|
|
7039
|
-
blocks.push(tb);
|
|
7040
|
-
}
|
|
7041
|
-
pushParagraphs(rest);
|
|
7042
|
-
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");
|
|
7043
|
-
return { blocks, text };
|
|
7044
|
-
}
|
|
7045
|
-
function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions = [], lex, ruled = [], rawRules = horizontals) {
|
|
7575
|
+
function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions = [], lex, ruled = [], rawRules = horizontals, verifiedRightArrows = []) {
|
|
7046
7576
|
const ocrPage = items.length > 0 && items.every((i) => i.fontName === "ocr");
|
|
7047
7577
|
const blocks = [];
|
|
7578
|
+
const frameParagraphUnits = [];
|
|
7048
7579
|
const usedItems = /* @__PURE__ */ new Set();
|
|
7049
7580
|
for (const r of ruled) {
|
|
7050
7581
|
for (const it of r.items) usedItems.add(it);
|
|
@@ -7101,7 +7632,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7101
7632
|
const nested = pendingNested.length ? takePendingNested(pendingNested, cell.bbox, !!grid.cells) : [];
|
|
7102
7633
|
if (nested.length > 0) {
|
|
7103
7634
|
nestedAttached = true;
|
|
7104
|
-
const built = buildFrameCellBlocks(cellItems, nested, pageNum,
|
|
7635
|
+
const built = buildFrameCellBlocks(cellItems, nested, pageNum, lex);
|
|
7105
7636
|
irGrid[cell.row][cell.col] = { text: built.text, colSpan: cell.colSpan, rowSpan: cell.rowSpan, blocks: built.blocks };
|
|
7106
7637
|
if (cellItems.length) recordCellLines(irGrid[cell.row][cell.col], cellItems);
|
|
7107
7638
|
takeClipCellEdges(cell, irGrid[cell.row][cell.col]);
|
|
@@ -7112,6 +7643,9 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7112
7643
|
colSpan: cell.colSpan,
|
|
7113
7644
|
rowSpan: cell.rowSpan
|
|
7114
7645
|
};
|
|
7646
|
+
if (numRows === 1 && numCols === 1 && cellItems.length) {
|
|
7647
|
+
irGrid[cell.row][cell.col].blocks = buildFrameCellBlocks(cellItems, [], pageNum, lex).blocks;
|
|
7648
|
+
}
|
|
7115
7649
|
const b = cell.bbox;
|
|
7116
7650
|
const isBackdrop = (r) => r.x1 <= b.x1 + 1 && r.x2 >= b.x2 - 1 && r.y1 <= b.y1 + 1 && r.y2 >= b.y2 - 1;
|
|
7117
7651
|
if (imageRegions.some((r) => {
|
|
@@ -7147,7 +7681,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7147
7681
|
}
|
|
7148
7682
|
if (!rebuiltUsed && attachUnitRow(items, grid, finalGrid, numCols, usedItems)) finalRows++;
|
|
7149
7683
|
let semanticOneColumn = false;
|
|
7150
|
-
if (!grid.cells && numCols === 1 && numGridRows >= 2) {
|
|
7684
|
+
if (!grid.cells && !nestedAttached && numCols === 1 && numGridRows >= 2) {
|
|
7151
7685
|
const populatedRows = finalGrid.filter((row) => row[0]?.text.trim());
|
|
7152
7686
|
if (populatedRows.length >= 4) {
|
|
7153
7687
|
const fontSizes = tableItems.map((item) => item.fontSize).filter((size) => size > 0).sort((a, b) => a - b);
|
|
@@ -7200,6 +7734,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7200
7734
|
recordRowRules(irTable, grid.cells, grid.bbox, rawRules);
|
|
7201
7735
|
}
|
|
7202
7736
|
TABLE_COLXS.set(irTable, grid.colXs);
|
|
7737
|
+
if (grid.cells) recordFrameTitle(irTable, tableItems, pageNum);
|
|
7203
7738
|
if (grid.cells && finalRows === numRows) TABLE_ROWYS.set(irTable, grid.rowYs);
|
|
7204
7739
|
if (grid.continues) CONT_PARTS.set(irTable, grid.continues);
|
|
7205
7740
|
const hasContent = finalGrid.some((row) => row.some((cell) => cell.text.trim() !== ""));
|
|
@@ -7251,7 +7786,14 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7251
7786
|
continue;
|
|
7252
7787
|
}
|
|
7253
7788
|
}
|
|
7254
|
-
if (!grid.cells && shouldDemoteTable(irTable)) {
|
|
7789
|
+
if (!grid.cells && !nestedAttached && shouldDemoteTable(irTable)) {
|
|
7790
|
+
const paragraphs = numRows === 1 && numCols === 1 ? irTable.cells[0]?.[0]?.blocks : void 0;
|
|
7791
|
+
if (paragraphs?.length) {
|
|
7792
|
+
blocks.push(...paragraphs);
|
|
7793
|
+
frameParagraphUnits.push(paragraphs);
|
|
7794
|
+
recordFrameReadingUnit(paragraphs, tableBbox);
|
|
7795
|
+
continue;
|
|
7796
|
+
}
|
|
7255
7797
|
const demoted = demoteTableToText(irTable);
|
|
7256
7798
|
if (demoted) {
|
|
7257
7799
|
const text = numGridRows === 1 ? "\n" + demoted + "\n" : demoted;
|
|
@@ -7305,9 +7847,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7305
7847
|
}
|
|
7306
7848
|
{
|
|
7307
7849
|
const rects = remaining.map((i) => ({ x: i.x, y: i.y, w: i.w, h: i.h > 0 ? i.h : i.fontSize }));
|
|
7308
|
-
for (const b of blocks) {
|
|
7309
|
-
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 });
|
|
7310
|
-
}
|
|
7850
|
+
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 });
|
|
7311
7851
|
gutterX = detectColumnGutter(rects) ?? findRuledColumnDivider(
|
|
7312
7852
|
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 })),
|
|
7313
7853
|
horizontals,
|
|
@@ -7320,14 +7860,15 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7320
7860
|
if (remaining.length > 0) {
|
|
7321
7861
|
if (gutterX !== null) {
|
|
7322
7862
|
const gx = gutterX;
|
|
7863
|
+
const spanning = detectListBlocks(takeFrameSpanningText(remaining, gx, pageNum, lex));
|
|
7864
|
+
for (const block of spanning) {
|
|
7865
|
+
finalTextBlocks.push(block);
|
|
7866
|
+
groupSizes.push(1);
|
|
7867
|
+
}
|
|
7323
7868
|
const allY = remaining.map((i) => i.y);
|
|
7324
7869
|
const pageH = safeMax(allY) - safeMin(allY);
|
|
7325
7870
|
const gapThreshold = Math.max(15, pageH * 0.03);
|
|
7326
|
-
const sides =
|
|
7327
|
-
remaining.filter((i) => i.x + i.w <= gx),
|
|
7328
|
-
remaining.filter((i) => i.x < gx && i.x + i.w > gx),
|
|
7329
|
-
remaining.filter((i) => i.x >= gx)
|
|
7330
|
-
];
|
|
7871
|
+
const sides = frameColumnTextBands(remaining, spanning, gx);
|
|
7331
7872
|
const textBlocks = [];
|
|
7332
7873
|
for (const side of sides) {
|
|
7333
7874
|
if (side.length === 0) continue;
|
|
@@ -7338,7 +7879,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7338
7879
|
groupSizes.push(groupBlocks.length);
|
|
7339
7880
|
}
|
|
7340
7881
|
}
|
|
7341
|
-
finalTextBlocks
|
|
7882
|
+
finalTextBlocks.push(...detectListBlocks(textBlocks));
|
|
7342
7883
|
} else {
|
|
7343
7884
|
const allY = remaining.map((i) => i.y);
|
|
7344
7885
|
const pageH = safeMax(allY) - safeMin(allY);
|
|
@@ -7354,7 +7895,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
7354
7895
|
finalTextBlocks = detectListBlocks(textBlocks);
|
|
7355
7896
|
}
|
|
7356
7897
|
}
|
|
7357
|
-
const units =
|
|
7898
|
+
const units = groupFrameParagraphUnits(groupFlowBoxUnits(blocks, grids, horizontals, verticals, verifiedRightArrows), frameParagraphUnits);
|
|
7358
7899
|
let off = 0;
|
|
7359
7900
|
for (const size of groupSizes) {
|
|
7360
7901
|
const unit = finalTextBlocks.slice(off, off + size);
|
|
@@ -7493,7 +8034,7 @@ function mergeAdjacentTableBlocks(blocks) {
|
|
|
7493
8034
|
table: merged,
|
|
7494
8035
|
bbox: { ...pb, y: cb.y, height: pb.y + pb.height - cb.y }
|
|
7495
8036
|
};
|
|
7496
|
-
} 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)) {
|
|
8037
|
+
} 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)) {
|
|
7497
8038
|
const merged = {
|
|
7498
8039
|
rows: prev.table.rows + curr.table.rows,
|
|
7499
8040
|
cols: prev.table.cols,
|
|
@@ -7508,6 +8049,12 @@ function mergeAdjacentTableBlocks(blocks) {
|
|
|
7508
8049
|
}
|
|
7509
8050
|
return result;
|
|
7510
8051
|
}
|
|
8052
|
+
function separateRepeatedHeadings(upper, lower) {
|
|
8053
|
+
const u = upper.table, d = lower.table, ub = upper.bbox, db = lower.bbox;
|
|
8054
|
+
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;
|
|
8055
|
+
const a = u.cells[0], b = d.cells[0], norm = (text) => text.replace(/<\/?u>|~~|\s+/g, "");
|
|
8056
|
+
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));
|
|
8057
|
+
}
|
|
7511
8058
|
function streamLines(items) {
|
|
7512
8059
|
if (items.some((i) => i.seq === void 0)) return groupByY([...items].sort((a, b) => b.y - a.y || a.x - b.x));
|
|
7513
8060
|
const lines = [];
|
|
@@ -7692,7 +8239,11 @@ export {
|
|
|
7692
8239
|
extractImageRegions,
|
|
7693
8240
|
filterHiddenText,
|
|
7694
8241
|
collapseEvenSpacing,
|
|
8242
|
+
computeBBox,
|
|
8243
|
+
dominantStyle,
|
|
7695
8244
|
normalizeItems,
|
|
8245
|
+
groupByY,
|
|
8246
|
+
mergeLineSimple,
|
|
7696
8247
|
WrapLexicon,
|
|
7697
8248
|
startsNewItem,
|
|
7698
8249
|
wrapJoiner,
|
|
@@ -7713,6 +8264,7 @@ export {
|
|
|
7713
8264
|
detectKoreanListBlocks,
|
|
7714
8265
|
removeHeaderFooterBlocks,
|
|
7715
8266
|
CLIP_TABLES,
|
|
8267
|
+
FRAME_TITLE_BLOCKS,
|
|
7716
8268
|
TABLE_COLXS,
|
|
7717
8269
|
TABLE_ROWYS,
|
|
7718
8270
|
TABLE_TAIL,
|
|
@@ -7726,7 +8278,11 @@ export {
|
|
|
7726
8278
|
trimTrailingEmptyTableCols,
|
|
7727
8279
|
NO_EDGES,
|
|
7728
8280
|
joinCellEdges,
|
|
8281
|
+
FRAME_READING_UNITS,
|
|
8282
|
+
recordFrameReadingUnit,
|
|
8283
|
+
restoreImageBullets,
|
|
8284
|
+
detectRightArrowRegions,
|
|
7729
8285
|
removeSideTabs,
|
|
7730
8286
|
extractPageBlocksWithLines
|
|
7731
8287
|
};
|
|
7732
|
-
//# sourceMappingURL=chunk-
|
|
8288
|
+
//# sourceMappingURL=chunk-2CRD4Q76.js.map
|