kordoc 4.14.2 → 4.14.4

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 (151) hide show
  1. package/README.md +51 -6
  2. package/dist/{-AQKXLFIM.js → -Z4TJ3QGK.js} +13 -11
  3. package/dist/{chunk-QOMNEWCQ.cjs → chunk-5LAZQCUJ.cjs} +305 -31
  4. package/dist/chunk-5LAZQCUJ.cjs.map +1 -0
  5. package/dist/{chunk-7IAQ4HOK.js → chunk-6BWU6SQX.js} +1 -1
  6. package/dist/chunk-6BWU6SQX.js.map +1 -0
  7. package/dist/{chunk-FOJZNMMK.js → chunk-6CUIXJOC.js} +1 -1
  8. package/dist/chunk-6CUIXJOC.js.map +1 -0
  9. package/dist/{chunk-ZWD734EY.js → chunk-7SE4EZ45.js} +2 -2
  10. package/dist/{chunk-TSFS5VKD.js → chunk-D4U2TXDC.js} +332 -141
  11. package/dist/chunk-D4U2TXDC.js.map +1 -0
  12. package/dist/chunk-DPWWXUOG.js +2222 -0
  13. package/dist/chunk-DPWWXUOG.js.map +1 -0
  14. package/dist/{chunk-GDW4YP7K.js → chunk-GLSBEEZJ.js} +2 -2
  15. package/dist/{chunk-JQEFP45L.js → chunk-GUJ4Q73I.js} +2 -2
  16. package/dist/{chunk-ZWOFQRIB.js → chunk-HIJUKZHM.js} +3 -3
  17. package/dist/chunk-IMAAFSAX.cjs +1352 -0
  18. package/dist/chunk-IMAAFSAX.cjs.map +1 -0
  19. package/dist/{chunk-TNCKOL2O.js → chunk-LCW7SEPG.js} +2 -2
  20. package/dist/chunk-LFSQAMSM.js +1352 -0
  21. package/dist/chunk-LFSQAMSM.js.map +1 -0
  22. package/dist/chunk-MG6DJEX4.js +1299 -0
  23. package/dist/chunk-MG6DJEX4.js.map +1 -0
  24. package/dist/{chunk-QC5T6D4J.js → chunk-NLU6LBLY.js} +299 -25
  25. package/dist/chunk-NLU6LBLY.js.map +1 -0
  26. package/dist/{chunk-EQZI77PP.cjs → chunk-QEJUY6SK.cjs} +3 -3
  27. package/dist/{chunk-EQZI77PP.cjs.map → chunk-QEJUY6SK.cjs.map} +1 -1
  28. package/dist/{chunk-VQ5W4MYO.js → chunk-QIF2VXBQ.js} +298 -24
  29. package/dist/chunk-QIF2VXBQ.js.map +1 -0
  30. package/dist/{chunk-UET462HB.js → chunk-TITDJWVZ.js} +2 -2
  31. package/dist/{chunk-247ANM72.cjs → chunk-USHQCF5T.cjs} +870 -147
  32. package/dist/chunk-USHQCF5T.cjs.map +1 -0
  33. package/dist/{chunk-C7FQBSON.js → chunk-V3DX4DUF.js} +2 -2
  34. package/dist/{chunk-DOGPOY4B.js → chunk-VDN7LMPL.js} +2 -2
  35. package/dist/{chunk-EDNJLUSE.js → chunk-VJIL6PIL.js} +2 -2
  36. package/dist/{chunk-L7DMSMAG.cjs → chunk-VWUYVEFN.cjs} +1 -1
  37. package/dist/chunk-VWUYVEFN.cjs.map +1 -0
  38. package/dist/{chunk-HR2XNERB.cjs → chunk-WJHAU73B.cjs} +2 -2
  39. package/dist/{chunk-HR2XNERB.cjs.map → chunk-WJHAU73B.cjs.map} +1 -1
  40. package/dist/{chunk-NS55SM7A.js → chunk-WJJGW5PL.js} +2 -2
  41. package/dist/{chunk-EISO3POT.js → chunk-XVXHXQIO.js} +788 -194
  42. package/dist/chunk-XVXHXQIO.js.map +1 -0
  43. package/dist/{chunk-ILU76UF3.js → chunk-YAKC46HZ.js} +2 -2
  44. package/dist/chunk-YAKC46HZ.js.map +1 -0
  45. package/dist/{chunk-3DUADAY2.js → chunk-YAVHVFRY.js} +851 -128
  46. package/dist/chunk-YAVHVFRY.js.map +1 -0
  47. package/dist/{chunk-A7QC2ZVP.js → chunk-YT3GC62E.js} +851 -128
  48. package/dist/chunk-YT3GC62E.js.map +1 -0
  49. package/dist/chunks-CCMRL4MJ.js +10 -0
  50. package/dist/cli.js +228 -97
  51. package/dist/cli.js.map +1 -1
  52. package/dist/{formula-PJJ6S3Z2.cjs → formula-5LOVHAKE.cjs} +9 -9
  53. package/dist/{formula-PJJ6S3Z2.cjs.map → formula-5LOVHAKE.cjs.map} +1 -1
  54. package/dist/{formula-JGFTXWYT.js → formula-7RANCW5L.js} +3 -3
  55. package/dist/{formula-5S7WWXGH.js → formula-7UYJOVTB.js} +4 -4
  56. package/dist/{image-ocr-WCAYXLOA.js → image-ocr-I6JOCATS.js} +34 -16
  57. package/dist/image-ocr-I6JOCATS.js.map +1 -0
  58. package/dist/{image-ocr-ZTYAGV3W.cjs → image-ocr-NYBJEOH2.cjs} +36 -18
  59. package/dist/image-ocr-NYBJEOH2.cjs.map +1 -0
  60. package/dist/{image-ocr-FLIL7MGN.js → image-ocr-ZV6PDBUQ.js} +32 -14
  61. package/dist/image-ocr-ZV6PDBUQ.js.map +1 -0
  62. package/dist/index.cjs +4048 -1216
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +66 -28
  65. package/dist/index.d.ts +66 -28
  66. package/dist/index.js +3487 -655
  67. package/dist/index.js.map +1 -1
  68. package/dist/mcp.js +74 -53
  69. package/dist/mcp.js.map +1 -1
  70. package/dist/{model-bundle-FSPZZ2EM.js → model-bundle-2C5IYDLE.js} +5 -5
  71. package/dist/{models-CJPAQK5R.js → models-SEQZHZFT.js} +5 -5
  72. package/dist/{parser-SCUTZAIJ.js → parser-3FNXEP6T.js} +708 -250
  73. package/dist/parser-3FNXEP6T.js.map +1 -0
  74. package/dist/{parser-A4TMPJAM.js → parser-FJBJXRJK.js} +708 -250
  75. package/dist/parser-FJBJXRJK.js.map +1 -0
  76. package/dist/{parser-VCXE4I5A.cjs → parser-HVEKF73B.cjs} +733 -275
  77. package/dist/parser-HVEKF73B.cjs.map +1 -0
  78. package/dist/pdf-ocr-JRDBJ6TA.cjs +14 -0
  79. package/dist/{pdf-ocr-MBZZ57LD.cjs.map → pdf-ocr-JRDBJ6TA.cjs.map} +1 -1
  80. package/dist/pdf-ocr-UUBWBEHL.js +16 -0
  81. package/dist/pdf-ocr-VJSF2SQC.js +13 -0
  82. package/dist/{profile-io-LBM263K7.js → profile-io-RUFZOZO6.js} +3 -3
  83. package/dist/{rasterize-46RG4ZF6.js → rasterize-IOYXR5SI.js} +3 -3
  84. package/dist/redact-NMIKVHMP.js +18 -0
  85. package/dist/redact-doc-QBHNJ2BU.js +1284 -0
  86. package/dist/redact-doc-QBHNJ2BU.js.map +1 -0
  87. package/dist/{render-NGP5T24S.js → render-YZ2TEC3N.js} +7 -7
  88. package/dist/seal-ECV44TUH.js +10 -0
  89. package/dist/{setup-AU4OCHNH.js → setup-MPIEP6XT.js} +3 -3
  90. package/dist/visual-ICMOWUCR.js +19 -0
  91. package/dist/{watch-MKPUCPXM.js → watch-RYO7MN5B.js} +12 -12
  92. package/package.json +2 -2
  93. package/dist/chunk-247ANM72.cjs.map +0 -1
  94. package/dist/chunk-3DUADAY2.js.map +0 -1
  95. package/dist/chunk-422427XJ.cjs +0 -571
  96. package/dist/chunk-422427XJ.cjs.map +0 -1
  97. package/dist/chunk-7IAQ4HOK.js.map +0 -1
  98. package/dist/chunk-A7QC2ZVP.js.map +0 -1
  99. package/dist/chunk-DZIXKL7E.js +0 -145
  100. package/dist/chunk-DZIXKL7E.js.map +0 -1
  101. package/dist/chunk-EISO3POT.js.map +0 -1
  102. package/dist/chunk-EP7KOI2V.js +0 -571
  103. package/dist/chunk-EP7KOI2V.js.map +0 -1
  104. package/dist/chunk-FOJZNMMK.js.map +0 -1
  105. package/dist/chunk-ILU76UF3.js.map +0 -1
  106. package/dist/chunk-KVWV4ULP.js +0 -516
  107. package/dist/chunk-KVWV4ULP.js.map +0 -1
  108. package/dist/chunk-L7DMSMAG.cjs.map +0 -1
  109. package/dist/chunk-QC5T6D4J.js.map +0 -1
  110. package/dist/chunk-QOMNEWCQ.cjs.map +0 -1
  111. package/dist/chunk-TSFS5VKD.js.map +0 -1
  112. package/dist/chunk-VQ5W4MYO.js.map +0 -1
  113. package/dist/chunks-SX77P5CV.js +0 -10
  114. package/dist/image-ocr-FLIL7MGN.js.map +0 -1
  115. package/dist/image-ocr-WCAYXLOA.js.map +0 -1
  116. package/dist/image-ocr-ZTYAGV3W.cjs.map +0 -1
  117. package/dist/parser-A4TMPJAM.js.map +0 -1
  118. package/dist/parser-SCUTZAIJ.js.map +0 -1
  119. package/dist/parser-VCXE4I5A.cjs.map +0 -1
  120. package/dist/pdf-ocr-76SAUXMZ.js +0 -13
  121. package/dist/pdf-ocr-CPU55CVF.js +0 -16
  122. package/dist/pdf-ocr-MBZZ57LD.cjs +0 -14
  123. package/dist/redact-7ILEAUTS.js +0 -12
  124. package/dist/seal-RGUPOLXD.js +0 -10
  125. package/dist/visual-NZLYIYEM.js +0 -19
  126. /package/dist/{-AQKXLFIM.js.map → -Z4TJ3QGK.js.map} +0 -0
  127. /package/dist/{chunk-ZWD734EY.js.map → chunk-7SE4EZ45.js.map} +0 -0
  128. /package/dist/{chunk-GDW4YP7K.js.map → chunk-GLSBEEZJ.js.map} +0 -0
  129. /package/dist/{chunk-JQEFP45L.js.map → chunk-GUJ4Q73I.js.map} +0 -0
  130. /package/dist/{chunk-ZWOFQRIB.js.map → chunk-HIJUKZHM.js.map} +0 -0
  131. /package/dist/{chunk-TNCKOL2O.js.map → chunk-LCW7SEPG.js.map} +0 -0
  132. /package/dist/{chunk-UET462HB.js.map → chunk-TITDJWVZ.js.map} +0 -0
  133. /package/dist/{chunk-C7FQBSON.js.map → chunk-V3DX4DUF.js.map} +0 -0
  134. /package/dist/{chunk-DOGPOY4B.js.map → chunk-VDN7LMPL.js.map} +0 -0
  135. /package/dist/{chunk-EDNJLUSE.js.map → chunk-VJIL6PIL.js.map} +0 -0
  136. /package/dist/{chunk-NS55SM7A.js.map → chunk-WJJGW5PL.js.map} +0 -0
  137. /package/dist/{chunks-SX77P5CV.js.map → chunks-CCMRL4MJ.js.map} +0 -0
  138. /package/dist/{formula-JGFTXWYT.js.map → formula-7RANCW5L.js.map} +0 -0
  139. /package/dist/{formula-5S7WWXGH.js.map → formula-7UYJOVTB.js.map} +0 -0
  140. /package/dist/{model-bundle-FSPZZ2EM.js.map → model-bundle-2C5IYDLE.js.map} +0 -0
  141. /package/dist/{models-CJPAQK5R.js.map → models-SEQZHZFT.js.map} +0 -0
  142. /package/dist/{pdf-ocr-76SAUXMZ.js.map → pdf-ocr-UUBWBEHL.js.map} +0 -0
  143. /package/dist/{pdf-ocr-CPU55CVF.js.map → pdf-ocr-VJSF2SQC.js.map} +0 -0
  144. /package/dist/{profile-io-LBM263K7.js.map → profile-io-RUFZOZO6.js.map} +0 -0
  145. /package/dist/{rasterize-46RG4ZF6.js.map → rasterize-IOYXR5SI.js.map} +0 -0
  146. /package/dist/{redact-7ILEAUTS.js.map → redact-NMIKVHMP.js.map} +0 -0
  147. /package/dist/{render-NGP5T24S.js.map → render-YZ2TEC3N.js.map} +0 -0
  148. /package/dist/{seal-RGUPOLXD.js.map → seal-ECV44TUH.js.map} +0 -0
  149. /package/dist/{setup-AU4OCHNH.js.map → setup-MPIEP6XT.js.map} +0 -0
  150. /package/dist/{visual-NZLYIYEM.js.map → visual-ICMOWUCR.js.map} +0 -0
  151. /package/dist/{watch-MKPUCPXM.js.map → watch-RYO7MN5B.js.map} +0 -0
