kordoc 3.8.2 → 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.
@@ -6,7 +6,7 @@ import {
6
6
  blocksToMarkdown,
7
7
  safeMax,
8
8
  safeMin
9
- } from "./chunk-553VTUVP.js";
9
+ } from "./chunk-7J73IGMK.js";
10
10
  import {
11
11
  parsePageRange
12
12
  } from "./chunk-GE43BE46.js";
@@ -1262,7 +1262,106 @@ function detectClusterTables(items, pageNum) {
1262
1262
  }
1263
1263
  }
1264
1264
  }
1265
- return results;
1265
+ return results.filter((r) => !isTwoColumnProse(r));
1266
+ }
1267
+ function isTwoColumnProse(r) {
1268
+ const t = r.table;
1269
+ if (t.rows < 8) return false;
1270
+ const dense = [];
1271
+ for (let c = 0; c < t.cols; c++) {
1272
+ const filled = t.cells.filter((row) => row[c]?.text.trim()).length;
1273
+ if (filled / t.rows >= 0.3) dense.push(c);
1274
+ }
1275
+ if (dense.length !== 2) return false;
1276
+ for (const c of dense) {
1277
+ const lens = t.cells.map((row) => row[c]?.text.replace(/\s+/g, "").length ?? 0).filter((n) => n > 0);
1278
+ const avg = lens.reduce((s, v) => s + v, 0) / (lens.length || 1);
1279
+ if (avg < 12) return false;
1280
+ }
1281
+ return findTwoColumnProseCutX([...r.usedItems]) !== null;
1282
+ }
1283
+ function findTwoColumnProseCutX(items) {
1284
+ const lines = groupByBaseline(items);
1285
+ if (lines.length < 8) return null;
1286
+ let minX = Infinity;
1287
+ let maxX = -Infinity;
1288
+ for (const i of items) {
1289
+ if (i.x < minX) minX = i.x;
1290
+ if (i.x + i.w > maxX) maxX = i.x + i.w;
1291
+ }
1292
+ if (!Number.isFinite(maxX - minX)) return null;
1293
+ if (maxX - minX < 100) return null;
1294
+ const lo = minX + (maxX - minX) * 0.3;
1295
+ const hi = minX + (maxX - minX) * 0.7;
1296
+ const step = Math.max(2, (hi - lo) / 400);
1297
+ let cutX = 0;
1298
+ let bestCover = Infinity;
1299
+ for (let x = lo; x <= hi; x += step) {
1300
+ let cover = 0;
1301
+ for (const line of lines) {
1302
+ if (line.items.some((i) => i.x < x && i.x + i.w > x)) cover++;
1303
+ }
1304
+ if (cover < bestCover) {
1305
+ bestCover = cover;
1306
+ cutX = x;
1307
+ }
1308
+ }
1309
+ if (bestCover / lines.length > 0.15) return null;
1310
+ const left = [];
1311
+ const right = [];
1312
+ let twoSide = 0;
1313
+ for (const line of lines) {
1314
+ let hasL = false;
1315
+ let hasR = false;
1316
+ for (const i of line.items) {
1317
+ if (i.x + i.w <= cutX) {
1318
+ left.push(i);
1319
+ hasL = true;
1320
+ } else if (i.x >= cutX) {
1321
+ right.push(i);
1322
+ hasR = true;
1323
+ }
1324
+ }
1325
+ if (hasL && hasR) twoSide++;
1326
+ }
1327
+ if (twoSide / lines.length < 0.55) return null;
1328
+ if (left.length < 5 || right.length < 5) return null;
1329
+ const allText = items.map((i) => i.text).join("").replace(/\s+/g, "");
1330
+ const digits = (allText.match(/[\d,.%△—-]/g) || []).length;
1331
+ if (allText.length === 0 || digits / allText.length > 0.15) return null;
1332
+ const stats = [left, right].map((side) => {
1333
+ let sMinX = Infinity;
1334
+ let sMaxR = -Infinity;
1335
+ let fsSum = 0;
1336
+ const rowEnds = /* @__PURE__ */ new Map();
1337
+ const rowLens = /* @__PURE__ */ new Map();
1338
+ const rowFirst = /* @__PURE__ */ new Map();
1339
+ for (const i of side) {
1340
+ if (i.x < sMinX) sMinX = i.x;
1341
+ const rgt = i.x + i.w;
1342
+ if (rgt > sMaxR) sMaxR = rgt;
1343
+ fsSum += i.fontSize;
1344
+ const key = Math.round(i.y / 4);
1345
+ rowEnds.set(key, Math.max(rowEnds.get(key) ?? -Infinity, rgt));
1346
+ rowLens.set(key, (rowLens.get(key) ?? 0) + i.text.replace(/\s+/g, "").length);
1347
+ const f = rowFirst.get(key);
1348
+ if (!f || i.x < f.x) rowFirst.set(key, i);
1349
+ }
1350
+ const ends = [...rowEnds.values()].sort((a, b) => a - b);
1351
+ const p85 = ends[Math.floor(ends.length * 0.85)] ?? sMaxR;
1352
+ const fs = fsSum / side.length;
1353
+ const justified = ends.filter((e) => Math.abs(e - p85) <= fs).length / ends.length;
1354
+ const lens = [...rowLens.values()];
1355
+ const avgLen = lens.reduce((s, v) => s + v, 0) / (lens.length || 1);
1356
+ const markers = [...rowFirst.values()].filter((i) => /^[•▪◦‣∙·\-–—□■◇◆▶※*]/.test(i.text)).length;
1357
+ return { width: sMaxR - sMinX, justified, avgLen, markerRatio: markers / (rowFirst.size || 1) };
1358
+ });
1359
+ if (stats.some((s) => s.avgLen < 12)) return null;
1360
+ if (stats.some((s) => s.markerRatio > 0.1)) return null;
1361
+ const widthSym = Math.min(stats[0].width, stats[1].width) / Math.max(stats[0].width, stats[1].width);
1362
+ if (widthSym < 0.6) return null;
1363
+ if (Math.min(stats[0].justified, stats[1].justified) < 0.55) return null;
1364
+ return cutX;
1266
1365
  }
