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.
Files changed (32) hide show
  1. package/README.md +12 -0
  2. package/dist/{-LD4BZDDJ.js → -F5IXBLQQ.js} +3 -3
  3. package/dist/{chunk-PELBIL4K.js → chunk-7J73IGMK.js} +2 -2
  4. package/dist/{chunk-KT2BCHXI.js → chunk-B27QMVL7.js} +872 -825
  5. package/dist/chunk-B27QMVL7.js.map +1 -0
  6. package/dist/{chunk-IFYJFWD2.js → chunk-KIWKBRCJ.js} +2 -2
  7. package/dist/{chunk-LFCS3UVG.cjs → chunk-XL6O3VAY.cjs} +2 -2
  8. package/dist/{chunk-LFCS3UVG.cjs.map → chunk-XL6O3VAY.cjs.map} +1 -1
  9. package/dist/cli.js +4 -4
  10. package/dist/index.cjs +1065 -1018
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +17 -8
  13. package/dist/index.d.ts +17 -8
  14. package/dist/index.js +871 -824
  15. package/dist/index.js.map +1 -1
  16. package/dist/mcp.js +3 -3
  17. package/dist/{parser-FFEBMLSH.js → parser-6GP535ZB.js} +211 -25
  18. package/dist/parser-6GP535ZB.js.map +1 -0
  19. package/dist/{parser-XEDROIM7.js → parser-TM3AS25T.js} +211 -25
  20. package/dist/parser-TM3AS25T.js.map +1 -0
  21. package/dist/{parser-IXK5V7YG.cjs → parser-WWKYMRGJ.cjs} +240 -52
  22. package/dist/parser-WWKYMRGJ.cjs.map +1 -0
  23. package/dist/{watch-MAWCDNFI.js → watch-HETTZ7BO.js} +3 -3
  24. package/package.json +2 -1
  25. package/dist/chunk-KT2BCHXI.js.map +0 -1
  26. package/dist/parser-FFEBMLSH.js.map +0 -1
  27. package/dist/parser-IXK5V7YG.cjs.map +0 -1
  28. package/dist/parser-XEDROIM7.js.map +0 -1
  29. /package/dist/{-LD4BZDDJ.js.map → -F5IXBLQQ.js.map} +0 -0
  30. /package/dist/{chunk-PELBIL4K.js.map → chunk-7J73IGMK.js.map} +0 -0
  31. /package/dist/{chunk-IFYJFWD2.js.map → chunk-KIWKBRCJ.js.map} +0 -0
  32. /package/dist/{watch-MAWCDNFI.js.map → watch-HETTZ7BO.js.map} +0 -0
@@ -6,11 +6,13 @@
6
6
 
7
7
 
8
8
 
9
- var _chunkLFCS3UVGcjs = require('./chunk-LFCS3UVG.cjs');
9
+ var _chunkXL6O3VAYcjs = require('./chunk-XL6O3VAY.cjs');
10
10
 
11
11
 
12
12
  var _chunkDCZVOIEOcjs = require('./chunk-DCZVOIEO.cjs');
