kordoc 4.0.7 → 4.1.0

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 (123) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +837 -806
  3. package/dist/{-6HWEFXVV.js → -AS4IABL2.js} +24 -11
  4. package/dist/{chunk-BKWHX3RC.js → chunk-37HJHCPA.js} +24 -15
  5. package/dist/chunk-37HJHCPA.js.map +1 -0
  6. package/dist/{chunk-U25XGCNH.cjs → chunk-37VKMUST.cjs} +174 -25
  7. package/dist/chunk-37VKMUST.cjs.map +1 -0
  8. package/dist/{chunk-5OKHAJ62.js → chunk-4KI23VHA.js} +162 -13
  9. package/dist/chunk-4KI23VHA.js.map +1 -0
  10. package/dist/{chunk-6GBLFQMA.js → chunk-5RPYBC2Q.js} +1 -1
  11. package/dist/chunk-5RPYBC2Q.js.map +1 -0
  12. package/dist/{chunk-NGSHDBQR.js → chunk-AX2R5Q2N.js} +7 -4
  13. package/dist/chunk-AX2R5Q2N.js.map +1 -0
  14. package/dist/{chunk-X34YWRL5.cjs → chunk-DCZVOIEO.cjs} +1 -1
  15. package/dist/chunk-DCZVOIEO.cjs.map +1 -0
  16. package/dist/chunk-DZIXKL7E.js +145 -0
  17. package/dist/chunk-DZIXKL7E.js.map +1 -0
  18. package/dist/chunk-F2ZU3IZG.js +82 -0
  19. package/dist/chunk-F2ZU3IZG.js.map +1 -0
  20. package/dist/{chunk-AIQ3ISQU.js → chunk-GE43BE46.js} +1 -1
  21. package/dist/chunk-GE43BE46.js.map +1 -0
  22. package/dist/{chunk-Q7EN4EUJ.js → chunk-GQVSHGG4.js} +12 -4
  23. package/dist/chunk-GQVSHGG4.js.map +1 -0
  24. package/dist/chunk-GS7T56RP.cjs.map +1 -1
  25. package/dist/{chunk-TJJTLM76.js → chunk-L2XQQTOY.js} +1422 -1121
  26. package/dist/chunk-L2XQQTOY.js.map +1 -0
  27. package/dist/{chunk-3TBUDJDE.js → chunk-MOL7MDBG.js} +1 -1
  28. package/dist/chunk-MOL7MDBG.js.map +1 -0
  29. package/dist/{chunk-CNM75ZSX.js → chunk-O5VS7RIR.js} +2 -2
  30. package/dist/chunk-O5VS7RIR.js.map +1 -0
  31. package/dist/{chunk-2SN3CKME.js → chunk-SSTK6IKK.js} +18 -21
  32. package/dist/chunk-SSTK6IKK.js.map +1 -0
  33. package/dist/chunk-UOO7LSDG.js +152 -0
  34. package/dist/chunk-UOO7LSDG.js.map +1 -0
  35. package/dist/{chunk-ONXVBURQ.js → chunk-WO52HVQJ.js} +2 -2
  36. package/dist/chunk-WO52HVQJ.js.map +1 -0
  37. package/dist/{chunk-CFQLK3LM.js → chunk-YOO6ET6M.js} +7 -3
  38. package/dist/chunk-YOO6ET6M.js.map +1 -0
  39. package/dist/chunks-WVMGF7JL.js +10 -0
  40. package/dist/cli.js +173 -38
  41. package/dist/cli.js.map +1 -1
  42. package/dist/{detect-NTR2FUEG.js → detect-YEZX2XCF.js} +2 -2
  43. package/dist/{formula-ZYUDQHD3.cjs → formula-5NKVS2LR.cjs} +1 -1
  44. package/dist/formula-5NKVS2LR.cjs.map +1 -0
  45. package/dist/{formula-KOQV353G.js → formula-JCNF43NE.js} +1 -1
  46. package/dist/formula-JCNF43NE.js.map +1 -0
  47. package/dist/{formula-MEDGYQXS.js → formula-RXVSQPXI.js} +1 -1
  48. package/dist/formula-RXVSQPXI.js.map +1 -0
  49. package/dist/index.cjs +1932 -1397
  50. package/dist/index.cjs.map +1 -1
  51. package/dist/index.d.cts +106 -2
  52. package/dist/index.d.ts +106 -2
  53. package/dist/index.js +1626 -1091
  54. package/dist/index.js.map +1 -1
  55. package/dist/mcp.js +275 -67
  56. package/dist/mcp.js.map +1 -1
  57. package/dist/page-range-737B4EZW.js +8 -0
  58. package/dist/page-range-LNMXJU6W.js +7 -0
  59. package/dist/page-range-P7SDW6LR.cjs +8 -0
  60. package/dist/page-range-P7SDW6LR.cjs.map +1 -0
  61. package/dist/{parser-E6U5TNAU.cjs → parser-N4A7UGDK.cjs} +314 -56
  62. package/dist/parser-N4A7UGDK.cjs.map +1 -0
  63. package/dist/{parser-5EHWYJMC.js → parser-PEOYBXBO.js} +287 -27
  64. package/dist/parser-PEOYBXBO.js.map +1 -0
  65. package/dist/{parser-UGB3NIVH.js → parser-XX4QTDFQ.js} +283 -25
  66. package/dist/parser-XX4QTDFQ.js.map +1 -0
  67. package/dist/{profile-io-CAKRPQRD.js → profile-io-PLDQFPJA.js} +3 -3
  68. package/dist/{provider-5K7O3Z2O.cjs → provider-4FAYHJ6N.cjs} +3 -3
  69. package/dist/provider-4FAYHJ6N.cjs.map +1 -0
  70. package/dist/{provider-H4WWSPOV.js → provider-C6IOGIS5.js} +3 -3
  71. package/dist/provider-C6IOGIS5.js.map +1 -0
  72. package/dist/{provider-7H4CPZYS.js → provider-UIBW2MIH.js} +3 -3
  73. package/dist/provider-UIBW2MIH.js.map +1 -0
  74. package/dist/rasterize-WWNQLKYW.js +40 -0
  75. package/dist/rasterize-WWNQLKYW.js.map +1 -0
  76. package/dist/redact-7ILEAUTS.js +12 -0
  77. package/dist/render-T7S6H6AN.js +10 -0
  78. package/dist/render-T7S6H6AN.js.map +1 -0
  79. package/dist/seal-7PTL6MXH.js +10 -0
  80. package/dist/seal-7PTL6MXH.js.map +1 -0
  81. package/dist/{setup-QSJ2INNS.js → setup-Q2PRE7UA.js} +5 -3
  82. package/dist/setup-Q2PRE7UA.js.map +1 -0
  83. package/dist/{watch-RMX427YR.js → watch-SFHXZALC.js} +78 -24
  84. package/dist/watch-SFHXZALC.js.map +1 -0
  85. package/package.json +97 -97
  86. package/dist/chunk-2SN3CKME.js.map +0 -1
  87. package/dist/chunk-3TBUDJDE.js.map +0 -1
  88. package/dist/chunk-5OKHAJ62.js.map +0 -1
  89. package/dist/chunk-6GBLFQMA.js.map +0 -1
  90. package/dist/chunk-AIQ3ISQU.js.map +0 -1
  91. package/dist/chunk-BKWHX3RC.js.map +0 -1
  92. package/dist/chunk-CFQLK3LM.js.map +0 -1
  93. package/dist/chunk-CNM75ZSX.js.map +0 -1
  94. package/dist/chunk-NGSHDBQR.js.map +0 -1
  95. package/dist/chunk-ONXVBURQ.js.map +0 -1
  96. package/dist/chunk-Q7EN4EUJ.js.map +0 -1
  97. package/dist/chunk-TJJTLM76.js.map +0 -1
  98. package/dist/chunk-U25XGCNH.cjs.map +0 -1
  99. package/dist/chunk-X34YWRL5.cjs.map +0 -1
  100. package/dist/formula-KOQV353G.js.map +0 -1
  101. package/dist/formula-MEDGYQXS.js.map +0 -1
  102. package/dist/formula-ZYUDQHD3.cjs.map +0 -1
  103. package/dist/page-range-CIRRJPXJ.js +0 -7
  104. package/dist/page-range-OF5I4PQY.js +0 -8
  105. package/dist/page-range-TPIRSA3J.cjs +0 -8
  106. package/dist/page-range-TPIRSA3J.cjs.map +0 -1
  107. package/dist/parser-5EHWYJMC.js.map +0 -1
  108. package/dist/parser-E6U5TNAU.cjs.map +0 -1
  109. package/dist/parser-UGB3NIVH.js.map +0 -1
  110. package/dist/provider-5K7O3Z2O.cjs.map +0 -1
  111. package/dist/provider-7H4CPZYS.js.map +0 -1
  112. package/dist/provider-H4WWSPOV.js.map +0 -1
  113. package/dist/render-P6663O4I.js +0 -10
  114. package/dist/seal-7PPTXKKV.js +0 -10
  115. package/dist/setup-QSJ2INNS.js.map +0 -1
  116. package/dist/watch-RMX427YR.js.map +0 -1
  117. /package/dist/{-6HWEFXVV.js.map → -AS4IABL2.js.map} +0 -0
  118. /package/dist/{detect-NTR2FUEG.js.map → chunks-WVMGF7JL.js.map} +0 -0
  119. /package/dist/{page-range-CIRRJPXJ.js.map → detect-YEZX2XCF.js.map} +0 -0
  120. /package/dist/{page-range-OF5I4PQY.js.map → page-range-737B4EZW.js.map} +0 -0
  121. /package/dist/{profile-io-CAKRPQRD.js.map → page-range-LNMXJU6W.js.map} +0 -0
  122. /package/dist/{render-P6663O4I.js.map → profile-io-PLDQFPJA.js.map} +0 -0
  123. /package/dist/{seal-7PPTXKKV.js.map → redact-7ILEAUTS.js.map} +0 -0