1267
1366
  function mergeEvenSpacedClusters(items) {
1268
1367
  const originMap = /* @__PURE__ */ new Map();
@@ -2459,7 +2558,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
2459
2558
  if (grids.length > 0) {
2460
2559
  return extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals);
2461
2560
  }
2462
- return extractPageBlocksFallback(items, pageNum);
2561
+ return extractPageBlocksFallback(items, pageNum, true);
2463
2562
  }
2464
2563
  var STRIKE_MAX_THICKNESS = 2;
2465
2564
  var STRIKE_MAX_THICKNESS_RATIO = 0.25;
@@ -2704,7 +2803,53 @@ function mergeAdjacentTableBlocks(blocks) {
2704
2803
  }
2705
2804
  return result;
2706
2805
  }
2707
- function extractPageBlocksFallback(items, pageNum) {
2806
+ function splitTwoColumnProse(items, cutX) {
2807
+ const left = [];
2808
+ const right = [];
2809
+ const cross = [];
2810
+ for (const i of items) {
2811
+ if (i.x + i.w <= cutX) left.push(i);
2812
+ else if (i.x >= cutX) right.push(i);
2813
+ else cross.push(i);
2814
+ }
2815
+ if (cross.length === 0) {
2816
+ return [left, right].filter((g2) => g2.length > 0);
2817
+ }
2818
+ cross.sort((a, b) => b.y - a.y);
2819
+ const crossLines = [];
2820
+ for (const c of cross) {
2821
+ const last = crossLines[crossLines.length - 1];
2822
+ if (last && Math.abs(last[0].y - c.y) <= 3) last.push(c);
2823
+ else crossLines.push([c]);
2824
+ }
2825
+ const bandItem = (arr) => arr.filter((i) => {
2826
+ for (const cl of crossLines) {
2827
+ if (Math.abs(cl[0].y - i.y) <= 3) {
2828
+ cl.push(i);
2829
+ return false;
2830
+ }
2831
+ }
2832
+ return true;
2833
+ });
2834
+ const leftRest = bandItem(left);
2835
+ const rightRest = bandItem(right);
2836
+ const boundYs = crossLines.map((cl) => cl[0].y);
2837
+ const bandOf = (y) => {
2838
+ let k = 0;
2839
+ while (k < boundYs.length && y < boundYs[k]) k++;
2840
+ return k;
2841
+ };
2842
+ const groups = [];
2843
+ for (let k = 0; k <= crossLines.length; k++) {
2844
+ const L = leftRest.filter((i) => bandOf(i.y) === k);
2845
+ const R = rightRest.filter((i) => bandOf(i.y) === k);
2846
+ if (L.length > 0) groups.push(L);
2847
+ if (R.length > 0) groups.push(R);
2848
+ if (k < crossLines.length) groups.push(crossLines[k]);
2849
+ }
2850
+ return groups;
2851
+ }
2852
+ function extractPageBlocksFallback(items, pageNum, fullPage = false) {
2708
2853
  if (items.length === 0) return [];
2709
2854
  const blocks = [];
2710
2855
  const clusterItems = items.map((i) => ({
@@ -2745,8 +2890,9 @@ function extractPageBlocksFallback(items, pageNum) {
2745
2890
  return by - ay;
2746
2891
  });
2747
2892
  } else {
2893
+ const proseCutX = fullPage ? findTwoColumnProseCutX(items) : null;
2748
2894
  const allYLines = mergeSuperscriptLines(groupByY(items));
2749
- const columns = detectColumns(allYLines);
2895
+ const columns = proseCutX !== null ? null : detectColumns(allYLines);
2750
2896
  if (columns && columns.length >= 3) {
2751
2897
  const tableText = extractWithColumns(allYLines, columns);
2752
2898
  const bbox = computeBBox(items, pageNum);
@@ -2755,7 +2901,7 @@ function extractPageBlocksFallback(items, pageNum) {
2755
2901
  const allY = items.map((i) => i.y);
2756
2902
  const pageHeight = safeMax(allY) - safeMin(allY);
2757
2903
  const gapThreshold = Math.max(15, pageHeight * 0.03);
2758
- const orderedGroups = xyCutOrder(items, gapThreshold);
2904
+ const orderedGroups = proseCutX !== null ? splitTwoColumnProse(items, proseCutX) : xyCutOrder(items, gapThreshold);
2759
2905
  for (const group of orderedGroups) {
2760
2906
  if (group.length === 0) continue;
2761
2907
  const yLines = mergeSuperscriptLines(groupByY(group));
@@ -3210,4 +3356,4 @@ export {
3210
3356
  parsePdfDocument,
3211
3357
  removeHeaderFooterBlocks
3212
3358
  };
3213
- //# sourceMappingURL=parser-NR2TYGO3.js.map
3359
+ //# sourceMappingURL=parser-TM3AS25T.js.map