@@ -1,11 +1,21 @@
1
1
  import {
2
+ WINGDINGS,
2
3
  blocksToMarkdown,
3
- encodePng
4
- } from "./chunk-VQ5W4MYO.js";
4
+ encodePng,
5
+ escapeLiteralDollar
6
+ } from "./chunk-QIF2VXBQ.js";
5
7
  import {
6
8
  parsePageRange
7
9
  } from "./chunk-GE43BE46.js";
8
10
  import {
11
+ CELL_LINES,
12
+ CLIP_TABLES,
13
+ CONT_PARTS,
14
+ EMPTY_PARTS,
15
+ FILLER_CELLS,
16
+ IMAGE_CELLS,
17
+ TABLE_COLXS,
18
+ WrapLexicon,
9
19
  collapseEvenSpacing,
10
20
  computeMedianFontSizeFromFreq,
11
21
  detectHeadings,
@@ -15,15 +25,16 @@ import {
15
25
  extractImageRegions,
16
26
  extractPageBlocksWithLines,
17
27
  filterHiddenText,
18
- mergeCrossPageTables,
28
+ joinPageBreakWraps,
19
29
  normalizeItems,
20
- removeHeaderFooterBlocks
21
- } from "./chunk-A7QC2ZVP.js";
22
- import "./chunk-FOJZNMMK.js";
30
+ removeHeaderFooterBlocks,
31
+ trimTrailingEmptyTableCols
32
+ } from "./chunk-YT3GC62E.js";
33
+ import "./chunk-6CUIXJOC.js";
23
34
  import {
24
35
  KordocError,
25
36
  sanitizeHref
26
- } from "./chunk-JQEFP45L.js";
37
+ } from "./chunk-GUJ4Q73I.js";
27
38
 
28
39
  // src/pdf/image-extract.ts
29
40
  import { OPS, ImageKind } from "pdfjs-dist/legacy/build/pdf.mjs";
@@ -107,7 +118,7 @@ function toRgba(img) {
107
118
  }
108
119
  return null;
109
120
  }