13
- require('./chunk-GS7T56RP.cjs');
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 pushRectangle(path, rx, ry, rw, rh) {
28
- if (Math.abs(rh) < ORIENTATION_TOL * 2) {
29
- path.push({ x1: rx, y1: ry + rh / 2, x2: rx + rw, y2: ry + rh / 2 });
30
- } else if (Math.abs(rw) < ORIENTATION_TOL * 2) {
31
- path.push({ x1: rx + rw / 2, y1: ry, x2: rx + rw / 2, y2: ry + rh });
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
- path.push(
34
- { x1: rx, y1: ry, x2: rx + rw, y2: ry },
35
- { x1: rx + rw, y1: ry, x2: rx + rw, y2: ry + rh },
36
- { x1: rx + rw, y1: ry + rh, x2: rx, y2: ry + rh },
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, lineWidth, horizontals, verticals);
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
- currentPath.push({ x1: curX, y1: curY, x2, y2 });
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(currentPath, rx, ry, rw, rh);
108
+ pushRectangle(rx, ry, rw, rh);
79
109
  } else if (subOp === _pdfmjs.OPS.closePath) {
80
110
  if (curX !== pathStartX || curY !== pathStartY) {
81
- currentPath.push({ x1: curX, y1: curY, x2: pathStartX, y2: pathStartY });
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
- currentPath.push({ x1: curX, y1: curY, x2, y2 });
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
- currentPath.push({ x1: curX, y1: curY, x2: pathStartX, y2: pathStartY });
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', _9 => _9[r], 'access', _10 => _10.find, 'call', _11 => _11((c) => c.text.trim()), 'optionalAccess', _12 => _12.text, 'access', _13 => _13.trim, 'call', _14 => _14()]) || "";
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 = _chunkLFCS3UVGcjs.safeMax.call(void 0, gaps);
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 = _chunkLFCS3UVGcjs.safeMax.call(void 0, allItems.map((i) => i.x + i.w)) - _chunkLFCS3UVGcjs.safeMin.call(void 0, allItems.map((i) => i.x));
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', _15 => _15.style, 'optionalAccess', _16 => _16.fontSize])) continue;
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 >= _chunkLFCS3UVGcjs.HEADING_RATIO_H1) level = 1;
2080
- else if (ratio >= _chunkLFCS3UVGcjs.HEADING_RATIO_H2) level = 2;
2081
- else if (ratio >= _chunkLFCS3UVGcjs.HEADING_RATIO_H3) level = 3;
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', _17 => _17.style, 'optionalAccess', _18 => _18.fontSize])) {
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', _19 => _19.text, 'optionalAccess', _20 => _20.trim, 'call', _21 => _21()])) continue;
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', _22 => _22.get, 'call', _23 => _23(p), 'optionalAccess', _24 => _24.size]), () => ( 0))) >= MIN_REPEAT) {
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 = _chunkLFCS3UVGcjs.safeMax.call(void 0, allY) - _chunkLFCS3UVGcjs.safeMin.call(void 0, allY);
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 extractPageBlocksFallback(items, pageNum) {
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 = _chunkLFCS3UVGcjs.safeMax.call(void 0, allY) - _chunkLFCS3UVGcjs.safeMin.call(void 0, allY);
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, _chunkLFCS3UVGcjs.KordocError)("PDF \uB85C\uB529 \uD0C0\uC784\uC544\uC6C3 (30\uCD08 \uCD08\uACFC)"));
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', _25 => _25.formulaOcr]) ? buffer.slice(0) : null;
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, _chunkLFCS3UVGcjs.KordocError)("PDF\uC5D0 \uD398\uC774\uC9C0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
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', _26 => _26.pages]) ? _chunkDCZVOIEOcjs.parsePageRange.call(void 0, options.pages, effectivePageCount) : null;
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, _chunkLFCS3UVGcjs.KordocError)("\uD14D\uC2A4\uD2B8 \uCD94\uCD9C \uD06C\uAE30 \uCD08\uACFC");
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', _27 => _27.onProgress, 'optionalCall', _28 => _28(parsedPages, totalTarget)]);
3233
+ _optionalChain([options, 'optionalAccess', _36 => _36.onProgress, 'optionalCall', _37 => _37(parsedPages, totalTarget)]);
3046
3234
  } catch (pageErr) {
3047
- if (pageErr instanceof _chunkLFCS3UVGcjs.KordocError) throw pageErr;
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', _29 => _29.ocr])) {
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 (e2) {
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', _30 => _30.removeHeaderFooter]) !== false && parsedPageCount >= 3) {
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', _31 => _31.formulaOcr]) && formulaBuffer) {
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(_chunkLFCS3UVGcjs.blocksToMarkdown.call(void 0, blocks));
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', _32 => _32.info])) return;
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 (e3) {
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-IXK5V7YG.cjs.map
3362
+ //# sourceMappingURL=parser-WWKYMRGJ.cjs.map