@@ -3,16 +3,19 @@ import {
3
3
  HEADING_RATIO_H1,
4
4
  HEADING_RATIO_H2,
5
5
  HEADING_RATIO_H3,
6
- blocksToMarkdown
7
- } from "./chunk-2SN3CKME.js";
6
+ encodePng
7
+ } from "./chunk-UOO7LSDG.js";
8
8
  import {
9
9
  parsePageRange
10
- } from "./chunk-3TBUDJDE.js";
10
+ } from "./chunk-MOL7MDBG.js";
11
+ import {
12
+ blocksToMarkdown
13
+ } from "./chunk-SSTK6IKK.js";
11
14
  import {
12
15
  KordocError,
13
16
  safeMax,
14
17
  safeMin
15
- } from "./chunk-CNM75ZSX.js";
18
+ } from "./chunk-O5VS7RIR.js";
16
19
 
17
20
  // src/pdf/line-extract.ts
18
21
  import { OPS } from "pdfjs-dist/legacy/build/pdf.mjs";
@@ -580,6 +583,18 @@ function buildVertices(horizontals, verticals) {
580
583
  }
581
584
  function mergeVertices(vertices) {
582
585
  if (vertices.length <= 1) return vertices;
586
+ let maxRadiusAll = 1;
587
+ for (const v of vertices) {
588
+ if (v.radius > maxRadiusAll) maxRadiusAll = v.radius;
589
+ }
590
+ const cell = Math.max(VERTEX_MERGE_FACTOR * maxRadiusAll, 1);
591
+ const buckets = /* @__PURE__ */ new Map();
592
+ for (let i = 0; i < vertices.length; i++) {
593
+ const key = Math.floor(vertices[i].x / cell) + "," + Math.floor(vertices[i].y / cell);
594
+ const arr = buckets.get(key);
595
+ if (arr) arr.push(i);
596
+ else buckets.set(key, [i]);
597
+ }
583
598
  const merged = [];
584
599
  const used = new Array(vertices.length).fill(false);
585
600
  for (let i = 0; i < vertices.length; i++) {
@@ -587,7 +602,20 @@ function mergeVertices(vertices) {
587
602
  let sumX = vertices[i].x, sumY = vertices[i].y;
588
603
  let maxRadius = vertices[i].radius;
589
604
  let count = 1;
590
- for (let j = i + 1; j < vertices.length; j++) {
605
+ const cx = Math.floor(vertices[i].x / cell);
606
+ const cy = Math.floor(vertices[i].y / cell);
607
+ const candidates = [];
608
+ for (let dx = -1; dx <= 1; dx++) {
609
+ for (let dy = -1; dy <= 1; dy++) {
610
+ const arr = buckets.get(cx + dx + "," + (cy + dy));
611
+ if (!arr) continue;
612
+ for (const j of arr) {
613
+ if (j > i && !used[j]) candidates.push(j);
614
+ }
615
+ }
616
+ }
617
+ candidates.sort((a, b) => a - b);
618
+ for (const j of candidates) {
591
619
  if (used[j]) continue;
592
620
  const mergeTol = VERTEX_MERGE_FACTOR * Math.max(maxRadius, vertices[j].radius);
593
621
  if (Math.abs(vertices[i].x - vertices[j].x) <= mergeTol && Math.abs(vertices[i].y - vertices[j].y) <= mergeTol) {
@@ -814,6 +842,7 @@ function splitStackedGroup(group) {
814
842
  }
815
843
  return bands.filter((b) => b.length > 0);
816
844
  }
845
+ var GROUP_BUCKET_CELL = 100;
817
846
  function groupConnectedLines(lines) {
818
847
  const parent = lines.map((_, i) => i);
819
848
  function find(x) {
@@ -827,10 +856,34 @@ function groupConnectedLines(lines) {
827
856
  const ra = find(a), rb = find(b);
828
857
  if (ra !== rb) parent[ra] = rb;
829
858
  }
859
+ const cellMap = /* @__PURE__ */ new Map();
830
860
  for (let i = 0; i < lines.length; i++) {
831
- for (let j = i + 1; j < lines.length; j++) {
832
- if (linesIntersect(lines[i], lines[j])) {
833
- union(i, j);
861
+ const l = lines[i];
862
+ const cx1 = Math.floor((Math.min(l.x1, l.x2) - CONNECT_TOL) / GROUP_BUCKET_CELL);
863
+ const cx2 = Math.floor((Math.max(l.x1, l.x2) + CONNECT_TOL) / GROUP_BUCKET_CELL);
864
+ const cy1 = Math.floor((Math.min(l.y1, l.y2) - CONNECT_TOL) / GROUP_BUCKET_CELL);
865
+ const cy2 = Math.floor((Math.max(l.y1, l.y2) + CONNECT_TOL) / GROUP_BUCKET_CELL);
866
+ for (let cx = cx1; cx <= cx2; cx++) {
867
+ for (let cy = cy1; cy <= cy2; cy++) {
868
+ const key = cx + "," + cy;
869
+ const arr = cellMap.get(key);
870
+ if (arr) arr.push(i);
871
+ else cellMap.set(key, [i]);
872
+ }
873
+ }
874
+ }
875
+ const tested = /* @__PURE__ */ new Set();
876
+ for (const arr of cellMap.values()) {
877
+ for (let a = 0; a < arr.length; a++) {
878
+ for (let b = a + 1; b < arr.length; b++) {
879
+ const i = Math.min(arr[a], arr[b]);
880
+ const j = Math.max(arr[a], arr[b]);
881
+ const key = i * lines.length + j;
882
+ if (tested.has(key)) continue;
883
+ tested.add(key);
884
+ if (linesIntersect(lines[i], lines[j])) {
885
+ union(i, j);
886
+ }
834
887
  }
835
888
  }
836
889
  }
@@ -1223,6 +1276,172 @@ function normalizeUndersegmentedTable(originalCells, colXs, items) {
1223
1276
  return rebuilt;
1224
1277
  }
1225
1278
 
1279
+ // src/pdf/image-extract.ts
1280
+ import { OPS as OPS3, ImageKind } from "pdfjs-dist/legacy/build/pdf.mjs";
1281
+ var IMAGE_RESOLVE_TIMEOUT_MS = 5e3;
1282
+ function resolveImgData(page, objId) {
1283
+ const store = objId.startsWith("g_") ? page.commonObjs : page.objs;
1284
+ return new Promise((resolve) => {
1285
+ let done = false;
1286
+ const timer = setTimeout(() => {
1287
+ if (!done) {
1288
+ done = true;
1289
+ resolve(null);
1290
+ }
1291
+ }, IMAGE_RESOLVE_TIMEOUT_MS);
1292
+ try {
1293
+ store.get(objId, (data) => {
1294
+ if (!done) {
1295
+ done = true;
1296
+ clearTimeout(timer);
1297
+ resolve(data ?? null);
1298
+ }
1299
+ });
1300
+ } catch {
1301
+ if (!done) {
1302
+ done = true;
1303
+ clearTimeout(timer);
1304
+ resolve(null);
1305
+ }
1306
+ }
1307
+ });
1308
+ }
1309
+ var MIN_DIM = 8;
1310
+ var MAX_PIXELS = 36e6;
1311
+ var MAX_IMAGES_PER_DOC = 200;
1312
+ var MAX_TOTAL_IMAGE_BYTES = 128 * 1024 * 1024;
1313
+ function createPdfImageState() {
1314
+ return { imageIndex: 0, totalBytes: 0, seen: /* @__PURE__ */ new Map(), capWarned: false };
1315
+ }
1316
+ function fnv1a(data) {
1317
+ let h = 2166136261;
1318
+ for (let i = 0; i < data.length; i++) {
1319
+ h ^= data[i];
1320
+ h = Math.imul(h, 16777619);
1321
+ }
1322
+ return h >>> 0;
1323
+ }
1324
+ function toRgba(img) {
1325
+ const { width: w, height: h, kind, data } = img;
1326
+ if (!data || !w || !h) return null;
1327
+ const rgba = new Uint8Array(w * h * 4);
1328
+ if (kind === ImageKind.RGBA_32BPP) {
1329
+ if (data.length < w * h * 4) return null;
1330
+ rgba.set(data.subarray(0, w * h * 4));
1331
+ return rgba;
1332
+ }
1333
+ if (kind === ImageKind.RGB_24BPP) {
1334
+ if (data.length < w * h * 3) return null;
1335
+ for (let i = 0, s = 0, d = 0; i < w * h; i++, s += 3, d += 4) {
1336
+ rgba[d] = data[s];
1337
+ rgba[d + 1] = data[s + 1];
1338
+ rgba[d + 2] = data[s + 2];
1339
+ rgba[d + 3] = 255;
1340
+ }
1341
+ return rgba;
1342
+ }
1343
+ if (kind === ImageKind.GRAYSCALE_1BPP) {
1344
+ const stride = w + 7 >> 3;
1345
+ if (data.length < stride * h) return null;
1346
+ for (let y = 0; y < h; y++) {
1347
+ for (let x = 0; x < w; x++) {
1348
+ const bit = data[y * stride + (x >> 3)] >> 7 - (x & 7) & 1;
1349
+ const v = bit ? 255 : 0;
1350
+ const d = (y * w + x) * 4;
1351
+ rgba[d] = v;
1352
+ rgba[d + 1] = v;
1353
+ rgba[d + 2] = v;
1354
+ rgba[d + 3] = 255;
1355
+ }
1356
+ }
1357
+ return rgba;
1358
+ }
1359
+ return null;
1360
+ }
1361
+ async function extractPageImages(page, fnArray, argsArray, pageNumber, state, warnings) {
1362
+ const blocks = [];
1363
+ const images = [];
1364
+ const pageSeenIds = /* @__PURE__ */ new Set();
1365
+ for (let i = 0; i < fnArray.length; i++) {
1366
+ const op = fnArray[i];
1367
+ let imgData = null;
1368
+ let dedupeId = null;
1369
+ if (op === OPS3.paintImageXObject || op === OPS3.paintImageXObjectRepeat) {
1370
+ const objId = argsArray[i]?.[0];
1371
+ if (typeof objId !== "string" || pageSeenIds.has(objId)) continue;
1372
+ pageSeenIds.add(objId);
1373
+ dedupeId = objId;
1374
+ } else if (op !== OPS3.paintInlineImageXObject) {
1375
+ continue;
1376
+ }
1377
+ if (state.imageIndex >= MAX_IMAGES_PER_DOC || state.totalBytes >= MAX_TOTAL_IMAGE_BYTES) {
1378
+ if (!state.capWarned) {
1379
+ state.capWarned = true;
1380
+ warnings.push({ page: pageNumber, message: `\uC774\uBBF8\uC9C0 \uCD94\uCD9C \uC0C1\uD55C \uB3C4\uB2EC (${MAX_IMAGES_PER_DOC}\uAC1C/128MB) \u2014 \uC774\uD6C4 \uC774\uBBF8\uC9C0 \uC0DD\uB7B5`, code: "SKIPPED_IMAGE" });
1381
+ }
1382
+ continue;
1383
+ }
1384
+ if (dedupeId) {
1385
+ imgData = await resolveImgData(page, dedupeId);
1386
+ } else {
1387
+ imgData = argsArray[i]?.[0];
1388
+ }
1389
+ if (!imgData?.data || !imgData.width || !imgData.height) continue;
1390
+ const { width: w, height: h } = imgData;
1391
+ if (w < MIN_DIM || h < MIN_DIM) continue;
1392
+ if (w * h > MAX_PIXELS) {
1393
+ warnings.push({ page: pageNumber, message: `\uC774\uBBF8\uC9C0 \uD06C\uAE30 \uCD08\uACFC\uB85C \uCD94\uCD9C \uC0DD\uB7B5 (${w}\xD7${h})`, code: "SKIPPED_IMAGE" });
1394
+ continue;
1395
+ }
1396
+ const hash = `${w}x${h}k${imgData.kind ?? "?"}h${fnv1a(imgData.data)}${dedupeId ? "" : "inline"}`;
1397
+ if (state.seen.has(hash)) continue;
1398
+ const rgba = toRgba(imgData);
1399
+ if (!rgba) continue;
1400
+ const png = encodePng(w, h, rgba);
1401
+ state.imageIndex++;
1402
+ state.totalBytes += png.length;
1403
+ const filename = `image_${String(state.imageIndex).padStart(3, "0")}.png`;
1404
+ state.seen.set(hash, filename);
1405
+ images.push({ filename, data: png, mimeType: "image/png" });
1406
+ blocks.push({ type: "image", text: filename, pageNumber });
1407
+ }
1408
+ return { blocks, images };
1409
+ }
1410
+ function injectPageImageBlocks(blocks, pageImages) {
1411
+ if (pageImages.size === 0) return;
1412
+ const lastIndexForPage = /* @__PURE__ */ new Map();
1413
+ for (let i = 0; i < blocks.length; i++) {
1414
+ const p = blocks[i].pageNumber;
1415
+ if (p !== void 0) lastIndexForPage.set(p, i);
1416
+ }
1417
+ const pageAtIndex = /* @__PURE__ */ new Map();
1418
+ for (const [p, last] of lastIndexForPage) pageAtIndex.set(last, p);
1419
+ const result = [];
1420
+ const injected = /* @__PURE__ */ new Set();
1421
+ for (let i = 0; i < blocks.length; i++) {
1422
+ result.push(blocks[i]);
1423
+ const p = pageAtIndex.get(i);
1424
+ if (p !== void 0 && pageImages.has(p)) {
1425
+ result.push(...pageImages.get(p));
1426
+ injected.add(p);
1427
+ }
1428
+ }
1429
+ for (const p of [...pageImages.keys()].sort((a, b) => a - b)) {
1430
+ if (injected.has(p)) continue;
1431
+ let at = result.length;
1432
+ for (let i = 0; i < result.length; i++) {
1433
+ const bp = result[i].pageNumber;
1434
+ if (bp !== void 0 && bp > p) {
1435
+ at = i;
1436
+ break;
1437
+ }
1438
+ }
1439
+ result.splice(at, 0, ...pageImages.get(p));
1440
+ }
1441
+ blocks.length = 0;
1442
+ blocks.push(...result);
1443
+ }
1444
+
1226
1445
  // src/pdf/quality.ts
1227
1446
  var RARE_JONG = /* @__PURE__ */ new Set([3, 5, 6, 9, 10, 11, 12, 13, 14, 15, 18, 24, 25, 26]);
1228
1447
  var MOJIBAKE_MIN_HANGUL = 30;
@@ -2518,11 +2737,12 @@ function buildGridTable(lines, columns) {
2518
2737
  if (filledCells < totalCells * 0.35 || merged.length < 2 || merged.length <= 3 && numCols >= 7) {
2519
2738
  return merged.map((r) => r.filter((c) => c).join(" ")).join("\n");
2520
2739
  }
2740
+ const escCell = (c) => c.replace(/\t/g, " ").replace(/\|/g, "\\|");
2521
2741
  const md = [];
2522
- md.push("| " + merged[0].join(" | ") + " |");
2742
+ md.push("| " + merged[0].map(escCell).join(" | ") + " |");
2523
2743
  md.push("| " + merged[0].map(() => "---").join(" | ") + " |");
2524
2744
  for (let r = 1; r < merged.length; r++) {
2525
- md.push("| " + merged[r].join(" | ") + " |");
2745
+ md.push("| " + merged[r].map(escCell).join(" | ") + " |");
2526
2746
  }
2527
2747
  return md.join("\n");
2528
2748
  }
@@ -2702,6 +2922,7 @@ function detectKoreanListBlocks(blocks) {
2702
2922
  }
2703
2923
  let familyStack = [];
2704
2924
  let lastTopLevelList = null;
2925
+ let prevListIdx = -2;
2705
2926
  const toRemove = /* @__PURE__ */ new Set();
2706
2927
  for (let i = 0; i < blocks.length; i++) {
2707
2928
  const b = blocks[i];
@@ -2730,7 +2951,7 @@ function detectKoreanListBlocks(blocks) {
2730
2951
  if (depth === 0) {
2731
2952
  blocks[i] = listBlock;
2732
2953
  lastTopLevelList = listBlock;
2733
- } else if (lastTopLevelList) {
2954
+ } else if (lastTopLevelList && i === prevListIdx + 1) {
2734
2955
  if (!lastTopLevelList.children) lastTopLevelList.children = [];
2735
2956
  lastTopLevelList.children.push(listBlock);
2736
2957
  toRemove.add(i);
@@ -2738,6 +2959,7 @@ function detectKoreanListBlocks(blocks) {
2738
2959
  blocks[i] = listBlock;
2739
2960
  lastTopLevelList = listBlock;
2740
2961
  }
2962
+ prevListIdx = i;
2741
2963
  }
2742
2964
  if (toRemove.size > 0) {
2743
2965
  const sorted = [...toRemove].sort((a, b) => b - a);
@@ -2863,8 +3085,8 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings) {
2863
3085
  const blockTop = ph - (b.bbox.y + b.bbox.height);
2864
3086
  const blockBottom = ph - b.bbox.y;
2865
3087
  const entry = { blockIdx: bi, page: b.pageNumber, text: b.text.trim() };
2866
- if (blockBottom <= ph * ZONE_RATIO) bottomEntries.push(entry);
2867
- else if (blockTop >= ph * (1 - ZONE_RATIO)) topEntries.push(entry);
3088
+ if (blockBottom <= ph * ZONE_RATIO) topEntries.push(entry);
3089
+ else if (blockTop >= ph * (1 - ZONE_RATIO)) bottomEntries.push(entry);
2868
3090
  }
2869
3091
  const removeSet = /* @__PURE__ */ new Set();
2870
3092
  for (const entries of [topEntries, bottomEntries]) {
@@ -3037,6 +3259,8 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3037
3259
  hasSpaceBefore: i.hasSpaceBefore
3038
3260
  }));
3039
3261
  const cellTextMap = mapTextToCells(textItems, cells);
3262
+ const assignedItems = /* @__PURE__ */ new Set();
3263
+ for (const arr of cellTextMap.values()) for (const it of arr) assignedItems.add(it);
3040
3264
  const numRows = grid.rowYs.length - 1;
3041
3265
  const numCols = grid.colXs.length - 1;
3042
3266
  const irGrid = Array.from(
@@ -3056,9 +3280,11 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3056
3280
  }
3057
3281
  let finalGrid = irGrid;
3058
3282
  let finalRows = numRows;
3283
+ let rebuiltUsed = false;
3059
3284
  if (numRows <= 2 && numCols >= 3) {
3060
3285
  const rebuilt = normalizeUndersegmentedTable(irGrid, grid.colXs, textItems);
3061
3286
  if (rebuilt) {
3287
+ rebuiltUsed = true;
3062
3288
  finalGrid = rebuilt.map((row) => row.map((rawText) => {
3063
3289
  const cleaned = rawText.replace(/^[\s]*[-–—]\s*\d+\s*[-–—][\s]*$/gm, "").trim();
3064
3290
  return {
@@ -3070,6 +3296,11 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3070
3296
  finalRows = finalGrid.length;
3071
3297
  }
3072
3298
  }
3299
+ if (!rebuiltUsed) {
3300
+ for (let ti = 0; ti < textItems.length; ti++) {
3301
+ if (!assignedItems.has(textItems[ti])) usedItems.delete(tableItems[ti]);
3302
+ }
3303
+ }
3073
3304
  const irTable = {
3074
3305
  rows: finalRows,
3075
3306
  cols: numCols,
@@ -3126,6 +3357,8 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3126
3357
  }
3127
3358
  remaining = remaining.filter((_, idx) => !usedClusterIndices.has(idx));
3128
3359
  }
3360
+ const groupSizes = [];
3361
+ let finalTextBlocks = [];
3129
3362
  if (remaining.length > 0) {
3130
3363
  const allY = remaining.map((i) => i.y);
3131
3364
  const pageH = safeMax(allY) - safeMin(allY);
@@ -3135,16 +3368,28 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3135
3368
  if (group.length === 0) continue;
3136
3369
  const groupBlocks = extractPageBlocksFallback(group, pageNum);
3137
3370
  for (const b of groupBlocks) textBlocks.push(b);
3371
+ groupSizes.push(groupBlocks.length);
3138
3372
  }
3139
- const finalTextBlocks = detectListBlocks(textBlocks);
3140
- for (const b of finalTextBlocks) blocks.push(b);
3373
+ finalTextBlocks = detectListBlocks(textBlocks);
3141
3374
  }
3142
- blocks.sort((a, b) => {
3143
- const ay = a.bbox ? a.bbox.y + a.bbox.height : 0;
3144
- const by = b.bbox ? b.bbox.y + b.bbox.height : 0;
3145
- return by - ay;
3146
- });
3147
- return mergeAdjacentTableBlocks(blocks);
3375
+ const units = blocks.map((b) => [b]);
3376
+ let off = 0;
3377
+ for (const size of groupSizes) {
3378
+ const unit = finalTextBlocks.slice(off, off + size);
3379
+ off += size;
3380
+ if (unit.length > 0) units.push(unit);
3381
+ }
3382
+ const unitTopY = (u) => {
3383
+ let top = 0;
3384
+ for (const b of u) {
3385
+ if (b.bbox && b.bbox.y + b.bbox.height > top) top = b.bbox.y + b.bbox.height;
3386
+ }
3387
+ return top;
3388
+ };
3389
+ units.sort((a, b) => unitTopY(b) - unitTopY(a));
3390
+ const ordered = [];
3391
+ for (const u of units) for (const b of u) ordered.push(b);
3392
+ return mergeAdjacentTableBlocks(ordered);
3148
3393
  }
3149
3394
  return mergeAdjacentTableBlocks(blocks);
3150
3395
  }
@@ -3390,7 +3635,7 @@ function mergeKoreanLines(text) {
3390
3635
 
3391
3636
  // src/pdf/formula-ocr.ts
3392
3637
  async function applyFormulaOcr(buffer, blocks, pageFilter, effectivePageCount, warnings, _onProgress) {
3393
- const formulaMod = await import("./formula-KOQV353G.js");
3638
+ const formulaMod = await import("./formula-JCNF43NE.js");
3394
3639
  const { FormulaPipeline, ensureFormulaModels } = formulaMod;
3395
3640
  await ensureFormulaModels((p) => {
3396
3641
  if (p.phase === "download" && p.total) {
@@ -3585,6 +3830,9 @@ async function parsePdfDocument(buffer, options) {
3585
3830
  const pageHeights = /* @__PURE__ */ new Map();
3586
3831
  const pagesWithLargeImage = /* @__PURE__ */ new Set();
3587
3832
  const skippedImagePages = /* @__PURE__ */ new Map();
3833
+ const imageState = createPdfImageState();
3834
+ const extractedImages = [];
3835
+ const pageImageBlocks = /* @__PURE__ */ new Map();
3588
3836
  let parsedPages = 0;
3589
3837
  for (let i = 1; i <= effectivePageCount; i++) {
3590
3838
  if (pageFilter && !pageFilter.has(i)) continue;
@@ -3622,9 +3870,19 @@ async function parsePdfDocument(buffer, options) {
3622
3870
  }
3623
3871
  const pageBlocks = extractPageBlocksWithLines(visible, i, opList, viewport.width, viewport.height);
3624
3872
  for (const b of pageBlocks) blocks.push(b);
3873
+ try {
3874
+ const { blocks: imgBlocks, images: pageImages } = await extractPageImages(page, opList.fnArray, opList.argsArray, i, imageState, warnings);
3875
+ if (imgBlocks.length > 0) pageImageBlocks.set(i, imgBlocks);
3876
+ extractedImages.push(...pageImages);
3877
+ } catch {
3878
+ }
3625
3879
  let pageText = "";
3626
3880
  for (const b of pageBlocks) {
3627
- const t = b.text || "";
3881
+ let t = b.text || "";
3882
+ if (b.type === "table" && b.table) {
3883
+ const cellText = b.table.cells.map((row) => row.map((c) => c.text).join(" ")).join("\n");
3884
+ t = t ? t + "\n" + cellText : cellText;
3885
+ }
3628
3886
  totalChars += t.replace(/\s/g, "").length;
3629
3887
  totalTextBytes += t.length * 2;
3630
3888
  pageText += pageText ? "\n" + t : t;
@@ -3643,11 +3901,11 @@ async function parsePdfDocument(buffer, options) {
3643
3901
  if (totalChars / Math.max(parsedPageCount, 1) < 10) {
3644
3902
  if (options?.ocr) {
3645
3903
  try {
3646
- const { ocrPages } = await import("./provider-7H4CPZYS.js");
3904
+ const { ocrPages } = await import("./provider-UIBW2MIH.js");
3647
3905
  const ocrBlocks = await ocrPages(doc, options.ocr, pageFilter, effectivePageCount);
3648
3906
  if (ocrBlocks.length > 0) {
3649
3907
  const ocrMarkdown = ocrBlocks.map((b) => b.text || "").filter(Boolean).join("\n\n");
3650
- return { markdown: ocrMarkdown, blocks: ocrBlocks, metadata, warnings, isImageBased: true, pageQuality, qualitySummary: summarizeDocumentQuality(pageQuality) };
3908
+ return { markdown: ocrMarkdown, blocks: ocrBlocks, metadata, warnings, isImageBased: true, pageQuality, qualitySummary: summarizeDocumentQuality(pageQuality), images: extractedImages.length > 0 ? extractedImages : void 0 };
3651
3909
  }
3652
3910
  } catch {
3653
3911
  }
@@ -3684,6 +3942,7 @@ async function parsePdfDocument(buffer, options) {
3684
3942
  }
3685
3943
  }
3686
3944
  mergeCrossPageTables(blocks);
3945
+ injectPageImageBlocks(blocks, pageImageBlocks);
3687
3946
  if (options?.formulaOcr && formulaBuffer) {
3688
3947
  try {
3689
3948
  await applyFormulaOcr(formulaBuffer, blocks, pageFilter, effectivePageCount, warnings, options.onProgress);
@@ -3712,7 +3971,8 @@ async function parsePdfDocument(buffer, options) {
3712
3971
  warnings: warnings.length > 0 ? warnings : void 0,
3713
3972
  isImageBased: isImageBased || void 0,
3714
3973
  pageQuality,
3715
- qualitySummary: summarizeDocumentQuality(pageQuality)
3974
+ qualitySummary: summarizeDocumentQuality(pageQuality),
3975
+ images: extractedImages.length > 0 ? extractedImages : void 0
3716
3976
  };
3717
3977
  } finally {
3718
3978
  await doc.destroy().catch(() => {
@@ -3762,4 +4022,4 @@ export {
3762
4022
  parsePdfDocument,
3763
4023
  removeHeaderFooterBlocks
3764
4024
  };
3765
- //# sourceMappingURL=parser-5EHWYJMC.js.map
4025
+ //# sourceMappingURL=parser-PEOYBXBO.js.map