110
- async function extractPageImages(page, fnArray, argsArray, pageNumber, state, warnings) {
121
+ async function extractPageImages(page, fnArray, argsArray, pageNumber, state, warnings, withBytes = true) {
111
122
  const blocks = [];
112
123
  const images = [];
113
124
  const pageSeenIds = /* @__PURE__ */ new Set();
@@ -146,12 +157,14 @@ async function extractPageImages(page, fnArray, argsArray, pageNumber, state, wa
146
157
  if (state.seen.has(hash)) continue;
147
158
  const rgba = toRgba(imgData);
148
159
  if (!rgba) continue;
149
- const png = encodePng(w, h, rgba);
150
160
  state.imageIndex++;
151
- state.totalBytes += png.length;
152
161
  const filename = `image_${String(state.imageIndex).padStart(3, "0")}.png`;
153
162
  state.seen.set(hash, filename);
154
- images.push({ filename, data: png, mimeType: "image/png" });
163
+ if (withBytes) {
164
+ const png = encodePng(w, h, rgba);
165
+ state.totalBytes += png.length;
166
+ images.push({ filename, data: png, mimeType: "image/png" });
167
+ }
155
168
  blocks.push({ type: "image", text: filename, pageNumber });
156
169
  }
157
170
  return { blocks, images };
@@ -196,7 +209,9 @@ var RARE_JONG = /* @__PURE__ */ new Set([3, 5, 6, 9, 10, 11, 12, 13, 14, 15, 18,
196
209
  var MOJIBAKE_MIN_HANGUL = 30;
197
210
  var MOJIBAKE_MAX_NOBATCHIM = 0.15;
198
211
  var MOJIBAKE_MIN_RAREBATCHIM = 0.25;
199
- function computePageQuality(page, text) {
212
+ var VECTOR_TEXT_MIN_GLYPHS = 40;
213
+ var VECTOR_TEXT_MIN_SHARE = 0.25;
214
+ function computePageQuality(page, text, vectorGlyphs = 0) {
200
215
  let total = 0;
201
216
  let hangul = 0;
202
217
  let hangulNoBatchim = 0;
@@ -237,7 +252,10 @@ function computePageQuality(page, text) {
237
252
  const garbledHangul = hangul >= MOJIBAKE_MIN_HANGUL && hangulNoBatchimRatio < MOJIBAKE_MAX_NOBATCHIM && hangulRareBatchimRatio >= MOJIBAKE_MIN_RAREBATCHIM;
238
253
  let needsOcr = false;
239
254
  let ocrReason;
240
- if (total < LOW_TEXT_THRESHOLD) {
255
+ if (vectorGlyphs >= VECTOR_TEXT_MIN_GLYPHS && vectorGlyphs >= (vectorGlyphs + total) * VECTOR_TEXT_MIN_SHARE) {
256
+ needsOcr = true;
257
+ ocrReason = "vector_text";
258
+ } else if (total < LOW_TEXT_THRESHOLD) {
241
259
  needsOcr = true;
242
260
  ocrReason = "low_text";
243
261
  } else if (puaRatio >= HIGH_PUA_THRESHOLD) {
@@ -322,232 +340,657 @@ function summarizeDocumentQuality(pages) {
322
340
  };
323
341
  }
324
342
 
325
- // src/pdf/symbol-fonts.ts
326
- var WINGDINGS = [
327
- "\u{1F589}",
328
- "\u2702",
329
- "\u2701",
330
- "\u{1F453}",
331
- "\u{1F56D}",
332
- "\u{1F56E}",
333
- "\u{1F56F}",
334
- "\u{1F57F}",
335
- "\u2706",
336
- "\u{1F582}",
337
- "\u{1F583}",
338
- "\u{1F4EA}",
339
- "\u{1F4EB}",
340
- "\u{1F4EC}",
341
- "\u{1F4ED}",
342
- "\u{1F4C1}",
343
- "\u{1F4C2}",
344
- "\u{1F4C4}",
345
- "\u{1F5CF}",
346
- "\u{1F5D0}",
347
- "\u{1F5C4}",
348
- "\u231B",
349
- "\u{1F5AE}",
350
- "\u{1F5B0}",
351
- "\u{1F5B2}",
352
- "\u{1F5B3}",
353
- "\u{1F5B4}",
354
- "\u{1F5AB}",
355
- "\u{1F5AC}",
356
- "\u2707",
357
- "\u270D",
358
- "\u{1F58E}",
359
- "\u270C",
360
- "\u{1F44C}",
361
- "\u{1F44D}",
362
- "\u{1F44E}",
363
- "\u261C",
364
- "\u261E",
365
- "\u261D",
366
- "\u261F",
367
- "\u{1F590}",
368
- "\u263A",
369
- "\u{1F610}",
370
- "\u2639",
371
- "\u{1F4A3}",
372
- "\u2620",
373
- "\u{1F3F3}",
374
- "\u{1F3F1}",
375
- "\u2708",
376
- "\u263C",
377
- "\u{1F4A7}",
378
- "\u2744",
379
- "\u{1F546}",
380
- "\u271E",
381
- "\u{1F548}",
382
- "\u2720",
383
- "\u2721",
384
- "\u262A",
385
- "\u262F",
386
- "\u0950",
387
- "\u2638",
388
- "\u2648",
389
- "\u2649",
390
- "\u264A",
391
- "\u264B",
392
- "\u264C",
393
- "\u264D",
394
- "\u264E",
395
- "\u264F",
396
- "\u2650",
397
- "\u2651",
398
- "\u2652",
399
- "\u2653",
400
- "\u{1F670}",
401
- "\u{1F675}",
402
- "\u25CF",
403
- "\u25CB",
404
- "\u25A0",
405
- "\u25A1",
406
- "\u25A1",
407
- "\u2751",
408
- "\u2752",
409
- "\u2B27",
410
- "\u29EB",
411
- "\u25C6",
412
- "\u2756",
413
- "\u2B25",
414
- "\u2327",
415
- "\u2BB9",
416
- "\u2318",
417
- "\u{1F3F5}",
418
- "\u{1F3F6}",
419
- "\u{1F676}",
420
- "\u{1F677}",
421
- "",
422
- "\u24EA",
423
- "\u2460",
424
- "\u2461",
425
- "\u2462",
426
- "\u2463",
427
- "\u2464",
428
- "\u2465",
429
- "\u2466",
430
- "\u2467",
431
- "\u2468",
432
- "\u2469",
433
- "\u24FF",
434
- "\u2776",
435
- "\u2777",
436
- "\u2778",
437
- "\u2779",
438
- "\u277A",
439
- "\u277B",
440
- "\u277C",
441
- "\u277D",
442
- "\u277E",
443
- "\u277F",
444
- "\u{1F662}",
445
- "\u{1F660}",
446
- "\u{1F661}",
447
- "\u{1F663}",
448
- "\u{1F65E}",
449
- "\u{1F65C}",
450
- "\u{1F65D}",
451
- "\u{1F65F}",
452
- "\xB7",
453
- "\u2022",
454
- "\u25AA",
455
- "\u26AA",
456
- "\u25CB",
457
- "\u25EF",
458
- "\u25C9",
459
- "\u25CE",
460
- "\u{1F53F}",
461
- "\u25AA",
462
- "\u25FB",
463
- "\u{1F7C2}",
464
- "\u2726",
465
- "\u2605",
466
- "\u2736",
467
- "\u2734",
468
- "\u2739",
469
- "\u2735",
470
- "\u2BD0",
471
- "\u2316",
472
- "\u27E1",
473
- "\u2311",
474
- "\u2BD1",
475
- "\u272A",
476
- "\u2730",
477
- "\u{1F550}",
478
- "\u{1F551}",
479
- "\u{1F552}",
480
- "\u{1F553}",
481
- "\u{1F554}",
482
- "\u{1F555}",
483
- "\u{1F556}",
484
- "\u{1F557}",
485
- "\u{1F558}",
486
- "\u{1F559}",
487
- "\u{1F55A}",
488
- "\u{1F55B}",
489
- "\u2BB0",
490
- "\u2BB1",
491
- "\u2BB2",
492
- "\u2BB3",
493
- "\u2BB4",
494
- "\u2BB5",
495
- "\u2BB6",
496
- "\u2BB7",
497
- "\u{1F66A}",
498
- "\u{1F66B}",
499
- "\u{1F655}",
500
- "\u{1F654}",
501
- "\u{1F657}",
502
- "\u{1F656}",
503
- "\u{1F650}",
504
- "\u{1F651}",
505
- "\u{1F652}",
506
- "\u{1F653}",
507
- "\u232B",
508
- "\u2326",
509
- "\u2B98",
510
- "\u2B9A",
511
- "\u2B99",
512
- "\u2B9B",
513
- "\u2B88",
514
- "\u2B8A",
515
- "\u2B89",
516
- "\u2B8B",
517
- "\u2190",
518
- "\u2192",
519
- "\u2191",
520
- "\u2193",
521
- "\u2196",
522
- "\u2197",
523
- "\u2199",
524
- "\u2198",
525
- "\u2B05",
526
- "\u2794",
527
- "\u2B06",
528
- "\u2B07",
529
- "\u2B09",
530
- "\u2B08",
531
- "\u2B0B",
532
- "\u2B0A",
533
- "\u21E6",
534
- "\u21E8",
535
- "\u21E7",
536
- "\u21E9",
537
- "\u2B04",
538
- "\u21F3",
539
- "\u2B00",
540
- "\u2B01",
541
- "\u2B03",
542
- "\u2B02",
543
- "\u{1F8AC}",
544
- "\u{1F8AD}",
545
- "\u2717",
546
- "\u2714",
547
- "\u2612",
548
- "\u2611",
549
- ""
343
+ // src/pdf/vector-glyphs.ts
344
+ import { OPS as OPS2 } from "pdfjs-dist/legacy/build/pdf.mjs";
345
+ var GLYPH_MIN_H = 3;
346
+ var GLYPH_MAX_H = 40;
347
+ var GLYPH_MAX_ASPECT = 2;
348
+ var GLYPH_MIN_SEGS = 8;
349
+ var GLYPH_MIN_SUBS = 2;
350
+ var RUN_GAP_EM = 1.5;
351
+ var RUN_MIN = 3;
352
+ var RUN_ALIGN_EM = 0.05;
353
+ var RUN_MAX_OVERLAP = 0.2;
354
+ var RUN_MIN_COLOR = 0.9;
355
+ var RUN_MIN_SHAPES = 0.5;
356
+ var mul = (m, t) => [
357
+ m[0] * t[0] + m[2] * t[1],
358
+ m[1] * t[0] + m[3] * t[1],
359
+ m[0] * t[2] + m[2] * t[3],
360
+ m[1] * t[2] + m[3] * t[3],
361
+ m[0] * t[4] + m[2] * t[5] + m[4],
362
+ m[1] * t[4] + m[3] * t[5] + m[5]
550
363
  ];
364
+ function collectGlyphPaths(fnArray, argsArray) {
365
+ const out = [];
366
+ let ctm = [1, 0, 0, 1, 0, 0];
367
+ let color = 0;
368
+ const stack = [];
369
+ let x1 = Infinity, y1 = Infinity, x2 = -Infinity, y2 = -Infinity;
370
+ let segs = 0, subs = 0, rects = 0;
371
+ let ops = [];
372
+ const add = (x, y) => {
373
+ const tx = ctm[0] * x + ctm[2] * y + ctm[4], ty = ctm[1] * x + ctm[3] * y + ctm[5];
374
+ if (tx < x1) x1 = tx;
375
+ if (tx > x2) x2 = tx;
376
+ if (ty < y1) y1 = ty;
377
+ if (ty > y2) y2 = ty;
378
+ };
379
+ const reset = () => {
380
+ x1 = Infinity;
381
+ y1 = Infinity;
382
+ x2 = -Infinity;
383
+ y2 = -Infinity;
384
+ segs = 0;
385
+ subs = 0;
386
+ rects = 0;
387
+ ops = [];
388
+ };
389
+ for (let i = 0; i < fnArray.length; i++) {
390
+ const op = fnArray[i];
391
+ const args = argsArray[i];
392
+ switch (op) {
393
+ case OPS2.save:
394
+ stack.push([ctm, color]);
395
+ break;
396
+ case OPS2.restore:
397
+ [ctm, color] = stack.pop() ?? [[1, 0, 0, 1, 0, 0], 0];
398
+ break;
399
+ case OPS2.transform:
400
+ ctm = mul(ctm, args);
401
+ break;
402
+ case OPS2.paintFormXObjectBegin: {
403
+ stack.push([ctm, color]);
404
+ const m = args[0];
405
+ if (Array.isArray(m) && m.length >= 6) ctm = mul(ctm, m);
406
+ break;
407
+ }
408
+ case OPS2.paintFormXObjectEnd:
409
+ [ctm, color] = stack.pop() ?? [[1, 0, 0, 1, 0, 0], 0];
410
+ break;
411
+ case OPS2.setFillRGBColor: {
412
+ const c = args;
413
+ color = c[0] << 16 | c[1] << 8 | c[2];
414
+ break;
415
+ }
416
+ case OPS2.constructPath: {
417
+ const [subOps, coords] = args;
418
+ if (!Array.isArray(subOps) || !Array.isArray(coords)) break;
419
+ ops.push(i);
420
+ let ci = 0;
421
+ for (const s of subOps) {
422
+ if (s === OPS2.moveTo) {
423
+ add(coords[ci], coords[ci + 1]);
424
+ ci += 2;
425
+ subs++;
426
+ } else if (s === OPS2.lineTo) {
427
+ add(coords[ci], coords[ci + 1]);
428
+ ci += 2;
429
+ segs++;
430
+ } else if (s === OPS2.curveTo) {
431
+ add(coords[ci], coords[ci + 1]);
432
+ add(coords[ci + 2], coords[ci + 3]);
433
+ add(coords[ci + 4], coords[ci + 5]);
434
+ ci += 6;
435
+ segs++;
436
+ } else if (s === OPS2.curveTo2 || s === OPS2.curveTo3) {
437
+ add(coords[ci], coords[ci + 1]);
438
+ add(coords[ci + 2], coords[ci + 3]);
439
+ ci += 4;
440
+ segs++;
441
+ } else if (s === OPS2.rectangle) {
442
+ const rx = coords[ci], ry = coords[ci + 1], rw = coords[ci + 2], rh = coords[ci + 3];
443
+ add(rx, ry);
444
+ add(rx + rw, ry + rh);
445
+ add(rx, ry + rh);
446
+ add(rx + rw, ry);
447
+ ci += 4;
448
+ rects++;
449
+ subs++;
450
+ segs += 4;
451
+ }
452
+ }
453
+ break;
454
+ }
455
+ case OPS2.fill:
456
+ case OPS2.eoFill:
457
+ case OPS2.fillStroke:
458
+ case OPS2.eoFillStroke:
459
+ case OPS2.closeFillStroke:
460
+ case OPS2.closeEOFillStroke: {
461
+ const w = x2 - x1, h = y2 - y1;
462
+ if (segs > rects * 4 && h >= GLYPH_MIN_H && h <= GLYPH_MAX_H && w <= h * GLYPH_MAX_ASPECT && segs >= GLYPH_MIN_SEGS && subs >= GLYPH_MIN_SUBS) {
463
+ out.push({ x1, y1, x2, y2, segs, subs, color, ops: [...ops, i] });
464
+ }
465
+ reset();
466
+ break;
467
+ }
468
+ case OPS2.stroke:
469
+ case OPS2.closeStroke:
470
+ case OPS2.endPath:
471
+ reset();
472
+ break;
473
+ }
474
+ }
475
+ return out;
476
+ }
477
+ function coveredByText(b, texts) {
478
+ const cx = (b.x1 + b.x2) / 2, cy = (b.y1 + b.y2) / 2;
479
+ for (const t of texts) {
480
+ if (cx >= t.x - 1 && cx <= t.x + t.w + 1 && cy >= t.y - t.h * 0.3 - 1 && cy <= t.y + t.h + 1 && t.text.trim()) return true;
481
+ }
482
+ return false;
483
+ }
484
+ var median = (a) => {
485
+ const s = a.slice().sort((x, y) => x - y);
486
+ return s[s.length >> 1];
487
+ };
488
+ var spread = (a) => {
489
+ const c = median(a);
490
+ return median(a.map((v) => Math.abs(v - c)));
491
+ };
492
+ function isTextRun(m, em) {
493
+ if (m.length < RUN_MIN) return false;
494
+ if (Math.min(spread(m.map((b) => b.y2)), spread(m.map((b) => b.y1))) > em * RUN_ALIGN_EM) return false;
495
+ let overlaps = 0;
496
+ for (let i = 1; i < m.length; i++) if (m[i].x1 < m[i - 1].x2 - em * 0.1) overlaps++;
497
+ if (overlaps > (m.length - 1) * RUN_MAX_OVERLAP) return false;
498
+ const colors = /* @__PURE__ */ new Map();
499
+ for (const b of m) colors.set(b.color, (colors.get(b.color) ?? 0) + 1);
500
+ if (Math.max(...colors.values()) < m.length * RUN_MIN_COLOR) return false;
501
+ const shapes = new Set(m.map((b) => `${Math.round((b.x2 - b.x1) * 2)}:${Math.round((b.y2 - b.y1) * 2)}:${b.segs}`));
502
+ return shapes.size >= m.length * RUN_MIN_SHAPES;
503
+ }
504
+ function scanVectorGlyphs(fnArray, argsArray, texts) {
505
+ const paths = collectGlyphPaths(fnArray, argsArray);
506
+ if (paths.length < RUN_MIN) return { glyphs: 0, paths };
507
+ const free = paths.filter((b) => !coveredByText(b, texts));
508
+ const sorted = free.slice().sort((a, b) => a.y1 + a.y2 - (b.y1 + b.y2));
509
+ let glyphs = 0;
510
+ let row = [];
511
+ let rowCy = 0, rowH = 0;
512
+ const flushRow = () => {
513
+ if (row.length < RUN_MIN) return;
514
+ row.sort((a, b) => a.x1 - b.x1);
515
+ const em = median(row.map((b) => b.y2 - b.y1));
516
+ let start = 0, maxX = row[0].x2;
517
+ for (let i = 1; i <= row.length; i++) {
518
+ if (i < row.length && row[i].x1 - maxX <= em * RUN_GAP_EM) {
519
+ if (row[i].x2 > maxX) maxX = row[i].x2;
520
+ continue;
521
+ }
522
+ const run = row.slice(start, i);
523
+ if (isTextRun(run, em)) glyphs += run.length;
524
+ if (i < row.length) {
525
+ start = i;
526
+ maxX = row[i].x2;
527
+ }
528
+ }
529
+ };
530
+ for (const b of sorted) {
531
+ const cy = (b.y1 + b.y2) / 2, h = b.y2 - b.y1;
532
+ if (row.length && Math.abs(cy - rowCy) <= Math.max(h, rowH) * 0.5) {
533
+ row.push(b);
534
+ continue;
535
+ }
536
+ flushRow();
537
+ row = [b];
538
+ rowCy = cy;
539
+ rowH = h;
540
+ }
541
+ flushRow();
542
+ return { glyphs, paths };
543
+ }
544
+ function ocrVectorOps(opList, paths) {
545
+ const drop = /* @__PURE__ */ new Set();
546
+ for (const p of paths) for (const i of p.ops) drop.add(i);
547
+ const fnArray = [];
548
+ const argsArray = [];
549
+ for (let i = 0; i < opList.fnArray.length; i++) {
550
+ const op = opList.fnArray[i];
551
+ if (drop.has(i) || op === OPS2.clip || op === OPS2.eoClip) continue;
552
+ fnArray.push(op);
553
+ argsArray.push(opList.argsArray[i]);
554
+ }
555
+ return { fnArray, argsArray };
556
+ }
557
+
558
+ // src/pdf/table-parts.ts
559
+ var PART_COL_TOL = 1;
560
+ function anchorsOf(table) {
561
+ const out = [];
562
+ const covered = /* @__PURE__ */ new Set();
563
+ for (let r = 0; r < table.rows; r++) {
564
+ for (let c = 0; c < table.cols; c++) {
565
+ if (covered.has(r * 1e5 + c)) continue;
566
+ const cell = table.cells[r]?.[c];
567
+ if (!cell) continue;
568
+ out.push({ r, c, rs: cell.rowSpan, cs: cell.colSpan, cell });
569
+ for (let dr = 0; dr < cell.rowSpan; dr++) {
570
+ for (let dc = 0; dc < cell.colSpan; dc++) if (dr || dc) covered.add((r + dr) * 1e5 + (c + dc));
571
+ }
572
+ }
573
+ }
574
+ return out;
575
+ }
576
+ function unionCoords(a, b) {
577
+ const out = [...a];
578
+ for (const v of b) if (!a.some((x) => Math.abs(x - v) <= PART_COL_TOL)) out.push(v);
579
+ return out.sort((x, y) => x - y);
580
+ }
581
+ var indexOf = (coords, x) => {
582
+ let best = -1, bestD = Infinity;
583
+ for (let i = 0; i < coords.length; i++) {
584
+ const d = Math.abs(coords[i] - x);
585
+ if (d < bestD) {
586
+ bestD = d;
587
+ best = i;
588
+ }
589
+ }
590
+ return bestD <= PART_COL_TOL ? best : -1;
591
+ };
592
+ var rowText = (anchors, r) => anchors.filter((a) => a.r === r).map((a) => a.cell.text.replace(/\s+/g, "")).join("|");
593
+ var hasText = (t) => t.replace(/\|/g, "") !== "";
594
+ function joinSplitParts(prev, pcx, curr, ccx, dx = 0, prevBottom) {
595
+ if (pcx.length !== prev.cols + 1 || ccx.length !== curr.cols + 1) return null;
596
+ const U = unionCoords(pcx, ccx);
597
+ const cols = U.length - 1;
598
+ if (cols < 1) return null;
599
+ const pa = anchorsOf(prev), ca = anchorsOf(curr);
600
+ let skip = 0;
601
+ while (skip < Math.min(3, curr.rows - 1, prev.rows) && rowText(ca, skip) !== "" && rowText(ca, skip) === rowText(pa, skip)) skip++;
602
+ for (let h = 1; h <= 2 && !skip; h++) {
603
+ while (skip < Math.min(3, curr.rows - 1, prev.rows - h) && hasText(rowText(ca, skip)) && rowText(ca, skip) === rowText(pa, h + skip)) skip++;
604
+ }
605
+ const rows = prev.rows + curr.rows - skip;
606
+ const grid = Array.from({ length: rows }, () => Array.from({ length: cols }, () => ({ text: "", colSpan: 1, rowSpan: 1 })));
607
+ const owner = Array.from({ length: rows }, () => new Array(cols).fill(null));
608
+ const place = (a, x, rowOff, shift = 0) => {
609
+ const c1 = indexOf(U, x[a.c]), c2 = indexOf(U, x[a.c + a.cs]);
610
+ if (c1 < 0 || c2 <= c1) return false;
611
+ const r = a.r + rowOff;
612
+ const placed = { r, c: c1, rs: a.rs, cs: c2 - c1, cell: a.cell };
613
+ for (let dr = 0; dr < a.rs; dr++) for (let dc = c1; dc < c2; dc++) {
614
+ if (r + dr < rows) owner[r + dr][dc] = placed;
615
+ }
616
+ grid[r][c1] = { ...a.cell, colSpan: c2 - c1, rowSpan: a.rs };
617
+ const lines = CELL_LINES.get(a.cell);
618
+ if (lines) CELL_LINES.set(grid[r][c1], shift ? lines.map((l) => ({ ...l, l: l.l + shift, r: l.r + shift })) : lines);
619
+ if (IMAGE_CELLS.has(a.cell)) IMAGE_CELLS.add(grid[r][c1]);
620
+ return true;
621
+ };
622
+ for (const a of pa) if (!FILLER_CELLS.has(a.cell) && !place(a, pcx, 0)) return null;
623
+ for (const a of ca) {
624
+ if (a.r < skip || FILLER_CELLS.has(a.cell)) continue;
625
+ if (!place(a, ccx, prev.rows - skip, dx)) return null;
626
+ }
627
+ const first = prev.rows;
628
+ for (let c = 0; c < cols; c++) {
629
+ const above = owner[first - 1]?.[c];
630
+ if (!above) continue;
631
+ let r = first;
632
+ while (r < rows && owner[r][c] === null) r++;
633
+ if (r === first) continue;
634
+ const span = r - first;
635
+ let ok = true;
636
+ for (let dc = above.c; dc < above.c + above.cs && ok; dc++) {
637
+ for (let rr = first; rr < first + span; rr++) if (owner[rr][dc] !== null) {
638
+ ok = false;
639
+ break;
640
+ }
641
+ }
642
+ if (!ok) continue;
643
+ const newRs = above.rs + span;
644
+ grid[above.r][above.c].rowSpan = newRs;
645
+ const grown = { ...above, rs: newRs };
646
+ for (let rr = above.r; rr < above.r + newRs; rr++) for (let dc = above.c; dc < above.c + above.cs; dc++) owner[rr][dc] = grown;
647
+ }
648
+ for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) if (owner[r][c] === null) FILLER_CELLS.add(grid[r][c]);
649
+ const table = { rows, cols, cells: grid, hasHeader: prev.hasHeader, ...prev.caption ? { caption: prev.caption } : {} };
650
+ const split = rows > prev.rows && mergeSplitRow(table, owner, prev.rows, U);
651
+ if (rows > prev.rows && !split && prevBottom !== void 0) mergeStraddlingCells(table, owner, prev.rows, prevBottom);
652
+ return { table, colXs: U, split, header: ca.filter((a) => a.r < skip && a.cell.text.trim()).length >= 2 };
653
+ }
654
+ function mergeStraddlingCells(table, owner, first, prevBottom) {
655
+ const last = first - 1;
656
+ if (!owner[first].some((o, c) => o !== null && o === owner[last][c])) return;
657
+ for (let c = 0; c < table.cols; ) {
658
+ const u = owner[last][c], d = owner[first][c];
659
+ if (!u) {
660
+ c++;
661
+ continue;
662
+ }
663
+ c = u.c + u.cs;
664
+ if (!d || d === u || u.r >= last || u.r + u.rs - 1 !== last || d.r !== first || d.c !== u.c || d.cs !== u.cs) continue;
665
+ const a = table.cells[u.r][u.c], b = table.cells[first][d.c];
666
+ const U = CELL_LINES.get(a);
667
+ if (!U?.length || U.length > STRADDLE_MAX_LINES || !hasContent(b)) continue;
668
+ const lu = U[U.length - 1];
669
+ if (lu.y - prevBottom > STRADDLE_BOTTOM * (lu.h || 10)) continue;
670
+ appendCell(a, b);
671
+ a.rowSpan = first + d.rs - u.r;
672
+ table.cells[first][d.c] = { text: "", colSpan: 1, rowSpan: 1 };
673
+ const grown = { ...u, rs: a.rowSpan };
674
+ for (let rr = u.r; rr < u.r + grown.rs; rr++) for (let dc = u.c; dc < u.c + u.cs; dc++) owner[rr][dc] = grown;
675
+ }
676
+ }
677
+ var FULL_LINE_TOL = 1;
678
+ var FULL_LINE_MIN_FRAC = 0.5;
679
+ var FULL_LINE_EDGE_MIN = 12;
680
+ var SINGLE_LINE_WORD_GAP = 3.5;
681
+ var SHORT_LINE_GAP = 1.5;
682
+ var STRADDLE_MAX_LINES = 3;
683
+ var STRADDLE_BOTTOM = 1.2;
684
+ var CARRIED_MIN_COL_W = 4;
685
+ var LABEL_ROOM = 1.5;
686
+ var HANGING_MIN = 0.5;
687
+ var HANGING_TOL = 1;
688
+ function continuesAcross(u, d, x1, x2) {
689
+ const U = CELL_LINES.get(u), D = CELL_LINES.get(d);
690
+ if (!U?.length || !D?.length) return false;
691
+ const last = U[U.length - 1];
692
+ const fs = last.h || 10;
693
+ let minL = Infinity, maxR = -Infinity;
694
+ for (const l of U) {
695
+ minL = Math.min(minL, l.l);
696
+ maxR = Math.max(maxR, l.r);
697
+ }
698
+ for (const l of D) {
699
+ minL = Math.min(minL, l.l);
700
+ maxR = Math.max(maxR, l.r);
701
+ }
702
+ maxR = Math.max(maxR, x2 - (minL - x1));
703
+ if (maxR - last.r > FULL_LINE_TOL * fs) return false;
704
+ if (U.length === 1 && x2 - last.r > Math.max(FULL_LINE_EDGE_MIN, SINGLE_LINE_WORD_GAP * fs)) return false;
705
+ if (last.r - last.l < FULL_LINE_MIN_FRAC * (x2 - x1)) return false;
706
+ const leftAligned = (l) => l.l - minL <= fs && maxR - l.r > SHORT_LINE_GAP * fs;
707
+ const hanging = U.length >= 2 && U.every((l) => maxR - l.r <= FULL_LINE_TOL * fs) && last.l - minL >= HANGING_MIN * fs && Math.abs(D[0].l - last.l) <= HANGING_TOL;
708
+ return U.some(leftAligned) || D.some(leftAligned) || hanging;
709
+ }
710
+ function lineEnded(c, x1, x2) {
711
+ const L = CELL_LINES.get(c);
712
+ if (!L || L.length !== 1) return false;
713
+ const l = L[0];
714
+ return x2 - l.r - (l.l - x1) >= LABEL_ROOM * (l.h || 10);
715
+ }
716
+ function appendCell(a, b) {
717
+ if (a.blocks?.length || b.blocks?.length) {
718
+ const asBlocks = (c) => c.blocks?.length ? c.blocks : c.text.split("\n").map((l) => l.trim()).filter(Boolean).map((text) => ({ type: "paragraph", text }));
719
+ a.blocks = [...asBlocks(a), ...asBlocks(b)];
720
+ }
721
+ if (b.text.trim()) a.text = a.text.trim() ? a.text + "\n" + b.text : b.text;
722
+ }
723
+ var hasContent = (cell) => !!cell.text.trim() || !!cell.blocks?.length || IMAGE_CELLS.has(cell);
724
+ function mergeSplitRow(table, owner, first, colXs) {
725
+ const last = first - 1;
726
+ const pairs = [];
727
+ let carried = false;
728
+ for (let c = 0; c < table.cols; ) {
729
+ const a = owner[last][c], b = owner[first][c];
730
+ if (!a && !b) {
731
+ if (colXs[c + 1] - colXs[c] >= CARRIED_MIN_COL_W) carried = true;
732
+ c++;
733
+ continue;
734
+ }
735
+ if (!a || !b) return false;
736
+ if (a !== b) {
737
+ if (a.c !== b.c || a.cs !== b.cs || a.r + a.rs - 1 !== last || b.r !== first || b.rs !== 1) return false;
738
+ pairs.push([a, b]);
739
+ } else if (a.r === last && a.rs === 2) carried = true;
740
+ c = a.c + a.cs;
741
+ }
742
+ const carriedSplit = carried && pairs.filter(([u, d]) => hasContent(u.cell) && hasContent(d.cell)).length <= 1 && !pairs.some(([u, d]) => !hasContent(u.cell) && hasContent(d.cell));
743
+ const cell = (a) => table.cells[a.r][a.c];
744
+ if (!carriedSplit) {
745
+ const norm = (c) => c.text.replace(/\s+/g, "");
746
+ if (pairs.some(([u, d]) => hasContent(d.cell) && norm(cell(d)) !== norm(cell(u)) && lineEnded(cell(u), colXs[u.c], colXs[u.c + u.cs]))) return false;
747
+ if (!pairs.some(([u, d]) => continuesAcross(cell(u), cell(d), colXs[u.c], colXs[u.c + u.cs]))) return false;
748
+ }
749
+ for (const [u, d] of pairs) appendCell(table.cells[u.r][u.c], table.cells[d.r][d.c]);
750
+ for (let r = 0; r < first; r++) for (let c = 0; c < table.cols; c++) {
751
+ const o = owner[r][c];
752
+ if (o && o.r === r && o.c === c && r + table.cells[r][c].rowSpan > first) table.cells[r][c].rowSpan--;
753
+ }
754
+ table.cells.splice(first, 1);
755
+ table.rows--;
756
+ return true;
757
+ }
758
+ var NEIGHBOR_TABLE_EPSILON = 0.2;
759
+ function besideOwn(b, p, c) {
760
+ if (!b.bbox) return false;
761
+ if (b.type === "table") return leftColumnOf(b, p);
762
+ const t = (b.pageNumber === p.pageNumber ? p : c).bbox;
763
+ const bx1 = b.bbox.x, bx2 = b.bbox.x + b.bbox.width;
764
+ return bx2 <= t.x + 1 || bx1 >= t.x + t.width - 1;
765
+ }
766
+ function leftColumnOf(b, t) {
767
+ return !!b.bbox && b.pageNumber === t.pageNumber && b.bbox.x + b.bbox.width <= t.bbox.x + 1;
768
+ }
769
+ function placeJoined(blocks, i, j, table) {
770
+ const prev = blocks[i];
771
+ blocks[i] = { ...prev, table };
772
+ blocks.splice(j, 1);
773
+ let k = j - 1;
774
+ while (k > i && !leftColumnOf(blocks[k], prev)) k--;
775
+ if (k > i) blocks.splice(k, 0, blocks.splice(i, 1)[0]);
776
+ }
777
+ function insideTable(b, t) {
778
+ if (!b.bbox || b.pageNumber !== t.pageNumber) return false;
779
+ const o = t.bbox;
780
+ return b.bbox.x >= o.x - 1 && b.bbox.x + b.bbox.width <= o.x + o.width + 1 && b.bbox.y >= o.y - 1 && b.bbox.y + b.bbox.height <= o.y + o.height + 1;
781
+ }
782
+ function mergeCrossPageTables(blocks, pageHeights) {
783
+ mergeColumnFlow(blocks, pageHeights);
784
+ for (let i = blocks.length - 2; i >= 0; i--) {
785
+ const prev = blocks[i];
786
+ if (prev.type !== "table" || !prev.table || !prev.bbox || !prev.pageNumber) continue;
787
+ let j = i + 1;
788
+ while (j < blocks.length && (blocks[j].type !== "table" || insideTable(blocks[j], prev) || leftColumnOf(blocks[j], prev)) && (blocks[j].pageNumber ?? 0) <= prev.pageNumber + 1) j++;
789
+ const curr = blocks[j];
790
+ if (!curr || curr.type !== "table" || !curr.table || !curr.bbox || curr.pageNumber !== prev.pageNumber + 1) continue;
791
+ const joined = j === i + 1 || blocks.slice(i + 1, j).every((b) => besideOwn(b, prev, curr) || insideTable(b, prev)) ? looksContinued(prev, curr, pageHeights) && !restartsTable(blocks, i, curr.table, pageHeights) ? joinClipParts(prev, curr, pageHeights) ?? false : null : null;
792
+ if (joined) {
793
+ placeJoined(blocks, i, j, joined);
794
+ continue;
795
+ }
796
+ if (EMPTY_PARTS.has(curr.table)) {
797
+ blocks.splice(j, 1);
798
+ i++;
799
+ continue;
800
+ }
801
+ if (joined === null) continue;
802
+ if (prev.table.cols !== curr.table.cols || EMPTY_PARTS.has(prev.table)) continue;
803
+ const width = Math.max(prev.bbox.width, curr.bbox.width, 1);
804
+ const leftDiff = Math.abs(prev.bbox.x - curr.bbox.x);
805
+ const rightDiff = Math.abs(prev.bbox.x + prev.bbox.width - (curr.bbox.x + curr.bbox.width));
806
+ if (leftDiff > width * NEIGHBOR_TABLE_EPSILON || rightDiff > width * NEIGHBOR_TABLE_EPSILON) continue;
807
+ const px = TABLE_COLXS.get(prev.table), cx = TABLE_COLXS.get(curr.table);
808
+ if (px && cx && !shiftedSame(px, cx, !CLIP_TABLES.has(prev.table) && !CLIP_TABLES.has(curr.table))) continue;
809
+ let currCells = curr.table.cells;
810
+ if (currCells.length > 1 && prev.table.cells.length > 0 && rowTextsEqual(prev.table.cells[0], currCells[0])) {
811
+ currCells = currCells.slice(1);
812
+ }
813
+ if (currCells.length === 0) {
814
+ blocks.splice(j, 1);
815
+ continue;
816
+ }
817
+ const merged = {
818
+ rows: prev.table.rows + currCells.length,
819
+ cols: prev.table.cols,
820
+ cells: [...prev.table.cells, ...currCells],
821
+ hasHeader: prev.table.hasHeader,
822
+ caption: prev.table.caption
823
+ };
824
+ if (px ?? cx) TABLE_COLXS.set(merged, px ?? cx);
825
+ if (CLIP_TABLES.has(prev.table) || CLIP_TABLES.has(curr.table)) CLIP_TABLES.add(merged);
826
+ placeJoined(blocks, i, j, merged);
827
+ }
828
+ for (let i = blocks.length - 1; i >= 0; i--) {
829
+ const t = blocks[i].table;
830
+ if (blocks[i].type === "table" && t && EMPTY_PARTS.has(t)) blocks.splice(i, 1);
831
+ }
832
+ }
833
+ function mergeColumnFlow(blocks, pageHeights) {
834
+ if (!pageHeights) return;
835
+ for (let i = 0; i < blocks.length; i++) {
836
+ const L = blocks[i];
837
+ if (L.type !== "table" || !L.table || !L.bbox || !L.pageNumber || !CLIP_TABLES.has(L.table) || EMPTY_PARTS.has(L.table)) continue;
838
+ const ph = pageHeights.get(L.pageNumber);
839
+ if (!ph || L.bbox.y > ph * PAGE_EDGE_BAND) continue;
840
+ let s0 = i, s1 = i;
841
+ while (s0 > 0 && blocks[s0 - 1].pageNumber === L.pageNumber) s0--;
842
+ while (s1 + 1 < blocks.length && blocks[s1 + 1].pageNumber === L.pageNumber) s1++;
843
+ let k = -1;
844
+ for (let q = s0; q <= s1; q++) {
845
+ const R2 = blocks[q];
846
+ if (q === i || R2.type !== "table" || !R2.table || !R2.bbox || !leftColumnOf(L, R2)) continue;
847
+ const top2 = R2.bbox.y + R2.bbox.height;
848
+ if (top2 < ph * (1 - PAGE_EDGE_BAND)) continue;
849
+ if (k < 0 || top2 > blocks[k].bbox.y + blocks[k].bbox.height) k = q;
850
+ }
851
+ if (k < 0) continue;
852
+ const R = blocks[k];
853
+ if (Math.abs(R.bbox.width - L.bbox.width) > Math.max(R.bbox.width, L.bbox.width) * NEIGHBOR_TABLE_EPSILON) continue;
854
+ if (!looksContinued(L, R) || restartsTable(blocks, i, R.table, pageHeights)) continue;
855
+ const joined = joinClipParts(L, R, pageHeights);
856
+ if (!joined) continue;
857
+ const top = L.bbox.y + L.bbox.height;
858
+ const at = Math.min(i, k);
859
+ blocks[at] = { ...L, table: joined, bbox: { ...L.bbox, y: R.bbox.y, height: Math.max(0, top - R.bbox.y) } };
860
+ blocks.splice(Math.max(i, k), 1);
861
+ i = at - 1;
862
+ }
863
+ }
864
+ function joinClipParts(prev, curr, pageHeights) {
865
+ const pt = prev.table, ct = curr.table;
866
+ if (!CLIP_TABLES.has(pt) || !CLIP_TABLES.has(ct)) return null;
867
+ const px = TABLE_COLXS.get(pt), cx = TABLE_COLXS.get(ct);
868
+ if (!px || !cx) return null;
869
+ let xs = cx, shifted = false, dx = 0;
870
+ if (!shiftedSame(px, cx, false)) {
871
+ if (!pageHeights?.get(prev.pageNumber) || !pageHeights?.get(curr.pageNumber)) return null;
872
+ dx = px[px.length - 1] - cx[cx.length - 1];
873
+ if (Math.abs(dx) > CONTINUATION_COL_TOL) {
874
+ xs = cx.map((x) => x + dx);
875
+ shifted = true;
876
+ } else dx = 0;
877
+ if (!px.some((x) => Math.abs(x - xs[0]) <= CONTINUATION_COL_TOL)) return null;
878
+ }
879
+ const res = joinSplitParts(pt, px, ct, xs, dx, prev.bbox?.y);
880
+ if (!res || shifted && !res.split && !res.header) return null;
881
+ TABLE_COLXS.set(res.table, res.colXs);
882
+ CLIP_TABLES.add(res.table);
883
+ return res.table;
884
+ }
885
+ var ANNEX_HEAD_RE = /^\s*[<\[(【]?\s*(?:붙\s*임|참\s*고|별\s*첨|별\s*지|별\s*표|첨\s*부|부\s*록)(?:\s*\d|\s*$|\s*[>\])】])|^\s*■/;
886
+ function looksContinued(prev, curr, pageHeights) {
887
+ const ph = pageHeights?.get(prev.pageNumber), ch = pageHeights?.get(curr.pageNumber);
888
+ if (ph && ch && (prev.bbox.y > ph * PAGE_EDGE_BAND || curr.bbox.y + curr.bbox.height < ch * (1 - PAGE_EDGE_BAND))) return false;
889
+ const firstText = curr.table.cells[0]?.find((c) => c.text.trim())?.text ?? "";
890
+ return !ANNEX_HEAD_RE.test(firstText);
891
+ }
892
+ function firstRowSig(t) {
893
+ const x = TABLE_COLXS.get(t);
894
+ if (!x || x.length !== t.cols + 1) return null;
895
+ return anchorsOf(t).filter((a) => a.r === 0).map((a) => ({ x1: x[a.c], x2: x[a.c + a.cs], t: a.cell.text.replace(/\s+/g, "") }));
896
+ }
897
+ function restartsTable(blocks, i, curr, pageHeights) {
898
+ const cs = firstRowSig(curr);
899
+ if (!cs || cs.length < RESTART_MIN_ANCHORS) return false;
900
+ const hs = firstRowSig(blocks[chainHead(blocks, i, pageHeights)].table);
901
+ if (!hs || hs.length !== cs.length) return false;
902
+ const dx = hs[hs.length - 1].x2 - cs[cs.length - 1].x2;
903
+ if (!hs.every((h, n) => Math.abs(h.x1 - cs[n].x1 - dx) <= CONTINUATION_COL_TOL && Math.abs(h.x2 - cs[n].x2 - dx) <= CONTINUATION_COL_TOL)) return false;
904
+ let same = 0, diff = 0;
905
+ for (let n = 0; n < hs.length; n++) {
906
+ if (!hs[n].t && !cs[n].t) continue;
907
+ if (hs[n].t === cs[n].t) same++;
908
+ else diff++;
909
+ }
910
+ return same >= 2 && diff >= 1;
911
+ }
912
+ function chainHead(blocks, i, pageHeights) {
913
+ let k = i;
914
+ for (let steps = 0; steps < RESTART_LOOKBACK_PAGES; steps++) {
915
+ const cur = blocks[k];
916
+ let p = k - 1;
917
+ while (p >= 0 && blocks[p].type !== "table" && (blocks[p].pageNumber ?? 0) >= (cur.pageNumber ?? 0) - 1) p--;
918
+ if (p < 0 || blocks[p].type !== "table" || !blocks[p].table || !blocks[p].bbox) break;
919
+ for (let q = p - 1; q >= 0 && blocks[q].pageNumber === blocks[p].pageNumber; q--) {
920
+ if (blocks[q].type === "table" && blocks[q].bbox && insideTable(blocks[p], blocks[q])) {
921
+ p = q;
922
+ break;
923
+ }
924
+ }
925
+ const pb = blocks[p];
926
+ if (pb.pageNumber !== (cur.pageNumber ?? 0) - 1) break;
927
+ if (!blocks.slice(p + 1, k).every((b) => besideOwn(b, pb, cur) || insideTable(b, pb))) break;
928
+ if (!looksContinued(pb, cur, pageHeights)) break;
929
+ const px = TABLE_COLXS.get(pb.table), cx = TABLE_COLXS.get(cur.table);
930
+ if (!px || !cx) break;
931
+ const dx = px[px.length - 1] - cx[cx.length - 1];
932
+ if (!shiftedSame(px, cx) && !px.some((x) => Math.abs(x - (cx[0] + dx)) <= CONTINUATION_COL_TOL)) break;
933
+ k = p;
934
+ }
935
+ return k;
936
+ }
937
+ function rowTextsEqual(a, b) {
938
+ if (a.length !== b.length) return false;
939
+ const norm = (t) => t.replace(/\s+/g, "");
940
+ for (let i = 0; i < a.length; i++) {
941
+ if (norm(a[i].text) !== norm(b[i].text)) return false;
942
+ }
943
+ return a.some((c) => c.text.trim() !== "");
944
+ }
945
+ var CONTINUATION_COL_TOL = 2;
946
+ function shiftedSame(px, cx, allowShift = true) {
947
+ if (px.length !== cx.length) return false;
948
+ const dx = allowShift ? px[px.length - 1] - cx[cx.length - 1] : 0;
949
+ return px.every((x, k) => Math.abs(x - cx[k] - dx) <= CONTINUATION_COL_TOL);
950
+ }
951
+ var PAGE_EDGE_BAND = 0.16;
952
+ var RESTART_MIN_ANCHORS = 3;
953
+ var RESTART_LOOKBACK_PAGES = 5;
954
+
955
+ // src/pdf/cell-continuation.ts
956
+ var COL_MATCH_TOL = 0.5;
957
+ function lastRowCell(t, x1, x2) {
958
+ const xs = TABLE_COLXS.get(t);
959
+ const covered = /* @__PURE__ */ new Set();
960
+ for (let r = 0; r < t.rows; r++) {
961
+ for (let c = 0; c < t.cols; c++) {
962
+ if (covered.has(r * 1e5 + c)) continue;
963
+ const cell = t.cells[r]?.[c];
964
+ if (!cell) continue;
965
+ for (let dr = 0; dr < cell.rowSpan; dr++) for (let dc = 0; dc < cell.colSpan; dc++) covered.add((r + dr) * 1e5 + c + dc);
966
+ if (r + cell.rowSpan !== t.rows) continue;
967
+ if (xs ? Math.abs(xs[c] - x1) <= COL_MATCH_TOL && Math.abs(xs[c + cell.colSpan] - x2) <= COL_MATCH_TOL : t.cols === 1) return cell;
968
+ }
969
+ }
970
+ return void 0;
971
+ }
972
+ var cellBlocks = (cell, pageNumber) => cell.blocks ?? cell.text.split("\n").map((t) => t.trim()).filter(Boolean).map((text) => ({ type: "paragraph", text, pageNumber }));
973
+ function mergeContinuedCells(blocks, pageHeights) {
974
+ for (let j = blocks.length - 1; j > 0; j--) {
975
+ const part = blocks[j];
976
+ const from = part.table ? CONT_PARTS.get(part.table) : void 0;
977
+ if (!from || !part.table) continue;
978
+ let i = j - 1;
979
+ while (i >= 0 && blocks[i].type !== "table") i--;
980
+ const prev = blocks[i];
981
+ if (i < 0 || !prev.table || prev.pageNumber !== (part.pageNumber ?? 0) - 1) continue;
982
+ const cell = lastRowCell(prev.table, from.x1, from.x2);
983
+ const add = part.table.cells[0]?.[0];
984
+ if (!cell || !add) continue;
985
+ if (cell.blocks || add.blocks) cell.blocks = [...cellBlocks(cell, prev.pageNumber), ...cellBlocks(add, part.pageNumber)];
986
+ cell.text = [cell.text, add.text].filter((s) => s.trim()).join("\n");
987
+ if (cell.text.trim() || cell.blocks?.length) EMPTY_PARTS.delete(prev.table);
988
+ blocks.splice(j, 1);
989
+ if (cell.blocks) mergeCrossPageTables(cell.blocks, pageHeights);
990
+ }
991
+ }
992
+
993
+ // src/pdf/symbol-fonts.ts
551
994
  var WINANSI_REVERSE = {
552
995
  8364: 128,
553
996
  8218: 130,
@@ -620,7 +1063,8 @@ function remapSymbolFontItems(items, resolveFontName) {
620
1063
  function normalizeAraea(text) {
621
1064
  return text.replace(/(?<![\u1100-\u115F])\u119E/g, "\u318D");
622
1065
  }
623
- var cleanChars = (text) => normalizeAraea(stripControlChars(text));
1066
+ var stripNoUnicodeGlyph = (text) => text.includes("\uF000") ? text.replace(/\uF000/g, "") : text;
1067
+ var cleanChars = (text) => normalizeAraea(stripNoUnicodeGlyph(stripControlChars(text)));
624
1068
  function sanitizeBlockControlChars(blocks) {
625
1069
  for (const b of blocks) {
626
1070
  if (b.text) b.text = cleanChars(b.text);
@@ -655,7 +1099,8 @@ function cleanPdfText(text) {
655
1099
  normalizeAraea(stripControlChars(text)).replace(/^\d{1,4}\n/, "").replace(/^[\s]*[-–—]\s*[-–—]?\d+[-–—]?[\s]*[-–—]?[\s]*$/gm, "").replace(/^\s*\d+\s*\/\s*\d+\s*$/gm, "").replace(/\n\d{1,4}\n/g, "\n").replace(/\n\d{1,4}$/, "").replace(/^#{1,6}\s*\d{1,4}\s*$/gm, "")
656
1100
  ).replace(/^(?!\| ---).*$/gm, (line) => {
657
1101
  if (/^\s*\${1,2}.+\${1,2}\s*$/.test(line)) return line;
658
- return collapseEvenSpacing(line);
1102
+ const mark = /^(?:#{1,6}|-) /.exec(line)?.[0] ?? "";
1103
+ return mark + collapseEvenSpacing(line.slice(mark.length));
659
1104
  }).replace(/([□■◆○●▶ㅇ])\s+([가-힣])\s+([가-힣])/g, "$1 $2$3").replace(/\\~\\~/g, "~~").replace(/~~~~/g, "").replace(/<u>\s*<\/u>/g, "").replace(/\n{3,}/g, "\n\n").trim();
660
1105
  }
661
1106
  function startsWithMarker(line) {
@@ -734,7 +1179,7 @@ function applyLinkAnnotations(items, annots) {
734
1179
 
735
1180
  // src/pdf/formula-ocr.ts
736
1181
  async function applyFormulaOcr(buffer, blocks, pageFilter, effectivePageCount, warnings, _onProgress) {
737
- const formulaMod = await import("./formula-JGFTXWYT.js");
1182
+ const formulaMod = await import("./formula-7RANCW5L.js");
738
1183
  const { FormulaPipeline, ensureFormulaModels } = formulaMod;
739
1184
  await ensureFormulaModels((p) => {
740
1185
  if (p.phase === "download" && p.total) {
@@ -934,6 +1379,9 @@ async function parsePdfDocument(buffer, options) {
934
1379
  const imageState = createPdfImageState();
935
1380
  const extractedImages = [];
936
1381
  const pageImageBlocks = /* @__PURE__ */ new Map();
1382
+ const carry = {};
1383
+ const vectorPageOps = /* @__PURE__ */ new Map();
1384
+ const wrapLexicon = new WrapLexicon();
937
1385
  let parsedPages = 0;
938
1386
  for (let i = 1; i <= effectivePageCount; i++) {
939
1387
  if (pageFilter && !pageFilter.has(i)) continue;
@@ -964,6 +1412,7 @@ async function parsePdfDocument(buffer, options) {
964
1412
  return void 0;
965
1413
  }
966
1414
  });
1415
+ for (const it of visible) if (it.text.includes("$")) it.text = escapeLiteralDollar(it.text);
967
1416
  const pageArea = viewport.width * viewport.height;
968
1417
  if (pageArea > 0) {
969
1418
  const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray);
@@ -972,19 +1421,19 @@ async function parsePdfDocument(buffer, options) {
972
1421
  const area = (r.x2 - r.x1) * (r.y2 - r.y1);
973
1422
  if (area < pageArea * 0.05) continue;
974
1423
  pagesWithLargeImage.add(i);
975
- const hasText = visible.some((it) => {
1424
+ const hasText2 = visible.some((it) => {
976
1425
  const cx = it.x + it.w / 2;
977
1426
  const cy = it.y + (it.h || it.fontSize) / 2;
978
1427
  return cx >= r.x1 && cx <= r.x2 && cy >= r.y1 && cy <= r.y2;
979
1428
  });
980
- if (!hasText) uncovered++;
1429
+ if (!hasText2) uncovered++;
981
1430
  }
982
1431
  if (uncovered > 0) skippedImagePages.set(i, uncovered);
983
1432
  }
984
- const pageBlocks = extractPageBlocksWithLines(visible, i, opList, viewport.width, viewport.height, void 0, options?.tables !== false);
1433
+ const pageBlocks = extractPageBlocksWithLines(visible, i, opList, viewport.width, viewport.height, void 0, options?.tables !== false, carry, wrapLexicon);
985
1434
  for (const b of pageBlocks) blocks.push(b);
986
1435
  try {
987
- const { blocks: imgBlocks, images: pageImages } = await extractPageImages(page, opList.fnArray, opList.argsArray, i, imageState, warnings);
1436
+ const { blocks: imgBlocks, images: pageImages } = await extractPageImages(page, opList.fnArray, opList.argsArray, i, imageState, warnings, options?.images !== false);
988
1437
  if (imgBlocks.length > 0) pageImageBlocks.set(i, imgBlocks);
989
1438
  extractedImages.push(...pageImages);
990
1439
  } catch {
@@ -1000,7 +1449,12 @@ async function parsePdfDocument(buffer, options) {
1000
1449
  totalTextBytes += t.length * 2;
1001
1450
  pageText += pageText ? "\n" + t : t;
1002
1451
  }
1003
- pageQuality.push(computePageQuality(i, pageText));
1452
+ const vector = scanVectorGlyphs(opList.fnArray, opList.argsArray, visible);
1453
+ const quality = computePageQuality(i, pageText, vector.glyphs);
1454
+ pageQuality.push(quality);
1455
+ if (options?.ocr && quality.ocrReason === "vector_text" && page.rotate % 360 === 0 && page.view[0] === 0 && page.view[1] === 0) {
1456
+ vectorPageOps.set(i, ocrVectorOps(opList, vector.paths));
1457
+ }
1004
1458
  if (totalTextBytes > MAX_TOTAL_TEXT) throw new KordocError("\uD14D\uC2A4\uD2B8 \uCD94\uCD9C \uD06C\uAE30 \uCD08\uACFC");
1005
1459
  parsedPages++;
1006
1460
  options?.onProgress?.(parsedPages, totalTarget);
@@ -1026,9 +1480,9 @@ async function parsePdfDocument(buffer, options) {
1026
1480
  }
1027
1481
  if (targets.size > 0) {
1028
1482
  try {
1029
- const { runPdfOcr } = await import("./pdf-ocr-76SAUXMZ.js");
1483
+ const { runPdfOcr } = await import("./pdf-ocr-VJSF2SQC.js");
1030
1484
  const mode = typeof options.ocr === "function" ? options.ocr : "builtin";
1031
- const ocrPageBlocks = await runPdfOcr(ocrBuffer, targets, mode, warnings, options.onProgress, options.tables !== false);
1485
+ const ocrPageBlocks = await runPdfOcr(ocrBuffer, targets, mode, warnings, options.onProgress, options.tables !== false, vectorPageOps);
1032
1486
  if (ocrPageBlocks.size > 0) {
1033
1487
  for (const p of ocrPageBlocks.keys()) ocrDone.add(p);
1034
1488
  const merged = blocks.filter((b) => !(b.pageNumber && ocrDone.has(b.pageNumber)));
@@ -1058,6 +1512,7 @@ async function parsePdfDocument(buffer, options) {
1058
1512
  }
1059
1513
  if (!isImageBased) {
1060
1514
  const OCR_REASON_MESSAGES = {
1515
+ vector_text: "\uAE00\uC790\uB97C \uACE1\uC120(\uBCA1\uD130 \uACBD\uB85C)\uC73C\uB85C \uADF8\uB9B0 \uD398\uC774\uC9C0 (\uD14D\uC2A4\uD2B8\uCE35\uC5D0 \uAE00\uC790 \uC5C6\uC74C)",
1061
1516
  low_text: "\uD14D\uC2A4\uD2B8\uAC00 \uAC70\uC758 \uC5C6\uB294 \uD398\uC774\uC9C0 (\uC2A4\uCE94/\uC774\uBBF8\uC9C0 \uCD94\uC815)",
1062
1517
  high_pua: "\uAE00\uAF34 \uB9E4\uD551 \uC2E4\uD328 (PUA \uBE44\uC728 \uB192\uC74C) \u2014 \uCD94\uCD9C \uD14D\uC2A4\uD2B8 \uC2E0\uB8B0 \uBD88\uAC00",
1063
1518
  high_control: "\uC81C\uC5B4\uBB38\uC790 \uBE44\uC728 \uB192\uC74C \u2014 \uCD94\uCD9C \uD14D\uC2A4\uD2B8 \uC2E0\uB8B0 \uBD88\uAC00",
@@ -1081,7 +1536,10 @@ async function parsePdfDocument(buffer, options) {
1081
1536
  blocks.splice(removed[ri], 1);
1082
1537
  }
1083
1538
  }
1084
- mergeCrossPageTables(blocks);
1539
+ mergeContinuedCells(blocks, pageHeights);
1540
+ mergeCrossPageTables(blocks, pageHeights);
1541
+ if (!options?.keepTrailingEmptyCols) trimTrailingEmptyTableCols(blocks);
1542
+ joinPageBreakWraps(blocks, wrapLexicon);
1085
1543
  injectPageImageBlocks(blocks, pageImageBlocks);
1086
1544
  if (options?.formulaOcr && formulaBuffer) {
1087
1545
  try {
@@ -1163,4 +1621,4 @@ export {
1163
1621
  parsePdfDocument,
1164
1622
  removeHeaderFooterBlocks
1165
1623
  };
1166
- //# sourceMappingURL=parser-A4TMPJAM.js.map
1624
+ //# sourceMappingURL=parser-FJBJXRJK.js.map