kordoc 3.8.1 → 3.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/{-LD4BZDDJ.js → -F5IXBLQQ.js} +3 -3
- package/dist/{chunk-PELBIL4K.js → chunk-7J73IGMK.js} +2 -2
- package/dist/{chunk-KT2BCHXI.js → chunk-B27QMVL7.js} +872 -825
- package/dist/chunk-B27QMVL7.js.map +1 -0
- package/dist/{chunk-IFYJFWD2.js → chunk-KIWKBRCJ.js} +2 -2
- package/dist/{chunk-LFCS3UVG.cjs → chunk-XL6O3VAY.cjs} +2 -2
- package/dist/{chunk-LFCS3UVG.cjs.map → chunk-XL6O3VAY.cjs.map} +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.cjs +1065 -1018
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -8
- package/dist/index.d.ts +17 -8
- package/dist/index.js +871 -824
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +3 -3
- package/dist/{parser-FFEBMLSH.js → parser-6GP535ZB.js} +211 -25
- package/dist/parser-6GP535ZB.js.map +1 -0
- package/dist/{parser-XEDROIM7.js → parser-TM3AS25T.js} +211 -25
- package/dist/parser-TM3AS25T.js.map +1 -0
- package/dist/{parser-IXK5V7YG.cjs → parser-WWKYMRGJ.cjs} +240 -52
- package/dist/parser-WWKYMRGJ.cjs.map +1 -0
- package/dist/{watch-MAWCDNFI.js → watch-HETTZ7BO.js} +3 -3
- package/package.json +2 -1
- package/dist/chunk-KT2BCHXI.js.map +0 -1
- package/dist/parser-FFEBMLSH.js.map +0 -1
- package/dist/parser-IXK5V7YG.cjs.map +0 -1
- package/dist/parser-XEDROIM7.js.map +0 -1
- /package/dist/{-LD4BZDDJ.js.map → -F5IXBLQQ.js.map} +0 -0
- /package/dist/{chunk-PELBIL4K.js.map → chunk-7J73IGMK.js.map} +0 -0
- /package/dist/{chunk-IFYJFWD2.js.map → chunk-KIWKBRCJ.js.map} +0 -0
- /package/dist/{watch-MAWCDNFI.js.map → watch-HETTZ7BO.js.map} +0 -0
|
@@ -6,11 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
var
|
|
9
|
+
var _chunkXL6O3VAYcjs = require('./chunk-XL6O3VAY.cjs');
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
var _chunkDCZVOIEOcjs = require('./chunk-DCZVOIEO.cjs');
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
var _chunkGS7T56RPcjs = require('./chunk-GS7T56RP.cjs');
|
|
14
16
|
|
|
15
17
|
// src/pdf/line-extract.ts
|
|
16
18
|
var _pdfmjs = require('pdfjs-dist/legacy/build/pdf.mjs');
|
|
@@ -21,21 +23,30 @@ function extractLines(fnArray, argsArray) {
|
|
|
21
23
|
const horizontals = [];
|
|
22
24
|
const verticals = [];
|
|
23
25
|
let lineWidth = 1;
|
|
26
|
+
let ctm = [1, 0, 0, 1, 0, 0];
|
|
27
|
+
const ctmStack = [];
|
|
28
|
+
const applyCtm = (x, y) => [ctm[0] * x + ctm[2] * y + ctm[4], ctm[1] * x + ctm[3] * y + ctm[5]];
|
|
29
|
+
const ctmScale = () => (Math.hypot(ctm[0], ctm[1]) + Math.hypot(ctm[2], ctm[3])) / 2;
|
|
24
30
|
let currentPath = [];
|
|
25
31
|
let pathStartX = 0, pathStartY = 0;
|
|
26
32
|
let curX = 0, curY = 0;
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
function pushSeg(x1, y1, x2, y2) {
|
|
34
|
+
const [tx1, ty1] = applyCtm(x1, y1);
|
|
35
|
+
const [tx2, ty2] = applyCtm(x2, y2);
|
|
36
|
+
currentPath.push({ x1: tx1, y1: ty1, x2: tx2, y2: ty2 });
|
|
37
|
+
}
|
|
38
|
+
function pushRectangle(rx, ry, rw, rh) {
|
|
39
|
+
const effH = Math.abs(rh) * Math.hypot(ctm[2], ctm[3]);
|
|
40
|
+
const effW = Math.abs(rw) * Math.hypot(ctm[0], ctm[1]);
|
|
41
|
+
if (effH < ORIENTATION_TOL * 2) {
|
|
42
|
+
pushSeg(rx, ry + rh / 2, rx + rw, ry + rh / 2);
|
|
43
|
+
} else if (effW < ORIENTATION_TOL * 2) {
|
|
44
|
+
pushSeg(rx + rw / 2, ry, rx + rw / 2, ry + rh);
|
|
32
45
|
} else {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
{ x1: rx, y1: ry + rh, x2: rx, y2: ry }
|
|
38
|
-
);
|
|
46
|
+
pushSeg(rx, ry, rx + rw, ry);
|
|
47
|
+
pushSeg(rx + rw, ry, rx + rw, ry + rh);
|
|
48
|
+
pushSeg(rx + rw, ry + rh, rx, ry + rh);
|
|
49
|
+
pushSeg(rx, ry + rh, rx, ry);
|
|
39
50
|
}
|
|
40
51
|
}
|
|
41
52
|
function flushPath(isStroke) {
|
|
@@ -43,8 +54,9 @@ function extractLines(fnArray, argsArray) {
|
|
|
43
54
|
currentPath = [];
|
|
44
55
|
return;
|
|
45
56
|
}
|
|
57
|
+
const effWidth = lineWidth * ctmScale();
|
|
46
58
|
for (const seg of currentPath) {
|
|
47
|
-
classifyAndAdd(seg,
|
|
59
|
+
classifyAndAdd(seg, effWidth, horizontals, verticals);
|
|
48
60
|
}
|
|
49
61
|
currentPath = [];
|
|
50
62
|
}
|
|
@@ -55,6 +67,24 @@ function extractLines(fnArray, argsArray) {
|
|
|
55
67
|
case _pdfmjs.OPS.setLineWidth:
|
|
56
68
|
lineWidth = args[0] || 1;
|
|
57
69
|
break;
|
|
70
|
+
case _pdfmjs.OPS.save:
|
|
71
|
+
ctmStack.push(ctm.slice());
|
|
72
|
+
break;
|
|
73
|
+
case _pdfmjs.OPS.restore:
|
|
74
|
+
ctm = _nullishCoalesce(ctmStack.pop(), () => ( [1, 0, 0, 1, 0, 0]));
|
|
75
|
+
break;
|
|
76
|
+
case _pdfmjs.OPS.transform: {
|
|
77
|
+
const t = args;
|
|
78
|
+
ctm = [
|
|
79
|
+
ctm[0] * t[0] + ctm[2] * t[1],
|
|
80
|
+
ctm[1] * t[0] + ctm[3] * t[1],
|
|
81
|
+
ctm[0] * t[2] + ctm[2] * t[3],
|
|
82
|
+
ctm[1] * t[2] + ctm[3] * t[3],
|
|
83
|
+
ctm[0] * t[4] + ctm[2] * t[5] + ctm[4],
|
|
84
|
+
ctm[1] * t[4] + ctm[3] * t[5] + ctm[5]
|
|
85
|
+
];
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
58
88
|
case _pdfmjs.OPS.constructPath: {
|
|
59
89
|
const arg0 = args[0];
|
|
60
90
|
if (Array.isArray(arg0)) {
|
|
@@ -69,16 +99,16 @@ function extractLines(fnArray, argsArray) {
|
|
|
69
99
|
pathStartY = curY;
|
|
70
100
|
} else if (subOp === _pdfmjs.OPS.lineTo) {
|
|
71
101
|
const x2 = coords[ci++], y2 = coords[ci++];
|
|
72
|
-
|
|
102
|
+
pushSeg(curX, curY, x2, y2);
|
|
73
103
|
curX = x2;
|
|
74
104
|
curY = y2;
|
|
75
105
|
} else if (subOp === _pdfmjs.OPS.rectangle) {
|
|
76
106
|
const rx = coords[ci++], ry = coords[ci++];
|
|
77
107
|
const rw = coords[ci++], rh = coords[ci++];
|
|
78
|
-
pushRectangle(
|
|
108
|
+
pushRectangle(rx, ry, rw, rh);
|
|
79
109
|
} else if (subOp === _pdfmjs.OPS.closePath) {
|
|
80
110
|
if (curX !== pathStartX || curY !== pathStartY) {
|
|
81
|
-
|
|
111
|
+
pushSeg(curX, curY, pathStartX, pathStartY);
|
|
82
112
|
}
|
|
83
113
|
curX = pathStartX;
|
|
84
114
|
curY = pathStartY;
|
|
@@ -104,7 +134,7 @@ function extractLines(fnArray, argsArray) {
|
|
|
104
134
|
pathStartY = curY;
|
|
105
135
|
} else if (drawOp === 1 /* lineTo */) {
|
|
106
136
|
const x2 = pathData[di++], y2 = pathData[di++];
|
|
107
|
-
|
|
137
|
+
pushSeg(curX, curY, x2, y2);
|
|
108
138
|
curX = x2;
|
|
109
139
|
curY = y2;
|
|
110
140
|
} else if (drawOp === 2 /* curveTo */) {
|
|
@@ -113,7 +143,7 @@ function extractLines(fnArray, argsArray) {
|
|
|
113
143
|
di += 4;
|
|
114
144
|
} else if (drawOp === 4 /* closePath */) {
|
|
115
145
|
if (curX !== pathStartX || curY !== pathStartY) {
|
|
116
|
-
|
|
146
|
+
pushSeg(curX, curY, pathStartX, pathStartY);
|
|
117
147
|
}
|
|
118
148
|
curX = pathStartX;
|
|
119
149
|
curY = pathStartY;
|
|
@@ -1235,7 +1265,106 @@ function detectClusterTables(items, pageNum) {
|
|
|
1235
1265
|
}
|
|
1236
1266
|
}
|
|
1237
1267
|
}
|
|
1238
|
-
return results;
|
|
1268
|
+
return results.filter((r) => !isTwoColumnProse(r));
|
|
1269
|
+
}
|
|
1270
|
+
function isTwoColumnProse(r) {
|
|
1271
|
+
const t = r.table;
|
|
1272
|
+
if (t.rows < 8) return false;
|
|
1273
|
+
const dense = [];
|
|
1274
|
+
for (let c = 0; c < t.cols; c++) {
|
|
1275
|
+
const filled = t.cells.filter((row) => _optionalChain([row, 'access', _9 => _9[c], 'optionalAccess', _10 => _10.text, 'access', _11 => _11.trim, 'call', _12 => _12()])).length;
|
|
1276
|
+
if (filled / t.rows >= 0.3) dense.push(c);
|
|
1277
|
+
}
|
|
1278
|
+
if (dense.length !== 2) return false;
|
|
1279
|
+
for (const c of dense) {
|
|
1280
|
+
const lens = t.cells.map((row) => _nullishCoalesce(_optionalChain([row, 'access', _13 => _13[c], 'optionalAccess', _14 => _14.text, 'access', _15 => _15.replace, 'call', _16 => _16(/\s+/g, ""), 'access', _17 => _17.length]), () => ( 0))).filter((n) => n > 0);
|
|
1281
|
+
const avg = lens.reduce((s, v) => s + v, 0) / (lens.length || 1);
|
|
1282
|
+
if (avg < 12) return false;
|
|
1283
|
+
}
|
|
1284
|
+
return findTwoColumnProseCutX([...r.usedItems]) !== null;
|
|
1285
|
+
}
|
|
1286
|
+
function findTwoColumnProseCutX(items) {
|
|
1287
|
+
const lines = groupByBaseline(items);
|
|
1288
|
+
if (lines.length < 8) return null;
|
|
1289
|
+
let minX = Infinity;
|
|
1290
|
+
let maxX = -Infinity;
|
|
1291
|
+
for (const i of items) {
|
|
1292
|
+
if (i.x < minX) minX = i.x;
|
|
1293
|
+
if (i.x + i.w > maxX) maxX = i.x + i.w;
|
|
1294
|
+
}
|
|
1295
|
+
if (!Number.isFinite(maxX - minX)) return null;
|
|
1296
|
+
if (maxX - minX < 100) return null;
|
|
1297
|
+
const lo = minX + (maxX - minX) * 0.3;
|
|
1298
|
+
const hi = minX + (maxX - minX) * 0.7;
|
|
1299
|
+
const step = Math.max(2, (hi - lo) / 400);
|
|
1300
|
+
let cutX = 0;
|
|
1301
|
+
let bestCover = Infinity;
|
|
1302
|
+
for (let x = lo; x <= hi; x += step) {
|
|
1303
|
+
let cover = 0;
|
|
1304
|
+
for (const line of lines) {
|
|
1305
|
+
if (line.items.some((i) => i.x < x && i.x + i.w > x)) cover++;
|
|
1306
|
+
}
|
|
1307
|
+
if (cover < bestCover) {
|
|
1308
|
+
bestCover = cover;
|
|
1309
|
+
cutX = x;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
if (bestCover / lines.length > 0.15) return null;
|
|
1313
|
+
const left = [];
|
|
1314
|
+
const right = [];
|
|
1315
|
+
let twoSide = 0;
|
|
1316
|
+
for (const line of lines) {
|
|
1317
|
+
let hasL = false;
|
|
1318
|
+
let hasR = false;
|
|
1319
|
+
for (const i of line.items) {
|
|
1320
|
+
if (i.x + i.w <= cutX) {
|
|
1321
|
+
left.push(i);
|
|
1322
|
+
hasL = true;
|
|
1323
|
+
} else if (i.x >= cutX) {
|
|
1324
|
+
right.push(i);
|
|
1325
|
+
hasR = true;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
if (hasL && hasR) twoSide++;
|
|
1329
|
+
}
|
|
1330
|
+
if (twoSide / lines.length < 0.55) return null;
|
|
1331
|
+
if (left.length < 5 || right.length < 5) return null;
|
|
1332
|
+
const allText = items.map((i) => i.text).join("").replace(/\s+/g, "");
|
|
1333
|
+
const digits = (allText.match(/[\d,.%△—-]/g) || []).length;
|
|
1334
|
+
if (allText.length === 0 || digits / allText.length > 0.15) return null;
|
|
1335
|
+
const stats = [left, right].map((side) => {
|
|
1336
|
+
let sMinX = Infinity;
|
|
1337
|
+
let sMaxR = -Infinity;
|
|
1338
|
+
let fsSum = 0;
|
|
1339
|
+
const rowEnds = /* @__PURE__ */ new Map();
|
|
1340
|
+
const rowLens = /* @__PURE__ */ new Map();
|
|
1341
|
+
const rowFirst = /* @__PURE__ */ new Map();
|
|
1342
|
+
for (const i of side) {
|
|
1343
|
+
if (i.x < sMinX) sMinX = i.x;
|
|
1344
|
+
const rgt = i.x + i.w;
|
|
1345
|
+
if (rgt > sMaxR) sMaxR = rgt;
|
|
1346
|
+
fsSum += i.fontSize;
|
|
1347
|
+
const key = Math.round(i.y / 4);
|
|
1348
|
+
rowEnds.set(key, Math.max(_nullishCoalesce(rowEnds.get(key), () => ( -Infinity)), rgt));
|
|
1349
|
+
rowLens.set(key, (_nullishCoalesce(rowLens.get(key), () => ( 0))) + i.text.replace(/\s+/g, "").length);
|
|
1350
|
+
const f = rowFirst.get(key);
|
|
1351
|
+
if (!f || i.x < f.x) rowFirst.set(key, i);
|
|
1352
|
+
}
|
|
1353
|
+
const ends = [...rowEnds.values()].sort((a, b) => a - b);
|
|
1354
|
+
const p85 = _nullishCoalesce(ends[Math.floor(ends.length * 0.85)], () => ( sMaxR));
|
|
1355
|
+
const fs = fsSum / side.length;
|
|
1356
|
+
const justified = ends.filter((e) => Math.abs(e - p85) <= fs).length / ends.length;
|
|
1357
|
+
const lens = [...rowLens.values()];
|
|
1358
|
+
const avgLen = lens.reduce((s, v) => s + v, 0) / (lens.length || 1);
|
|
1359
|
+
const markers = [...rowFirst.values()].filter((i) => /^[•▪◦‣∙·\-–—□■◇◆▶※*]/.test(i.text)).length;
|
|
1360
|
+
return { width: sMaxR - sMinX, justified, avgLen, markerRatio: markers / (rowFirst.size || 1) };
|
|
1361
|
+
});
|
|
1362
|
+
if (stats.some((s) => s.avgLen < 12)) return null;
|
|
1363
|
+
if (stats.some((s) => s.markerRatio > 0.1)) return null;
|
|
1364
|
+
const widthSym = Math.min(stats[0].width, stats[1].width) / Math.max(stats[0].width, stats[1].width);
|
|
1365
|
+
if (widthSym < 0.6) return null;
|
|
1366
|
+
if (Math.min(stats[0].justified, stats[1].justified) < 0.55) return null;
|
|
1367
|
+
return cutX;
|
|
1239
1368
|
}
|
|
1240
1369
|
function mergeEvenSpacedClusters(items) {
|
|
1241
1370
|
const originMap = /* @__PURE__ */ new Map();
|
|
@@ -1625,7 +1754,7 @@ function buildClusterTable(rows, columns, pageNum) {
|
|
|
1625
1754
|
const nonEmptyCols = cells[r].filter((c) => c.text.trim()).length;
|
|
1626
1755
|
if (nonEmptyCols !== 1) continue;
|
|
1627
1756
|
if (cells[r][0].text.trim() !== "") continue;
|
|
1628
|
-
const contentText = _optionalChain([cells, 'access',
|
|
1757
|
+
const contentText = _optionalChain([cells, 'access', _18 => _18[r], 'access', _19 => _19.find, 'call', _20 => _20((c) => c.text.trim()), 'optionalAccess', _21 => _21.text, 'access', _22 => _22.trim, 'call', _23 => _23()]) || "";
|
|
1629
1758
|
if (/^[○●▶\-·]/.test(contentText)) continue;
|
|
1630
1759
|
for (let pr = r - 1; pr >= 0; pr--) {
|
|
1631
1760
|
if (cells[pr].some((c) => c.text.trim())) {
|
|
@@ -1847,14 +1976,14 @@ function isProseSpread(items) {
|
|
|
1847
1976
|
for (let i = 1; i < sorted.length; i++) {
|
|
1848
1977
|
gaps.push(sorted[i].x - (sorted[i - 1].x + sorted[i - 1].w));
|
|
1849
1978
|
}
|
|
1850
|
-
const maxGap =
|
|
1979
|
+
const maxGap = _chunkXL6O3VAYcjs.safeMax.call(void 0, gaps);
|
|
1851
1980
|
const avgLen = items.reduce((s, i) => s + i.text.length, 0) / items.length;
|
|
1852
1981
|
return maxGap < 40 && avgLen < 5;
|
|
1853
1982
|
}
|
|
1854
1983
|
function detectColumns(yLines) {
|
|
1855
1984
|
const allItems = yLines.flat();
|
|
1856
1985
|
if (allItems.length === 0) return null;
|
|
1857
|
-
const pageWidth =
|
|
1986
|
+
const pageWidth = _chunkXL6O3VAYcjs.safeMax.call(void 0, allItems.map((i) => i.x + i.w)) - _chunkXL6O3VAYcjs.safeMin.call(void 0, allItems.map((i) => i.x));
|
|
1858
1987
|
if (pageWidth < 100) return null;
|
|
1859
1988
|
let bigoLineIdx = -1;
|
|
1860
1989
|
for (let i = 0; i < yLines.length; i++) {
|
|
@@ -2070,15 +2199,15 @@ function computeMedianFontSizeFromFreq(freq) {
|
|
|
2070
2199
|
}
|
|
2071
2200
|
function detectHeadings(blocks, medianFontSize) {
|
|
2072
2201
|
for (const block of blocks) {
|
|
2073
|
-
if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access',
|
|
2202
|
+
if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access', _24 => _24.style, 'optionalAccess', _25 => _25.fontSize])) continue;
|
|
2074
2203
|
const text = block.text.trim();
|
|
2075
2204
|
if (text.length === 0 || text.length > 200) continue;
|
|
2076
2205
|
if (/^\d+$/.test(text)) continue;
|
|
2077
2206
|
const ratio = block.style.fontSize / medianFontSize;
|
|
2078
2207
|
let level = 0;
|
|
2079
|
-
if (ratio >=
|
|
2080
|
-
else if (ratio >=
|
|
2081
|
-
else if (ratio >=
|
|
2208
|
+
if (ratio >= _chunkXL6O3VAYcjs.HEADING_RATIO_H1) level = 1;
|
|
2209
|
+
else if (ratio >= _chunkXL6O3VAYcjs.HEADING_RATIO_H2) level = 2;
|
|
2210
|
+
else if (ratio >= _chunkXL6O3VAYcjs.HEADING_RATIO_H3) level = 3;
|
|
2082
2211
|
if (level > 0) {
|
|
2083
2212
|
block.type = "heading";
|
|
2084
2213
|
block.level = level;
|
|
@@ -2127,7 +2256,7 @@ function detectMarkerHeadings(blocks) {
|
|
|
2127
2256
|
block.level = 4;
|
|
2128
2257
|
continue;
|
|
2129
2258
|
}
|
|
2130
|
-
if (/^[가-힣]{2,6}$/.test(text) && _optionalChain([block, 'access',
|
|
2259
|
+
if (/^[가-힣]{2,6}$/.test(text) && _optionalChain([block, 'access', _26 => _26.style, 'optionalAccess', _27 => _27.fontSize])) {
|
|
2131
2260
|
const prev = blocks[i - 1];
|
|
2132
2261
|
const next = blocks[i + 1];
|
|
2133
2262
|
const prevIsStructural = !prev || prev.type === "table" || prev.type === "heading" || prev.type === "separator";
|
|
@@ -2380,7 +2509,7 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings) {
|
|
|
2380
2509
|
const bottomEntries = [];
|
|
2381
2510
|
for (let bi = 0; bi < blocks.length; bi++) {
|
|
2382
2511
|
const b = blocks[bi];
|
|
2383
|
-
if (!b.bbox || !b.pageNumber || !_optionalChain([b, 'access',
|
|
2512
|
+
if (!b.bbox || !b.pageNumber || !_optionalChain([b, 'access', _28 => _28.text, 'optionalAccess', _29 => _29.trim, 'call', _30 => _30()])) continue;
|
|
2384
2513
|
const ph = pageHeights.get(b.bbox.page) || pageHeights.get(b.pageNumber);
|
|
2385
2514
|
if (!ph) continue;
|
|
2386
2515
|
const blockTop = ph - (b.bbox.y + b.bbox.height);
|
|
@@ -2403,7 +2532,7 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings) {
|
|
|
2403
2532
|
}
|
|
2404
2533
|
const repeatedPatterns = /* @__PURE__ */ new Set();
|
|
2405
2534
|
for (const [p, count] of patternCount) {
|
|
2406
|
-
if (count >= MIN_REPEAT && (_nullishCoalesce(_optionalChain([patternPages, 'access',
|
|
2535
|
+
if (count >= MIN_REPEAT && (_nullishCoalesce(_optionalChain([patternPages, 'access', _31 => _31.get, 'call', _32 => _32(p), 'optionalAccess', _33 => _33.size]), () => ( 0))) >= MIN_REPEAT) {
|
|
2407
2536
|
repeatedPatterns.add(p);
|
|
2408
2537
|
}
|
|
2409
2538
|
}
|
|
@@ -2432,7 +2561,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
2432
2561
|
if (grids.length > 0) {
|
|
2433
2562
|
return extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals);
|
|
2434
2563
|
}
|
|
2435
|
-
return extractPageBlocksFallback(items, pageNum);
|
|
2564
|
+
return extractPageBlocksFallback(items, pageNum, true);
|
|
2436
2565
|
}
|
|
2437
2566
|
var STRIKE_MAX_THICKNESS = 2;
|
|
2438
2567
|
var STRIKE_MAX_THICKNESS_RATIO = 0.25;
|
|
@@ -2597,7 +2726,7 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
|
|
|
2597
2726
|
}
|
|
2598
2727
|
if (remaining.length > 0) {
|
|
2599
2728
|
const allY = remaining.map((i) => i.y);
|
|
2600
|
-
const pageH =
|
|
2729
|
+
const pageH = _chunkXL6O3VAYcjs.safeMax.call(void 0, allY) - _chunkXL6O3VAYcjs.safeMin.call(void 0, allY);
|
|
2601
2730
|
const groups = xyCutOrder(remaining, Math.max(15, pageH * 0.03));
|
|
2602
2731
|
const textBlocks = [];
|
|
2603
2732
|
for (const group of groups) {
|
|
@@ -2677,7 +2806,53 @@ function mergeAdjacentTableBlocks(blocks) {
|
|
|
2677
2806
|
}
|
|
2678
2807
|
return result;
|
|
2679
2808
|
}
|
|
2680
|
-
function
|
|
2809
|
+
function splitTwoColumnProse(items, cutX) {
|
|
2810
|
+
const left = [];
|
|
2811
|
+
const right = [];
|
|
2812
|
+
const cross = [];
|
|
2813
|
+
for (const i of items) {
|
|
2814
|
+
if (i.x + i.w <= cutX) left.push(i);
|
|
2815
|
+
else if (i.x >= cutX) right.push(i);
|
|
2816
|
+
else cross.push(i);
|
|
2817
|
+
}
|
|
2818
|
+
if (cross.length === 0) {
|
|
2819
|
+
return [left, right].filter((g2) => g2.length > 0);
|
|
2820
|
+
}
|
|
2821
|
+
cross.sort((a, b) => b.y - a.y);
|
|
2822
|
+
const crossLines = [];
|
|
2823
|
+
for (const c of cross) {
|
|
2824
|
+
const last = crossLines[crossLines.length - 1];
|
|
2825
|
+
if (last && Math.abs(last[0].y - c.y) <= 3) last.push(c);
|
|
2826
|
+
else crossLines.push([c]);
|
|
2827
|
+
}
|
|
2828
|
+
const bandItem = (arr) => arr.filter((i) => {
|
|
2829
|
+
for (const cl of crossLines) {
|
|
2830
|
+
if (Math.abs(cl[0].y - i.y) <= 3) {
|
|
2831
|
+
cl.push(i);
|
|
2832
|
+
return false;
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
return true;
|
|
2836
|
+
});
|
|
2837
|
+
const leftRest = bandItem(left);
|
|
2838
|
+
const rightRest = bandItem(right);
|
|
2839
|
+
const boundYs = crossLines.map((cl) => cl[0].y);
|
|
2840
|
+
const bandOf = (y) => {
|
|
2841
|
+
let k = 0;
|
|
2842
|
+
while (k < boundYs.length && y < boundYs[k]) k++;
|
|
2843
|
+
return k;
|
|
2844
|
+
};
|
|
2845
|
+
const groups = [];
|
|
2846
|
+
for (let k = 0; k <= crossLines.length; k++) {
|
|
2847
|
+
const L = leftRest.filter((i) => bandOf(i.y) === k);
|
|
2848
|
+
const R = rightRest.filter((i) => bandOf(i.y) === k);
|
|
2849
|
+
if (L.length > 0) groups.push(L);
|
|
2850
|
+
if (R.length > 0) groups.push(R);
|
|
2851
|
+
if (k < crossLines.length) groups.push(crossLines[k]);
|
|
2852
|
+
}
|
|
2853
|
+
return groups;
|
|
2854
|
+
}
|
|
2855
|
+
function extractPageBlocksFallback(items, pageNum, fullPage = false) {
|
|
2681
2856
|
if (items.length === 0) return [];
|
|
2682
2857
|
const blocks = [];
|
|
2683
2858
|
const clusterItems = items.map((i) => ({
|
|
@@ -2718,17 +2893,18 @@ function extractPageBlocksFallback(items, pageNum) {
|
|
|
2718
2893
|
return by - ay;
|
|
2719
2894
|
});
|
|
2720
2895
|
} else {
|
|
2896
|
+
const proseCutX = fullPage ? findTwoColumnProseCutX(items) : null;
|
|
2721
2897
|
const allYLines = mergeSuperscriptLines(groupByY(items));
|
|
2722
|
-
const columns = detectColumns(allYLines);
|
|
2898
|
+
const columns = proseCutX !== null ? null : detectColumns(allYLines);
|
|
2723
2899
|
if (columns && columns.length >= 3) {
|
|
2724
2900
|
const tableText = extractWithColumns(allYLines, columns);
|
|
2725
2901
|
const bbox = computeBBox(items, pageNum);
|
|
2726
2902
|
blocks.push({ type: "paragraph", text: tableText, pageNumber: pageNum, bbox, style: dominantStyle(items) });
|
|
2727
2903
|
} else {
|
|
2728
2904
|
const allY = items.map((i) => i.y);
|
|
2729
|
-
const pageHeight =
|
|
2905
|
+
const pageHeight = _chunkXL6O3VAYcjs.safeMax.call(void 0, allY) - _chunkXL6O3VAYcjs.safeMin.call(void 0, allY);
|
|
2730
2906
|
const gapThreshold = Math.max(15, pageHeight * 0.03);
|
|
2731
|
-
const orderedGroups = xyCutOrder(items, gapThreshold);
|
|
2907
|
+
const orderedGroups = proseCutX !== null ? splitTwoColumnProse(items, proseCutX) : xyCutOrder(items, gapThreshold);
|
|
2732
2908
|
for (const group of orderedGroups) {
|
|
2733
2909
|
if (group.length === 0) continue;
|
|
2734
2910
|
const yLines = mergeSuperscriptLines(groupByY(group));
|
|
@@ -2949,16 +3125,28 @@ g.pdfjsWorker = pdfjsWorker;
|
|
|
2949
3125
|
|
|
2950
3126
|
// src/pdf/parser.ts
|
|
2951
3127
|
|
|
3128
|
+
var _module = require('module');
|
|
3129
|
+
var _path = require('path');
|
|
2952
3130
|
_pdfmjs.GlobalWorkerOptions.workerSrc = "";
|
|
2953
3131
|
var MAX_PAGES = 5e3;
|
|
2954
3132
|
var MAX_TOTAL_TEXT = 100 * 1024 * 1024;
|
|
2955
3133
|
var PDF_LOAD_TIMEOUT_MS = 3e4;
|
|
3134
|
+
var pdfjsAssets = {};
|
|
3135
|
+
try {
|
|
3136
|
+
const _require = _module.createRequire.call(void 0, _chunkGS7T56RPcjs.importMetaUrl);
|
|
3137
|
+
const pkgDir = _path.dirname.call(void 0, _require.resolve("pdfjs-dist/package.json"));
|
|
3138
|
+
pdfjsAssets.cMapUrl = _path.join.call(void 0, pkgDir, "cmaps") + "/";
|
|
3139
|
+
pdfjsAssets.cMapPacked = true;
|
|
3140
|
+
pdfjsAssets.standardFontDataUrl = _path.join.call(void 0, pkgDir, "standard_fonts") + "/";
|
|
3141
|
+
} catch (e2) {
|
|
3142
|
+
}
|
|
2956
3143
|
async function loadPdfWithTimeout(buffer) {
|
|
2957
3144
|
const loadingTask = _pdfmjs.getDocument.call(void 0, {
|
|
2958
3145
|
data: new Uint8Array(buffer),
|
|
2959
3146
|
useSystemFonts: true,
|
|
2960
3147
|
disableFontFace: true,
|
|
2961
|
-
isEvalSupported: false
|
|
3148
|
+
isEvalSupported: false,
|
|
3149
|
+
...pdfjsAssets
|
|
2962
3150
|
});
|
|
2963
3151
|
let timer;
|
|
2964
3152
|
try {
|
|
@@ -2967,7 +3155,7 @@ async function loadPdfWithTimeout(buffer) {
|
|
|
2967
3155
|
new Promise((_, reject) => {
|
|
2968
3156
|
timer = setTimeout(() => {
|
|
2969
3157
|
loadingTask.destroy();
|
|
2970
|
-
reject(new (0,
|
|
3158
|
+
reject(new (0, _chunkXL6O3VAYcjs.KordocError)("PDF \uB85C\uB529 \uD0C0\uC784\uC544\uC6C3 (30\uCD08 \uCD08\uACFC)"));
|
|
2971
3159
|
}, PDF_LOAD_TIMEOUT_MS);
|
|
2972
3160
|
})
|
|
2973
3161
|
]);
|
|
@@ -2976,11 +3164,11 @@ async function loadPdfWithTimeout(buffer) {
|
|
|
2976
3164
|
}
|
|
2977
3165
|
}
|
|
2978
3166
|
async function parsePdfDocument(buffer, options) {
|
|
2979
|
-
const formulaBuffer = _optionalChain([options, 'optionalAccess',
|
|
3167
|
+
const formulaBuffer = _optionalChain([options, 'optionalAccess', _34 => _34.formulaOcr]) ? buffer.slice(0) : null;
|
|
2980
3168
|
const doc = await loadPdfWithTimeout(buffer);
|
|
2981
3169
|
try {
|
|
2982
3170
|
const pageCount = doc.numPages;
|
|
2983
|
-
if (pageCount === 0) throw new (0,
|
|
3171
|
+
if (pageCount === 0) throw new (0, _chunkXL6O3VAYcjs.KordocError)("PDF\uC5D0 \uD398\uC774\uC9C0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
2984
3172
|
const metadata = { pageCount };
|
|
2985
3173
|
await extractPdfMetadata(doc, metadata);
|
|
2986
3174
|
const blocks = [];
|
|
@@ -2989,7 +3177,7 @@ async function parsePdfDocument(buffer, options) {
|
|
|
2989
3177
|
let totalChars = 0;
|
|
2990
3178
|
let totalTextBytes = 0;
|
|
2991
3179
|
const effectivePageCount = Math.min(pageCount, MAX_PAGES);
|
|
2992
|
-
const pageFilter = _optionalChain([options, 'optionalAccess',
|
|
3180
|
+
const pageFilter = _optionalChain([options, 'optionalAccess', _35 => _35.pages]) ? _chunkDCZVOIEOcjs.parsePageRange.call(void 0, options.pages, effectivePageCount) : null;
|
|
2993
3181
|
const totalTarget = pageFilter ? pageFilter.size : effectivePageCount;
|
|
2994
3182
|
const fontSizeFreq = /* @__PURE__ */ new Map();
|
|
2995
3183
|
const pageHeights = /* @__PURE__ */ new Map();
|
|
@@ -3040,18 +3228,18 @@ async function parsePdfDocument(buffer, options) {
|
|
|
3040
3228
|
pageText += pageText ? "\n" + t : t;
|
|
3041
3229
|
}
|
|
3042
3230
|
pageQuality.push(computePageQuality(i, pageText));
|
|
3043
|
-
if (totalTextBytes > MAX_TOTAL_TEXT) throw new (0,
|
|
3231
|
+
if (totalTextBytes > MAX_TOTAL_TEXT) throw new (0, _chunkXL6O3VAYcjs.KordocError)("\uD14D\uC2A4\uD2B8 \uCD94\uCD9C \uD06C\uAE30 \uCD08\uACFC");
|
|
3044
3232
|
parsedPages++;
|
|
3045
|
-
_optionalChain([options, 'optionalAccess',
|
|
3233
|
+
_optionalChain([options, 'optionalAccess', _36 => _36.onProgress, 'optionalCall', _37 => _37(parsedPages, totalTarget)]);
|
|
3046
3234
|
} catch (pageErr) {
|
|
3047
|
-
if (pageErr instanceof
|
|
3235
|
+
if (pageErr instanceof _chunkXL6O3VAYcjs.KordocError) throw pageErr;
|
|
3048
3236
|
warnings.push({ page: i, message: `\uD398\uC774\uC9C0 ${i} \uD30C\uC2F1 \uC2E4\uD328: ${pageErr instanceof Error ? pageErr.message : "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}`, code: "PARTIAL_PARSE" });
|
|
3049
3237
|
}
|
|
3050
3238
|
}
|
|
3051
3239
|
const parsedPageCount = parsedPages || (pageFilter ? pageFilter.size : effectivePageCount);
|
|
3052
3240
|
let isImageBased = false;
|
|
3053
3241
|
if (totalChars / Math.max(parsedPageCount, 1) < 10) {
|
|
3054
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
3242
|
+
if (_optionalChain([options, 'optionalAccess', _38 => _38.ocr])) {
|
|
3055
3243
|
try {
|
|
3056
3244
|
const { ocrPages } = await Promise.resolve().then(() => _interopRequireWildcard(require("./provider-G4C2V2PD.cjs")));
|
|
3057
3245
|
const ocrBlocks = await ocrPages(doc, options.ocr, pageFilter, effectivePageCount);
|
|
@@ -3059,7 +3247,7 @@ async function parsePdfDocument(buffer, options) {
|
|
|
3059
3247
|
const ocrMarkdown = ocrBlocks.map((b) => b.text || "").filter(Boolean).join("\n\n");
|
|
3060
3248
|
return { markdown: ocrMarkdown, blocks: ocrBlocks, metadata, warnings, isImageBased: true, pageQuality, qualitySummary: summarizeDocumentQuality(pageQuality) };
|
|
3061
3249
|
}
|
|
3062
|
-
} catch (
|
|
3250
|
+
} catch (e3) {
|
|
3063
3251
|
}
|
|
3064
3252
|
}
|
|
3065
3253
|
isImageBased = true;
|
|
@@ -3086,14 +3274,14 @@ async function parsePdfDocument(buffer, options) {
|
|
|
3086
3274
|
warnings.push({ page, message: `${count}\uAC1C \uC774\uBBF8\uC9C0 \uC601\uC5ED\uC5D0 \uCD94\uCD9C \uAC00\uB2A5\uD55C \uD14D\uC2A4\uD2B8 \uC5C6\uC74C (\uADF8\uB9BC/\uCC28\uD2B8/\uB3C4\uC7A5 \uB0B4\uC6A9 \uB204\uB77D \uAC00\uB2A5)`, code: "SKIPPED_IMAGE" });
|
|
3087
3275
|
}
|
|
3088
3276
|
}
|
|
3089
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
3277
|
+
if (_optionalChain([options, 'optionalAccess', _39 => _39.removeHeaderFooter]) !== false && parsedPageCount >= 3) {
|
|
3090
3278
|
const removed = removeHeaderFooterBlocks(blocks, pageHeights, warnings);
|
|
3091
3279
|
for (let ri = removed.length - 1; ri >= 0; ri--) {
|
|
3092
3280
|
blocks.splice(removed[ri], 1);
|
|
3093
3281
|
}
|
|
3094
3282
|
}
|
|
3095
3283
|
mergeCrossPageTables(blocks);
|
|
3096
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
3284
|
+
if (_optionalChain([options, 'optionalAccess', _40 => _40.formulaOcr]) && formulaBuffer) {
|
|
3097
3285
|
try {
|
|
3098
3286
|
await applyFormulaOcr(formulaBuffer, blocks, pageFilter, effectivePageCount, warnings, options.onProgress);
|
|
3099
3287
|
} catch (e) {
|
|
@@ -3112,7 +3300,7 @@ async function parsePdfDocument(buffer, options) {
|
|
|
3112
3300
|
detectKoreanListBlocks(blocks);
|
|
3113
3301
|
const outline = blocks.filter((b) => b.type === "heading" && b.level && b.text).map((b) => ({ level: b.level, text: b.text, pageNumber: b.pageNumber }));
|
|
3114
3302
|
sanitizeBlockControlChars(blocks);
|
|
3115
|
-
let markdown = cleanPdfText(
|
|
3303
|
+
let markdown = cleanPdfText(_chunkXL6O3VAYcjs.blocksToMarkdown.call(void 0, blocks));
|
|
3116
3304
|
return {
|
|
3117
3305
|
markdown,
|
|
3118
3306
|
blocks,
|
|
@@ -3131,7 +3319,7 @@ async function parsePdfDocument(buffer, options) {
|
|
|
3131
3319
|
async function extractPdfMetadata(doc, metadata) {
|
|
3132
3320
|
try {
|
|
3133
3321
|
const result = await doc.getMetadata();
|
|
3134
|
-
if (!_optionalChain([result, 'optionalAccess',
|
|
3322
|
+
if (!_optionalChain([result, 'optionalAccess', _41 => _41.info])) return;
|
|
3135
3323
|
const info = result.info;
|
|
3136
3324
|
if (typeof info.Title === "string" && info.Title.trim()) metadata.title = info.Title.trim();
|
|
3137
3325
|
if (typeof info.Author === "string" && info.Author.trim()) metadata.author = info.Author.trim();
|
|
@@ -3142,7 +3330,7 @@ async function extractPdfMetadata(doc, metadata) {
|
|
|
3142
3330
|
}
|
|
3143
3331
|
if (typeof info.CreationDate === "string") metadata.createdAt = parsePdfDate(info.CreationDate);
|
|
3144
3332
|
if (typeof info.ModDate === "string") metadata.modifiedAt = parsePdfDate(info.ModDate);
|
|
3145
|
-
} catch (
|
|
3333
|
+
} catch (e4) {
|
|
3146
3334
|
}
|
|
3147
3335
|
}
|
|
3148
3336
|
function parsePdfDate(dateStr) {
|
|
@@ -3171,4 +3359,4 @@ async function extractPdfMetadataOnly(buffer) {
|
|
|
3171
3359
|
|
|
3172
3360
|
|
|
3173
3361
|
exports.cleanPdfText = cleanPdfText; exports.detectKoreanListBlocks = detectKoreanListBlocks; exports.detectTableCaptions = detectTableCaptions; exports.extractPdfMetadataOnly = extractPdfMetadataOnly; exports.mergeCrossPageTables = mergeCrossPageTables; exports.parsePdfDocument = parsePdfDocument; exports.removeHeaderFooterBlocks = removeHeaderFooterBlocks;
|
|
3174
|
-
//# sourceMappingURL=parser-
|
|
3362
|
+
//# sourceMappingURL=parser-WWKYMRGJ.cjs.map
|