n8n-nodes-kordoc 0.1.39 → 0.1.41

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.
@@ -44,6 +44,9 @@ var init_cjs_shims = __esm({
44
44
  });
45
45
 
46
46
  // .kordoc-source/src/script-tags.ts
47
+ function escapeLiteralTags(text2) {
48
+ return text2.includes("<") ? text2.replace(LITERAL_TAG, "\\<") : text2;
49
+ }
47
50
  function wrapScript(text2, kind) {
48
51
  if (!kind) return text2;
49
52
  const m = /^(\s*)([\s\S]*?)(\s*)$/.exec(text2);
@@ -51,11 +54,11 @@ function wrapScript(text2, kind) {
51
54
  }
52
55
  function tidyScriptTags(text2) {
53
56
  if (!text2.includes("<su")) return text2;
54
- return text2.replace(/<\/(sup|sub)><\1>/g, "").replace(/<(sup|sub)>(\s+)/g, "$2<$1>").replace(/(\s+)<\/(sup|sub)>/g, "</$2>$1").replace(/<(sup|sub)><\/\1>/g, "");
57
+ return text2.replace(/(?<!\\)<\/(sup|sub)><\1>/g, "").replace(/(?<!\\)<(sup|sub)>(\s+)/g, "$2<$1>").replace(/(\s+)<\/(sup|sub)>/g, "</$2>$1").replace(/(?<!\\)<(sup|sub)><\/\1>/g, "");
55
58
  }
56
59
  function plainScripts(md2) {
57
60
  if (!md2.includes("<su")) return md2;
58
- return md2.replace(/<(sup|sub)>([^<\n]*)<\/\1>/g, (_, kind, body) => {
61
+ return md2.replace(/(?<!\\)<(sup|sub)>([^<\n]*)<\/\1>/g, (_, kind, body) => {
59
62
  const mark = kind === "sup" ? "^" : "_";
60
63
  return /^(?:[+\-−]?[\p{L}\p{N}]+|[*∗†‡§¶]+)$/u.test(body) ? mark + body : `${mark}(${body})`;
61
64
  });
@@ -85,12 +88,70 @@ function stripScriptTags(r) {
85
88
  for (const p of (_a2 = r.pages) != null ? _a2 : []) p.markdown = s(p.markdown);
86
89
  return r;
87
90
  }
88
- var TAG_RE;
91
+ var LITERAL_TAG, TAG_RE;
89
92
  var init_script_tags = __esm({
90
93
  ".kordoc-source/src/script-tags.ts"() {
91
94
  "use strict";
92
95
  init_cjs_shims();
93
- TAG_RE = /<\/?su[bp]>/g;
96
+ LITERAL_TAG = /<(?=\/?(?:u|sup|sub)>)/g;
97
+ TAG_RE = /(?<!\\)<\/?su[bp]>/g;
98
+ }
99
+ });
100
+
101
+ // .kordoc-source/src/page-range.ts
102
+ var page_range_exports = {};
103
+ __export(page_range_exports, {
104
+ hasRequestedPagesAfter: () => hasRequestedPagesAfter,
105
+ parsePageRange: () => parsePageRange
106
+ });
107
+ function parsePageRange(spec, maxPages) {
108
+ const result = /* @__PURE__ */ new Set();
109
+ if (maxPages <= 0) return result;
110
+ if (Array.isArray(spec)) {
111
+ for (const n of spec) {
112
+ const page = Math.round(n);
113
+ if (page >= 1 && page <= maxPages) result.add(page);
114
+ }
115
+ return result;
116
+ }
117
+ if (typeof spec !== "string" || spec.trim() === "") return result;
118
+ const parts = spec.split(",");
119
+ for (const part of parts) {
120
+ const trimmed = part.trim();
121
+ if (!trimmed) continue;
122
+ const rangeMatch = trimmed.match(/^(\d+)\s*-\s*(\d+)$/);
123
+ if (rangeMatch) {
124
+ const start = Math.max(1, parseInt(rangeMatch[1], 10));
125
+ const end = Math.min(maxPages, parseInt(rangeMatch[2], 10));
126
+ for (let i = start; i <= end; i++) result.add(i);
127
+ } else {
128
+ const page = parseInt(trimmed, 10);
129
+ if (!isNaN(page) && page >= 1 && page <= maxPages) result.add(page);
130
+ }
131
+ }
132
+ return result;
133
+ }
134
+ function hasRequestedPagesAfter(spec, maxParsed, total) {
135
+ if (total <= 0 || total <= maxParsed) return false;
136
+ const beyond = (page) => page >= 1 && page <= total && page > maxParsed;
137
+ if (Array.isArray(spec)) return spec.some((n) => beyond(Math.round(n)));
138
+ if (typeof spec !== "string" || spec.trim() === "") return false;
139
+ for (const part of spec.split(",")) {
140
+ const trimmed = part.trim();
141
+ if (!trimmed) continue;
142
+ const rangeMatch = trimmed.match(/^(\d+)\s*-\s*(\d+)$/);
143
+ if (rangeMatch) {
144
+ const start = Math.max(1, parseInt(rangeMatch[1], 10), Math.floor(maxParsed) + 1);
145
+ const end = Math.min(total, parseInt(rangeMatch[2], 10));
146
+ if (start <= end) return true;
147
+ } else if (beyond(parseInt(trimmed, 10))) return true;
148
+ }
149
+ return false;
150
+ }
151
+ var init_page_range = __esm({
152
+ ".kordoc-source/src/page-range.ts"() {
153
+ "use strict";
154
+ init_cjs_shims();
94
155
  }
95
156
  });
96
157
 
@@ -9872,9 +9933,9 @@ var require_lib3 = __commonJS({
9872
9933
  "node_modules/jszip/lib/index.js"(exports2, module2) {
9873
9934
  "use strict";
9874
9935
  init_cjs_shims();
9875
- function JSZip15() {
9876
- if (!(this instanceof JSZip15)) {
9877
- return new JSZip15();
9936
+ function JSZip16() {
9937
+ if (!(this instanceof JSZip16)) {
9938
+ return new JSZip16();
9878
9939
  }
9879
9940
  if (arguments.length) {
9880
9941
  throw new Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.");
@@ -9883,7 +9944,7 @@ var require_lib3 = __commonJS({
9883
9944
  this.comment = null;
9884
9945
  this.root = "";
9885
9946
  this.clone = function() {
9886
- var newObj = new JSZip15();
9947
+ var newObj = new JSZip16();
9887
9948
  for (var i in this) {
9888
9949
  if (typeof this[i] !== "function") {
9889
9950
  newObj[i] = this[i];
@@ -9892,16 +9953,16 @@ var require_lib3 = __commonJS({
9892
9953
  return newObj;
9893
9954
  };
9894
9955
  }
9895
- JSZip15.prototype = require_object();
9896
- JSZip15.prototype.loadAsync = require_load();
9897
- JSZip15.support = require_support();
9898
- JSZip15.defaults = require_defaults();
9899
- JSZip15.version = "3.10.1";
9900
- JSZip15.loadAsync = function(content, options) {
9901
- return new JSZip15().loadAsync(content, options);
9956
+ JSZip16.prototype = require_object();
9957
+ JSZip16.prototype.loadAsync = require_load();
9958
+ JSZip16.support = require_support();
9959
+ JSZip16.defaults = require_defaults();
9960
+ JSZip16.version = "3.10.1";
9961
+ JSZip16.loadAsync = function(content, options) {
9962
+ return new JSZip16().loadAsync(content, options);
9902
9963
  };
9903
- JSZip15.external = require_external();
9904
- module2.exports = JSZip15;
9964
+ JSZip16.external = require_external();
9965
+ module2.exports = JSZip16;
9905
9966
  }
9906
9967
  });
9907
9968
 
@@ -9975,8 +10036,9 @@ function precheckZipSize(buffer, maxUncompressedSize = 256 * 1024 * 1024, maxEnt
9975
10036
  const extraLen = data.getUint16(pos + 30, true);
9976
10037
  const commentLen = data.getUint16(pos + 32, true);
9977
10038
  const isMedia = !!media && pos + 46 + nameLen <= len && media.re.test(new TextDecoder().decode(new Uint8Array(buffer, pos + 46, nameLen)));
9978
- if (isMedia) mediaUncompressed += size;
9979
- if (!(isMedia && (media == null ? void 0 : media.skip))) totalUncompressed += size;
10039
+ const never = isMedia && !!(media == null ? void 0 : media.never) && media.never.test(new TextDecoder().decode(new Uint8Array(buffer, pos + 46, nameLen)));
10040
+ if (isMedia && !never) mediaUncompressed += size;
10041
+ if (!(isMedia && ((media == null ? void 0 : media.skip) || never))) totalUncompressed += size;
9980
10042
  pos += 46 + nameLen + extraLen + commentLen;
9981
10043
  }
9982
10044
  if (totalUncompressed > maxUncompressedSize) {
@@ -10030,12 +10092,16 @@ function classifyError(err) {
10030
10092
  if (msg2.includes("\uC2DC\uADF8\uB2C8\uCC98") || msg2.includes("\uBCF5\uAD6C\uD560 \uC218 \uC5C6")) return "CORRUPTED";
10031
10093
  return "PARSE_ERROR";
10032
10094
  }
10095
+ function partExtension(path) {
10096
+ var _a2, _b;
10097
+ return ((_b = (_a2 = /\.([A-Za-z0-9]{1,5})$/.exec(path.slice(path.lastIndexOf("/") + 1))) == null ? void 0 : _a2[1]) != null ? _b : "bin").toLowerCase();
10098
+ }
10033
10099
  var VERSION, KordocError, MAX_UNZIP_ENV_MB, SAFE_HREF_RE, HREF_ESCAPE, HTML_ENTITY, OPTIONAL_DEP_INSTALL_HINT;
10034
10100
  var init_utils = __esm({
10035
10101
  ".kordoc-source/src/utils.ts"() {
10036
10102
  "use strict";
10037
10103
  init_cjs_shims();
10038
- VERSION = true ? "4.18.0" : "0.0.0-dev";
10104
+ VERSION = true ? "4.18.8" : "0.0.0-dev";
10039
10105
  KordocError = class extends Error {
10040
10106
  constructor(message) {
10041
10107
  super(message);
@@ -10649,7 +10715,7 @@ function escapeGfm(text2) {
10649
10715
  spans.push(m);
10650
10716
  return NUL + (spans.length - 1) + NUL;
10651
10717
  });
10652
- const escaped = masked.replace(/\\(?=[!-#%-\/:-@\[-\x60{}~])/g, "\\\\").replace(/([~*_`])/g, "\\$1").replace(/(?<!\\)\|/g, "\\|").replace(/^([ \t]*)(?=#{1,6}(?:[ \t]|$))/gm, "$1\\").replace(/<(?!\/?(?:u|sup|sub)>)(?=[A-Za-z/!?])/g, "\\<");
10718
+ const escaped = masked.replace(/\\(?=[!-#%-\/:-@\[-\x60{}~])(?!<\/?(?:u|sup|sub)>)/g, "\\\\").replace(/([~*_`])/g, "\\$1").replace(/(?<!\\)\|/g, "\\|").replace(/^([ \t]*)(?=#{1,6}(?:[ \t]|$))/gm, "$1\\").replace(/<(?!\/?(?:u|sup|sub)>)(?=[A-Za-z/!?])/g, "\\<");
10653
10719
  return escaped.replace(new RegExp(NUL + "(\\d+)" + NUL, "g"), (_, n) => spans[Number(n)]);
10654
10720
  }
10655
10721
  function escapeLiteralDollar(text2) {
@@ -10823,6 +10889,7 @@ function blocksToMarkdown(blocks) {
10823
10889
  if (block2.type === "paragraph" && (block2.text || block2.footnoteText)) {
10824
10890
  let text2 = sanitizeText((_a2 = block2.text) != null ? _a2 : "");
10825
10891
  if (!text2 && !block2.footnoteText) continue;
10892
+ if (lines.length && lines[lines.length - 1] !== "") lines.push("");
10826
10893
  if (/^\[별표\s*\d+/.test(text2)) {
10827
10894
  const nextBlock = blocks[i + 1];
10828
10895
  if ((nextBlock == null ? void 0 : nextBlock.type) === "paragraph" && nextBlock.text && /관련\)?$/.test(nextBlock.text)) {
@@ -10917,7 +10984,7 @@ function visibleText(b) {
10917
10984
  return ((_a2 = b.spans) == null ? void 0 : _a2.some((s) => s.placeholder)) ? b.spans.filter((s) => !s.placeholder).map((s) => s.text).join("") : (_b = b.text) != null ? _b : "";
10918
10985
  }
10919
10986
  function escapeHtmlCellText(text2) {
10920
- return escapeHtml(text2).replace(/&lt;(\/?)(u|sup|sub)&gt;/g, "<$1$2>");
10987
+ return escapeHtml(text2).replace(/(\\)?&lt;(\/?)(u|sup|sub)&gt;/g, (_, esc2, sl, tag) => esc2 ? `&lt;${sl}${tag}&gt;` : `<${sl}${tag}>`);
10921
10988
  }
10922
10989
  function cellInnerHtml(cell2) {
10923
10990
  var _a2;
@@ -11009,7 +11076,7 @@ function tableToMarkdown(table3) {
11009
11076
  if (skip.has(`${r},${c}`)) continue;
11010
11077
  const cell2 = (_a2 = cells[r]) == null ? void 0 : _a2[c];
11011
11078
  if (!cell2) continue;
11012
- display[r][c] = cellToMarkdown(cell2, "<br>").replace(/\n/g, "<br>").replace(/(?<!\\)\|/g, "\\|");
11079
+ display[r][c] = cellToMarkdown(cell2, "<br>").replace(/\r\n|\r|\n/g, "<br>").replace(/(?<!\\)\|/g, "\\|");
11013
11080
  for (let dr = 0; dr < cell2.rowSpan; dr++) {
11014
11081
  for (let dc = 0; dc < cell2.colSpan; dc++) {
11015
11082
  if (dr === 0 && dc === 0) continue;
@@ -11087,7 +11154,7 @@ function ruleGrids(t, anchors2) {
11087
11154
  return { H, V };
11088
11155
  }
11089
11156
  function toTex(s) {
11090
- return s.replace(/<\/?u>/g, "").replace(/([\\{}%#&_$])/g, "\\$1").replace(/<sup>(.*?)<\/sup>/g, "^{$1}").replace(/<sub>(.*?)<\/sub>/g, "_{$1}").replace(/[가-힣ㄱ-ㅎㅏ-ㅣ][가-힣ㄱ-ㅎㅏ-ㅣ\s·ㆍ]*/g, (m) => `\\text{${m.trim()}}`).trim();
11157
+ return s.replace(/\\\$/g, "$").replace(/\\</g, "").replace(/<\/?u>/g, "").replace(/([\\{}%#&_$])/g, "\\$1").replace(/<sup>(.*?)<\/sup>/g, "^{$1}").replace(/<sub>(.*?)<\/sub>/g, "_{$1}").replace(/\u0001/g, "<").replace(/[가-힣ㄱ-ㅎㅏ-ㅣ][가-힣ㄱ-ㅎㅏ-ㅣ\s·ㆍ]*/g, (m) => `\\text{${m.trim()}}`).trim();
11091
11158
  }
11092
11159
  function fractionPart(cell2) {
11093
11160
  var _a2;
@@ -11101,7 +11168,8 @@ function mergeFractions(t, anchors2, H, V) {
11101
11168
  for (const u of anchors2) {
11102
11169
  const d = at.get((u.r + u.rs) * t.cols + u.c);
11103
11170
  if (!d || d.cs !== u.cs || u.rs !== 1 || d.rs !== 1 || !fractionPart(u.cell) || !fractionPart(d.cell)) continue;
11104
- if (u.cs === t.cols && anchors2.length !== 2) continue;
11171
+ const besideText = anchors2.some((a) => a !== u && a !== d && a.r <= d.r && a.r + a.rs > u.r && a.cell.text.trim());
11172
+ if (!besideText && anchors2.filter((a) => a.cell.text.trim()).length !== 2) continue;
11105
11173
  const bar = d.r, c1 = u.c, c2 = u.c + u.cs;
11106
11174
  let ok = true;
11107
11175
  for (let c = c1; c < c2 && ok; c++) if (!H[bar][c]) ok = false;
@@ -11152,9 +11220,10 @@ function bandTable(t, anchors2, V, H, r0, r1, keepEmptyCols) {
11152
11220
  const shift = (y) => y - drop.filter((d) => d < y).length;
11153
11221
  list2 = list2.filter((a) => !drop.includes(a.r)).map((a) => ({ ...a, r: shift(a.r), rs: shift(a.r + a.rs) - shift(a.r) })).filter((a) => a.rs > 0);
11154
11222
  }
11223
+ const emptyBand = list2.every(blank2);
11155
11224
  for (let right = keepEmptyCols ? 0 : Math.max(...list2.map((a) => a.c + a.cs)); right > 1; ) {
11156
11225
  const starts = list2.filter((a) => a.c === right - 1);
11157
- if (!starts.length || !starts.every(blank2)) break;
11226
+ if (!starts.length || !starts.every(blank2) || starts.length === list2.length) break;
11158
11227
  list2 = list2.filter((a) => a.c !== right - 1).map((a) => a.c + a.cs === right ? { ...a, cs: a.cs - 1 } : a);
11159
11228
  right--;
11160
11229
  }
@@ -11175,7 +11244,7 @@ function bandTable(t, anchors2, V, H, r0, r1, keepEmptyCols) {
11175
11244
  a.cell.colSpan = cx.indexOf(a.c + a.cs) - c;
11176
11245
  cells[r][c] = a.cell;
11177
11246
  }
11178
- return { rows, cols, cells, hasHeader: t.hasHeader };
11247
+ return { rows, cols, cells, hasHeader: t.hasHeader, ...emptyBand ? { renderAsTable: true } : {} };
11179
11248
  }
11180
11249
  function textRow(row, out, pageNumber, keepEmptyCols) {
11181
11250
  var _a2;
@@ -11212,8 +11281,18 @@ function unframeTable(t, pageNumber, keepEmptyCols) {
11212
11281
  const ruled = ruledRows(t, anchors2, H, V);
11213
11282
  if (ruled.every(Boolean)) {
11214
11283
  const whole = bandTable(t, anchors2, V, H, 0, t.rows - 1, keepEmptyCols);
11215
- if (!whole || whole.rows === t.rows && whole.cols === t.cols) return null;
11216
- return [{ type: "table", table: { ...t, rows: whole.rows, cols: whole.cols, cells: whole.cells }, pageNumber }];
11284
+ if (!whole) return null;
11285
+ if (whole.rows === t.rows && whole.cols === t.cols) {
11286
+ if (whole.renderAsTable) t.renderAsTable = true;
11287
+ return null;
11288
+ }
11289
+ return [{ type: "table", table: {
11290
+ ...t,
11291
+ rows: whole.rows,
11292
+ cols: whole.cols,
11293
+ cells: whole.cells,
11294
+ ...whole.renderAsTable ? { renderAsTable: true } : {}
11295
+ }, pageNumber }];
11217
11296
  }
11218
11297
  const out = [];
11219
11298
  if ((_a2 = t.captionBlocks) == null ? void 0 : _a2.length) out.push(...t.captionBlocks);
@@ -11264,63 +11343,6 @@ var init_layout_frames = __esm({
11264
11343
  }
11265
11344
  });
11266
11345
 
11267
- // .kordoc-source/src/page-range.ts
11268
- var page_range_exports = {};
11269
- __export(page_range_exports, {
11270
- hasRequestedPagesAfter: () => hasRequestedPagesAfter,
11271
- parsePageRange: () => parsePageRange
11272
- });
11273
- function parsePageRange(spec, maxPages) {
11274
- const result = /* @__PURE__ */ new Set();
11275
- if (maxPages <= 0) return result;
11276
- if (Array.isArray(spec)) {
11277
- for (const n of spec) {
11278
- const page = Math.round(n);
11279
- if (page >= 1 && page <= maxPages) result.add(page);
11280
- }
11281
- return result;
11282
- }
11283
- if (typeof spec !== "string" || spec.trim() === "") return result;
11284
- const parts = spec.split(",");
11285
- for (const part of parts) {
11286
- const trimmed = part.trim();
11287
- if (!trimmed) continue;
11288
- const rangeMatch = trimmed.match(/^(\d+)\s*-\s*(\d+)$/);
11289
- if (rangeMatch) {
11290
- const start = Math.max(1, parseInt(rangeMatch[1], 10));
11291
- const end = Math.min(maxPages, parseInt(rangeMatch[2], 10));
11292
- for (let i = start; i <= end; i++) result.add(i);
11293
- } else {
11294
- const page = parseInt(trimmed, 10);
11295
- if (!isNaN(page) && page >= 1 && page <= maxPages) result.add(page);
11296
- }
11297
- }
11298
- return result;
11299
- }
11300
- function hasRequestedPagesAfter(spec, maxParsed, total) {
11301
- if (total <= 0 || total <= maxParsed) return false;
11302
- const beyond = (page) => page >= 1 && page <= total && page > maxParsed;
11303
- if (Array.isArray(spec)) return spec.some((n) => beyond(Math.round(n)));
11304
- if (typeof spec !== "string" || spec.trim() === "") return false;
11305
- for (const part of spec.split(",")) {
11306
- const trimmed = part.trim();
11307
- if (!trimmed) continue;
11308
- const rangeMatch = trimmed.match(/^(\d+)\s*-\s*(\d+)$/);
11309
- if (rangeMatch) {
11310
- const start = Math.max(1, parseInt(rangeMatch[1], 10), Math.floor(maxParsed) + 1);
11311
- const end = Math.min(total, parseInt(rangeMatch[2], 10));
11312
- if (start <= end) return true;
11313
- } else if (beyond(parseInt(trimmed, 10))) return true;
11314
- }
11315
- return false;
11316
- }
11317
- var init_page_range = __esm({
11318
- ".kordoc-source/src/page-range.ts"() {
11319
- "use strict";
11320
- init_cjs_shims();
11321
- }
11322
- });
11323
-
11324
11346
  // node_modules/@xmldom/xmldom/lib/conventions.js
11325
11347
  var require_conventions = __commonJS({
11326
11348
  "node_modules/@xmldom/xmldom/lib/conventions.js"(exports2) {
@@ -17379,7 +17401,7 @@ var require_dom_parser = __commonJS({
17379
17401
  function normalizeLineEndings(input) {
17380
17402
  return input.replace(/\r[\n\u0085]/g, "\n").replace(/[\r\u0085\u2028\u2029]/g, "\n");
17381
17403
  }
17382
- function DOMParser6(options) {
17404
+ function DOMParser7(options) {
17383
17405
  options = options || {};
17384
17406
  if (options.locator === void 0) {
17385
17407
  options.locator = true;
@@ -17396,7 +17418,7 @@ var require_dom_parser = __commonJS({
17396
17418
  this.locator = !!options.locator;
17397
17419
  this.xmlns = this.assign(/* @__PURE__ */ Object.create(null), options.xmlns);
17398
17420
  }
17399
- DOMParser6.prototype.parseFromString = function(source, mimeType) {
17421
+ DOMParser7.prototype.parseFromString = function(source, mimeType) {
17400
17422
  if (!isValidMimeType(mimeType)) {
17401
17423
  throw new TypeError('DOMParser.parseFromString: the provided mimeType "' + mimeType + '" is not valid.');
17402
17424
  }
@@ -17618,7 +17640,7 @@ var require_dom_parser = __commonJS({
17618
17640
  throw "onWarningStopParsing";
17619
17641
  }
17620
17642
  exports2.__DOMHandler = DOMHandler;
17621
- exports2.DOMParser = DOMParser6;
17643
+ exports2.DOMParser = DOMParser7;
17622
17644
  exports2.normalizeLineEndings = normalizeLineEndings;
17623
17645
  exports2.onErrorStopParsing = onErrorStopParsing;
17624
17646
  exports2.onWarningStopParsing = onWarningStopParsing;
@@ -19345,6 +19367,17 @@ var init_crop = __esm({
19345
19367
  }
19346
19368
  });
19347
19369
 
19370
+ // .kordoc-source/src/ocr/runtime-env.ts
19371
+ function disableOrtTelemetry() {
19372
+ if (typeof process !== "undefined" && process.env) process.env.ORT_DISABLE_TELEMETRY = "1";
19373
+ }
19374
+ var init_runtime_env = __esm({
19375
+ ".kordoc-source/src/ocr/runtime-env.ts"() {
19376
+ "use strict";
19377
+ init_cjs_shims();
19378
+ }
19379
+ });
19380
+
19348
19381
  // .kordoc-source/src/ocr/engine.ts
19349
19382
  function median(gray) {
19350
19383
  const hist = new Uint32Array(256);
@@ -19472,6 +19505,7 @@ var init_engine = __esm({
19472
19505
  init_glyph_restore();
19473
19506
  init_postprocess();
19474
19507
  init_crop();
19508
+ init_runtime_env();
19475
19509
  DEFAULT_OCR_TUNING = Object.freeze({
19476
19510
  detLongSide: 960,
19477
19511
  detThresh: 0.3,
@@ -19508,6 +19542,7 @@ var init_engine = __esm({
19508
19542
  }
19509
19543
  static async create() {
19510
19544
  var _a2;
19545
+ disableOrtTelemetry();
19511
19546
  const [ortMod, sharpModRaw] = await Promise.all([
19512
19547
  tryImport("onnxruntime-node", () => import("onnxruntime-node")),
19513
19548
  tryImport(
@@ -21523,13 +21558,13 @@ function classifyAndAdd(seg, lineWidth, horizontals, verticals, fromFill = false
21523
21558
  verticals.push({ x1: x, y1, x2: x, y2, lineWidth, fromFill });
21524
21559
  }
21525
21560
  }
21526
- function preprocessLines(horizontals, verticals) {
21561
+ function preprocessLines(horizontals, verticals, nonRules) {
21527
21562
  let h = horizontals.filter((l) => l.lineWidth <= MAX_LINE_WIDTH);
21528
21563
  let v = verticals.filter((l) => l.lineWidth <= MAX_LINE_WIDTH);
21529
21564
  h = dropShadingStacks(h, "h");
21530
21565
  v = dropShadingStacks(v, "v");
21531
- h = mergeParallelLines(h, "h");
21532
- v = mergeParallelLines(v, "v");
21566
+ h = mergeParallelLines(h, "h", nonRules);
21567
+ v = mergeParallelLines(v, "v", nonRules);
21533
21568
  return { horizontals: h, verticals: v };
21534
21569
  }
21535
21570
  function dropShadingStacks(lines, dir) {
@@ -21678,15 +21713,15 @@ function closeOpenTableEdges(horizontals, verticals) {
21678
21713
  const hasInterior = verticals.some((v) => v.x1 > x1 + EDGE_INSET && v.x1 < x2 - EDGE_INSET && crossCount(v) >= 2);
21679
21714
  if (!hasInterior) continue;
21680
21715
  for (const edgeX of [x1, x2]) {
21681
- const closed = verticals.some((v) => Math.abs(v.x1 - edgeX) <= EDGE_NEAR && v.y1 <= yMax + EDGE_CONNECT_TOL && v.y2 >= yMin - EDGE_CONNECT_TOL);
21682
- if (!closed) {
21716
+ const closed2 = verticals.some((v) => Math.abs(v.x1 - edgeX) <= EDGE_NEAR && v.y1 <= yMax + EDGE_CONNECT_TOL && v.y2 >= yMin - EDGE_CONNECT_TOL);
21717
+ if (!closed2) {
21683
21718
  synthesized.push({ x1: edgeX, y1: yMin, x2: edgeX, y2: yMax, lineWidth: 0.5 });
21684
21719
  }
21685
21720
  }
21686
21721
  }
21687
21722
  return synthesized.length ? [...verticals, ...synthesized] : verticals;
21688
21723
  }
21689
- function mergeParallelLines(lines, dir) {
21724
+ function mergeParallelLines(lines, dir, nonRules) {
21690
21725
  if (lines.length <= 1) return lines;
21691
21726
  const sorted = [...lines].sort((a, b) => {
21692
21727
  const posA = dir === "h" ? a.y1 : a.x1;
@@ -21709,6 +21744,7 @@ function mergeParallelLines(lines, dir) {
21709
21744
  const overlap2 = Math.min(prevEnd, currEnd) - Math.max(prevStart, currStart);
21710
21745
  const minLen = Math.min(prevEnd - prevStart, currEnd - currStart);
21711
21746
  if (overlap2 > minLen * 0.3) {
21747
+ if ((nonRules == null ? void 0 : nonRules.has(prev)) && !nonRules.has(curr)) nonRules.delete(prev);
21712
21748
  if (dir === "h") {
21713
21749
  prev.x1 = Math.min(prev.x1, curr.x1);
21714
21750
  prev.x2 = Math.max(prev.x2, curr.x2);
@@ -23252,7 +23288,7 @@ function isTableOfContents(table3) {
23252
23288
  const texts = row.map((cell2) => cell2.text.trim());
23253
23289
  const last = texts[texts.length - 1];
23254
23290
  if (!last) continue;
23255
- if (!PAGE_LABEL.test(last)) return false;
23291
+ if (!PAGE_LABEL2.test(last)) return false;
23256
23292
  if (/\p{L}/u.test(texts.slice(0, -1).join(""))) entries++;
23257
23293
  labels.push(last);
23258
23294
  }
@@ -23332,19 +23368,21 @@ function isExamLayoutTable(table3) {
23332
23368
  const layout2 = texts.filter((text2) => /\$|[①-⑤]|문\d+)/.test(text2) || !/[\p{L}\p{N}]/u.test(text2)).length;
23333
23369
  return layout2 >= texts.length * 0.6;
23334
23370
  }
23335
- var TOC_BLOCKS, PAGE_LABEL, NUMERIC_CELL;
23371
+ var TOC_BLOCKS, PAGE_LABEL2, NUMERIC_CELL;
23336
23372
  var init_table_roles = __esm({
23337
23373
  ".kordoc-source/src/pdf/table-roles.ts"() {
23338
23374
  "use strict";
23339
23375
  init_cjs_shims();
23340
23376
  TOC_BLOCKS = /* @__PURE__ */ new WeakSet();
23341
- PAGE_LABEL = /^(?:\d{1,4}|[ivxlc]{1,7})$/i;
23377
+ PAGE_LABEL2 = /^(?:\d{1,4}|[ivxlc]{1,7})$/i;
23342
23378
  NUMERIC_CELL = /^[\s\d.,%()+\-–−$€£¥]*\d[\s\d.,%()+\-–−$€£¥]*$/;
23343
23379
  }
23344
23380
  });
23345
23381
 
23346
23382
  // .kordoc-source/src/pdf/cluster-detector.ts
23347
23383
  function detectClusterTables(items, pageNum, rejected) {
23384
+ const tab = sideTabGlyphs(items);
23385
+ if (tab.size) items = items.filter((i) => !tab.has(i));
23348
23386
  if (items.length < MIN_ROWS * MIN_COLS) return [];
23349
23387
  const { merged, originMap } = mergeEvenSpacedClusters(items);
23350
23388
  const rows = mergeOverlappingRows(groupByBaseline(merged));
@@ -23404,6 +23442,71 @@ function detectClusterTables(items, pageNum, rejected) {
23404
23442
  return !prose;
23405
23443
  });
23406
23444
  }
23445
+ function sideTabGlyphs(items) {
23446
+ var _a2;
23447
+ const found = /* @__PURE__ */ new Set();
23448
+ const singles = items.filter((i) => i.fontSize > 0 && [...i.text.trim()].length === 1);
23449
+ if (singles.length < SIDE_TAB_MIN) return found;
23450
+ const cols = [];
23451
+ for (const it of [...singles].sort((a, b) => a.x - b.x)) {
23452
+ const c = cols.find((col) => Math.abs(col[0].x - it.x) <= Math.max(1.5, it.fontSize * 0.25));
23453
+ if (c) c.push(it);
23454
+ else cols.push([it]);
23455
+ }
23456
+ const cands = [];
23457
+ for (const col of cols) {
23458
+ if (col.length < 2) continue;
23459
+ if (col.filter((g4) => /[\p{L}\p{N}]/u.test(g4.text)).length < col.length * 0.8) continue;
23460
+ col.sort((a, b) => b.y - a.y);
23461
+ const fs = [...col.map((i) => i.fontSize)].sort((a, b) => a - b)[col.length >> 1];
23462
+ if (col.slice(1).some((it, k) => col[k].y - it.y > fs * 3)) continue;
23463
+ cands.push({ col, fs });
23464
+ }
23465
+ const bands = [];
23466
+ for (const c of cands.sort((a, b) => a.col[0].x - b.col[0].x)) {
23467
+ const last = bands[bands.length - 1];
23468
+ if (last) {
23469
+ const lastRight = Math.max(...last.col.map((i) => i.x + i.w));
23470
+ const gap = Math.min(...c.col.map((i) => i.x)) - lastRight;
23471
+ const lTop = Math.max(...last.col.map((i) => i.y)), lBot = Math.min(...last.col.map((i) => i.y));
23472
+ const cTop = c.col[0].y, cBot = c.col[c.col.length - 1].y;
23473
+ if (gap <= Math.max(last.fs, c.fs) * 1.5 && Math.min(lTop, cTop) >= Math.max(lBot, cBot)) {
23474
+ last.col.push(...c.col);
23475
+ last.fs = Math.max(last.fs, c.fs);
23476
+ last.anchored || (last.anchored = c.col.length >= SIDE_TAB_MIN);
23477
+ continue;
23478
+ }
23479
+ }
23480
+ bands.push({ col: [...c.col], fs: c.fs, anchored: c.col.length >= SIDE_TAB_MIN });
23481
+ }
23482
+ for (const { col, fs, anchored } of bands) {
23483
+ if (!anchored) continue;
23484
+ col.sort((a, b) => b.y - a.y);
23485
+ const members = new Set(col);
23486
+ const top = col[0].y + fs, bottom = col[col.length - 1].y - fs;
23487
+ const others = items.filter((i) => !members.has(i) && i.text.trim() && i.y <= top && i.y >= bottom);
23488
+ if (!others.length) continue;
23489
+ const left = Math.min(...col.map((i) => i.x)), right = Math.max(...col.map((i) => i.x + i.w));
23490
+ const rest = items.filter((i) => !members.has(i) && i.text.trim());
23491
+ const cap = (i) => i.y > top && i.y - top <= fs * 3 && i.w <= fs * 3 && i.fontSize <= fs * 3 && [...i.text.trim()].length <= 3 && Math.abs(i.x + i.w / 2 - (left + right) / 2) <= fs * 0.5;
23492
+ const bodyRest = rest.filter((i) => !cap(i));
23493
+ const outside = bodyRest.every((i) => i.x >= right + fs) || bodyRest.every((i) => i.x + i.w <= left - fs);
23494
+ if (!outside) continue;
23495
+ const alone = col.filter((g4) => !others.some((i) => Math.abs(i.y - g4.y) <= Y_TOL)).length;
23496
+ if (alone < col.length * 0.4) continue;
23497
+ const legacyOutside = rest.every((i) => i.x >= right + fs) || rest.every((i) => i.x + i.w <= left - fs);
23498
+ const head = !legacyOutside ? rest.find(cap) : void 0;
23499
+ for (const g4 of col) {
23500
+ found.add(g4);
23501
+ if (head) {
23502
+ const caps = (_a2 = SIDE_TAB_CAP_GROUPS.get(found)) != null ? _a2 : /* @__PURE__ */ new Map();
23503
+ caps.set(g4, head);
23504
+ SIDE_TAB_CAP_GROUPS.set(found, caps);
23505
+ }
23506
+ }
23507
+ }
23508
+ return found;
23509
+ }
23407
23510
  function detectCompactStatisticalTables(rows, pageNum) {
23408
23511
  const found = [];
23409
23512
  const parts = /* @__PURE__ */ new Map();
@@ -24121,7 +24224,7 @@ function joinCellItems(items) {
24121
24224
  return s;
24122
24225
  }).join(" ");
24123
24226
  }
24124
- var Y_TOL, COL_CLUSTER_TOL, MIN_ROWS, MIN_COLS, MIN_GAP_FACTOR, MIN_GAP_ABSOLUTE, MIN_COL_FILL_RATIO;
24227
+ var Y_TOL, COL_CLUSTER_TOL, MIN_ROWS, MIN_COLS, MIN_GAP_FACTOR, MIN_GAP_ABSOLUTE, MIN_COL_FILL_RATIO, SIDE_TAB_MIN, SIDE_TAB_CAP_GROUPS;
24125
24228
  var init_cluster_detector = __esm({
24126
24229
  ".kordoc-source/src/pdf/cluster-detector.ts"() {
24127
24230
  "use strict";
@@ -24136,6 +24239,8 @@ var init_cluster_detector = __esm({
24136
24239
  MIN_GAP_FACTOR = 2;
24137
24240
  MIN_GAP_ABSOLUTE = 20;
24138
24241
  MIN_COL_FILL_RATIO = 0.4;
24242
+ SIDE_TAB_MIN = 6;
24243
+ SIDE_TAB_CAP_GROUPS = /* @__PURE__ */ new WeakMap();
24139
24244
  }
24140
24245
  });
24141
24246
 
@@ -24386,7 +24491,9 @@ function findVerticalCutWithOutlierFilter(items, minGap) {
24386
24491
  const filtered = items.filter((i) => i.w >= narrowThreshold);
24387
24492
  if (filtered.length >= 2 && filtered.length < items.length && filtered.length >= items.length * 0.7) {
24388
24493
  const filteredCut = findVerticalCut(filtered);
24389
- if (filteredCut.gap > edgeCut.gap && filteredCut.gap >= minGap) {
24494
+ const sameRow = (a, b) => Math.abs(a.y - b.y) <= Math.max(a.fontSize, b.fontSize) * 0.5;
24495
+ const inLine = items.some((r) => r.w < narrowThreshold && r.x < filteredCut.position && r.x + r.w > filteredCut.position && filtered.some((o) => sameRow(o, r) && o.x + o.w <= r.x + 1) && filtered.some((o) => sameRow(o, r) && o.x >= r.x + r.w - 1));
24496
+ if (filteredCut.gap > edgeCut.gap && filteredCut.gap >= minGap && !inLine) {
24390
24497
  return filteredCut;
24391
24498
  }
24392
24499
  }
@@ -25853,8 +25960,13 @@ function detectSpecialKoreanTables(blocks) {
25853
25960
  flushKvTable();
25854
25961
  return result;
25855
25962
  }
25856
- function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables = false) {
25963
+ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables = false, context = []) {
25857
25964
  var _a2, _b, _c, _d, _e, _f, _g, _h;
25965
+ if (context.length && !tables) {
25966
+ const removed = removeHeaderFooterBlocks([...blocks, ...context], pageHeights, [], notes).filter((index) => index < blocks.length);
25967
+ if (removed.length) warnings.push({ message: `${removed.length}\uAC1C \uBA38\uB9AC\uAE00/\uBC14\uB2E5\uAE00 \uC694\uC18C \uC81C\uAC70\uB428`, code: "HIDDEN_TEXT_FILTERED" });
25968
+ return removed;
25969
+ }
25858
25970
  const ZONE_RATIO = 0.12;
25859
25971
  const MIN_REPEAT2 = 3;
25860
25972
  const topEntries = [];
@@ -25950,13 +26062,44 @@ var init_block_detect = __esm({
25950
26062
  });
25951
26063
 
25952
26064
  // .kordoc-source/src/pdf/underline.ts
25953
- function markUnderlineItems(items, horizontals, verticals) {
26065
+ function markUnderlineItems(items, horizontals, verticals, nonRules) {
25954
26066
  const underlines = [];
26067
+ if (nonRules == null ? void 0 : nonRules.size) horizontals = horizontals.filter((line) => !nonRules.has(line));
25955
26068
  if (items.length === 0 || horizontals.length === 0) return underlines;
26069
+ const tightOwners = /* @__PURE__ */ new Map();
26070
+ const tightlyOwned = (line) => {
26071
+ const cached = tightOwners.get(line);
26072
+ if (cached !== void 0) return cached;
26073
+ const owners = items.filter((item) => {
26074
+ const below = item.y - line.y1;
26075
+ return item.w > 0 && item.text.trim() && below >= 0.5 && below <= 3 && Math.min(line.x2, item.x + item.w) > Math.max(line.x1, item.x);
26076
+ }).sort((a, b) => a.x - b.x);
26077
+ let owned = owners.length > 0 && (Math.abs(owners[0].x - line.x1) <= UNDER_GRID_EPS || owners.length === 1 && line.x1 > owners[0].x && line.x1 - owners[0].x <= Math.max(owners[0].h, owners[0].fontSize, 1) * 3) && Math.abs(owners[owners.length - 1].x + owners[owners.length - 1].w - line.x2) <= UNDER_GRID_EPS;
26078
+ for (let i = 1; owned && i < owners.length; i++) {
26079
+ const em = Math.max(owners[i].h, owners[i].fontSize, 1);
26080
+ if (owners[i].x - (owners[i - 1].x + owners[i - 1].w) > em * UNDER_COLUMN_GAP_EM) owned = false;
26081
+ }
26082
+ tightOwners.set(line, owned);
26083
+ return owned;
26084
+ };
26085
+ const paragraphUnderline = (line) => {
26086
+ if (!tightlyOwned(line)) return false;
26087
+ const width = line.x2 - line.x1;
26088
+ const ys = [];
26089
+ for (const other of horizontals) {
26090
+ const overlap2 = Math.min(line.x2, other.x2) - Math.max(line.x1, other.x1);
26091
+ if (other.lineWidth > UNDER_MAX_THICKNESS || overlap2 / Math.max(width, other.x2 - other.x1) < UNDER_SPAN_OVERLAP_RATIO || !tightlyOwned(other)) continue;
26092
+ if (!ys.some((y) => Math.abs(y - other.y1) < UNDER_GRID_EPS)) ys.push(other.y1);
26093
+ if (ys.length >= UNDER_REPEATED_SPAN_LEVELS) return true;
26094
+ }
26095
+ return false;
26096
+ };
25956
26097
  for (const line of horizontals) {
25957
26098
  if (line.lineWidth > UNDER_MAX_THICKNESS) continue;
25958
26099
  const enclosed = insideTallCell(line, verticals, 0);
25959
- if (!enclosed && (touchesVertical(line, verticals) || isRepeatedSpanRule(line, horizontals))) continue;
26100
+ const repeated = isRepeatedSpanRule(line, horizontals);
26101
+ const textSeries = repeated && paragraphUnderline(line);
26102
+ if (!enclosed && (touchesVertical(line, verticals) || repeated && !textSeries)) continue;
25960
26103
  const matches = [];
25961
26104
  for (const item of items) {
25962
26105
  const h = item.h > 0 ? item.h : item.fontSize;
@@ -25976,11 +26119,11 @@ function markUnderlineItems(items, horizontals, verticals) {
25976
26119
  covered += m.w;
25977
26120
  }
25978
26121
  const inset = enclosed && insideTallCell(line, verticals, maxH);
25979
- if (enclosed && !inset && (touchesVertical(line, verticals) || isRepeatedSpanRule(line, horizontals))) continue;
26122
+ if (enclosed && !inset && (touchesVertical(line, verticals) || repeated && !textSeries)) continue;
25980
26123
  const pad = Math.max(maxH * UNDER_OWNER_PAD_EM, UNDER_OWNER_PAD_MIN_PT);
25981
26124
  if (line.x1 < x1 - pad || line.x2 > x2 + pad) continue;
25982
26125
  if (covered < (line.x2 - line.x1) * UNDER_MIN_COVERAGE) continue;
25983
- if (hasBoxTopPair(line, maxH, horizontals, inset ? items : void 0)) continue;
26126
+ if (hasBoxTopPair(line, maxH, horizontals, inset || textSeries || tightlyOwned(line) ? items : void 0)) continue;
25984
26127
  matches.sort((a, b) => a.x - b.x);
25985
26128
  let hole = false;
25986
26129
  for (let i = 1; i < matches.length; i++) {
@@ -26011,6 +26154,7 @@ function touchesVertical(line, verticals) {
26011
26154
  for (const v of verticals) {
26012
26155
  if (v.x1 < line.x1 - UNDER_GRID_EPS || v.x1 > line.x2 + UNDER_GRID_EPS) continue;
26013
26156
  const lo = Math.min(v.y1, v.y2), hi = Math.max(v.y1, v.y2);
26157
+ if (hi - lo <= UNDER_GRID_EPS) continue;
26014
26158
  if (lo <= line.y1 + UNDER_GRID_EPS && hi >= line.y1 - UNDER_GRID_EPS) return true;
26015
26159
  }
26016
26160
  return false;
@@ -26138,12 +26282,13 @@ function recordRowRules(table3, cells, bbox, hs) {
26138
26282
  }
26139
26283
  ROW_RULES.set(table3, { top: edge(bbox.y2, (c) => c.bbox.y2), bottom: edge(bbox.y1, (c) => c.bbox.y1), innerRuled, innerOpen });
26140
26284
  }
26141
- var CLIP_TABLES, TABLE_COLXS, TABLE_ROWYS, TABLE_TAIL, PART_COLXS, EMPTY_PARTS, IMAGE_CELLS, FILLER_CELLS, CONT_PARTS, CELL_LINES, ROW_RULES;
26285
+ var CLIP_TABLES, FRAME_TITLE_BLOCKS, TABLE_COLXS, TABLE_ROWYS, TABLE_TAIL, PART_COLXS, EMPTY_PARTS, IMAGE_CELLS, FILLER_CELLS, CONT_PARTS, CELL_LINES, ROW_RULES;
26142
26286
  var init_table_meta = __esm({
26143
26287
  ".kordoc-source/src/pdf/table-meta.ts"() {
26144
26288
  "use strict";
26145
26289
  init_cjs_shims();
26146
26290
  CLIP_TABLES = /* @__PURE__ */ new WeakSet();
26291
+ FRAME_TITLE_BLOCKS = /* @__PURE__ */ new WeakMap();
26147
26292
  TABLE_COLXS = /* @__PURE__ */ new WeakMap();
26148
26293
  TABLE_ROWYS = /* @__PURE__ */ new WeakMap();
26149
26294
  TABLE_TAIL = /* @__PURE__ */ new WeakMap();
@@ -26405,6 +26550,64 @@ var init_page_frame = __esm({
26405
26550
  }
26406
26551
  });
26407
26552
 
26553
+ // .kordoc-source/src/pdf/shaded-open-table.ts
26554
+ function closeShadedTableEdges(clipGrids, horizontals, verticals, fillRects) {
26555
+ var _a2;
26556
+ const near2 = (a, b) => Math.abs(a - b) <= 1.5;
26557
+ let hs = horizontals, vs = verticals;
26558
+ const restored = [];
26559
+ for (const grid of clipGrids) {
26560
+ if (grid.clipParent || grid.rowYs.length !== 2 || grid.colXs.length < 3 || !((_a2 = grid.cells) == null ? void 0 : _a2.length) || grid.cells.some((c) => c.filler || c.rowSpan !== 1 || c.colSpan !== 1)) continue;
26561
+ const { x1, x2, y1: mid, y2: top } = grid.bbox;
26562
+ if (!grid.cells.every((c) => fillRects.some((f) => near2(f.x1, c.bbox.x1) && near2(f.x2, c.bbox.x2) && near2(f.y1, c.bbox.y1) && near2(f.y2, c.bbox.y2)))) continue;
26563
+ const topRule = hs.find((h) => near2(h.y1, top) && near2(h.x1, x1) && near2(h.x2, x2));
26564
+ if (!topRule) continue;
26565
+ const dividers = grid.colXs.slice(1, -1).map((x) => vs.find((v) => near2(v.x1, x) && near2(v.y2, top) && v.y1 <= mid - 6));
26566
+ if (dividers.some((v) => !v)) continue;
26567
+ const bottom = dividers[0].y1;
26568
+ if (!dividers.every((v) => near2(v.y1, bottom))) continue;
26569
+ const bottomRule = hs.find((h) => near2(h.y1, bottom) && near2(h.x1, x1) && near2(h.x2, x2));
26570
+ if (!bottomRule) continue;
26571
+ const missing = [x1, x2].filter((x) => !vs.some((v) => near2(v.x1, x) && v.y1 <= bottom + 1.5 && v.y2 >= top - 1.5));
26572
+ if (!missing.length) continue;
26573
+ restored.push({ x1, x2, y1: bottom, y2: top });
26574
+ vs = vs.concat(missing.map((x) => ({ x1: x, x2: x, y1: bottom, y2: top, lineWidth: topRule.lineWidth })));
26575
+ if (!hs.some((h) => near2(h.y1, mid) && near2(h.x1, x1) && near2(h.x2, x2))) {
26576
+ hs = hs.concat({ x1, x2, y1: mid, y2: mid, lineWidth: topRule.lineWidth });
26577
+ }
26578
+ }
26579
+ return { horizontals: hs, verticals: vs, restored };
26580
+ }
26581
+ function nestRestoredShadedGrids(grids, restored, horizontals, verticals) {
26582
+ const near2 = (a, b) => Math.abs(a - b) <= 1.5;
26583
+ if (restored.length === 0) return;
26584
+ const nested = /* @__PURE__ */ new Set();
26585
+ for (const grid of grids) {
26586
+ const b = grid.bbox;
26587
+ if (!restored.some((r) => near2(r.x1, b.x1) && near2(r.x2, b.x2) && near2(r.y1, b.y1) && near2(r.y2, b.y2))) continue;
26588
+ if (grids.some((g4) => g4 !== grid && b.x1 - g4.bbox.x1 >= 0.8 && g4.bbox.x2 - b.x2 >= 0.8 && b.y1 - g4.bbox.y1 >= 0.8 && g4.bbox.y2 - b.y2 >= 0.8)) {
26589
+ grid.lineNested = true;
26590
+ nested.add(grid);
26591
+ }
26592
+ }
26593
+ for (const frame of grids) {
26594
+ const b = frame.bbox;
26595
+ if (frame.lineNested || ![...nested].some((g4) => g4.bbox.x1 > b.x1 && g4.bbox.x2 < b.x2 && g4.bbox.y1 > b.y1 && g4.bbox.y2 < b.y2)) continue;
26596
+ const fullH = horizontals.filter((h) => near2(h.x1, b.x1) && near2(h.x2, b.x2) && h.y1 >= b.y1 - 1.5 && h.y1 <= b.y2 + 1.5);
26597
+ if (!fullH.some((h) => near2(h.y1, b.y1)) || !fullH.some((h) => near2(h.y1, b.y2)) || fullH.some((h) => h.y1 > b.y1 + 1.5 && h.y1 < b.y2 - 1.5)) continue;
26598
+ const fullV = verticals.filter((v) => v.y1 <= b.y1 + 1.5 && v.y2 >= b.y2 - 1.5 && v.x1 >= b.x1 - 1.5 && v.x1 <= b.x2 + 1.5);
26599
+ if (!fullV.some((v) => near2(v.x1, b.x1)) || !fullV.some((v) => near2(v.x1, b.x2)) || fullV.some((v) => v.x1 > b.x1 + 1.5 && v.x1 < b.x2 - 1.5)) continue;
26600
+ frame.colXs = [b.x1, b.x2];
26601
+ frame.rowYs = [b.y2, b.y1];
26602
+ }
26603
+ }
26604
+ var init_shaded_open_table = __esm({
26605
+ ".kordoc-source/src/pdf/shaded-open-table.ts"() {
26606
+ "use strict";
26607
+ init_cjs_shims();
26608
+ }
26609
+ });
26610
+
26408
26611
  // .kordoc-source/src/pdf/open-table-ends.ts
26409
26612
  function chainVerticals2(verticals) {
26410
26613
  const sorted = [...verticals].sort((a, b) => a.x1 - b.x1 || a.y1 - b.y1);
@@ -26777,6 +26980,628 @@ var init_text_box_table = __esm({
26777
26980
  }
26778
26981
  });
26779
26982
 
26983
+ // .kordoc-source/src/pdf/frame-cell-blocks.ts
26984
+ function recordFrameReadingUnit(blocks, bbox) {
26985
+ for (const block2 of blocks) FRAME_SOURCE_BOUNDS.set(block2, bbox);
26986
+ if (blocks.length < 2) return;
26987
+ const unit = { blocks, bbox };
26988
+ for (const block2 of blocks) FRAME_READING_UNITS.set(block2, unit);
26989
+ }
26990
+ function frameLayoutBoxes(blocks) {
26991
+ const boxes = [], seen2 = /* @__PURE__ */ new Set();
26992
+ for (const block2 of blocks) {
26993
+ const frame = FRAME_SOURCE_BOUNDS.get(block2);
26994
+ if (frame) {
26995
+ if (!seen2.has(frame)) {
26996
+ boxes.push(frame);
26997
+ seen2.add(frame);
26998
+ }
26999
+ } else if (block2.bbox) boxes.push(block2.bbox);
27000
+ }
27001
+ return boxes;
27002
+ }
27003
+ function takeFrameSpanningText(items, cutX, pageNum, lex) {
27004
+ let minX = Infinity, maxR = -Infinity;
27005
+ for (const item of items) {
27006
+ minX = Math.min(minX, item.x);
27007
+ maxR = Math.max(maxR, item.x + item.w);
27008
+ }
27009
+ const span2 = maxR - minX;
27010
+ const rows = groupByY([...items].sort((a, b) => b.y - a.y || a.x - b.x)).map((line) => {
27011
+ const runs = [];
27012
+ for (const item of [...line].sort((a, b) => a.x - b.x)) {
27013
+ const run = runs[runs.length - 1], prev = run == null ? void 0 : run[run.length - 1];
27014
+ if (prev && item.x - (prev.x + prev.w) <= Math.max(prev.fontSize, item.fontSize) * 0.6) run.push(item);
27015
+ else runs.push([item]);
27016
+ }
27017
+ return runs;
27018
+ });
27019
+ const taken = /* @__PURE__ */ new Set(), blocks = [];
27020
+ for (let r = 0; r < rows.length; r++) for (const run of rows[r]) {
27021
+ if (taken.has(run[0]) || run[0].x >= cutX || Math.max(...run.map((i) => i.x + i.w)) <= cutX) continue;
27022
+ const lines = [run], fs = Math.max(...run.map((i) => i.fontSize));
27023
+ const left = run[0].x, right = Math.max(...run.map((i) => i.x + i.w));
27024
+ if (right - left < span2 * 0.75) continue;
27025
+ let prevY = run[0].y;
27026
+ for (let next = r + 1; next < rows.length && rows[next].length === 1; next++) {
27027
+ const tail = rows[next][0], y = tail[0].y;
27028
+ if (taken.has(tail[0]) || prevY - y > fs * 1.8 || tail[0].x < left - 1 || tail[0].x > left + fs * 2 || tail.some((i) => Math.abs(i.fontSize - fs) > fs * 0.15) || Math.max(...tail.map((i) => i.x + i.w)) > right + 1) break;
27029
+ lines.push(tail);
27030
+ prevY = y;
27031
+ }
27032
+ for (const line of lines) for (const item of line) taken.add(item);
27033
+ pushLineParagraphs(blocks, mergeSuperscriptLines(lines), pageNum, lex);
27034
+ }
27035
+ let keep = 0;
27036
+ for (const item of items) if (!taken.has(item)) items[keep++] = item;
27037
+ items.length = keep;
27038
+ return blocks;
27039
+ }
27040
+ function frameColumnTextBands(items, spanning, cutX) {
27041
+ var _a2;
27042
+ const tops = spanning.filter((b) => b.bbox).map((b) => b.bbox.y + b.bbox.height).sort((a, b) => b - a);
27043
+ const bands = /* @__PURE__ */ new Map();
27044
+ for (const item of items) {
27045
+ let band = 0;
27046
+ while (band < tops.length && tops[band] > item.y + item.h) band++;
27047
+ const sides = (_a2 = bands.get(band)) != null ? _a2 : [[], [], []];
27048
+ sides[item.x + item.w <= cutX ? 0 : item.x >= cutX ? 2 : 1].push(item);
27049
+ bands.set(band, sides);
27050
+ }
27051
+ return [...bands].sort((a, b) => a[0] - b[0]).flatMap(([, sides]) => sides.filter((side) => side.length));
27052
+ }
27053
+ function groupFrameParagraphUnits(units, frames) {
27054
+ var _a2;
27055
+ const source = /* @__PURE__ */ new Map();
27056
+ for (const unit of units) for (const block2 of unit) source.set(block2, unit);
27057
+ const members = /* @__PURE__ */ new Map(), emitted = /* @__PURE__ */ new Set();
27058
+ for (const frame of frames) {
27059
+ if (frame.length < 2 || frame.some((block2) => {
27060
+ var _a3;
27061
+ return block2.type !== "paragraph" || ((_a3 = source.get(block2)) == null ? void 0 : _a3.length) !== 1;
27062
+ })) continue;
27063
+ for (const block2 of frame) members.set(block2, frame);
27064
+ }
27065
+ const out = [];
27066
+ for (const unit of units) {
27067
+ const frame = unit.length === 1 ? members.get(unit[0]) : void 0;
27068
+ if (!frame) out.push(unit);
27069
+ else if (!emitted.has(frame)) {
27070
+ out.push(frame);
27071
+ emitted.add(frame);
27072
+ }
27073
+ }
27074
+ for (const unit of out) {
27075
+ if (unit.length < 2 || ((_a2 = FRAME_READING_UNITS.get(unit[0])) == null ? void 0 : _a2.blocks) === unit) continue;
27076
+ const bs = unit.map((b) => b.bbox).filter((b) => !!b);
27077
+ if (bs.length !== unit.length) continue;
27078
+ const x = Math.min(...bs.map((b) => b.x)), y = Math.min(...bs.map((b) => b.y));
27079
+ recordFrameReadingUnit(unit, {
27080
+ page: bs[0].page,
27081
+ x,
27082
+ y,
27083
+ width: Math.max(...bs.map((b) => b.x + b.width)) - x,
27084
+ height: Math.max(...bs.map((b) => b.y + b.height)) - y
27085
+ });
27086
+ }
27087
+ return out;
27088
+ }
27089
+ function recordFrameTitle(table3, source, pageNum) {
27090
+ var _a2;
27091
+ if (!CLIP_TABLES.has(table3) || table3.rows !== 1 || table3.cols !== 3 || source.length < 2) return;
27092
+ const cells = table3.cells[0];
27093
+ if (cells.length !== 3 || cells.some((c) => {
27094
+ var _a3;
27095
+ return c.colSpan !== 1 || c.rowSpan !== 1 || ((_a3 = c.blocks) == null ? void 0 : _a3.length) || c.text.includes("\n");
27096
+ })) return;
27097
+ const [label, spacer, title] = cells;
27098
+ if (!/^(?:붙임|별첨|첨부|부록)\s*\d{1,3}$/.test(label.text.trim()) || spacer.text.trim() || !title.text.trim()) return;
27099
+ if (cells.some((c) => {
27100
+ const e = CELL_EDGES.get(c);
27101
+ return !e || e.t || e.b || e.l || e.r;
27102
+ })) return;
27103
+ const xs = TABLE_COLXS.get(table3), style = dominantStyle(source), fs = (_a2 = style == null ? void 0 : style.fontSize) != null ? _a2 : 0;
27104
+ if (!xs || xs.length !== 4 || fs <= 0) return;
27105
+ const width = xs[3] - xs[0], gap = xs[2] - xs[1];
27106
+ if (width < fs * 12 || gap <= 0 || gap > fs * 1.5 || xs[1] - xs[0] > width * 0.25 || xs[3] - xs[2] < width * 0.6) return;
27107
+ if (source.some((i) => i.fontName !== source[0].fontName || Math.abs(i.fontSize - fs) > fs * 0.15)) return;
27108
+ if (groupByY([...source].sort((a, b) => b.y - a.y)).length !== 1) return;
27109
+ FRAME_TITLE_BLOCKS.set(table3, {
27110
+ type: "paragraph",
27111
+ text: `${label.text.trim()} ${title.text.trim()}`,
27112
+ pageNumber: pageNum,
27113
+ bbox: computeBBox(source, pageNum),
27114
+ style
27115
+ });
27116
+ }
27117
+ function takePendingNested(pending, cellBox, clipCell) {
27118
+ const out = [];
27119
+ for (let i = pending.length - 1; i >= 0; i--) {
27120
+ const p = pending[i].parent;
27121
+ if (pending[i].contained ? p.x1 >= cellBox.x1 - FRAME_RECT_TOL && p.x2 <= cellBox.x2 + FRAME_RECT_TOL && p.y1 >= cellBox.y1 - FRAME_RECT_TOL && p.y2 <= cellBox.y2 + FRAME_RECT_TOL : clipCell && Math.abs(p.x1 - cellBox.x1) <= FRAME_RECT_TOL && Math.abs(p.x2 - cellBox.x2) <= FRAME_RECT_TOL && Math.abs(p.y1 - cellBox.y1) <= FRAME_RECT_TOL && Math.abs(p.y2 - cellBox.y2) <= FRAME_RECT_TOL) {
27122
+ out.push(pending[i].block);
27123
+ pending.splice(i, 1);
27124
+ }
27125
+ }
27126
+ return out;
27127
+ }
27128
+ function buildFrameCellBlocks(cellItems, nested, pageNum, lex) {
27129
+ const tables = [...nested].sort((a, b) => b.bbox.y + b.bbox.height - (a.bbox.y + a.bbox.height));
27130
+ const blocks = [];
27131
+ let rest = [...cellItems];
27132
+ const pushParagraphs2 = (items) => {
27133
+ var _a2;
27134
+ if (items.length === 0) return;
27135
+ const source = items.map((it) => ({ ...it, isHidden: false })).sort((a, b) => b.y - a.y || a.x - b.x);
27136
+ const paragraphs = [];
27137
+ pushLineParagraphs(paragraphs, mergeSuperscriptLines(groupByY(source)), pageNum, lex);
27138
+ for (const block2 of paragraphs) {
27139
+ block2.text = cleanCellText((_a2 = block2.text) != null ? _a2 : "");
27140
+ if (block2.text) blocks.push(block2);
27141
+ }
27142
+ };
27143
+ for (const tb of tables) {
27144
+ const bottom = tb.bbox.y;
27145
+ pushParagraphs2(rest.filter((it) => it.y >= bottom));
27146
+ rest = rest.filter((it) => it.y < bottom);
27147
+ blocks.push(tb);
27148
+ }
27149
+ pushParagraphs2(rest);
27150
+ const text2 = blocks.map((b) => {
27151
+ var _a2;
27152
+ return b.type === "table" && b.table ? b.table.cells.flat().map((c) => c.text).filter(Boolean).join("\n") : (_a2 = b.text) != null ? _a2 : "";
27153
+ }).filter(Boolean).join("\n");
27154
+ return { blocks, text: text2 };
27155
+ }
27156
+ var FRAME_READING_UNITS, FRAME_SOURCE_BOUNDS, FRAME_RECT_TOL;
27157
+ var init_frame_cell_blocks = __esm({
27158
+ ".kordoc-source/src/pdf/frame-cell-blocks.ts"() {
27159
+ "use strict";
27160
+ init_cjs_shims();
27161
+ init_text_line();
27162
+ init_paragraph_lines();
27163
+ init_cell_text();
27164
+ init_layout_frames();
27165
+ init_table_meta();
27166
+ FRAME_READING_UNITS = /* @__PURE__ */ new WeakMap();
27167
+ FRAME_SOURCE_BOUNDS = /* @__PURE__ */ new WeakMap();
27168
+ FRAME_RECT_TOL = 1.5;
27169
+ }
27170
+ });
27171
+
27172
+ // .kordoc-source/src/pdf/image-bullets.ts
27173
+ function hollowCircle(image2) {
27174
+ if (!(image2 == null ? void 0 : image2.data) || image2.width < 16 || image2.width > 128 || image2.height < 16 || image2.height > 128 || Math.abs(image2.width - image2.height) > Math.min(image2.width, image2.height) * 0.1) return false;
27175
+ const stride = image2.kind === import_pdf5.ImageKind.RGB_24BPP ? 3 : image2.kind === import_pdf5.ImageKind.RGBA_32BPP ? 4 : 0;
27176
+ const { width, height, data } = image2;
27177
+ if (!stride || data.length < width * height * stride) return false;
27178
+ const dark = [];
27179
+ let white = 0;
27180
+ for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) {
27181
+ const i = (y * width + x) * stride;
27182
+ if (stride === 4 && data[i + 3] < 240) return false;
27183
+ const min = Math.min(data[i], data[i + 1], data[i + 2]), max = Math.max(data[i], data[i + 1], data[i + 2]);
27184
+ if (max - min > 15) return false;
27185
+ if (min >= 235) white++;
27186
+ if (max < 180) dark.push({ x, y });
27187
+ }
27188
+ if (white < width * height * 0.65 || dark.length < width * height * 0.025 || dark.length > width * height * 0.3) return false;
27189
+ const x0 = Math.min(...dark.map((p) => p.x)), x1 = Math.max(...dark.map((p) => p.x));
27190
+ const y0 = Math.min(...dark.map((p) => p.y)), y1 = Math.max(...dark.map((p) => p.y));
27191
+ const w = x1 - x0 + 1, h = y1 - y0 + 1, radius = (w + h) / 4;
27192
+ const cx = (x0 + x1) / 2, cy = (y0 + y1) / 2;
27193
+ if (Math.abs(w - h) > Math.min(w, h) * 0.15 || w < width * 0.4 || w > width * 0.85 || h < height * 0.4 || h > height * 0.85 || x0 < width * 0.04 || y0 < height * 0.04 || x1 >= width * 0.96 || y1 >= height * 0.96 || Math.abs(cx - width / 2) > width * 0.15 || Math.abs(cy - height / 2) > height * 0.15) return false;
27194
+ const sectors = /* @__PURE__ */ new Set();
27195
+ for (const point of dark) {
27196
+ const r = Math.hypot(point.x - cx, point.y - cy) / radius;
27197
+ if (r < 0.65 || r > 1.15) return false;
27198
+ sectors.add(Math.floor((Math.atan2(point.y - cy, point.x - cx) + Math.PI) / (Math.PI * 2) * 8) % 8);
27199
+ }
27200
+ return sectors.size === 8;
27201
+ }
27202
+ async function resolveImagePixels(page, id) {
27203
+ const objects = id.startsWith("g_") ? page.commonObjs : page.objs;
27204
+ return new Promise((resolve) => {
27205
+ const timer = setTimeout(() => resolve(null), 5e3);
27206
+ try {
27207
+ objects.get(id, (value) => {
27208
+ clearTimeout(timer);
27209
+ resolve(value != null ? value : null);
27210
+ });
27211
+ } catch {
27212
+ clearTimeout(timer);
27213
+ resolve(null);
27214
+ }
27215
+ });
27216
+ }
27217
+ function smallVisibleImagePaints(fnArray, argsArray) {
27218
+ var _a2, _b, _c, _d, _e;
27219
+ const paints = [];
27220
+ let ctm = [1, 0, 0, 1, 0, 0];
27221
+ let alpha = 1, clip = null, unknownClip = false;
27222
+ const stack = [];
27223
+ let pathRect, pendingClip = false;
27224
+ const intersectClip = (box) => {
27225
+ clip = clip ? {
27226
+ x1: Math.max(clip.x1, box.x1),
27227
+ y1: Math.max(clip.y1, box.y1),
27228
+ x2: Math.min(clip.x2, box.x2),
27229
+ y2: Math.min(clip.y2, box.y2)
27230
+ } : box;
27231
+ };
27232
+ const rectangle = (x, y, w, h) => extractImageRegions(
27233
+ [import_pdf5.OPS.transform, import_pdf5.OPS.transform, import_pdf5.OPS.paintImageXObject],
27234
+ [ctm, [w, 0, 0, h, x, y], ["bounds"]]
27235
+ )[0];
27236
+ for (let i = 0; i < fnArray.length; i++) {
27237
+ const op = fnArray[i], args = argsArray[i];
27238
+ if (op === import_pdf5.OPS.save || op === import_pdf5.OPS.paintFormXObjectBegin) {
27239
+ stack.push({ ctm, alpha, clip, unknownClip });
27240
+ const matrix = op === import_pdf5.OPS.paintFormXObjectBegin ? args == null ? void 0 : args[0] : void 0;
27241
+ if (Array.isArray(matrix) && matrix.length >= 6) ctm = multiply(ctm, matrix);
27242
+ const bounds = op === import_pdf5.OPS.paintFormXObjectBegin ? args == null ? void 0 : args[1] : void 0;
27243
+ if (Array.isArray(bounds) && bounds.length === 4) {
27244
+ const box = rectangle(bounds[0], bounds[1], bounds[2] - bounds[0], bounds[3] - bounds[1]);
27245
+ if (box && ctm[1] === 0 && ctm[2] === 0) intersectClip(box);
27246
+ else unknownClip = true;
27247
+ }
27248
+ } else if (op === import_pdf5.OPS.restore || op === import_pdf5.OPS.paintFormXObjectEnd) {
27249
+ const state = stack.pop();
27250
+ ctm = (_a2 = state == null ? void 0 : state.ctm) != null ? _a2 : [1, 0, 0, 1, 0, 0];
27251
+ alpha = (_b = state == null ? void 0 : state.alpha) != null ? _b : 1;
27252
+ clip = (_c = state == null ? void 0 : state.clip) != null ? _c : null;
27253
+ unknownClip = (_d = state == null ? void 0 : state.unknownClip) != null ? _d : false;
27254
+ } else if (op === import_pdf5.OPS.setGState) {
27255
+ for (const [key, value] of (_e = args == null ? void 0 : args[0]) != null ? _e : []) {
27256
+ if (key === "ca") alpha = typeof value === "number" ? value : 0;
27257
+ }
27258
+ } else if (op === import_pdf5.OPS.constructPath) {
27259
+ const [operations, coordinates] = args;
27260
+ pathRect = pathRect === void 0 && (operations == null ? void 0 : operations.length) === 1 && operations[0] === import_pdf5.OPS.rectangle && (coordinates == null ? void 0 : coordinates.length) >= 4 && ctm[1] === 0 && ctm[2] === 0 ? rectangle(coordinates[0], coordinates[1], coordinates[2], coordinates[3]) : null;
27261
+ } else if (op === import_pdf5.OPS.clip || op === import_pdf5.OPS.eoClip) pendingClip = true;
27262
+ else if ([
27263
+ import_pdf5.OPS.endPath,
27264
+ import_pdf5.OPS.stroke,
27265
+ import_pdf5.OPS.closeStroke,
27266
+ import_pdf5.OPS.fill,
27267
+ import_pdf5.OPS.eoFill,
27268
+ import_pdf5.OPS.fillStroke,
27269
+ import_pdf5.OPS.eoFillStroke,
27270
+ import_pdf5.OPS.closeFillStroke,
27271
+ import_pdf5.OPS.closeEOFillStroke
27272
+ ].includes(op)) {
27273
+ if (pendingClip) {
27274
+ if (pathRect) intersectClip(pathRect);
27275
+ else unknownClip = true;
27276
+ }
27277
+ pendingClip = false;
27278
+ pathRect = void 0;
27279
+ } else if (op === import_pdf5.OPS.transform && Array.isArray(args) && args.length >= 6) ctm = multiply(ctm, args);
27280
+ else if (op === import_pdf5.OPS.paintImageXObject && typeof (args == null ? void 0 : args[0]) === "string") {
27281
+ if (typeof args[1] !== "number" || typeof args[2] !== "number" || args[1] < 16 || args[1] > 128 || args[2] < 16 || args[2] > 128) continue;
27282
+ const box = extractImageRegions([import_pdf5.OPS.transform, import_pdf5.OPS.paintImageXObject], [ctm, args])[0];
27283
+ if (!box || ctm[1] !== 0 || ctm[2] !== 0 || alpha < 0.99 || unknownClip || clip && (box.x1 + (box.x2 - box.x1) * 0.03 < clip.x1 || box.y1 + (box.y2 - box.y1) * 0.03 < clip.y1 || box.x2 - (box.x2 - box.x1) * 0.03 > clip.x2 || box.y2 - (box.y2 - box.y1) * 0.03 > clip.y2)) continue;
27284
+ const width = box.x2 - box.x1, height = box.y2 - box.y1;
27285
+ if (width < 3 || width > 24 || height < 3 || height > 24 || width / height < 0.5 || width / height > 2) continue;
27286
+ paints.push({ id: args[0], box, mirrored: ctm[0] < 0 });
27287
+ }
27288
+ }
27289
+ return paints;
27290
+ }
27291
+ async function restoreImageBullets(items, page, fnArray, argsArray, shapes = /* @__PURE__ */ new Map()) {
27292
+ const candidates = [];
27293
+ for (const { id, box } of smallVisibleImagePaints(fnArray, argsArray)) {
27294
+ const width = box.x2 - box.x1, height = box.y2 - box.y1;
27295
+ if (Math.abs(width - height) > Math.min(width, height) * 0.1) continue;
27296
+ const line = items.filter((item) => !item.isHidden && item.fontSize > 0 && item.x >= box.x2 && item.x - box.x2 <= item.fontSize * 0.7 && Math.abs(item.y + item.h / 2 - (box.y1 + box.y2) / 2) <= item.fontSize * 0.4 && height >= item.fontSize * 0.5 && height <= item.fontSize * 1.2).sort((a, b) => a.x - b.x)[0];
27297
+ if (!line || /^[○●•◦□■∙]/.test(line.text.trim()) || !/\p{L}/u.test(line.text)) continue;
27298
+ const row = items.filter((item) => Math.abs(item.y - line.y) <= 2 && item.x >= line.x);
27299
+ if (row.reduce((n, item) => {
27300
+ var _a2, _b;
27301
+ return n + ((_b = (_a2 = item.text.match(/\p{L}/gu)) == null ? void 0 : _a2.length) != null ? _b : 0);
27302
+ }, 0) < 12 || items.some((item) => item !== line && Math.abs(item.y - line.y) <= 2 && item.x < line.x)) continue;
27303
+ candidates.push({ id, x: box.x1, width, line });
27304
+ }
27305
+ let restored = 0;
27306
+ const used = /* @__PURE__ */ new Set();
27307
+ for (const candidate of candidates) {
27308
+ const same = candidates.filter((other) => other.id === candidate.id && other.line !== candidate.line && Math.abs(other.line.x - candidate.line.x) <= 1 && Math.abs(other.x - candidate.x) <= 1 && Math.abs(other.width - candidate.width) <= 1 && other.line.fontSize === candidate.line.fontSize && Math.abs(other.line.y - candidate.line.y) >= candidate.line.fontSize * 2);
27309
+ const numbered = items.filter((item) => {
27310
+ var _a2, _b;
27311
+ return !item.isHidden && /^[①-⑮]\s*/.test(item.text.trim()) && item.fontName === candidate.line.fontName && item.fontSize === candidate.line.fontSize && Math.abs(item.x - candidate.x) <= 1 && ((_b = (_a2 = item.text.match(/\p{L}/gu)) == null ? void 0 : _a2.length) != null ? _b : 0) >= 12;
27312
+ }).sort((a, b) => b.y - a.y);
27313
+ const numberedList = numbered.some((item, index) => index > 0 && item.text.trim().charCodeAt(0) === numbered[index - 1].text.trim().charCodeAt(0) + 1);
27314
+ if (!same.length && !numberedList || used.has(candidate.line)) continue;
27315
+ if (!shapes.has(candidate.id)) shapes.set(candidate.id, hollowCircle(await resolveImagePixels(page, candidate.id)));
27316
+ if (!shapes.get(candidate.id)) continue;
27317
+ used.add(candidate.line);
27318
+ items.push({ ...candidate.line, text: "\u25CB", x: candidate.x, w: candidate.width, strike: false, underline: false, hasSpaceBefore: false, syntheticSpace: false });
27319
+ restored++;
27320
+ }
27321
+ return restored;
27322
+ }
27323
+ var import_pdf5, multiply;
27324
+ var init_image_bullets = __esm({
27325
+ ".kordoc-source/src/pdf/image-bullets.ts"() {
27326
+ "use strict";
27327
+ init_cjs_shims();
27328
+ import_pdf5 = require("pdfjs-dist/legacy/build/pdf.mjs");
27329
+ init_image_regions();
27330
+ multiply = (m, t) => [
27331
+ m[0] * t[0] + m[2] * t[1],
27332
+ m[1] * t[0] + m[3] * t[1],
27333
+ m[0] * t[2] + m[2] * t[3],
27334
+ m[1] * t[2] + m[3] * t[3],
27335
+ m[0] * t[4] + m[2] * t[5] + m[4],
27336
+ m[1] * t[4] + m[3] * t[5] + m[5]
27337
+ ];
27338
+ }
27339
+ });
27340
+
27341
+ // .kordoc-source/src/pdf/flow-boxes.ts
27342
+ function closed(grid, hs, vs) {
27343
+ const b = grid.bbox;
27344
+ return [b.y1, b.y2].every((y) => hs.some((h) => Math.abs(h.y1 - y) <= 1 && h.x1 <= b.x1 + 1 && h.x2 >= b.x2 - 1)) && [b.x1, b.x2].every((x) => vs.some((v) => Math.abs(v.x1 - x) <= 1 && v.y1 <= b.y1 + 1 && v.y2 >= b.y2 - 1));
27345
+ }
27346
+ function groupFlowBoxUnits(blocks, grids, hs, vs, images) {
27347
+ const candidates = grids.filter((g4) => g4.bbox.y2 - g4.bbox.y1 >= 30 && closed(g4, hs, vs) && !grids.some((other) => other !== g4 && contains2(other.bbox, g4.bbox, 0) && (other.bbox.x2 - other.bbox.x1) * (other.bbox.y2 - other.bbox.y1) > (g4.bbox.x2 - g4.bbox.x1) * (g4.bbox.y2 - g4.bbox.y1) + 1));
27348
+ const bands = [], visited = /* @__PURE__ */ new Set();
27349
+ for (const first of candidates) {
27350
+ if (visited.has(first)) continue;
27351
+ const row = candidates.filter((g4) => Math.abs(g4.bbox.y1 - first.bbox.y1) <= 1 && Math.abs(g4.bbox.y2 - first.bbox.y2) <= 1).sort((a, b) => a.bbox.x1 - b.bbox.x1);
27352
+ row.forEach((g4) => visited.add(g4));
27353
+ if (row.length < 4 || row.filter((g4) => g4.rowYs.length === 2 && g4.colXs.length === 2).length < 3) continue;
27354
+ const connectors = [];
27355
+ for (let i = 1; i < row.length; i++) {
27356
+ const left = row[i - 1].bbox, right = row[i].bbox, gap = right.x1 - left.x2;
27357
+ if (gap < 4 || gap > Math.min(left.x2 - left.x1, right.x2 - right.x1) * 0.6) break;
27358
+ const centerX = (left.x2 + right.x1) / 2, centerY = (left.y1 + left.y2) / 2;
27359
+ const connector = images.find((p) => {
27360
+ const w = p.x2 - p.x1, h = p.y2 - p.y1;
27361
+ return p.x1 >= left.x2 && p.x2 <= right.x1 && w >= gap * 0.4 && w <= gap * 0.9 && h >= 3 && h <= (left.y2 - left.y1) * 0.2 && w / h >= 0.8 && w / h <= 1.6 && Math.abs((p.x1 + p.x2) / 2 - centerX) <= gap * 0.15 && Math.abs((p.y1 + p.y2) / 2 - centerY) <= (left.y2 - left.y1) * 0.1;
27362
+ });
27363
+ if (!connector) break;
27364
+ connectors.push(connector);
27365
+ }
27366
+ if (connectors.length !== row.length - 1 || connectors.some((p) => Math.abs(p.x2 - p.x1 - (connectors[0].x2 - connectors[0].x1)) > (connectors[0].x2 - connectors[0].x1) * 0.2 || Math.abs(p.y2 - p.y1 - (connectors[0].y2 - connectors[0].y1)) > (connectors[0].y2 - connectors[0].y1) * 0.2)) continue;
27367
+ bands.push(row);
27368
+ }
27369
+ const members = /* @__PURE__ */ new Map();
27370
+ for (const band of bands) {
27371
+ const columns = band.map((g4) => blocks.filter((b) => b.bbox && contains2(g4.bbox, {
27372
+ x1: b.bbox.x,
27373
+ y1: b.bbox.y,
27374
+ x2: b.bbox.x + b.bbox.width,
27375
+ y2: b.bbox.y + b.bbox.height
27376
+ })).sort((a, b) => b.bbox.y + b.bbox.height - a.bbox.y - a.bbox.height || a.bbox.x - b.bbox.x));
27377
+ if (columns.some((column) => !column.length)) continue;
27378
+ const unit = columns.flat();
27379
+ for (const block2 of unit) members.set(block2, unit);
27380
+ }
27381
+ const units = [], emitted = /* @__PURE__ */ new Set();
27382
+ for (const block2 of blocks) {
27383
+ const unit = members.get(block2);
27384
+ if (!unit) units.push([block2]);
27385
+ else if (!emitted.has(unit)) {
27386
+ units.push(unit);
27387
+ emitted.add(unit);
27388
+ }
27389
+ }
27390
+ return units;
27391
+ }
27392
+ function arrowDirection(image2) {
27393
+ if (!(image2 == null ? void 0 : image2.data) || image2.width < 16 || image2.width > 128 || image2.height < 16 || image2.height > 128) return 0;
27394
+ const { width, height, data } = image2;
27395
+ const stride = image2.kind === import_pdf6.ImageKind.RGB_24BPP ? 3 : image2.kind === import_pdf6.ImageKind.RGBA_32BPP ? 4 : 0;
27396
+ if (!stride || data.length < width * height * stride) return 0;
27397
+ const ink = [];
27398
+ let white = 0;
27399
+ for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) {
27400
+ const offset = (y * width + x) * stride;
27401
+ if (stride === 4 && data[offset + 3] < 240) return 0;
27402
+ const min = Math.min(data[offset], data[offset + 1], data[offset + 2]);
27403
+ if (min >= 235) white++;
27404
+ if (min < 230) ink.push({ x, y });
27405
+ }
27406
+ if (white < width * height * 0.55 || !ink.length) return 0;
27407
+ const x0 = Math.min(...ink.map((p) => p.x)), x1 = Math.max(...ink.map((p) => p.x));
27408
+ const y0 = Math.min(...ink.map((p) => p.y)), y1 = Math.max(...ink.map((p) => p.y));
27409
+ const w = x1 - x0 + 1, h = y1 - y0 + 1, centerY = (y0 + y1) / 2;
27410
+ if (w < width * 0.5 || h < height * 0.5 || x0 < width * 0.04 || y0 < height * 0.04 || x1 >= width * 0.96 || y1 >= height * 0.96) return 0;
27411
+ const pointsRight = (mirror) => {
27412
+ const points = ink.map((p) => ({ x: mirror ? x0 + x1 - p.x : p.x, y: p.y }));
27413
+ const tail = points.filter((p) => p.x <= x0 + w * 0.25), tip = points.filter((p) => p.x >= x1 - w * 0.1);
27414
+ if (!tail.length || !tip.length) return false;
27415
+ const span2 = (points2) => Math.max(...points2.map((p) => p.y)) - Math.min(...points2.map((p) => p.y)) + 1;
27416
+ if (span2(tail) > h * 0.4 || span2(tip) > h * 0.45 || Math.abs((Math.max(...tail.map((p) => p.y)) + Math.min(...tail.map((p) => p.y))) / 2 - centerY) > h * 0.1 || Math.abs((Math.max(...tip.map((p) => p.y)) + Math.min(...tip.map((p) => p.y))) / 2 - centerY) > h * 0.1) return false;
27417
+ let head = 0;
27418
+ for (let x = Math.ceil(x0 + w * 0.45); x <= x0 + w * 0.75; x++) {
27419
+ const column = points.filter((p) => p.x === x);
27420
+ if (column.length) head = Math.max(head, span2(column));
27421
+ }
27422
+ const middle = new Set(points.filter((p) => Math.abs(p.y - centerY) <= 1).map((p) => p.x));
27423
+ return head >= h * 0.8 && middle.size >= w * 0.9;
27424
+ };
27425
+ return pointsRight(false) ? 1 : pointsRight(true) ? -1 : 0;
27426
+ }
27427
+ async function detectRightArrowRegions(page, fnArray, argsArray, directions = /* @__PURE__ */ new Map()) {
27428
+ var _a2;
27429
+ const regions = [];
27430
+ const paints = smallVisibleImagePaints(fnArray, argsArray);
27431
+ for (const paint of paints) {
27432
+ const row = paints.filter((other) => other.id === paint.id && Math.abs(other.box.y1 - paint.box.y1) <= 1 && Math.abs(other.box.y2 - paint.box.y2) <= 1 && Math.abs(other.box.x2 - other.box.x1 - (paint.box.x2 - paint.box.x1)) <= 1);
27433
+ const positions = new Set(row.map((other) => Math.round(other.box.x1)));
27434
+ if (positions.size < 3) continue;
27435
+ if (!directions.has(paint.id)) directions.set(paint.id, arrowDirection(await resolveImagePixels(page, paint.id)));
27436
+ const direction = (_a2 = directions.get(paint.id)) != null ? _a2 : 0;
27437
+ if (direction && (paint.mirrored ? -direction : direction) === 1) regions.push(paint.box);
27438
+ }
27439
+ return regions;
27440
+ }
27441
+ var import_pdf6, contains2;
27442
+ var init_flow_boxes = __esm({
27443
+ ".kordoc-source/src/pdf/flow-boxes.ts"() {
27444
+ "use strict";
27445
+ init_cjs_shims();
27446
+ import_pdf6 = require("pdfjs-dist/legacy/build/pdf.mjs");
27447
+ init_image_bullets();
27448
+ contains2 = (outer, inner, tolerance = 1) => inner.x1 >= outer.x1 - tolerance && inner.x2 <= outer.x2 + tolerance && inner.y1 >= outer.y1 - tolerance && inner.y2 <= outer.y2 + tolerance;
27449
+ }
27450
+ });
27451
+
27452
+ // .kordoc-source/src/pdf/nested-shaded-headers.ts
27453
+ function extendNestedShadedHeaders(clipGrids, lineGrids, horizontals, verticals, fills) {
27454
+ var _a2;
27455
+ const near2 = (a, b) => Math.abs(a - b) <= 1.5;
27456
+ const contains3 = (a, b) => b.x1 >= a.x1 - 1.5 && b.x2 <= a.x2 + 1.5 && b.y1 >= a.y1 - 1.5 && b.y2 <= a.y2 + 1.5;
27457
+ const extended = [];
27458
+ for (let i = 0; i < clipGrids.length; i++) {
27459
+ const c = clipGrids[i], parent = c.clipParent;
27460
+ if (!parent || c.rowYs.length !== 2 || c.colXs.length < 3 || !((_a2 = c.cells) == null ? void 0 : _a2.length) || c.cells.some((cell2) => cell2.filler || cell2.rowSpan !== 1 || cell2.colSpan !== 1)) continue;
27461
+ if (!clipGrids.some((g4) => g4.rowYs.length === 2 && g4.colXs.length === 2 && near2(g4.bbox.x1, parent.x1) && near2(g4.bbox.x2, parent.x2) && near2(g4.bbox.y1, parent.y1) && near2(g4.bbox.y2, parent.y2))) continue;
27462
+ if (!c.cells.every((cell2) => fills.some((f) => near2(f.x1, cell2.bbox.x1) && near2(f.x2, cell2.bbox.x2) && near2(f.y1, cell2.bbox.y1) && near2(f.y2, cell2.bbox.y2)))) continue;
27463
+ const host2 = lineGrids.find((l) => l.rowYs.length > 2 && l.colXs.length === c.colXs.length && c.colXs.every((x, k) => near2(x, l.colXs[k])) && c.rowYs.every((y, k) => near2(y, l.rowYs[k])) && contains3(parent, l.bbox) && l.rowYs.every((y) => horizontals.some((h) => near2(h.y1, y) && near2(h.x1, l.bbox.x1) && near2(h.x2, l.bbox.x2))) && l.colXs.every((x) => verticals.some((v) => near2(v.x1, x) && v.y1 <= l.bbox.y1 + 1.5 && v.y2 >= l.bbox.y2 - 1.5)) && !clipGrids.some((o) => o !== c && !contains3(o.bbox, l.bbox) && Math.min(o.bbox.x2, l.bbox.x2) > Math.max(o.bbox.x1, l.bbox.x1) && Math.min(o.bbox.y2, l.bbox.y2) > Math.max(o.bbox.y1, l.bbox.y1)));
27464
+ if (!host2) continue;
27465
+ const grid = { ...host2, clipParent: parent, cells: extractCells(host2, horizontals, verticals) };
27466
+ clipGrids[i] = grid;
27467
+ extended.push(grid);
27468
+ }
27469
+ return extended;
27470
+ }
27471
+ var init_nested_shaded_headers = __esm({
27472
+ ".kordoc-source/src/pdf/nested-shaded-headers.ts"() {
27473
+ "use strict";
27474
+ init_cjs_shims();
27475
+ init_cell_extract();
27476
+ }
27477
+ });
27478
+
27479
+ // .kordoc-source/src/pdf/side-tabs.ts
27480
+ function isSideTabTable(box, table3, others, pageWidth, pageHeight) {
27481
+ if (table3.cols !== 1 || box.x2 - box.x1 > pageWidth * BAND || box.y2 - box.y1 < pageHeight * TAB_MIN_HEIGHT) return false;
27482
+ const side = box.x1 >= pageWidth * (1 - BAND) ? "R" : box.x2 <= pageWidth * BAND ? "L" : null;
27483
+ if (!side) return false;
27484
+ const texts = table3.cells.flat().map((c) => c.text.replace(/\s+/g, ""));
27485
+ if (!texts.some(Boolean) || texts.some((t) => [...t].length > TAB_CELL_CHARS)) return false;
27486
+ const overlap2 = others.filter((it) => it.y >= box.y1 && it.y <= box.y2);
27487
+ return overlap2.length > 0 && overlap2.every((it) => side === "R" ? it.x + it.w <= box.x1 + 1 : it.x >= box.x2 - 1);
27488
+ }
27489
+ function removeSideTabs(blocks, pageWidths) {
27490
+ var _a2, _b, _c, _d, _e;
27491
+ const edges = /* @__PURE__ */ new Map();
27492
+ for (const b of blocks) {
27493
+ if (!b.bbox || b.pageNumber === void 0 || [...(_b = (_a2 = b.text) == null ? void 0 : _a2.trim()) != null ? _b : ""].length <= MAX_CHARS) continue;
27494
+ const e = (_c = edges.get(b.pageNumber)) != null ? _c : { lefts: [], rights: [] };
27495
+ e.lefts.push(b.bbox.x);
27496
+ e.rights.push(b.bbox.x + b.bbox.width);
27497
+ edges.set(b.pageNumber, e);
27498
+ }
27499
+ const q = (xs, p) => {
27500
+ const v = [...xs].sort((a, b) => a - b);
27501
+ return v[Math.min(v.length - 1, Math.floor(p * v.length))];
27502
+ };
27503
+ const body = /* @__PURE__ */ new Map();
27504
+ for (const [page, e] of edges) body.set(page, { left: q(e.lefts, 0.2), right: q(e.rights, 0.8) });
27505
+ const all = [...body.values()];
27506
+ const fallback = all.length ? { left: q(all.map((e) => e.left), 0.5), right: q(all.map((e) => e.right), 0.5) } : void 0;
27507
+ const key = (b) => {
27508
+ var _a3, _b2;
27509
+ const w = b.pageNumber !== void 0 ? pageWidths.get(b.pageNumber) : void 0;
27510
+ const text2 = (_a3 = b.text) == null ? void 0 : _a3.trim();
27511
+ const area = (_b2 = b.pageNumber !== void 0 ? body.get(b.pageNumber) : void 0) != null ? _b2 : fallback;
27512
+ if (b.type === "table") {
27513
+ if (!w || !b.bbox || !b.table || !SIDE_TAB_TABLES.has(b.table)) return null;
27514
+ return `${b.bbox.x >= w * (1 - BAND) ? "R" : "L"}${Math.round(b.bbox.x / 8)}`;
27515
+ }
27516
+ if (!w || !area || !b.bbox || !text2 || [...text2].length > MAX_CHARS) return null;
27517
+ const side = b.bbox.x + b.bbox.width <= Math.min(w * BAND, area.left - 1) ? "L" : b.bbox.x >= Math.max(w * (1 - BAND), area.right + 1) ? "R" : null;
27518
+ return side && `${side}\0${text2.replace(/\s+/g, "")}`;
27519
+ };
27520
+ const pages = /* @__PURE__ */ new Map();
27521
+ for (const b of blocks) {
27522
+ const k = key(b);
27523
+ if (k) pages.set(k, ((_d = pages.get(k)) != null ? _d : /* @__PURE__ */ new Set()).add(b.pageNumber));
27524
+ }
27525
+ const running = /* @__PURE__ */ new Set();
27526
+ for (const [k, ps] of pages) {
27527
+ const list2 = [...ps].sort((a, b) => a - b);
27528
+ const steps = list2.slice(1).map((p, i) => p - list2[i]).sort((a, b) => a - b);
27529
+ const gap = Math.max(RUN_GAP, ((_e = steps[steps.length >> 1]) != null ? _e : 1) * 3);
27530
+ let run = [];
27531
+ const flush = () => {
27532
+ if (run.length >= MIN_REPEAT && run.length >= (run[run.length - 1] - run[0] + 1) * 0.4) for (const p of run) running.add(`${p}\0${k}`);
27533
+ run = [];
27534
+ };
27535
+ for (const p of list2) {
27536
+ if (run.length && p - run[run.length - 1] > gap) flush();
27537
+ run.push(p);
27538
+ }
27539
+ flush();
27540
+ }
27541
+ return running.size ? blocks.filter((b) => {
27542
+ const k = key(b);
27543
+ return !k || !running.has(`${b.pageNumber}\0${k}`);
27544
+ }) : blocks;
27545
+ }
27546
+ var BAND, MAX_CHARS, MIN_REPEAT, RUN_GAP, TAB_CELL_CHARS, TAB_MIN_HEIGHT, SIDE_TAB_TABLES;
27547
+ var init_side_tabs = __esm({
27548
+ ".kordoc-source/src/pdf/side-tabs.ts"() {
27549
+ "use strict";
27550
+ init_cjs_shims();
27551
+ BAND = 0.12;
27552
+ MAX_CHARS = 10;
27553
+ MIN_REPEAT = 3;
27554
+ RUN_GAP = 5;
27555
+ TAB_CELL_CHARS = 24;
27556
+ TAB_MIN_HEIGHT = 0.3;
27557
+ SIDE_TAB_TABLES = /* @__PURE__ */ new WeakSet();
27558
+ }
27559
+ });
27560
+
27561
+ // .kordoc-source/src/pdf/side-tab-blocks.ts
27562
+ function attachSideTabBlocks(tab, body, pageNum) {
27563
+ var _a2;
27564
+ const ordered = [...tab].sort((a, b) => b.y - a.y);
27565
+ const caps = SIDE_TAB_CAP_GROUPS.get(tab);
27566
+ const block2 = (items) => ({
27567
+ type: "paragraph",
27568
+ text: mergeLineSimple(items).trim(),
27569
+ pageNumber: pageNum,
27570
+ bbox: computeBBox(items, pageNum),
27571
+ style: dominantStyle(items)
27572
+ });
27573
+ const prefix = ordered.filter((g4) => !(caps == null ? void 0 : caps.has(g4))).map((g4) => ({
27574
+ type: "paragraph",
27575
+ text: g4.text.trim(),
27576
+ pageNumber: pageNum,
27577
+ bbox: computeBBox([g4], pageNum),
27578
+ style: dominantStyle([g4])
27579
+ }));
27580
+ const groups = /* @__PURE__ */ new Map();
27581
+ for (const g4 of ordered) {
27582
+ const cap = caps == null ? void 0 : caps.get(g4);
27583
+ if (cap) groups.set(cap, [...(_a2 = groups.get(cap)) != null ? _a2 : [], g4]);
27584
+ }
27585
+ for (const [cap, glyphs] of groups) {
27586
+ const blocks = groupByY(glyphs).map(block2);
27587
+ const anchor = body.reduce((best, b, i) => {
27588
+ const box = b.bbox;
27589
+ if (b.type === "image" || b.type === "separator" || !box || !b.text && !b.table || box.x > cap.x + 1 || box.x + box.width < cap.x + cap.w - 1 || box.y > cap.y + 1 || box.y + box.height < cap.y + cap.fontSize - 1) return best;
27590
+ return best < 0 || box.width * box.height < body[best].bbox.width * body[best].bbox.height ? i : best;
27591
+ }, -1);
27592
+ body.splice(anchor >= 0 ? anchor + 1 : body.length, 0, ...blocks);
27593
+ }
27594
+ return [...prefix, ...body];
27595
+ }
27596
+ var init_side_tab_blocks = __esm({
27597
+ ".kordoc-source/src/pdf/side-tab-blocks.ts"() {
27598
+ "use strict";
27599
+ init_cjs_shims();
27600
+ init_cluster_detector();
27601
+ init_text_line();
27602
+ }
27603
+ });
27604
+
26780
27605
  // .kordoc-source/src/pdf/page-regions.ts
26781
27606
  function splitTwoColumnProse(items, cutX) {
26782
27607
  const left = [];
@@ -27119,11 +27944,16 @@ var init_page_regions = __esm({
27119
27944
  });
27120
27945
 
27121
27946
  // .kordoc-source/src/pdf/page-blocks.ts
27122
- function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeight, extraLines, detectTables = true, carry, lexicon) {
27947
+ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeight, extraLines, detectTables = true, carry, lexicon, verifiedRightArrows = []) {
27123
27948
  if (items.length === 0) {
27124
27949
  if (carry) carry.clip = void 0;
27125
27950
  return [];
27126
27951
  }
27952
+ const tab = sideTabGlyphs(items);
27953
+ if (tab.size) {
27954
+ const body = extractPageBlocksWithLines(items.filter((i) => !tab.has(i)), pageNum, opList, pageWidth, pageHeight, extraLines, detectTables, carry, lexicon, verifiedRightArrows);
27955
+ return attachSideTabBlocks(tab, body, pageNum);
27956
+ }
27127
27957
  const lex = lexicon != null ? lexicon : new WrapLexicon();
27128
27958
  for (const line of streamLines(items)) lex.addLine(mergeLineSimple(line));
27129
27959
  const extracted = extractLines(opList.fnArray, opList.argsArray);
@@ -27150,19 +27980,28 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
27150
27980
  }
27151
27981
  ;
27152
27982
  ({ horizontals, verticals } = filterPageBorderLines(horizontals, verticals, pageWidth, pageHeight));
27153
- ({ horizontals, verticals } = preprocessLines(horizontals, verticals));
27983
+ ({ horizontals, verticals } = preprocessLines(horizontals, verticals, extracted.nonRules));
27984
+ markStrikethroughItems(items, horizontals);
27985
+ wrapStrikethroughRuns(items);
27986
+ const underlines = new Set(markUnderlineItems(items, horizontals, verticals, extracted.nonRules));
27987
+ if (underlines.size) horizontals = horizontals.filter((l) => !underlines.has(l));
27988
+ wrapUnderlineRuns(items);
27154
27989
  horizontals = closeOpenTableEnds(horizontals, verticals, items.every((it) => it.seq !== void 0));
27155
27990
  verticals = closeOpenTableEdges(horizontals, verticals);
27156
27991
  verticals = bridgeSplitColumnVerticals(horizontals, verticals);
27157
27992
  if (detectTables && clipGrids.length === 0) verticals = bridgeSkippedRowVerticals(horizontals, verticals, items);
27158
27993
  if (detectTables && clipGrids.length === 0) ({ horizontals, verticals } = extendHeaderBoxRows(horizontals, verticals, items));
27159
- markStrikethroughItems(items, horizontals);
27160
- wrapStrikethroughRuns(items);
27161
- const underlines = new Set(markUnderlineItems(items, horizontals, verticals));
27162
- if (underlines.size) horizontals = horizontals.filter((l) => !underlines.has(l));
27163
- wrapUnderlineRuns(items);
27994
+ const shadedEdges = detectTables ? closeShadedTableEdges(clipGrids, horizontals, verticals, extracted.fillRects) : void 0;
27995
+ if (shadedEdges) ({ horizontals, verticals } = shadedEdges);
27164
27996
  const lineGrids = detectTables ? buildTableGrids(horizontals, verticals) : [];
27997
+ if (shadedEdges) nestRestoredShadedGrids(lineGrids, shadedEdges.restored, horizontals, verticals);
27165
27998
  const tableClipGrids = dropHeadBandClipGrids(dropInsetClipGrids(dropShadingClipGrids(clipGrids, lineGrids, extracted.fillRects, verticals), lineGrids), lineGrids);
27999
+ recordClipCellEdges(
28000
+ extendNestedShadedHeaders(tableClipGrids, lineGrids, horizontals, verticals, extracted.fillRects),
28001
+ extracted.horizontals.concat(extracted.shortH),
28002
+ extracted.verticals.concat(extracted.shortV),
28003
+ extracted.nonRules
28004
+ );
27166
28005
  const grids = [...tableClipGrids, ...dropGridsInside(lineGrids, tableClipGrids, clipResult.containers)];
27167
28006
  const figures = () => extractImageRegions(opList.fnArray, opList.argsArray, true).filter((r) => r.x2 - r.x1 >= 40 && r.y2 - r.y1 >= 40).map((r) => ({ x: r.x1, y: r.y1, w: r.x2 - r.x1, h: r.y2 - r.y1 }));
27168
28007
  if (grids.length === 1 && grids[0].rowYs.length === 2 && grids[0].colXs.length === 2 && grids[0].bbox.x2 - grids[0].bbox.x1 > pageWidth * 1.2 && grids[0].bbox.y2 - grids[0].bbox.y1 > pageHeight * 1.2) {
@@ -27172,7 +28011,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
27172
28011
  if (detectTables && clipGrids.length === 0 && ruled.length === 0 && lineGrids.length === 0) ruled.push(...detectTextBoxTables(extracted.hiddenBoxes, items, pageNum));
27173
28012
  if (ruled.length > 0) {
27174
28013
  const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray).filter((r) => r.x2 - r.x1 >= 8 && r.y2 - r.y1 >= 8);
27175
- return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, ruled, rawRules);
28014
+ return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, ruled, rawRules, verifiedRightArrows);
27176
28015
  }
27177
28016
  if (detectTables && stackedTableBands(items)) {
27178
28017
  return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures());
@@ -27183,7 +28022,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
27183
28022
  }
27184
28023
  if (grids.length > 0) {
27185
28024
  const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray).filter((r) => r.x2 - r.x1 >= 8 && r.y2 - r.y1 >= 8);
27186
- return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, [], rawRules);
28025
+ return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, [], rawRules, verifiedRightArrows);
27187
28026
  }
27188
28027
  return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures());
27189
28028
  }
@@ -27278,45 +28117,11 @@ function isSparseProseGrid(table3) {
27278
28117
  const prose = filled.filter((t) => t.length >= 60 && /[.!?。]/.test(t)).reduce((n, t) => n + t.length, 0);
27279
28118
  return prose >= chars * 0.6;
27280
28119
  }
27281
- function takePendingNested(pending, cellBox, clipCell) {
27282
- const out = [];
27283
- for (let i = pending.length - 1; i >= 0; i--) {
27284
- const p = pending[i].parent;
27285
- if (pending[i].contained ? p.x1 >= cellBox.x1 - FRAME_RECT_TOL && p.x2 <= cellBox.x2 + FRAME_RECT_TOL && p.y1 >= cellBox.y1 - FRAME_RECT_TOL && p.y2 <= cellBox.y2 + FRAME_RECT_TOL : clipCell && Math.abs(p.x1 - cellBox.x1) <= FRAME_RECT_TOL && Math.abs(p.x2 - cellBox.x2) <= FRAME_RECT_TOL && Math.abs(p.y1 - cellBox.y1) <= FRAME_RECT_TOL && Math.abs(p.y2 - cellBox.y2) <= FRAME_RECT_TOL) {
27286
- out.push(pending[i].block);
27287
- pending.splice(i, 1);
27288
- }
27289
- }
27290
- return out;
27291
- }
27292
- function buildFrameCellBlocks(cellItems, nested, pageNum, wrap) {
27293
- const tables = [...nested].sort((a, b) => b.bbox.y + b.bbox.height - (a.bbox.y + a.bbox.height));
27294
- const blocks = [];
27295
- let rest = [...cellItems];
27296
- const pushParagraphs = (items) => {
27297
- if (items.length === 0) return;
27298
- for (const line of cleanCellText(cellTextToString(items, wrap)).split("\n")) {
27299
- const t = line.trim();
27300
- if (t) blocks.push({ type: "paragraph", text: t, pageNumber: pageNum });
27301
- }
27302
- };
27303
- for (const tb of tables) {
27304
- const bottom = tb.bbox.y;
27305
- pushParagraphs(rest.filter((it) => it.y >= bottom));
27306
- rest = rest.filter((it) => it.y < bottom);
27307
- blocks.push(tb);
27308
- }
27309
- pushParagraphs(rest);
27310
- const text2 = blocks.map((b) => {
27311
- var _a2;
27312
- return b.type === "table" && b.table ? b.table.cells.flat().map((c) => c.text).filter(Boolean).join("\n") : (_a2 = b.text) != null ? _a2 : "";
27313
- }).filter(Boolean).join("\n");
27314
- return { blocks, text: text2 };
27315
- }
27316
- function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions = [], lex, ruled = [], rawRules = horizontals) {
27317
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
28120
+ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions = [], lex, ruled = [], rawRules = horizontals, verifiedRightArrows = []) {
28121
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
27318
28122
  const ocrPage = items.length > 0 && items.every((i) => i.fontName === "ocr");
27319
28123
  const blocks = [];
28124
+ const frameParagraphUnits = [];
27320
28125
  const usedItems = /* @__PURE__ */ new Set();
27321
28126
  for (const r of ruled) {
27322
28127
  for (const it of r.items) usedItems.add(it);
@@ -27373,7 +28178,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
27373
28178
  const nested = pendingNested.length ? takePendingNested(pendingNested, cell2.bbox, !!grid.cells) : [];
27374
28179
  if (nested.length > 0) {
27375
28180
  nestedAttached = true;
27376
- const built = buildFrameCellBlocks(cellItems, nested, pageNum, { box: cell2.bbox, lex });
28181
+ const built = buildFrameCellBlocks(cellItems, nested, pageNum, lex);
27377
28182
  irGrid[cell2.row][cell2.col] = { text: built.text, colSpan: cell2.colSpan, rowSpan: cell2.rowSpan, blocks: built.blocks };
27378
28183
  if (cellItems.length) recordCellLines(irGrid[cell2.row][cell2.col], cellItems);
27379
28184
  takeClipCellEdges(cell2, irGrid[cell2.row][cell2.col]);
@@ -27384,6 +28189,9 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
27384
28189
  colSpan: cell2.colSpan,
27385
28190
  rowSpan: cell2.rowSpan
27386
28191
  };
28192
+ if (numRows === 1 && numCols === 1 && cellItems.length) {
28193
+ irGrid[cell2.row][cell2.col].blocks = buildFrameCellBlocks(cellItems, [], pageNum, lex).blocks;
28194
+ }
27387
28195
  const b = cell2.bbox;
27388
28196
  const isBackdrop = (r) => r.x1 <= b.x1 + 1 && r.x2 >= b.x2 - 1 && r.y1 <= b.y1 + 1 && r.y2 >= b.y2 - 1;
27389
28197
  if (imageRegions.some((r) => {
@@ -27419,7 +28227,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
27419
28227
  }
27420
28228
  if (!rebuiltUsed && attachUnitRow(items, grid, finalGrid, numCols, usedItems)) finalRows++;
27421
28229
  let semanticOneColumn = false;
27422
- if (!grid.cells && numCols === 1 && numGridRows >= 2) {
28230
+ if (!grid.cells && !nestedAttached && numCols === 1 && numGridRows >= 2) {
27423
28231
  const populatedRows = finalGrid.filter((row) => {
27424
28232
  var _a3;
27425
28233
  return (_a3 = row[0]) == null ? void 0 : _a3.text.trim();
@@ -27475,12 +28283,19 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
27475
28283
  recordRowRules(irTable, grid.cells, grid.bbox, rawRules);
27476
28284
  }
27477
28285
  TABLE_COLXS.set(irTable, grid.colXs);
28286
+ if (grid.cells) recordFrameTitle(irTable, tableItems, pageNum);
27478
28287
  if (grid.cells && finalRows === numRows) TABLE_ROWYS.set(irTable, grid.rowYs);
27479
28288
  if (grid.continues) CONT_PARTS.set(irTable, grid.continues);
27480
28289
  const hasContent2 = finalGrid.some((row) => row.some((cell2) => cell2.text.trim() !== ""));
27481
28290
  const emptyPart = !hasContent2 && !!grid.cells && !grid.clipParent && !nestedAttached;
27482
28291
  if (!hasContent2 && !emptyPart) continue;
27483
28292
  if (emptyPart) EMPTY_PARTS.add(irTable);
28293
+ const ownItems = numCols === 1 ? new Set(tableItems) : null;
28294
+ if (ownItems && isSideTabTable(grid.bbox, irTable, items.filter((it) => !ownItems.has(it)), pageWidth, pageHeight)) {
28295
+ SIDE_TAB_TABLES.add(irTable);
28296
+ blocks.push({ type: "table", table: irTable, pageNumber: pageNum, bbox: { page: pageNum, x: grid.bbox.x1, y: grid.bbox.y1, width: gridW, height: grid.bbox.y2 - grid.bbox.y1 } });
28297
+ continue;
28298
+ }
27484
28299
  if (grid.clipParent) {
27485
28300
  const nb = { page: pageNum, x: grid.bbox.x1, y: grid.bbox.y1, width: grid.bbox.x2 - grid.bbox.x1, height: grid.bbox.y2 - grid.bbox.y1 };
27486
28301
  pendingNested.push({ parent: grid.clipParent, block: { type: "table", table: irTable, pageNumber: pageNum, bbox: nb } });
@@ -27520,7 +28335,14 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
27520
28335
  continue;
27521
28336
  }
27522
28337
  }
27523
- if (!grid.cells && shouldDemoteTable(irTable)) {
28338
+ if (!grid.cells && !nestedAttached && shouldDemoteTable(irTable)) {
28339
+ const paragraphs = numRows === 1 && numCols === 1 ? (_k = (_j = irTable.cells[0]) == null ? void 0 : _j[0]) == null ? void 0 : _k.blocks : void 0;
28340
+ if (paragraphs == null ? void 0 : paragraphs.length) {
28341
+ blocks.push(...paragraphs);
28342
+ frameParagraphUnits.push(paragraphs);
28343
+ recordFrameReadingUnit(paragraphs, tableBbox);
28344
+ continue;
28345
+ }
27524
28346
  const demoted = demoteTableToText(irTable);
27525
28347
  if (demoted) {
27526
28348
  const text2 = numGridRows === 1 ? "\n" + demoted + "\n" : demoted;
@@ -27577,10 +28399,8 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
27577
28399
  }
27578
28400
  {
27579
28401
  const rects = remaining.map((i) => ({ x: i.x, y: i.y, w: i.w, h: i.h > 0 ? i.h : i.fontSize }));
27580
- for (const b of blocks) {
27581
- if (b.bbox && !(b.table && EMPTY_PARTS.has(b.table))) rects.push({ x: b.bbox.x, y: b.bbox.y, w: b.bbox.width, h: b.bbox.height });
27582
- }
27583
- gutterX = (_j = detectColumnGutter(rects)) != null ? _j : findRuledColumnDivider(
28402
+ for (const b of frameLayoutBoxes(blocks.filter((b2) => !(b2.table && EMPTY_PARTS.has(b2.table))))) rects.push({ x: b.x, y: b.y, w: b.width, h: b.height });
28403
+ gutterX = (_l = detectColumnGutter(rects)) != null ? _l : findRuledColumnDivider(
27584
28404
  blocks.filter((b) => b.type === "table" && b.bbox && b.table && !EMPTY_PARTS.has(b.table)).map((b) => ({ x: b.bbox.x, y: b.bbox.y, w: b.bbox.width, h: b.bbox.height })),
27585
28405
  horizontals,
27586
28406
  verticals,
@@ -27592,14 +28412,15 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
27592
28412
  if (remaining.length > 0) {
27593
28413
  if (gutterX !== null) {
27594
28414
  const gx = gutterX;
28415
+ const spanning = detectListBlocks(takeFrameSpanningText(remaining, gx, pageNum, lex));
28416
+ for (const block2 of spanning) {
28417
+ finalTextBlocks.push(block2);
28418
+ groupSizes.push(1);
28419
+ }
27595
28420
  const allY = remaining.map((i) => i.y);
27596
28421
  const pageH = safeMax(allY) - safeMin(allY);
27597
28422
  const gapThreshold = Math.max(15, pageH * 0.03);
27598
- const sides = [
27599
- remaining.filter((i) => i.x + i.w <= gx),
27600
- remaining.filter((i) => i.x < gx && i.x + i.w > gx),
27601
- remaining.filter((i) => i.x >= gx)
27602
- ];
28423
+ const sides = frameColumnTextBands(remaining, spanning, gx);
27603
28424
  const textBlocks = [];
27604
28425
  for (const side of sides) {
27605
28426
  if (side.length === 0) continue;
@@ -27610,7 +28431,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
27610
28431
  groupSizes.push(groupBlocks.length);
27611
28432
  }
27612
28433
  }
27613
- finalTextBlocks = detectListBlocks(textBlocks);
28434
+ finalTextBlocks.push(...detectListBlocks(textBlocks));
27614
28435
  } else {
27615
28436
  const allY = remaining.map((i) => i.y);
27616
28437
  const pageH = safeMax(allY) - safeMin(allY);
@@ -27626,7 +28447,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
27626
28447
  finalTextBlocks = detectListBlocks(textBlocks);
27627
28448
  }
27628
28449
  }
27629
- const units = blocks.map((b) => [b]);
28450
+ const units = groupFrameParagraphUnits(groupFlowBoxUnits(blocks, grids, horizontals, verticals, verifiedRightArrows), frameParagraphUnits);
27630
28451
  let off = 0;
27631
28452
  for (const size of groupSizes) {
27632
28453
  const unit = finalTextBlocks.slice(off, off + size);
@@ -27763,7 +28584,7 @@ function mergeAdjacentTableBlocks(blocks) {
27763
28584
  table: merged,
27764
28585
  bbox: { ...pb, y: cb.y, height: pb.y + pb.height - cb.y }
27765
28586
  };
27766
- } else if (prev.type === "table" && curr.type === "table" && prev.table && curr.table && prev.table.cols === curr.table.cols && prev.table.renderAsTable === curr.table.renderAsTable && !CLIP_TABLES.has(prev.table) && !CLIP_TABLES.has(curr.table)) {
28587
+ } else if (prev.type === "table" && curr.type === "table" && prev.table && curr.table && prev.table.cols === curr.table.cols && prev.table.renderAsTable === curr.table.renderAsTable && !CLIP_TABLES.has(prev.table) && !CLIP_TABLES.has(curr.table) && !separateRepeatedHeadings(prev, curr)) {
27767
28588
  const merged = {
27768
28589
  rows: prev.table.rows + curr.table.rows,
27769
28590
  cols: prev.table.cols,
@@ -27778,6 +28599,12 @@ function mergeAdjacentTableBlocks(blocks) {
27778
28599
  }
27779
28600
  return result;
27780
28601
  }
28602
+ function separateRepeatedHeadings(upper, lower) {
28603
+ const u = upper.table, d = lower.table, ub = upper.bbox, db = lower.bbox;
28604
+ if (!ub || !db || ub.page !== db.page || u.rows < 2 || d.rows < 2 || !u.hasHeader || !d.hasHeader || ub.y - (db.y + db.height) <= 1 || Math.abs(ub.x - db.x) > 1 || Math.abs(ub.width - db.width) > 1) return false;
28605
+ const a = u.cells[0], b = d.cells[0], norm2 = (text2) => text2.replace(/<\/?u>|~~|\s+/g, "");
28606
+ return a.filter((cell2) => norm2(cell2.text)).length >= 2 && a.length === b.length && a.every((cell2, c) => cell2.colSpan === b[c].colSpan && cell2.rowSpan === b[c].rowSpan && norm2(cell2.text) === norm2(b[c].text));
28607
+ }
27781
28608
  function streamLines(items) {
27782
28609
  if (items.some((i) => i.seq === void 0)) return groupByY([...items].sort((a, b) => b.y - a.y || a.x - b.x));
27783
28610
  const lines = [];
@@ -27950,7 +28777,7 @@ function extractPageBlocksFallback(items, pageNum, fullPage = false, detectTable
27950
28777
  }
27951
28778
  return detectTables ? detectSpecialKoreanTables(blocks) : blocks;
27952
28779
  }
27953
- var STRIKE_MAX_THICKNESS, STRIKE_MAX_THICKNESS_RATIO, STRIKE_CENTER_TOLERANCE, STRIKE_MIN_OVERLAP_RATIO, STRIKE_MAX_LINE_TO_TEXT_RATIO, PROSEBOX_FULLWIDTH_MIN, PROSEBOX_LONG_CELL_CHARS, PROSEBOX_LONG_CELL_MIN, PROSEBOX_LONG_CELL_RATIO, PROSEBOX_X_TOL, FRAME_RECT_TOL, SIDEBAR_ITEMS, STACKED_ROWS;
28780
+ var STRIKE_MAX_THICKNESS, STRIKE_MAX_THICKNESS_RATIO, STRIKE_CENTER_TOLERANCE, STRIKE_MIN_OVERLAP_RATIO, STRIKE_MAX_LINE_TO_TEXT_RATIO, PROSEBOX_FULLWIDTH_MIN, PROSEBOX_LONG_CELL_CHARS, PROSEBOX_LONG_CELL_MIN, PROSEBOX_LONG_CELL_RATIO, PROSEBOX_X_TOL, SIDEBAR_ITEMS, STACKED_ROWS;
27954
28781
  var init_page_blocks = __esm({
27955
28782
  ".kordoc-source/src/pdf/page-blocks.ts"() {
27956
28783
  "use strict";
@@ -27980,6 +28807,7 @@ var init_page_blocks = __esm({
27980
28807
  init_table_unit_row();
27981
28808
  init_line_wrap();
27982
28809
  init_page_frame();
28810
+ init_shaded_open_table();
27983
28811
  init_open_table_ends();
27984
28812
  init_header_box_rows();
27985
28813
  init_ruled_band_tables();
@@ -27987,7 +28815,12 @@ var init_page_blocks = __esm({
27987
28815
  init_vertical_bridge();
27988
28816
  init_local_regions();
27989
28817
  init_paragraph_lines();
28818
+ init_frame_cell_blocks();
28819
+ init_flow_boxes();
28820
+ init_nested_shaded_headers();
27990
28821
  init_table_roles();
28822
+ init_side_tabs();
28823
+ init_side_tab_blocks();
27991
28824
  init_page_regions();
27992
28825
  STRIKE_MAX_THICKNESS = 2;
27993
28826
  STRIKE_MAX_THICKNESS_RATIO = 0.25;
@@ -27999,7 +28832,6 @@ var init_page_blocks = __esm({
27999
28832
  PROSEBOX_LONG_CELL_MIN = 3;
28000
28833
  PROSEBOX_LONG_CELL_RATIO = 0.4;
28001
28834
  PROSEBOX_X_TOL = 8;
28002
- FRAME_RECT_TOL = 1.5;
28003
28835
  SIDEBAR_ITEMS = /* @__PURE__ */ new WeakMap();
28004
28836
  STACKED_ROWS = /* @__PURE__ */ new WeakSet();
28005
28837
  }
@@ -28434,9 +29266,14 @@ function mergeOcrImageRegions(blocks, page, regions, ocrBlocks) {
28434
29266
  const overlapH = Math.max(0, Math.min(b.y + b.height, region.y2) - Math.max(b.y, region.y1));
28435
29267
  return overlapW * overlapH >= b.width * b.height * 0.8;
28436
29268
  });
29269
+ const labels = candidates.filter((b) => {
29270
+ var _a2, _b, _c;
29271
+ return b.type === "paragraph" && b.bbox.height <= 24 && ((_c = (_b = (_a2 = b.text) == null ? void 0 : _a2.match(/[\p{L}\p{N}]/gu)) == null ? void 0 : _b.length) != null ? _c : 0) >= 2;
29272
+ });
29273
+ const axisFragments = rotatedAxisFragments(candidates);
28437
29274
  const accepted = candidates.filter((b) => {
28438
29275
  var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
28439
- if (b.type === "paragraph") return ((_c = (_b = (_a2 = b.text) == null ? void 0 : _a2.match(/[\p{L}\p{N}]/gu)) == null ? void 0 : _b.length) != null ? _c : 0) >= 2;
29276
+ if (b.type === "paragraph") return ((_c = (_b = (_a2 = b.text) == null ? void 0 : _a2.match(/[\p{L}\p{N}]/gu)) == null ? void 0 : _b.length) != null ? _c : 0) >= 2 || !axisFragments.has(b) && supportedDiagramLabel(b, labels, region);
28440
29277
  const t = b.table;
28441
29278
  if (b.type !== "table" || !t) return false;
28442
29279
  if (t.rows === 1 && t.cols === 1) {
@@ -28450,29 +29287,99 @@ function mergeOcrImageRegions(blocks, page, regions, ocrBlocks) {
28450
29287
  var _a2;
28451
29288
  return /[\p{L}\p{N}]{2}/u.test((_a2 = p.text) != null ? _a2 : "");
28452
29289
  }) : []);
28453
- for (const block2 of selected) {
29290
+ const hasOriginal = (block2) => blocks.some((existing) => {
28454
29291
  const b = block2.bbox;
28455
- const hasOriginal = blocks.some((existing) => {
28456
- if (existing.pageNumber !== page || !existing.bbox || existing.type === "image") return false;
28457
- const e = existing.bbox;
28458
- const x = Math.max(0, Math.min(e.x + e.width, b.x + b.width) - Math.max(e.x, b.x));
28459
- const y = Math.max(0, Math.min(e.y + e.height, b.y + b.height) - Math.max(e.y, b.y));
28460
- return x * y > b.width * b.height * 0.2;
28461
- });
28462
- if (hasOriginal) continue;
28463
- const index = blocks.findIndex((existing) => {
28464
- const e = existing.bbox;
28465
- if (existing.pageNumber !== page || !e) return false;
28466
- const beside = e.y < region.y2 && e.y + e.height > region.y1 && e.x >= region.x2 - 1;
28467
- return e.y < b.y || beside;
28468
- });
28469
- const placed = block2.type === "paragraph" ? { ...block2, style: void 0 } : block2;
28470
- blocks.splice(index < 0 ? blocks.length : index, 0, placed);
28471
- added++;
29292
+ if (existing.pageNumber !== page || !existing.bbox || existing.type === "image") return false;
29293
+ const e = existing.bbox;
29294
+ const x = Math.max(0, Math.min(e.x + e.width, b.x + b.width) - Math.max(e.x, b.x));
29295
+ const y = Math.max(0, Math.min(e.y + e.height, b.y + b.height) - Math.max(e.y, b.y));
29296
+ return x * y > b.width * b.height * 0.2;
29297
+ });
29298
+ const selectedSet = new Set(selected), seen2 = /* @__PURE__ */ new Set();
29299
+ for (const block2 of selected) {
29300
+ if (seen2.has(block2)) continue;
29301
+ const frame = FRAME_READING_UNITS.get(block2);
29302
+ const source = (frame == null ? void 0 : frame.blocks.every((member) => selectedSet.has(member))) ? frame.blocks : [block2];
29303
+ source.forEach((member) => seen2.add(member));
29304
+ const available = source.filter((member) => !hasOriginal(member));
29305
+ const units = frame && available.length === source.length && source === frame.blocks ? [{ blocks: available, bbox: frame.bbox, atomic: true }] : available.map((member) => ({ blocks: [member], bbox: member.bbox, atomic: false }));
29306
+ for (const unit of units) {
29307
+ const b = unit.bbox;
29308
+ const index = blocks.findIndex((existing) => {
29309
+ var _a2, _b;
29310
+ const e = (_b = (_a2 = FRAME_READING_UNITS.get(existing)) == null ? void 0 : _a2.bbox) != null ? _b : existing.bbox;
29311
+ if (existing.pageNumber !== page || !e) return false;
29312
+ const beside = e.y < region.y2 && e.y + e.height > region.y1 && e.x >= region.x2 - 1;
29313
+ return e.y < b.y || beside;
29314
+ });
29315
+ const placed = unit.blocks.map((member) => member.type === "paragraph" ? { ...member, style: void 0 } : member);
29316
+ if (unit.atomic) recordFrameReadingUnit(placed, unit.bbox);
29317
+ blocks.splice(index < 0 ? blocks.length : index, 0, ...placed);
29318
+ added += placed.length;
29319
+ }
28472
29320
  }
28473
29321
  }
28474
29322
  return added;
28475
29323
  }
29324
+ function supportedDiagramLabel(block2, labels, region) {
29325
+ var _a2, _b;
29326
+ const b = block2.bbox, text2 = (_b = (_a2 = block2.text) == null ? void 0 : _a2.trim()) != null ? _b : "";
29327
+ if (!b || !/^[\p{L}\p{N}]$/u.test(text2) || b.height < 4 || b.width < 1 || b.width > b.height * 2 || b.x < region.x1 || b.y < region.y1 || b.x + b.width > region.x2 || b.y + b.height > region.y2 || b.width * b.height > (region.x2 - region.x1) * (region.y2 - region.y1) * 5e-3 || labels.length < 3 || !labels.some((l) => {
29328
+ var _a3;
29329
+ return /\p{L}{3}/u.test((_a3 = l.text) != null ? _a3 : "");
29330
+ }) || labels.filter((l) => {
29331
+ var _a3, _b2, _c, _d;
29332
+ return !/\p{L}/u.test((_a3 = l.text) != null ? _a3 : "") && ((_d = (_c = (_b2 = l.text) == null ? void 0 : _b2.match(/\p{N}/gu)) == null ? void 0 : _c.length) != null ? _d : 0) >= 2;
29333
+ }).length < 2) return false;
29334
+ let above = false, below = false;
29335
+ for (const label of labels) {
29336
+ const a = label.bbox, em = Math.max(b.height, a.height);
29337
+ if (b.x + b.width < a.x - em * 2 || b.x > a.x + a.width + em * 2) continue;
29338
+ const upperGap = a.y - (b.y + b.height), lowerGap = b.y - (a.y + a.height);
29339
+ if (upperGap >= 0 && upperGap <= em * 4) above = true;
29340
+ if (lowerGap >= 0 && lowerGap <= em * 4) below = true;
29341
+ }
29342
+ return above && below;
29343
+ }
29344
+ function rotatedAxisFragments(candidates) {
29345
+ var _a2, _b, _c, _d;
29346
+ const paragraphs = candidates.filter((b) => b.type === "paragraph" && b.bbox.height <= 24);
29347
+ const axes = [];
29348
+ for (const block2 of paragraphs) {
29349
+ const b = block2.bbox, text2 = (_b = (_a2 = block2.text) == null ? void 0 : _a2.trim()) != null ? _b : "";
29350
+ if (!/^[\d\s.,%+−-]+$/u.test(text2) || !/\d/u.test(text2) || b.width > b.height * 6) continue;
29351
+ const axis = axes.find((a) => Math.abs(a[0].bbox.x + a[0].bbox.width - b.x - b.width) <= Math.max(a[0].bbox.height, b.height) * 0.5);
29352
+ if (axis) axis.push(block2);
29353
+ else axes.push([block2]);
29354
+ }
29355
+ const fragments = /* @__PURE__ */ new Set();
29356
+ const aligned = (a, b) => {
29357
+ const x = a.bbox, y = b.bbox, tolerance = Math.max(x.height, y.height) * 0.5;
29358
+ return Math.abs(x.x - y.x) <= tolerance || Math.abs(x.x + x.width - y.x - y.width) <= tolerance;
29359
+ };
29360
+ for (const axis of axes) {
29361
+ if (axis.length < 3) continue;
29362
+ const bottom = Math.min(...axis.map((a) => a.bbox.y)), top = Math.max(...axis.map((a) => a.bbox.y + a.bbox.height));
29363
+ const em = Math.max(...axis.map((a) => a.bbox.height)), right = axis[0].bbox.x + axis[0].bbox.width;
29364
+ if (top - bottom < em * 6) continue;
29365
+ const left = paragraphs.filter((block2) => {
29366
+ var _a3, _b2, _c2, _d2;
29367
+ const b = block2.bbox, text2 = (_b2 = (_a3 = block2.text) == null ? void 0 : _a3.trim()) != null ? _b2 : "";
29368
+ return /\p{Script=Latin}/u.test(text2) && ((_d2 = (_c2 = text2.match(/[\p{L}\p{N}]/gu)) == null ? void 0 : _c2.length) != null ? _d2 : 0) <= 3 && b.width <= b.height * 3 && b.x + b.width >= right - em * 6 && b.x + b.width <= right - Math.max(em, b.height) && b.y >= bottom && b.y + b.height <= top;
29369
+ });
29370
+ const stack = left.filter((a) => left.some((b) => {
29371
+ if (a === b || !aligned(a, b)) return false;
29372
+ const x = a.bbox, y = b.bbox, gap = Math.max(x.y, y.y) - Math.min(x.y + x.height, y.y + y.height);
29373
+ return gap >= -Math.min(x.height, y.height) * 0.5 && gap <= Math.max(x.height, y.height);
29374
+ }));
29375
+ if (stack.length < 2) continue;
29376
+ for (const block2 of paragraphs) {
29377
+ const b = block2.bbox;
29378
+ if (b.y >= bottom && b.y + b.height <= top && b.x + b.width >= right - em * 6 && b.x + b.width <= right - Math.max(em, b.height) && /^[\p{L}\p{N}]$/u.test((_d = (_c = block2.text) == null ? void 0 : _c.trim()) != null ? _d : "") && stack.some((s) => aligned(s, block2))) fragments.add(block2);
29379
+ }
29380
+ }
29381
+ return fragments;
29382
+ }
28476
29383
  function rowParagraphs(block2) {
28477
29384
  const t = block2.table, b = block2.bbox;
28478
29385
  const h = b.height / t.rows;
@@ -28487,6 +29394,7 @@ var init_ocr_region_merge = __esm({
28487
29394
  ".kordoc-source/src/pdf/ocr-region-merge.ts"() {
28488
29395
  "use strict";
28489
29396
  init_cjs_shims();
29397
+ init_frame_cell_blocks();
28490
29398
  }
28491
29399
  });
28492
29400
 
@@ -28527,14 +29435,14 @@ function contentHash(data) {
28527
29435
  function toRgba(img, convert = true) {
28528
29436
  const { width: w, height: h, kind, data } = img;
28529
29437
  if (!data || !w || !h) return null;
28530
- if (kind === import_pdf5.ImageKind.RGBA_32BPP) {
29438
+ if (kind === import_pdf7.ImageKind.RGBA_32BPP) {
28531
29439
  if (data.length < w * h * 4) return null;
28532
29440
  if (!convert) return NO_BYTES;
28533
29441
  const rgba = new Uint8Array(w * h * 4);
28534
29442
  rgba.set(data.subarray(0, w * h * 4));
28535
29443
  return rgba;
28536
29444
  }
28537
- if (kind === import_pdf5.ImageKind.RGB_24BPP) {
29445
+ if (kind === import_pdf7.ImageKind.RGB_24BPP) {
28538
29446
  if (data.length < w * h * 3) return null;
28539
29447
  if (!convert) return NO_BYTES;
28540
29448
  const rgba = new Uint8Array(w * h * 4);
@@ -28546,7 +29454,7 @@ function toRgba(img, convert = true) {
28546
29454
  }
28547
29455
  return rgba;
28548
29456
  }
28549
- if (kind === import_pdf5.ImageKind.GRAYSCALE_1BPP) {
29457
+ if (kind === import_pdf7.ImageKind.GRAYSCALE_1BPP) {
28550
29458
  const stride = w + 7 >> 3;
28551
29459
  if (data.length < stride * h) return null;
28552
29460
  if (!convert) return NO_BYTES;
@@ -28575,12 +29483,12 @@ async function extractPageImages(page, fnArray, argsArray, pageNumber, state, wa
28575
29483
  const op = fnArray[i];
28576
29484
  let imgData = null;
28577
29485
  let dedupeId = null;
28578
- if (op === import_pdf5.OPS.paintImageXObject || op === import_pdf5.OPS.paintImageXObjectRepeat) {
29486
+ if (op === import_pdf7.OPS.paintImageXObject || op === import_pdf7.OPS.paintImageXObjectRepeat) {
28579
29487
  const objId = (_a2 = argsArray[i]) == null ? void 0 : _a2[0];
28580
29488
  if (typeof objId !== "string" || pageSeenIds.has(objId)) continue;
28581
29489
  pageSeenIds.add(objId);
28582
29490
  dedupeId = objId;
28583
- } else if (op !== import_pdf5.OPS.paintInlineImageXObject) {
29491
+ } else if (op !== import_pdf7.OPS.paintInlineImageXObject) {
28584
29492
  continue;
28585
29493
  }
28586
29494
  if (state.imageIndex >= MAX_IMAGES_PER_DOC || state.totalBytes >= MAX_TOTAL_IMAGE_BYTES) {
@@ -28657,13 +29565,13 @@ function injectPageImageBlocks(blocks, pageImages) {
28657
29565
  blocks.length = 0;
28658
29566
  for (const b of result) blocks.push(b);
28659
29567
  }
28660
- var import_node_crypto2, import_pdf5, IMAGE_RESOLVE_TIMEOUT_MS, MIN_DIM, MAX_PIXELS2, MAX_IMAGES_PER_DOC, MAX_TOTAL_IMAGE_BYTES, NO_BYTES;
29568
+ var import_node_crypto2, import_pdf7, IMAGE_RESOLVE_TIMEOUT_MS, MIN_DIM, MAX_PIXELS2, MAX_IMAGES_PER_DOC, MAX_TOTAL_IMAGE_BYTES, NO_BYTES;
28661
29569
  var init_image_extract = __esm({
28662
29570
  ".kordoc-source/src/pdf/image-extract.ts"() {
28663
29571
  "use strict";
28664
29572
  init_cjs_shims();
28665
29573
  import_node_crypto2 = require("crypto");
28666
- import_pdf5 = require("pdfjs-dist/legacy/build/pdf.mjs");
29574
+ import_pdf7 = require("pdfjs-dist/legacy/build/pdf.mjs");
28667
29575
  init_transcode();
28668
29576
  IMAGE_RESOLVE_TIMEOUT_MS = 5e3;
28669
29577
  MIN_DIM = 8;
@@ -28848,55 +29756,55 @@ function collectGlyphPaths(fnArray, argsArray) {
28848
29756
  const op = fnArray[i];
28849
29757
  const args = argsArray[i];
28850
29758
  switch (op) {
28851
- case import_pdf6.OPS.save:
29759
+ case import_pdf8.OPS.save:
28852
29760
  stack.push([ctm, color]);
28853
29761
  break;
28854
- case import_pdf6.OPS.restore:
29762
+ case import_pdf8.OPS.restore:
28855
29763
  [ctm, color] = (_a2 = stack.pop()) != null ? _a2 : [[1, 0, 0, 1, 0, 0], 0];
28856
29764
  break;
28857
- case import_pdf6.OPS.transform:
29765
+ case import_pdf8.OPS.transform:
28858
29766
  ctm = mul(ctm, args);
28859
29767
  break;
28860
- case import_pdf6.OPS.paintFormXObjectBegin: {
29768
+ case import_pdf8.OPS.paintFormXObjectBegin: {
28861
29769
  stack.push([ctm, color]);
28862
29770
  const m = args[0];
28863
29771
  if (Array.isArray(m) && m.length >= 6) ctm = mul(ctm, m);
28864
29772
  break;
28865
29773
  }
28866
- case import_pdf6.OPS.paintFormXObjectEnd:
29774
+ case import_pdf8.OPS.paintFormXObjectEnd:
28867
29775
  [ctm, color] = (_b = stack.pop()) != null ? _b : [[1, 0, 0, 1, 0, 0], 0];
28868
29776
  break;
28869
- case import_pdf6.OPS.setFillRGBColor: {
29777
+ case import_pdf8.OPS.setFillRGBColor: {
28870
29778
  const c = args;
28871
29779
  color = c[0] << 16 | c[1] << 8 | c[2];
28872
29780
  break;
28873
29781
  }
28874
- case import_pdf6.OPS.constructPath: {
29782
+ case import_pdf8.OPS.constructPath: {
28875
29783
  const [subOps, coords] = args;
28876
29784
  if (!Array.isArray(subOps) || !Array.isArray(coords)) break;
28877
29785
  ops.push(i);
28878
29786
  let ci = 0;
28879
29787
  for (const s of subOps) {
28880
- if (s === import_pdf6.OPS.moveTo) {
29788
+ if (s === import_pdf8.OPS.moveTo) {
28881
29789
  add2(coords[ci], coords[ci + 1]);
28882
29790
  ci += 2;
28883
29791
  subs++;
28884
- } else if (s === import_pdf6.OPS.lineTo) {
29792
+ } else if (s === import_pdf8.OPS.lineTo) {
28885
29793
  add2(coords[ci], coords[ci + 1]);
28886
29794
  ci += 2;
28887
29795
  segs++;
28888
- } else if (s === import_pdf6.OPS.curveTo) {
29796
+ } else if (s === import_pdf8.OPS.curveTo) {
28889
29797
  add2(coords[ci], coords[ci + 1]);
28890
29798
  add2(coords[ci + 2], coords[ci + 3]);
28891
29799
  add2(coords[ci + 4], coords[ci + 5]);
28892
29800
  ci += 6;
28893
29801
  segs++;
28894
- } else if (s === import_pdf6.OPS.curveTo2 || s === import_pdf6.OPS.curveTo3) {
29802
+ } else if (s === import_pdf8.OPS.curveTo2 || s === import_pdf8.OPS.curveTo3) {
28895
29803
  add2(coords[ci], coords[ci + 1]);
28896
29804
  add2(coords[ci + 2], coords[ci + 3]);
28897
29805
  ci += 4;
28898
29806
  segs++;
28899
- } else if (s === import_pdf6.OPS.rectangle) {
29807
+ } else if (s === import_pdf8.OPS.rectangle) {
28900
29808
  const rx = coords[ci], ry = coords[ci + 1], rw = coords[ci + 2], rh = coords[ci + 3];
28901
29809
  add2(rx, ry);
28902
29810
  add2(rx + rw, ry + rh);
@@ -28910,12 +29818,12 @@ function collectGlyphPaths(fnArray, argsArray) {
28910
29818
  }
28911
29819
  break;
28912
29820
  }
28913
- case import_pdf6.OPS.fill:
28914
- case import_pdf6.OPS.eoFill:
28915
- case import_pdf6.OPS.fillStroke:
28916
- case import_pdf6.OPS.eoFillStroke:
28917
- case import_pdf6.OPS.closeFillStroke:
28918
- case import_pdf6.OPS.closeEOFillStroke: {
29821
+ case import_pdf8.OPS.fill:
29822
+ case import_pdf8.OPS.eoFill:
29823
+ case import_pdf8.OPS.fillStroke:
29824
+ case import_pdf8.OPS.eoFillStroke:
29825
+ case import_pdf8.OPS.closeFillStroke:
29826
+ case import_pdf8.OPS.closeEOFillStroke: {
28919
29827
  const w = x2 - x1, h = y2 - y1;
28920
29828
  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) {
28921
29829
  out.push({ x1, y1, x2, y2, segs, subs, color, ops: [...ops, i] });
@@ -28923,9 +29831,9 @@ function collectGlyphPaths(fnArray, argsArray) {
28923
29831
  reset();
28924
29832
  break;
28925
29833
  }
28926
- case import_pdf6.OPS.stroke:
28927
- case import_pdf6.OPS.closeStroke:
28928
- case import_pdf6.OPS.endPath:
29834
+ case import_pdf8.OPS.stroke:
29835
+ case import_pdf8.OPS.closeStroke:
29836
+ case import_pdf8.OPS.endPath:
28929
29837
  reset();
28930
29838
  break;
28931
29839
  }
@@ -28999,18 +29907,18 @@ function ocrVectorOps(opList, paths) {
28999
29907
  const argsArray = [];
29000
29908
  for (let i = 0; i < opList.fnArray.length; i++) {
29001
29909
  const op = opList.fnArray[i];
29002
- if (drop.has(i) || op === import_pdf6.OPS.clip || op === import_pdf6.OPS.eoClip) continue;
29910
+ if (drop.has(i) || op === import_pdf8.OPS.clip || op === import_pdf8.OPS.eoClip) continue;
29003
29911
  fnArray.push(op);
29004
29912
  argsArray.push(opList.argsArray[i]);
29005
29913
  }
29006
29914
  return { fnArray, argsArray };
29007
29915
  }
29008
- var import_pdf6, GLYPH_MIN_H, GLYPH_MAX_H, GLYPH_MAX_ASPECT, GLYPH_MIN_SEGS, GLYPH_MIN_SUBS, RUN_GAP_EM, RUN_MIN, RUN_ALIGN_EM, RUN_MAX_OVERLAP, RUN_MIN_COLOR, RUN_MIN_SHAPES, mul, median3, spread;
29916
+ var import_pdf8, GLYPH_MIN_H, GLYPH_MAX_H, GLYPH_MAX_ASPECT, GLYPH_MIN_SEGS, GLYPH_MIN_SUBS, RUN_GAP_EM, RUN_MIN, RUN_ALIGN_EM, RUN_MAX_OVERLAP, RUN_MIN_COLOR, RUN_MIN_SHAPES, mul, median3, spread;
29009
29917
  var init_vector_glyphs = __esm({
29010
29918
  ".kordoc-source/src/pdf/vector-glyphs.ts"() {
29011
29919
  "use strict";
29012
29920
  init_cjs_shims();
29013
- import_pdf6 = require("pdfjs-dist/legacy/build/pdf.mjs");
29921
+ import_pdf8 = require("pdfjs-dist/legacy/build/pdf.mjs");
29014
29922
  GLYPH_MIN_H = 3;
29015
29923
  GLYPH_MAX_H = 40;
29016
29924
  GLYPH_MAX_ASPECT = 2;
@@ -29296,6 +30204,15 @@ function filledToBottom(U, bottom) {
29296
30204
  const lu = U[U.length - 1];
29297
30205
  return lu.y - bottom < (U[0].y - lu.y) / (U.length - 1) + FILL_SLACK * (lu.h || 10);
29298
30206
  }
30207
+ function nextItemHead(prev, next) {
30208
+ const a = ITEM_MARK.exec(prev), b = ITEM_MARK.exec(next);
30209
+ if (!a || !b) return false;
30210
+ const succ = (x, y) => /^\d+$/.test(x) ? /^\d+$/.test(y) && Number(y) === Number(x) + 1 : KO_ITEMS.indexOf(x) >= 0 && KO_ITEMS.indexOf(y) === KO_ITEMS.indexOf(x) + 1;
30211
+ if (a[1] && b[1]) return succ(a[1], b[1]);
30212
+ if (a[2] && b[2]) return succ(a[2], b[2]) && prev.trimStart()[a[2].length] === next.trimStart()[b[2].length];
30213
+ if (a[3] && b[3]) return succ(a[3], b[3]);
30214
+ return false;
30215
+ }
29299
30216
  function continuesAcross(u, d, x1, x2) {
29300
30217
  const U = CELL_LINES.get(u), D = CELL_LINES.get(d);
29301
30218
  if (!(U == null ? void 0 : U.length) || !(D == null ? void 0 : D.length)) return false;
@@ -29424,6 +30341,11 @@ function mergeSplitRow(table3, owner, first, colXs, textOnly = false, cut = NO_C
29424
30341
  if (!carriedSplit) {
29425
30342
  const norm2 = (c) => flowText(c.text).replace(/\s+/g, "");
29426
30343
  if (pairs.some(([u, d]) => hasContent(d.cell) && norm2(cell2(d)) !== norm2(cell2(u)) && lineEnded(cell2(u), colXs[u.c], colXs[u.c + u.cs], cell2(d)))) return false;
30344
+ const oneLine = (c) => {
30345
+ var _a2;
30346
+ return ((_a2 = CELL_LINES.get(c)) == null ? void 0 : _a2.length) === 1;
30347
+ };
30348
+ if (pairs.some(([u, d]) => nextItemHead(cell2(u).text, cell2(d).text)) && pairs.some(([u, d]) => hasContent(u.cell) && hasContent(d.cell) && oneLine(cell2(u)) && oneLine(cell2(d)) && norm2(cell2(u)) !== norm2(cell2(d)))) return false;
29427
30349
  const flows = ([u, d]) => continuesAcross(cell2(u), cell2(d), colXs[u.c], colXs[u.c + u.cs]) || clauseContinues(cell2(u), cell2(d));
29428
30350
  if (!(cut.open && !newCell)) {
29429
30351
  if (pairs.some((p) => p[1].rs > 1 && !flows(p))) return false;
@@ -29484,7 +30406,7 @@ function sameHeadShape(a, b) {
29484
30406
  let tall = false;
29485
30407
  for (let c = 0; c < a.length; c++) {
29486
30408
  if (a[c].colSpan !== b[c].colSpan || a[c].rowSpan !== b[c].rowSpan) return false;
29487
- if (a[c].rowSpan >= 2 && a[c].text.trim()) tall = true;
30409
+ if (a[c].rowSpan >= 2 && a[c].text.trim() && b[c].text.trim()) tall = true;
29488
30410
  }
29489
30411
  return tall;
29490
30412
  }
@@ -29522,9 +30444,10 @@ function mergeCrossPageTables(blocks, pageHeights, lex) {
29522
30444
  if (px && cx && !shiftedSame(px, cx, !CLIP_TABLES.has(prev.table) && !CLIP_TABLES.has(curr.table))) continue;
29523
30445
  if (!rowTextsEqual(prev.table.cells[0], curr.table.cells[0]) && sameHeadShape(prev.table.cells[0], curr.table.cells[0])) continue;
29524
30446
  let currCells = curr.table.cells;
29525
- if (currCells.length > 1 && prev.table.cells.length > 0 && rowTextsEqual(prev.table.cells[0], currCells[0])) {
29526
- currCells = currCells.slice(1);
29527
- }
30447
+ const headRows = repeatedHeaderRows(prev.table, curr.table);
30448
+ if (headRows < 0) continue;
30449
+ if (headRows) currCells = currCells.slice(headRows);
30450
+ if (currCells.length) continueRowSpans(prev.table.cells, currCells);
29528
30451
  if (currCells.length === 0) {
29529
30452
  blocks.splice(j, 1);
29530
30453
  continue;
@@ -29734,6 +30657,45 @@ function chainHead(blocks, i, pageHeights) {
29734
30657
  }
29735
30658
  return k;
29736
30659
  }
30660
+ function continueRowSpans(prevCells, currCells) {
30661
+ var _a2;
30662
+ const first = currCells[0];
30663
+ const last = prevCells.length;
30664
+ for (let c = 0; c < first.length; c++) {
30665
+ const cell2 = first[c];
30666
+ if (hasContent(cell2) || (cell2.rowSpan || 1) < 2) continue;
30667
+ let anchor;
30668
+ for (let r = last - 1; r >= 0 && !anchor; r--) {
30669
+ const a = (_a2 = prevCells[r]) == null ? void 0 : _a2[c];
30670
+ if (a && r + (a.rowSpan || 1) === last && (a.colSpan || 1) === (cell2.colSpan || 1) && (hasContent(a) || a.rowSpan >= 2)) anchor = a;
30671
+ }
30672
+ if (!anchor) continue;
30673
+ if (!hasContent(anchor)) {
30674
+ ROW_CONTINUATIONS.set(anchor, cell2);
30675
+ continue;
30676
+ }
30677
+ for (let part = cell2; part; ) {
30678
+ const next = ROW_CONTINUATIONS.get(part);
30679
+ anchor.rowSpan = (anchor.rowSpan || 1) + part.rowSpan;
30680
+ part.rowSpan = 1;
30681
+ part.colSpan = 1;
30682
+ ROW_CONTINUATIONS.delete(part);
30683
+ part = next;
30684
+ }
30685
+ }
30686
+ }
30687
+ function repeatedHeaderRows(prev, curr) {
30688
+ if (!rowTextsEqual(prev.cells[0], curr.cells[0])) return 0;
30689
+ const pa = anchorsOf2(prev), ca = anchorsOf2(curr);
30690
+ let depth = 1;
30691
+ for (let r = 0; r < depth && r < prev.rows; r++) {
30692
+ for (const a of pa) if (a.r === r) depth = Math.max(depth, r + a.rs);
30693
+ }
30694
+ if (depth >= curr.rows || depth > prev.rows) return -1;
30695
+ const p = pa.filter((a) => a.r < depth), d = ca.filter((a) => a.r < depth);
30696
+ const norm2 = (text2) => flowText(text2).replace(/\s+/g, "");
30697
+ return p.length === d.length && p.every((a, i) => a.r === d[i].r && a.c === d[i].c && a.rs === d[i].rs && a.cs === d[i].cs && norm2(a.cell.text) === norm2(d[i].cell.text)) ? depth : -1;
30698
+ }
29737
30699
  function rowTextsEqual(a, b) {
29738
30700
  if (a.length !== b.length) return false;
29739
30701
  const norm2 = (t) => flowText(t).replace(/\s+/g, "");
@@ -29747,7 +30709,7 @@ function shiftedSame(px, cx, allowShift = true) {
29747
30709
  const dx = allowShift ? px[px.length - 1] - cx[cx.length - 1] : 0;
29748
30710
  return px.every((x, k) => Math.abs(x - cx[k] - dx) <= CONTINUATION_COL_TOL);
29749
30711
  }
29750
- var flowText, PART_COL_TOL, PART_COL_SNAP, indexOf, rowText, hasText, FULL_LINE_TOL, FULL_LINE_MIN_FRAC, FULL_LINE_EDGE_MIN, SINGLE_LINE_WORD_GAP, SHORT_LINE_GAP, STRADDLE_MAX_LINES, STRADDLE_BOTTOM, STRADDLE_BOTTOM_ONE_ROW, FILL_SLACK, CARRIED_MIN_COL_W, LABEL_ROOM, HANGING_MIN, HANGING_TOL, OUTLINE_HEAD, OUTLINE_ITEM, hasContent, CLAUSE_OPEN_ENDING, batchim, KO_ORDER, NO_CUT, NEIGHBOR_TABLE_EPSILON, PAGE_NUMBER_TEXT, ANNEX_HEAD_RE, CONTINUATION_COL_TOL, FOREIGN_FIRST_ROW_CELLS, PAGE_EDGE_BAND, RESTART_MIN_ANCHORS, TITLE_ROW_MAX_CHARS, RESTART_LOOKBACK_PAGES;
30712
+ var flowText, PART_COL_TOL, PART_COL_SNAP, indexOf, rowText, hasText, FULL_LINE_TOL, FULL_LINE_MIN_FRAC, FULL_LINE_EDGE_MIN, SINGLE_LINE_WORD_GAP, SHORT_LINE_GAP, STRADDLE_MAX_LINES, STRADDLE_BOTTOM, STRADDLE_BOTTOM_ONE_ROW, FILL_SLACK, CARRIED_MIN_COL_W, LABEL_ROOM, HANGING_MIN, HANGING_TOL, KO_ITEMS, ITEM_MARK, OUTLINE_HEAD, OUTLINE_ITEM, hasContent, CLAUSE_OPEN_ENDING, batchim, KO_ORDER, NO_CUT, NEIGHBOR_TABLE_EPSILON, PAGE_NUMBER_TEXT, ANNEX_HEAD_RE, ROW_CONTINUATIONS, CONTINUATION_COL_TOL, FOREIGN_FIRST_ROW_CELLS, PAGE_EDGE_BAND, RESTART_MIN_ANCHORS, TITLE_ROW_MAX_CHARS, RESTART_LOOKBACK_PAGES;
29751
30713
  var init_table_parts = __esm({
29752
30714
  ".kordoc-source/src/pdf/table-parts.ts"() {
29753
30715
  "use strict";
@@ -29786,6 +30748,8 @@ var init_table_parts = __esm({
29786
30748
  LABEL_ROOM = 1.5;
29787
30749
  HANGING_MIN = 0.5;
29788
30750
  HANGING_TOL = 1;
30751
+ KO_ITEMS = "\uAC00\uB098\uB2E4\uB77C\uB9C8\uBC14\uC0AC\uC544\uC790\uCC28\uCE74\uD0C0\uD30C\uD558\uAC70\uB108\uB354\uB7EC\uBA38\uBC84\uC11C\uC5B4\uC800\uCC98\uCEE4\uD130\uD37C\uD5C8\uACE0\uB178\uB3C4\uB85C\uBAA8\uBCF4\uC18C\uC624\uC870\uCD08\uCF54\uD1A0\uD3EC\uD638\uAD6C\uB204\uB450\uB8E8\uBB34\uBD80\uC218\uC6B0\uC8FC\uCD94\uCFE0\uD22C\uD478\uD6C4";
30752
+ ITEM_MARK = /^\s*(?:([가-힣])\.|(\d{1,3})[.)]|\(([가-힣\d]{1,3})\))(?=\s)/;
29789
30753
  OUTLINE_HEAD = /^[□■]\s*\S/;
29790
30754
  OUTLINE_ITEM = /^[ㅇ○◦\-‐–·․‧※*]\s*\S/;
29791
30755
  hasContent = (cell2) => {
@@ -29802,6 +30766,7 @@ var init_table_parts = __esm({
29802
30766
  NEIGHBOR_TABLE_EPSILON = 0.2;
29803
30767
  PAGE_NUMBER_TEXT = /^[-–—]?\s*\d{1,4}\s*[-–—]?$/;
29804
30768
  ANNEX_HEAD_RE = /^\s*[<\[(【]?\s*(?:붙\s*임|참\s*고|별\s*첨|별\s*지|별\s*표|첨\s*부|부\s*록)(?:\s*\d|\s*$|\s*[>\])】])|^\s*■/;
30769
+ ROW_CONTINUATIONS = /* @__PURE__ */ new WeakMap();
29805
30770
  CONTINUATION_COL_TOL = 2;
29806
30771
  FOREIGN_FIRST_ROW_CELLS = 3;
29807
30772
  PAGE_EDGE_BAND = 0.16;
@@ -29902,6 +30867,41 @@ var init_cell_continuation = __esm({
29902
30867
  }
29903
30868
  });
29904
30869
 
30870
+ // .kordoc-source/src/pdf/selection-context.ts
30871
+ function selectionContextPages(selected, pageCount) {
30872
+ const out = /* @__PURE__ */ new Set();
30873
+ for (const page of selected) {
30874
+ for (let distance = 1; distance <= 4; distance++) {
30875
+ for (const neighbor2 of [page - distance, page + distance]) {
30876
+ if (neighbor2 < 1 || neighbor2 > pageCount || selected.has(neighbor2)) continue;
30877
+ out.add(neighbor2);
30878
+ }
30879
+ }
30880
+ }
30881
+ return [...out].sort((a, b) => a - b);
30882
+ }
30883
+ function marginContextBlocks(raw, page, view) {
30884
+ const [x1, y1, x2, y2] = view;
30885
+ const width = x2 - x1, height = y2 - y1;
30886
+ const items = filterHiddenText(normalizeItems(raw), width, height, x1, y1).visible;
30887
+ for (const item of items) {
30888
+ item.x -= x1;
30889
+ item.y -= y1;
30890
+ }
30891
+ return groupByY(items).flatMap((line) => {
30892
+ const bbox = computeBBox(line, page);
30893
+ if (bbox.y + bbox.height < height * 0.88 && bbox.y > height * 0.12) return [];
30894
+ return [{ type: "paragraph", text: mergeLineSimple(line), pageNumber: page, bbox, style: dominantStyle(line) }];
30895
+ });
30896
+ }
30897
+ var init_selection_context = __esm({
30898
+ ".kordoc-source/src/pdf/selection-context.ts"() {
30899
+ "use strict";
30900
+ init_cjs_shims();
30901
+ init_text_line();
30902
+ }
30903
+ });
30904
+
29905
30905
  // .kordoc-source/src/pdf/symbol-fonts.ts
29906
30906
  function symbolFontTable(fontName) {
29907
30907
  if (!fontName) return void 0;
@@ -30205,7 +31205,9 @@ function glyphNameText(name) {
30205
31205
  let out = "";
30206
31206
  for (const part of base2.split("_")) {
30207
31207
  const uni = (_a2 = /^uni([0-9A-F]{4})$/.exec(part)) != null ? _a2 : /^u([0-9A-F]{4,6})$/.exec(part);
30208
- const ch = /^[A-Za-z]$/.test(part) ? part : (_b = NAMED[part]) != null ? _b : uni ? String.fromCodePoint(parseInt(uni[1], 16)) : void 0;
31208
+ const code2 = uni ? parseInt(uni[1], 16) : void 0;
31209
+ if (code2 !== void 0 && (code2 > 1114111 || code2 >= 55296 && code2 <= 57343)) return void 0;
31210
+ const ch = /^[A-Za-z]$/.test(part) ? part : (_b = NAMED[part]) != null ? _b : code2 !== void 0 ? String.fromCodePoint(code2) : void 0;
30209
31211
  if (ch === void 0) return void 0;
30210
31212
  out += ch;
30211
31213
  }
@@ -30255,10 +31257,10 @@ function restoreNamedGlyphs(items, fnArray, argsArray, differencesOf, faceOf = (
30255
31257
  for (let i = 0; i < fnArray.length; i++) {
30256
31258
  const fn = fnArray[i];
30257
31259
  const args = argsArray[i];
30258
- if (fn === import_pdf7.OPS.setFont) font = String(args[0]);
30259
- else if (fn === import_pdf7.OPS.save || fn === import_pdf7.OPS.paintFormXObjectBegin) saved.push(font);
30260
- else if (fn === import_pdf7.OPS.restore || fn === import_pdf7.OPS.paintFormXObjectEnd) font = (_b = saved.pop()) != null ? _b : font;
30261
- else if (fn === import_pdf7.OPS.showText && targets.get(font)) {
31260
+ if (fn === import_pdf9.OPS.setFont) font = String(args[0]);
31261
+ else if (fn === import_pdf9.OPS.save || fn === import_pdf9.OPS.paintFormXObjectBegin) saved.push(font);
31262
+ else if (fn === import_pdf9.OPS.restore || fn === import_pdf9.OPS.paintFormXObjectEnd) font = (_b = saved.pop()) != null ? _b : font;
31263
+ else if (fn === import_pdf9.OPS.showText && targets.get(font)) {
30262
31264
  let list2 = streams.get(font);
30263
31265
  if (!list2) streams.set(font, list2 = []);
30264
31266
  for (const g4 of args[0]) if (g4 && typeof g4 === "object") list2.push(g4);
@@ -30289,7 +31291,7 @@ function restoreNamedGlyphs(items, fnArray, argsArray, differencesOf, faceOf = (
30289
31291
  const code2 = (_g = g4.originalCharCode) != null ? _g : -1;
30290
31292
  const name = diffs[code2];
30291
31293
  const raw = (_h = g4.unicode) != null ? _h : "";
30292
- const exp = /^\p{Cf}$/u.test(raw) ? "" : (0, import_pdf7.normalizeUnicode)(raw);
31294
+ const exp = /^\p{Cf}$/u.test(raw) ? "" : (0, import_pdf9.normalizeUnicode)(raw);
30293
31295
  const tex = texCmGlyph(faceOf(fontName), code2, name);
30294
31296
  if (tex !== void 0 && (exp === "" || s.startsWith(exp, k))) {
30295
31297
  out += tex;
@@ -30327,7 +31329,7 @@ function restoreNamedGlyphs(items, fnArray, argsArray, differencesOf, faceOf = (
30327
31329
  continue;
30328
31330
  }
30329
31331
  let j = gi + 1;
30330
- while (j < glyphs.length && j <= gi + 8 && !s.startsWith((0, import_pdf7.normalizeUnicode)((_i = glyphs[j].unicode) != null ? _i : "") || "\0", k)) j++;
31332
+ while (j < glyphs.length && j <= gi + 8 && !s.startsWith((0, import_pdf9.normalizeUnicode)((_i = glyphs[j].unicode) != null ? _i : "") || "\0", k)) j++;
30331
31333
  if (j < glyphs.length && j <= gi + 8) {
30332
31334
  gi = j;
30333
31335
  continue;
@@ -30348,12 +31350,12 @@ function restoreNamedGlyphs(items, fnArray, argsArray, differencesOf, faceOf = (
30348
31350
  }
30349
31351
  return changed;
30350
31352
  }
30351
- var import_pdf7, NAMED, isSmallCapName, isRestorableCode, TEX_CM_SYMBOL_NAMES, TEX_CM_ITALIC_CODES, texCmGlyph;
31353
+ var import_pdf9, NAMED, isSmallCapName, isRestorableCode, TEX_CM_SYMBOL_NAMES, TEX_CM_ITALIC_CODES, texCmGlyph;
30352
31354
  var init_glyph_names = __esm({
30353
31355
  ".kordoc-source/src/pdf/glyph-names.ts"() {
30354
31356
  "use strict";
30355
31357
  init_cjs_shims();
30356
- import_pdf7 = require("pdfjs-dist/legacy/build/pdf.mjs");
31358
+ import_pdf9 = require("pdfjs-dist/legacy/build/pdf.mjs");
30357
31359
  NAMED = {
30358
31360
  zero: "0",
30359
31361
  one: "1",
@@ -30385,6 +31387,9 @@ var init_glyph_names = __esm({
30385
31387
  quotedblright: "\u201D",
30386
31388
  quotesingle: "'",
30387
31389
  quotedbl: '"',
31390
+ bullet: "\u2022",
31391
+ openbullet: "\u25E6",
31392
+ whitebullet: "\u25E6",
30388
31393
  question: "?",
30389
31394
  exclam: "!",
30390
31395
  percent: "%",
@@ -30437,15 +31442,15 @@ function occludedTextItems(items, fnArray, argsArray) {
30437
31442
  for (let i = 0; i < fnArray.length; i++) {
30438
31443
  const fn = fnArray[i];
30439
31444
  const args = argsArray[i];
30440
- if (fn === import_pdf8.OPS.save || fn === import_pdf8.OPS.paintFormXObjectBegin) {
31445
+ if (fn === import_pdf10.OPS.save || fn === import_pdf10.OPS.paintFormXObjectBegin) {
30441
31446
  stack.push({ ctm: ctm.slice(), alpha, normalBlend, clip });
30442
- const m = fn === import_pdf8.OPS.paintFormXObjectBegin ? args[0] : null;
31447
+ const m = fn === import_pdf10.OPS.paintFormXObjectBegin ? args[0] : null;
30443
31448
  if (Array.isArray(m) && m.length >= 6) ctm = mul2(ctm, m);
30444
- } else if (fn === import_pdf8.OPS.restore || fn === import_pdf8.OPS.paintFormXObjectEnd) {
31449
+ } else if (fn === import_pdf10.OPS.restore || fn === import_pdf10.OPS.paintFormXObjectEnd) {
30445
31450
  const s = stack.pop();
30446
31451
  if (s) ({ ctm, alpha, normalBlend, clip } = s);
30447
- } else if (fn === import_pdf8.OPS.transform) ctm = mul2(ctm, args);
30448
- else if (fn === import_pdf8.OPS.setGState) {
31452
+ } else if (fn === import_pdf10.OPS.transform) ctm = mul2(ctm, args);
31453
+ else if (fn === import_pdf10.OPS.setGState) {
30449
31454
  const entries = args[0];
30450
31455
  if (Array.isArray(entries)) for (const e of entries) {
30451
31456
  if (!Array.isArray(e)) continue;
@@ -30453,11 +31458,11 @@ function occludedTextItems(items, fnArray, argsArray) {
30453
31458
  else if (e[0] === "BM") normalBlend = e[1] === "source-over" || e[1] === "Normal";
30454
31459
  else if (e[0] === "SMask" && e[1]) normalBlend = false;
30455
31460
  }
30456
- } else if (fn === import_pdf8.OPS.showText) {
31461
+ } else if (fn === import_pdf10.OPS.showText) {
30457
31462
  for (const g4 of args[0]) {
30458
31463
  if (g4 && typeof g4 === "object" && typeof g4.unicode === "string") drawn += glyphText(g4.unicode);
30459
31464
  }
30460
- } else if (fn === import_pdf8.OPS.constructPath) {
31465
+ } else if (fn === import_pdf10.OPS.constructPath) {
30461
31466
  const sub = args[0];
30462
31467
  const coords = args[1];
30463
31468
  if (!Array.isArray(sub)) {
@@ -30466,18 +31471,18 @@ function occludedTextItems(items, fnArray, argsArray) {
30466
31471
  }
30467
31472
  let ci = 0;
30468
31473
  for (const op of sub) {
30469
- if (op === import_pdf8.OPS.rectangle) {
31474
+ if (op === import_pdf10.OPS.rectangle) {
30470
31475
  path.push(box(coords[ci], coords[ci + 1], coords[ci + 2], coords[ci + 3]));
30471
31476
  ci += 4;
30472
31477
  } else {
30473
31478
  pathOk = false;
30474
- ci += op === import_pdf8.OPS.curveTo ? 6 : op === import_pdf8.OPS.curveTo2 || op === import_pdf8.OPS.curveTo3 ? 4 : op === import_pdf8.OPS.closePath ? 0 : 2;
31479
+ ci += op === import_pdf10.OPS.curveTo ? 6 : op === import_pdf10.OPS.curveTo2 || op === import_pdf10.OPS.curveTo3 ? 4 : op === import_pdf10.OPS.closePath ? 0 : 2;
30475
31480
  }
30476
31481
  }
30477
- } else if (fn === import_pdf8.OPS.clip || fn === import_pdf8.OPS.eoClip) {
31482
+ } else if (fn === import_pdf10.OPS.clip || fn === import_pdf10.OPS.eoClip) {
30478
31483
  clip = clip === null || !pathOk || path.length !== 1 ? null : clip ? meet(clip, path[0]) : path[0];
30479
- } else if (fn === import_pdf8.OPS.fill || fn === import_pdf8.OPS.eoFill || fn === import_pdf8.OPS.fillStroke || fn === import_pdf8.OPS.eoFillStroke || fn === import_pdf8.OPS.endPath || fn === import_pdf8.OPS.stroke || fn === import_pdf8.OPS.closeStroke || fn === import_pdf8.OPS.closeFillStroke || fn === import_pdf8.OPS.closeEOFillStroke) {
30480
- const fills = fn !== import_pdf8.OPS.endPath && fn !== import_pdf8.OPS.stroke && fn !== import_pdf8.OPS.closeStroke;
31484
+ } else if (fn === import_pdf10.OPS.fill || fn === import_pdf10.OPS.eoFill || fn === import_pdf10.OPS.fillStroke || fn === import_pdf10.OPS.eoFillStroke || fn === import_pdf10.OPS.endPath || fn === import_pdf10.OPS.stroke || fn === import_pdf10.OPS.closeStroke || fn === import_pdf10.OPS.closeFillStroke || fn === import_pdf10.OPS.closeEOFillStroke) {
31485
+ const fills = fn !== import_pdf10.OPS.endPath && fn !== import_pdf10.OPS.stroke && fn !== import_pdf10.OPS.closeStroke;
30481
31486
  if (fills && pathOk && path.length === 1 && alpha >= 1 && normalBlend && clip !== null && drawn.length > 0) {
30482
31487
  const rect = clip ? meet(path[0], clip) : path[0];
30483
31488
  if (rect.x2 > rect.x1 && rect.y2 > rect.y1) covers.push({ at: drawn.length, rect });
@@ -30512,13 +31517,13 @@ function mul2(m, t) {
30512
31517
  m[1] * t[4] + m[3] * t[5] + m[5]
30513
31518
  ];
30514
31519
  }
30515
- var import_pdf8, glyphText;
31520
+ var import_pdf10, glyphText;
30516
31521
  var init_occluded_text = __esm({
30517
31522
  ".kordoc-source/src/pdf/occluded-text.ts"() {
30518
31523
  "use strict";
30519
31524
  init_cjs_shims();
30520
- import_pdf8 = require("pdfjs-dist/legacy/build/pdf.mjs");
30521
- glyphText = (s) => (0, import_pdf8.normalizeUnicode)(s).replace(/\s+/g, "");
31525
+ import_pdf10 = require("pdfjs-dist/legacy/build/pdf.mjs");
31526
+ glyphText = (s) => (0, import_pdf10.normalizeUnicode)(s).replace(/\s+/g, "");
30522
31527
  }
30523
31528
  });
30524
31529
 
@@ -30614,14 +31619,14 @@ function restoreTrackedSpacing(items, fnArray, argsArray) {
30614
31619
  for (let i = 0; i < fnArray.length; i++) {
30615
31620
  const fn = fnArray[i];
30616
31621
  const args = argsArray[i];
30617
- if (fn === import_pdf9.OPS.setFont) font = String(args[0]);
30618
- else if (fn === import_pdf9.OPS.save || fn === import_pdf9.OPS.paintFormXObjectBegin) saved.push(font);
30619
- else if (fn === import_pdf9.OPS.restore || fn === import_pdf9.OPS.paintFormXObjectEnd) font = (_a2 = saved.pop()) != null ? _a2 : font;
30620
- else if (fn === import_pdf9.OPS.showText) {
31622
+ if (fn === import_pdf11.OPS.setFont) font = String(args[0]);
31623
+ else if (fn === import_pdf11.OPS.save || fn === import_pdf11.OPS.paintFormXObjectBegin) saved.push(font);
31624
+ else if (fn === import_pdf11.OPS.restore || fn === import_pdf11.OPS.paintFormXObjectEnd) font = (_a2 = saved.pop()) != null ? _a2 : font;
31625
+ else if (fn === import_pdf11.OPS.showText) {
30621
31626
  let list2 = streams.get(font);
30622
31627
  if (!list2) streams.set(font, list2 = []);
30623
31628
  for (const g4 of args[0]) {
30624
- if (g4 && typeof g4 === "object" && typeof g4.unicode === "string") list2.push((0, import_pdf9.normalizeUnicode)(g4.unicode));
31629
+ if (g4 && typeof g4 === "object" && typeof g4.unicode === "string") list2.push((0, import_pdf11.normalizeUnicode)(g4.unicode));
30625
31630
  }
30626
31631
  }
30627
31632
  }
@@ -30666,14 +31671,14 @@ function markSyntheticSpaces(items, fnArray, argsArray) {
30666
31671
  for (let i = 0; i < fnArray.length; i++) {
30667
31672
  const fn = fnArray[i];
30668
31673
  const args = argsArray[i];
30669
- if (fn === import_pdf9.OPS.setFont) font = String(args[0]);
30670
- else if (fn === import_pdf9.OPS.save || fn === import_pdf9.OPS.paintFormXObjectBegin) saved.push(font);
30671
- else if (fn === import_pdf9.OPS.restore || fn === import_pdf9.OPS.paintFormXObjectEnd) font = (_a2 = saved.pop()) != null ? _a2 : font;
30672
- else if (fn === import_pdf9.OPS.showText) {
31674
+ if (fn === import_pdf11.OPS.setFont) font = String(args[0]);
31675
+ else if (fn === import_pdf11.OPS.save || fn === import_pdf11.OPS.paintFormXObjectBegin) saved.push(font);
31676
+ else if (fn === import_pdf11.OPS.restore || fn === import_pdf11.OPS.paintFormXObjectEnd) font = (_a2 = saved.pop()) != null ? _a2 : font;
31677
+ else if (fn === import_pdf11.OPS.showText) {
30673
31678
  let list2 = streams.get(font);
30674
31679
  if (!list2) streams.set(font, list2 = []);
30675
31680
  for (const g4 of args[0]) {
30676
- if (g4 && typeof g4 === "object" && typeof g4.unicode === "string") list2.push((0, import_pdf9.normalizeUnicode)(g4.unicode));
31681
+ if (g4 && typeof g4 === "object" && typeof g4.unicode === "string") list2.push((0, import_pdf11.normalizeUnicode)(g4.unicode));
30677
31682
  }
30678
31683
  }
30679
31684
  }
@@ -30704,12 +31709,12 @@ function markSyntheticSpaces(items, fnArray, argsArray) {
30704
31709
  }
30705
31710
  for (const it of marks) if (!failed.has((_d = it.fontName) != null ? _d : "")) it.synthetic = true;
30706
31711
  }
30707
- var import_pdf9, TRACKED;
31712
+ var import_pdf11, TRACKED;
30708
31713
  var init_tracked_text = __esm({
30709
31714
  ".kordoc-source/src/pdf/tracked-text.ts"() {
30710
31715
  "use strict";
30711
31716
  init_cjs_shims();
30712
- import_pdf9 = require("pdfjs-dist/legacy/build/pdf.mjs");
31717
+ import_pdf11 = require("pdfjs-dist/legacy/build/pdf.mjs");
30713
31718
  TRACKED = /^(?:[^\s\u1100-\u11ff\u3130-\u318f\uac00-\ud7a3] ){3,}[^\s\u1100-\u11ff\u3130-\u318f\uac00-\ud7a3]$/;
30714
31719
  }
30715
31720
  });
@@ -30871,70 +31876,6 @@ var init_two_up = __esm({
30871
31876
  }
30872
31877
  });
30873
31878
 
30874
- // .kordoc-source/src/pdf/side-tabs.ts
30875
- function removeSideTabs(blocks, pageWidths) {
30876
- var _a2, _b, _c, _d;
30877
- const edges = /* @__PURE__ */ new Map();
30878
- for (const b of blocks) {
30879
- if (!b.bbox || b.pageNumber === void 0 || [...(_b = (_a2 = b.text) == null ? void 0 : _a2.trim()) != null ? _b : ""].length <= MAX_CHARS) continue;
30880
- const e = (_c = edges.get(b.pageNumber)) != null ? _c : { lefts: [], rights: [] };
30881
- e.lefts.push(b.bbox.x);
30882
- e.rights.push(b.bbox.x + b.bbox.width);
30883
- edges.set(b.pageNumber, e);
30884
- }
30885
- const q = (xs, p) => {
30886
- const v = [...xs].sort((a, b) => a - b);
30887
- return v[Math.min(v.length - 1, Math.floor(p * v.length))];
30888
- };
30889
- const body = /* @__PURE__ */ new Map();
30890
- for (const [page, e] of edges) body.set(page, { left: q(e.lefts, 0.2), right: q(e.rights, 0.8) });
30891
- const all = [...body.values()];
30892
- const fallback = all.length ? { left: q(all.map((e) => e.left), 0.5), right: q(all.map((e) => e.right), 0.5) } : void 0;
30893
- const key = (b) => {
30894
- var _a3, _b2;
30895
- const w = b.pageNumber !== void 0 ? pageWidths.get(b.pageNumber) : void 0;
30896
- const text2 = (_a3 = b.text) == null ? void 0 : _a3.trim();
30897
- const area = (_b2 = b.pageNumber !== void 0 ? body.get(b.pageNumber) : void 0) != null ? _b2 : fallback;
30898
- if (!w || !area || !b.bbox || !text2 || b.type === "table" || [...text2].length > MAX_CHARS) return null;
30899
- const side = b.bbox.x + b.bbox.width <= Math.min(w * BAND, area.left - 1) ? "L" : b.bbox.x >= Math.max(w * (1 - BAND), area.right + 1) ? "R" : null;
30900
- return side && text2.replace(/\s+/g, "");
30901
- };
30902
- const pages = /* @__PURE__ */ new Map();
30903
- for (const b of blocks) {
30904
- const k = key(b);
30905
- if (k) pages.set(k, ((_d = pages.get(k)) != null ? _d : /* @__PURE__ */ new Set()).add(b.pageNumber));
30906
- }
30907
- const running = /* @__PURE__ */ new Set();
30908
- for (const [k, ps] of pages) {
30909
- const list2 = [...ps].sort((a, b) => a - b);
30910
- let run = [];
30911
- const flush = () => {
30912
- if (run.length >= MIN_REPEAT && run.length >= (run[run.length - 1] - run[0] + 1) * 0.4) for (const p of run) running.add(`${p}\0${k}`);
30913
- run = [];
30914
- };
30915
- for (const p of list2) {
30916
- if (run.length && p - run[run.length - 1] > RUN_GAP) flush();
30917
- run.push(p);
30918
- }
30919
- flush();
30920
- }
30921
- return running.size ? blocks.filter((b) => {
30922
- const k = key(b);
30923
- return !k || !running.has(`${b.pageNumber}\0${k}`);
30924
- }) : blocks;
30925
- }
30926
- var BAND, MAX_CHARS, MIN_REPEAT, RUN_GAP;
30927
- var init_side_tabs = __esm({
30928
- ".kordoc-source/src/pdf/side-tabs.ts"() {
30929
- "use strict";
30930
- init_cjs_shims();
30931
- BAND = 0.12;
30932
- MAX_CHARS = 10;
30933
- MIN_REPEAT = 3;
30934
- RUN_GAP = 5;
30935
- }
30936
- });
30937
-
30938
31879
  // .kordoc-source/src/pdf/footnotes.ts
30939
31880
  function footnoteSeparators(horizontals, pageWidth, pageHeight) {
30940
31881
  return horizontals.filter((l) => l.x2 - l.x1 >= 30 && l.x2 - l.x1 <= pageWidth * 0.45 && l.y1 < pageHeight * 0.6).map((l) => l.y1);
@@ -31029,7 +31970,7 @@ function unbalancedClose(text2) {
31029
31970
  return ((_b = (_a2 = text2.match(/\)/g)) == null ? void 0 : _a2.length) != null ? _b : 0) > ((_d = (_c = text2.match(/\(/g)) == null ? void 0 : _c.length) != null ? _d : 0);
31030
31971
  }
31031
31972
  function demoteNonHeadingRoles(blocks, pageHeights, faceNames) {
31032
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U;
31973
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da;
31033
31974
  const byPage = /* @__PURE__ */ new Map();
31034
31975
  for (const block2 of blocks) {
31035
31976
  const page = (_b = byPage.get((_a2 = block2.pageNumber) != null ? _a2 : 0)) != null ? _b : [];
@@ -31064,58 +32005,94 @@ function demoteNonHeadingRoles(blocks, pageHeights, faceNames) {
31064
32005
  }
31065
32006
  }
31066
32007
  }
32008
+ const citedProse = /* @__PURE__ */ new Set();
32009
+ const numberedProse = /* @__PURE__ */ new Set();
32010
+ for (const page of byPage.values()) {
32011
+ const numbered = page.filter((b) => {
32012
+ var _a3, _b2, _c2, _d2;
32013
+ return (b.type === "heading" || b.type === "paragraph") && /^[①-⑮]\s*/.test((_b2 = (_a3 = b.text) == null ? void 0 : _a3.trim()) != null ? _b2 : "") && b.bbox && ((_c2 = b.style) == null ? void 0 : _c2.fontName) && b.style.fontSize && !/Bold|Black|Heavy|Semibold/i.test((_d2 = faceNames == null ? void 0 : faceNames.get(b.style.fontName)) != null ? _d2 : "");
32014
+ });
32015
+ let chain = [];
32016
+ const finish = () => {
32017
+ var _a3, _b2, _c2, _d2, _e2, _f2, _g2;
32018
+ if (chain.length < 3 || !chain.some((b) => {
32019
+ var _a4, _b3;
32020
+ return ((_b3 = (_a4 = b.text) == null ? void 0 : _a4.length) != null ? _b3 : 0) >= 40 && b.bbox.height >= b.style.fontSize * 2.4;
32021
+ })) return;
32022
+ for (const b of chain) numberedProse.add(b);
32023
+ const first = chain[0], size = first.style.fontSize;
32024
+ for (const b of page) if (/^[○●•◦]\s/.test((_b2 = (_a3 = b.text) == null ? void 0 : _a3.trim()) != null ? _b2 : "") && ((_c2 = b.style) == null ? void 0 : _c2.fontName) === ((_d2 = first.style) == null ? void 0 : _d2.fontName) && ((_e2 = b.style) == null ? void 0 : _e2.fontSize) === size && b.bbox && Math.abs(b.bbox.x - first.bbox.x) <= size * 0.5 && ((_g2 = (_f2 = b.text) == null ? void 0 : _f2.length) != null ? _g2 : 0) >= 15) numberedProse.add(b);
32025
+ };
32026
+ for (const b of numbered) {
32027
+ const prev = chain.at(-1), size = b.style.fontSize;
32028
+ if (!prev || b.text.trim().charCodeAt(0) !== prev.text.trim().charCodeAt(0) + 1 || b.style.fontName !== prev.style.fontName || size !== prev.style.fontSize || Math.abs(b.bbox.x - prev.bbox.x) > size * 0.5 || prev.bbox.y - (b.bbox.y + b.bbox.height) > size * 8) {
32029
+ finish();
32030
+ chain = [];
32031
+ }
32032
+ chain.push(b);
32033
+ }
32034
+ finish();
32035
+ }
32036
+ for (let i = 0; i + 1 < blocks.length; i++) {
32037
+ const prose = blocks[i], reference2 = blocks[i + 1];
32038
+ const a = prose.bbox, b = reference2.bbox, size = (_i = (_h = prose.style) == null ? void 0 : _h.fontSize) != null ? _i : 0;
32039
+ const source = (_k = (_j = reference2.text) == null ? void 0 : _j.replace(/<[^>]+>/g, "").trim()) != null ? _k : "";
32040
+ if (prose.type !== "heading" && prose.type !== "paragraph" && prose.type !== "list" || reference2.type !== "heading" && reference2.type !== "paragraph" || ((_m = (_l = prose.text) == null ? void 0 : _l.length) != null ? _m : 0) < 40 || !a || !b || size <= 0 || a.height < size * 2.4 || prose.pageNumber !== reference2.pageNumber || ((_n = prose.style) == null ? void 0 : _n.fontName) !== ((_o = reference2.style) == null ? void 0 : _o.fontName) || ((_p = prose.style) == null ? void 0 : _p.fontSize) !== ((_q = reference2.style) == null ? void 0 : _q.fontSize) || Math.abs(a.x - b.x) > size && !(/^[○●•◦]\s/.test((_r = prose.text) != null ? _r : "") && b.x >= a.x && b.x - a.x <= size * 2) || a.y - (b.y + b.height) < 0 || a.y - (b.y + b.height) > size || !/^[((].*(?:제\s*\d+\s*조|(?:Article|Section)\s+\d+).*[))]$/i.test(source)) continue;
32041
+ citedProse.add(prose);
32042
+ citedProse.add(reference2);
32043
+ }
31067
32044
  for (let i = 0; i < blocks.length; i++) {
31068
32045
  const block2 = blocks[i];
31069
32046
  if (block2.type !== "heading" || !block2.text) continue;
31070
32047
  const text2 = block2.text.replace(/<[^>]+>/g, "").trim();
31071
- const fsz = (_i = (_h = block2.style) == null ? void 0 : _h.fontSize) != null ? _i : 0;
32048
+ const fsz = (_t = (_s = block2.style) == null ? void 0 : _s.fontSize) != null ? _t : 0;
31072
32049
  const tocEntry = i > 0 && TOC_BLOCKS.has(blocks[i - 1]) && TOC_BLOCKS.has(blocks[i + 1]);
31073
- const page = (_k = byPage.get((_j = block2.pageNumber) != null ? _j : 0)) != null ? _k : [];
31074
- const proseStyle = ((_l = block2.style) == null ? void 0 : _l.fontName) && bodyStyle.get((_m = block2.pageNumber) != null ? _m : 0) === `${block2.style.fontName}:${block2.style.fontSize}` && text2.length > 60;
32050
+ const page = (_v = byPage.get((_u = block2.pageNumber) != null ? _u : 0)) != null ? _v : [];
32051
+ const proseStyle = ((_w = block2.style) == null ? void 0 : _w.fontName) && bodyStyle.get((_x = block2.pageNumber) != null ? _x : 0) === `${block2.style.fontName}:${block2.style.fontSize}` && text2.length > 60;
31075
32052
  const next = blocks[i + 1];
31076
32053
  const nb = next == null ? void 0 : next.bbox, bb = block2.bbox;
31077
- const chapterNumber = !!nb && !!bb && fsz >= ((_o = (_n = next == null ? void 0 : next.style) == null ? void 0 : _n.fontSize) != null ? _o : 0) * 1.2 && Math.abs(bb.x - nb.x) > fsz && Math.abs(bb.x + bb.width / 2 - (nb.x + nb.width / 2)) < nb.width * 0.1;
32054
+ const chapterNumber = !!nb && !!bb && fsz >= ((_z = (_y = next == null ? void 0 : next.style) == null ? void 0 : _y.fontSize) != null ? _z : 0) * 1.2 && Math.abs(bb.x - nb.x) > fsz && Math.abs(bb.x + bb.width / 2 - (nb.x + nb.width / 2)) < nb.width * 0.1;
31078
32055
  if (/^\d+(?:\.\d+)*\.?$/.test(text2) && (next == null ? void 0 : next.type) === "heading" && next.text && next.pageNumber === block2.pageNumber && !chapterNumber) {
31079
32056
  next.text = `${block2.text.trim()} ${next.text.trim()}`;
31080
32057
  blocks.splice(i--, 1);
31081
32058
  continue;
31082
32059
  }
31083
- if (((next == null ? void 0 : next.type) === "paragraph" || (next == null ? void 0 : next.type) === "heading" && !CAPTION.test(text2)) && next.pageNumber === block2.pageNumber && next.text && next.bbox && block2.bbox && ((_p = next.style) == null ? void 0 : _p.fontName) === ((_q = block2.style) == null ? void 0 : _q.fontName) && ((_r = next.style) == null ? void 0 : _r.fontSize) === ((_s = block2.style) == null ? void 0 : _s.fontSize) && fsz > 0 && /^[a-z]/.test(next.text.trim()) && next.text.trim().length <= 40 && !/[.:;!?]$/.test(next.text.trim()) && block2.bbox.y - (next.bbox.y + next.bbox.height) < fsz * 1.2 && Math.abs(next.bbox.x - block2.bbox.x) < fsz) {
32060
+ if (((next == null ? void 0 : next.type) === "paragraph" || (next == null ? void 0 : next.type) === "heading" && !CAPTION.test(text2)) && next.pageNumber === block2.pageNumber && next.text && next.bbox && block2.bbox && ((_A = next.style) == null ? void 0 : _A.fontName) === ((_B = block2.style) == null ? void 0 : _B.fontName) && ((_C = next.style) == null ? void 0 : _C.fontSize) === ((_D = block2.style) == null ? void 0 : _D.fontSize) && fsz > 0 && /^[a-z]/.test(next.text.trim()) && next.text.trim().length <= 40 && !/[.:;!?]$/.test(next.text.trim()) && block2.bbox.y - (next.bbox.y + next.bbox.height) < fsz * 1.2 && Math.abs(next.bbox.x - block2.bbox.x) < fsz) {
31084
32061
  block2.text = `${block2.text.trim()} ${next.text.trim()}`;
31085
32062
  block2.bbox = { ...block2.bbox, y: next.bbox.y, height: block2.bbox.y + block2.bbox.height - next.bbox.y };
31086
32063
  blocks.splice(i + 1, 1);
31087
32064
  }
31088
32065
  const after2 = blocks[i + 2];
31089
- if (((next == null ? void 0 : next.type) === "paragraph" || (next == null ? void 0 : next.type) === "heading") && /^(?:&|\+|and|or)$/i.test((_u = (_t = next.text) == null ? void 0 : _t.trim()) != null ? _u : "") && (after2 == null ? void 0 : after2.type) === "heading" && after2.text && after2.pageNumber === block2.pageNumber && next.pageNumber === block2.pageNumber && ((_v = after2.style) == null ? void 0 : _v.fontSize) === ((_w = block2.style) == null ? void 0 : _w.fontSize)) {
32066
+ if (((next == null ? void 0 : next.type) === "paragraph" || (next == null ? void 0 : next.type) === "heading") && /^(?:&|\+|and|or)$/i.test((_F = (_E = next.text) == null ? void 0 : _E.trim()) != null ? _F : "") && (after2 == null ? void 0 : after2.type) === "heading" && after2.text && after2.pageNumber === block2.pageNumber && next.pageNumber === block2.pageNumber && ((_G = after2.style) == null ? void 0 : _G.fontSize) === ((_H = block2.style) == null ? void 0 : _H.fontSize)) {
31090
32067
  block2.text = `${block2.text.trim()} ${next.text.trim()} ${after2.text.trim()}`;
31091
32068
  blocks.splice(i + 1, 2);
31092
32069
  }
31093
32070
  const tiny = fsz > 0 && fsz < 7.5;
31094
32071
  const prev = blocks[i - 1];
31095
- if ((prev == null ? void 0 : prev.type) === "paragraph" && prev.pageNumber === block2.pageNumber && /^[a-z]{1,3}[.)]$/.test((_y = (_x = prev.text) == null ? void 0 : _x.trim()) != null ? _y : "") && prev.bbox && block2.bbox && Math.abs(prev.bbox.y - block2.bbox.y) < 2 && prev.bbox.x + prev.bbox.width <= block2.bbox.x) {
32072
+ if ((prev == null ? void 0 : prev.type) === "paragraph" && prev.pageNumber === block2.pageNumber && /^[a-z]{1,3}[.)]$/.test((_J = (_I = prev.text) == null ? void 0 : _I.trim()) != null ? _J : "") && prev.bbox && block2.bbox && Math.abs(prev.bbox.y - block2.bbox.y) < 2 && prev.bbox.x + prev.bbox.width <= block2.bbox.x) {
31096
32073
  prev.text = `${prev.text.trim()} ${block2.text.trim()}`;
31097
32074
  prev.bbox = { ...prev.bbox, width: block2.bbox.x + block2.bbox.width - prev.bbox.x };
31098
32075
  blocks.splice(i--, 1);
31099
32076
  continue;
31100
32077
  }
31101
- if ((prev == null ? void 0 : prev.type) === "paragraph" && prev.pageNumber === block2.pageNumber && /^\d{1,2}(?:\.\d{1,2})*\.?$/.test((_A = (_z = prev.text) == null ? void 0 : _z.trim()) != null ? _A : "") && prev.bbox && block2.bbox && fsz > 0 && (Math.abs(prev.bbox.y - block2.bbox.y) < 2 && prev.bbox.x + prev.bbox.width <= block2.bbox.x && block2.bbox.x - (prev.bbox.x + prev.bbox.width) < fsz * 3 || Math.abs(prev.bbox.x - block2.bbox.x) < 2 && ((_C = (_B = prev.style) == null ? void 0 : _B.fontSize) != null ? _C : 0) >= fsz && prev.bbox.y - (block2.bbox.y + block2.bbox.height) < fsz * 1.5)) {
32078
+ if ((prev == null ? void 0 : prev.type) === "paragraph" && prev.pageNumber === block2.pageNumber && /^\d{1,2}(?:\.\d{1,2})*\.?$/.test((_L = (_K = prev.text) == null ? void 0 : _K.trim()) != null ? _L : "") && prev.bbox && block2.bbox && fsz > 0 && (Math.abs(prev.bbox.y - block2.bbox.y) < 2 && prev.bbox.x + prev.bbox.width <= block2.bbox.x && block2.bbox.x - (prev.bbox.x + prev.bbox.width) < fsz * 3 || Math.abs(prev.bbox.x - block2.bbox.x) < 2 && ((_N = (_M = prev.style) == null ? void 0 : _M.fontSize) != null ? _N : 0) >= fsz && prev.bbox.y - (block2.bbox.y + block2.bbox.height) < fsz * 1.5)) {
31102
32079
  block2.text = `${prev.text.trim()} ${block2.text.trim()}`;
31103
32080
  blocks.splice(i - 1, 1);
31104
32081
  i -= 2;
31105
32082
  continue;
31106
32083
  }
31107
- const box = block2.bbox, size = (_E = (_D = block2.style) == null ? void 0 : _D.fontSize) != null ? _E : 0;
31108
- const kicker = !!box && size > 0 && (next == null ? void 0 : next.type) === "heading" && next.pageNumber === block2.pageNumber && !!next.bbox && (((_F = block2.style) == null ? void 0 : _F.fontName) !== "ocr" || size < ((_H = bodySizes.get((_G = block2.pageNumber) != null ? _G : 0)) != null ? _H : Infinity) * 2) && ((_J = (_I = next.style) == null ? void 0 : _I.fontSize) != null ? _J : 0) >= size * 1.3 && box.y - (next.bbox.y + next.bbox.height) <= size * 3 && Math.min(box.x + box.width, next.bbox.x + next.bbox.width) - Math.max(box.x, next.bbox.x) >= Math.min(box.width, next.bbox.width) * 0.5 && !page.some((o) => o !== block2 && o.bbox && o.bbox.y > box.y + box.height && o.type !== "image");
31109
- const face = (_M = faceNames == null ? void 0 : faceNames.get((_L = (_K = block2.style) == null ? void 0 : _K.fontName) != null ? _L : "")) != null ? _M : "";
31110
- const [bodyFace, bodySize] = ((_O = bodyStyle.get((_N = block2.pageNumber) != null ? _N : 0)) != null ? _O : "").split(":");
31111
- const byline = /Italic|Oblique/i.test(face) && !/Bold|Black|Heavy|Semibold/i.test(face) && !!bodyFace && size <= Number(bodySize) + 0.5 && ((_P = blocks[i - 1]) == null ? void 0 : _P.type) === "heading" && blocks[i - 1].pageNumber === block2.pageNumber;
31112
- const ocrFragment = ((_Q = block2.style) == null ? void 0 : _Q.fontName) === "ocr" && (/^[.,;:…·•-]/.test(text2) || text2.includes("\u2026") || ((_S = (_R = text2.match(/\p{L}/gu)) == null ? void 0 : _R.length) != null ? _S : 0) < 2 || text2.split(/\s+/).length > 7);
31113
- const crowdedOcr = ((_T = block2.style) == null ? void 0 : _T.fontName) === "ocr" && !!box && [prev, next].every((o) => {
32084
+ const box = block2.bbox, size = (_P = (_O = block2.style) == null ? void 0 : _O.fontSize) != null ? _P : 0;
32085
+ const kicker = !!box && size > 0 && (next == null ? void 0 : next.type) === "heading" && next.pageNumber === block2.pageNumber && !!next.bbox && (((_Q = block2.style) == null ? void 0 : _Q.fontName) !== "ocr" || size < ((_S = bodySizes.get((_R = block2.pageNumber) != null ? _R : 0)) != null ? _S : Infinity) * 2) && ((_U = (_T = next.style) == null ? void 0 : _T.fontSize) != null ? _U : 0) >= size * 1.3 && box.y - (next.bbox.y + next.bbox.height) <= size * 3 && Math.min(box.x + box.width, next.bbox.x + next.bbox.width) - Math.max(box.x, next.bbox.x) >= Math.min(box.width, next.bbox.width) * 0.5 && !page.some((o) => o !== block2 && o.bbox && o.bbox.y > box.y + box.height && o.type !== "image");
32086
+ const face = (_X = faceNames == null ? void 0 : faceNames.get((_W = (_V = block2.style) == null ? void 0 : _V.fontName) != null ? _W : "")) != null ? _X : "";
32087
+ const [bodyFace, bodySize] = ((_Z = bodyStyle.get((_Y = block2.pageNumber) != null ? _Y : 0)) != null ? _Z : "").split(":");
32088
+ const byline = /Italic|Oblique/i.test(face) && !/Bold|Black|Heavy|Semibold/i.test(face) && !!bodyFace && size <= Number(bodySize) + 0.5 && ((__ = blocks[i - 1]) == null ? void 0 : __.type) === "heading" && blocks[i - 1].pageNumber === block2.pageNumber;
32089
+ const ocrFragment = ((_$ = block2.style) == null ? void 0 : _$.fontName) === "ocr" && (/^[.,;:…·•-]/.test(text2) || text2.includes("\u2026") || ((_ba = (_aa = text2.match(/\p{L}/gu)) == null ? void 0 : _aa.length) != null ? _ba : 0) < 2 || text2.split(/\s+/).length > 7);
32090
+ const crowdedOcr = ((_ca = block2.style) == null ? void 0 : _ca.fontName) === "ocr" && !!box && [prev, next].every((o) => {
31114
32091
  var _a3, _b2, _c2;
31115
32092
  return (o == null ? void 0 : o.type) === "paragraph" && o.pageNumber === block2.pageNumber && ((_a3 = o.style) == null ? void 0 : _a3.fontName) === "ocr" && !!o.bbox && ((_c2 = (_b2 = o.text) == null ? void 0 : _b2.length) != null ? _c2 : 0) >= 15 && Math.abs(o.bbox.x - box.x) <= size * 0.25 && Math.min(o.bbox.y + o.bbox.height, box.y + box.height) - Math.max(o.bbox.y, box.y) >= o.bbox.height * 0.2;
31116
32093
  }) && prev.bbox.y > box.y && next.bbox.y < box.y;
31117
- if (ocrFragment || crowdedOcr || tocEntry || proseStyle || kicker || byline || tiny || !/\p{L}/u.test(text2) && !chapterNumber || /^[a-z]/.test(text2) || CAPTION.test(text2) || EQUATION_NUMBER.test(block2.text) || DISPLAY_MATH.test(text2) || // 닫는 괄호가 여는 괄호보다 많으면 앞 줄에서 이어진 문장 조각이다 ("Fact-checking) and is used …") — "1)"·"가)" 앞머리 번호는 빼고 센다
31118
- unbalancedClose(text2.replace(/^\s*[\dA-Za-z가-힣ⅰ-ⅹ]{1,3}\)\s*/, "")) || isRunningHead(block2, page, pageHeights.get((_U = block2.pageNumber) != null ? _U : 0))) {
32094
+ if (numberedProse.has(block2) || citedProse.has(block2) || ocrFragment || crowdedOcr || tocEntry || proseStyle || kicker || byline || tiny || !/\p{L}/u.test(text2) && !chapterNumber || /^[a-z]/.test(text2) || CAPTION.test(text2) || EQUATION_NUMBER.test(block2.text) || DISPLAY_MATH.test(text2) || // 닫는 괄호가 여는 괄호보다 많으면 앞 줄에서 이어진 문장 조각이다 ("Fact-checking) and is used …") — "1)"·"가)" 앞머리 번호는 빼고 센다
32095
+ unbalancedClose(text2.replace(/^\s*[\dA-Za-z가-힣ⅰ-ⅹ]{1,3}\)\s*/, "")) || isRunningHead(block2, page, pageHeights.get((_da = block2.pageNumber) != null ? _da : 0))) {
31119
32096
  block2.type = "paragraph";
31120
32097
  block2.level = void 0;
31121
32098
  }
@@ -31164,6 +32141,11 @@ function splitSingleCellTables(blocks) {
31164
32141
  const out = [];
31165
32142
  for (const b of blocks) {
31166
32143
  const t = b.type === "table" ? b.table : void 0;
32144
+ const title = t && FRAME_TITLE_BLOCKS.get(t);
32145
+ if (title) {
32146
+ out.push({ ...title, text: `${t.cells[0][0].text.trim()} ${t.cells[0][2].text.trim()}` });
32147
+ continue;
32148
+ }
31167
32149
  const only = t && t.rows === 1 && t.cols === 1 && ((_c = (_b = (_a2 = t.cells[0]) == null ? void 0 : _a2[0]) == null ? void 0 : _b.blocks) == null ? void 0 : _c.length) === 1 ? t.cells[0][0].blocks[0] : void 0;
31168
32150
  const squash = (s) => s.replace(/\s/g, "");
31169
32151
  const inner = only && (!squash(t.cells[0][0].text) || only.type === "table" && squash(t.cells[0][0].text) === squash(only.table.cells.flat().map((c) => c.text).join(""))) ? only : void 0;
@@ -31173,12 +32155,16 @@ function splitSingleCellTables(blocks) {
31173
32155
  continue;
31174
32156
  }
31175
32157
  const cell2 = t && t.rows === 1 && t.cols === 1 ? (_e = t.cells[0]) == null ? void 0 : _e[0] : void 0;
31176
- if (!cell2 || ((_f = cell2.blocks) == null ? void 0 : _f.some((x) => x.type === "table"))) {
32158
+ if (!cell2) {
31177
32159
  out.push(b);
31178
32160
  continue;
31179
32161
  }
31180
- const lines = ((_g = cell2.text) != null ? _g : "").split(/\n/).map((l) => l.trim()).filter(Boolean);
31181
- if ((_h = t == null ? void 0 : t.caption) == null ? void 0 : _h.trim()) out.push({ type: "paragraph", text: t.caption.trim(), pageNumber: b.pageNumber, bbox: b.bbox });
32162
+ const lines = ((_f = cell2.text) != null ? _f : "").split(/\n/).map((l) => l.trim()).filter(Boolean);
32163
+ if ((_g = t == null ? void 0 : t.caption) == null ? void 0 : _g.trim()) out.push({ type: "paragraph", text: t.caption.trim(), pageNumber: b.pageNumber, bbox: b.bbox });
32164
+ if ((_h = cell2.blocks) == null ? void 0 : _h.length) {
32165
+ out.push(...splitSingleCellTables(cell2.blocks));
32166
+ continue;
32167
+ }
31182
32168
  for (const text2 of lines) out.push({ type: "paragraph", text: text2, pageNumber: b.pageNumber, bbox: b.bbox });
31183
32169
  }
31184
32170
  return out;
@@ -31263,6 +32249,7 @@ var init_text_clean = __esm({
31263
32249
  init_quality();
31264
32250
  init_text_line();
31265
32251
  init_line_wrap();
32252
+ init_table_meta();
31266
32253
  stripNoUnicodeGlyph = (text2) => text2.includes("\uF000") ? text2.replace(/\uF000/g, "") : text2;
31267
32254
  CHOSEONG_COMPAT = "\u3131\u3132\u3134\u3137\u3138\u3139\u3141\u3142\u3143\u3145\u3146\u3147\u3148\u3149\u314A\u314B\u314C\u314D\u314E";
31268
32255
  normalizeLoneChoseong = (text2) => /[\u1100-\u1112]/.test(text2) ? text2.replace(/[\u1100-\u1112](?![\u1160-\u11A7\uD7B0-\uD7C6])/g, (c) => CHOSEONG_COMPAT[c.charCodeAt(0) - 4352]) : text2;
@@ -32094,6 +33081,7 @@ var init_pipeline = __esm({
32094
33081
  init_recognizer();
32095
33082
  init_models();
32096
33083
  import_path5 = require("path");
33084
+ init_runtime_env();
32097
33085
  RENDER_SCALE = 2;
32098
33086
  FormulaPipeline = class _FormulaPipeline {
32099
33087
  constructor(parts) {
@@ -32112,6 +33100,7 @@ var init_pipeline = __esm({
32112
33100
  */
32113
33101
  static async create(options) {
32114
33102
  var _a2, _b, _c, _d;
33103
+ disableOrtTelemetry();
32115
33104
  const opts = {
32116
33105
  scale: (_a2 = options == null ? void 0 : options.scale) != null ? _a2 : RENDER_SCALE,
32117
33106
  maxRegionsPerPage: (_b = options == null ? void 0 : options.maxRegionsPerPage) != null ? _b : 50,
@@ -32479,7 +33468,7 @@ function ocrImageRegions(regions, large, all) {
32479
33468
  return out;
32480
33469
  }
32481
33470
  async function loadPdfWithTimeout(buffer) {
32482
- const loadingTask = (0, import_pdf10.getDocument)({
33471
+ const loadingTask = (0, import_pdf12.getDocument)({
32483
33472
  // pdfjs transfers its input to the worker; retain the caller's buffer for reuse.
32484
33473
  data: new Uint8Array(buffer.slice(0)),
32485
33474
  useSystemFonts: true,
@@ -32540,12 +33529,29 @@ async function parsePdfDocument(buffer, options) {
32540
33529
  const uncoveredImageRegions = /* @__PURE__ */ new Map();
32541
33530
  const largeImageRegions = /* @__PURE__ */ new Set();
32542
33531
  const imageState = createPdfImageState();
33532
+ const imageBulletShapes = /* @__PURE__ */ new Map();
33533
+ const imageArrowDirections = /* @__PURE__ */ new Map();
32543
33534
  const extractedImages = [];
32544
33535
  const pageImageBlocks = /* @__PURE__ */ new Map();
32545
33536
  const carry = {};
32546
33537
  const vectorPageOps = /* @__PURE__ */ new Map();
32547
33538
  const wrapLexicon = new WrapLexicon();
32548
33539
  const noteMarks = /* @__PURE__ */ new Map();
33540
+ const headerContext = [];
33541
+ if (pageFilter && (options == null ? void 0 : options.removeHeaderFooter) !== false && pageFilter.size < effectivePageCount) {
33542
+ for (const number of selectionContextPages(pageFilter, effectivePageCount)) {
33543
+ let contextPage;
33544
+ try {
33545
+ contextPage = await doc.getPage(number);
33546
+ const content = await contextPage.getTextContent();
33547
+ pageHeights.set(number, contextPage.view[3] - contextPage.view[1]);
33548
+ headerContext.push(...marginContextBlocks(content.items, number, contextPage.view));
33549
+ } catch {
33550
+ } finally {
33551
+ contextPage == null ? void 0 : contextPage.cleanup();
33552
+ }
33553
+ }
33554
+ }
32549
33555
  let parsedPages = 0;
32550
33556
  for (let i = 1; i <= effectivePageCount; i++) {
32551
33557
  if (pageFilter && !pageFilter.has(i)) continue;
@@ -32600,7 +33606,7 @@ async function parsePdfDocument(buffer, options) {
32600
33606
  item.y -= viewY1;
32601
33607
  }
32602
33608
  const opList = shifted ? {
32603
- fnArray: [import_pdf10.OPS.transform, ...rawOps.fnArray],
33609
+ fnArray: [import_pdf12.OPS.transform, ...rawOps.fnArray],
32604
33610
  argsArray: [[1, 0, 0, 1, -viewX1, -viewY1], ...rawOps.argsArray]
32605
33611
  } : rawOps;
32606
33612
  remapSymbolFontItems(visible, (loadedName) => {
@@ -32608,6 +33614,7 @@ async function parsePdfDocument(buffer, options) {
32608
33614
  return (_a3 = fontObj(loadedName)) == null ? void 0 : _a3.name;
32609
33615
  });
32610
33616
  remapControlGlyphs(visible, differencesOf);
33617
+ await restoreImageBullets(visible, page, opList.fnArray, opList.argsArray, imageBulletShapes);
32611
33618
  const faces = /* @__PURE__ */ new Map();
32612
33619
  for (const it of visible) {
32613
33620
  if (!it.fontName) continue;
@@ -32621,6 +33628,7 @@ async function parsePdfDocument(buffer, options) {
32621
33628
  if (!faceNames.has(face)) faceNames.set(face, ((_c = (_b = fontObj(face)) == null ? void 0 : _b.name) != null ? _c : "").replace(/^[A-Z]{6}\+/, ""));
32622
33629
  }
32623
33630
  for (const it of visible) if (it.text.includes("$")) it.text = escapeLiteralDollar(it.text);
33631
+ for (const it of visible) if (it.text.includes("<")) it.text = escapeLiteralTags(it.text);
32624
33632
  wrapEquationRuns(visible, (face) => faceNames.get(face));
32625
33633
  const pageArea = pageW * pageH;
32626
33634
  if (pageArea > 0) {
@@ -32653,7 +33661,8 @@ async function parsePdfDocument(buffer, options) {
32653
33661
  if (marks.length) noteMarks.set(i, { marks, seps: footnoteSeparators(extractLines(opList.fnArray, opList.argsArray).horizontals, pageW, pageH) });
32654
33662
  const stamp = marginStamp(visible);
32655
33663
  const flow = stamp.length ? visible.filter((it) => !stamp.includes(it)) : visible;
32656
- const pageBlocks = orderTwoUpPage(extractPageBlocksWithLines(flow, i, opList, pageW, pageH, void 0, (options == null ? void 0 : options.tables) !== false, carry, wrapLexicon), pageW, pageH);
33664
+ const rightArrows = (options == null ? void 0 : options.tables) !== false ? await detectRightArrowRegions(page, opList.fnArray, opList.argsArray, imageArrowDirections) : [];
33665
+ const pageBlocks = orderTwoUpPage(extractPageBlocksWithLines(flow, i, opList, pageW, pageH, void 0, (options == null ? void 0 : options.tables) !== false, carry, wrapLexicon, rightArrows), pageW, pageH);
32657
33666
  if (stamp.length) pageBlocks.unshift({ type: "paragraph", text: [...stamp].sort((a, b) => a.y - b.y).map((it) => it.text).join(" "), pageNumber: i });
32658
33667
  for (const b of pageBlocks) blocks.push(b);
32659
33668
  try {
@@ -32782,8 +33791,8 @@ async function parsePdfDocument(buffer, options) {
32782
33791
  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 \u2014 \uADF8\uB9BC \uC18D \uAE00\uC740 ocr: true / CLI --ocr \uB85C \uC77D\uC2B5\uB2C8\uB2E4)`, code: "SKIPPED_IMAGE" });
32783
33792
  }
32784
33793
  }
32785
- if ((options == null ? void 0 : options.removeHeaderFooter) !== false && parsedPageCount >= 3) {
32786
- const removed = removeHeaderFooterBlocks(blocks, pageHeights, warnings, noteMarks);
33794
+ if ((options == null ? void 0 : options.removeHeaderFooter) !== false && (parsedPageCount >= 3 || headerContext.length)) {
33795
+ const removed = removeHeaderFooterBlocks(blocks, pageHeights, warnings, noteMarks, false, headerContext);
32787
33796
  for (let ri = removed.length - 1; ri >= 0; ri--) {
32788
33797
  blocks.splice(removed[ri], 1);
32789
33798
  }
@@ -32831,6 +33840,10 @@ async function parsePdfDocument(buffer, options) {
32831
33840
  const outline = blocks.filter((b) => b.type === "heading" && b.level && b.text).map((b) => ({ level: b.level, text: b.text, pageNumber: b.pageNumber }));
32832
33841
  sanitizeBlockControlChars(blocks);
32833
33842
  let outBlocks = splitSingleCellTables(blocks);
33843
+ if ((options == null ? void 0 : options.layoutTables) !== "keep") {
33844
+ blocks.length = 0;
33845
+ for (const block2 of outBlocks) blocks.push(block2);
33846
+ }
32834
33847
  outBlocks = inlineFootnotes(outBlocks, noteMarks);
32835
33848
  outBlocks = relocateEndnotes(outBlocks);
32836
33849
  if ((options == null ? void 0 : options.removeHeaderFooter) !== false) outBlocks = outBlocks.filter((b) => {
@@ -32939,7 +33952,7 @@ function marginStamp(items) {
32939
33952
  };
32940
33953
  return rotated.every(outside) ? rotated : [];
32941
33954
  }
32942
- var import_pdf10, import_node_module, import_node_path2, MAX_PAGES, MAX_TOTAL_TEXT, PDF_LOAD_TIMEOUT_MS, pdfjsAssets;
33955
+ var import_pdf12, import_node_module, import_node_path2, MAX_PAGES, MAX_TOTAL_TEXT, PDF_LOAD_TIMEOUT_MS, pdfjsAssets;
32943
33956
  var init_parser = __esm({
32944
33957
  ".kordoc-source/src/pdf/parser.ts"() {
32945
33958
  "use strict";
@@ -32962,6 +33975,9 @@ var init_parser = __esm({
32962
33975
  init_table_parts();
32963
33976
  init_cell_continuation();
32964
33977
  init_table_trim();
33978
+ init_selection_context();
33979
+ init_image_bullets();
33980
+ init_flow_boxes();
32965
33981
  init_symbol_fonts2();
32966
33982
  init_equation_runs();
32967
33983
  init_glyph_names();
@@ -32979,12 +33995,12 @@ var init_parser = __esm({
32979
33995
  init_links();
32980
33996
  init_formula_ocr();
32981
33997
  init_polyfill();
32982
- import_pdf10 = require("pdfjs-dist/legacy/build/pdf.mjs");
33998
+ import_pdf12 = require("pdfjs-dist/legacy/build/pdf.mjs");
32983
33999
  import_node_module = require("module");
32984
34000
  import_node_path2 = require("path");
32985
34001
  init_models2();
32986
34002
  init_contact_table();
32987
- import_pdf10.GlobalWorkerOptions.workerSrc = "";
34003
+ import_pdf12.GlobalWorkerOptions.workerSrc = "";
32988
34004
  MAX_PAGES = 5e3;
32989
34005
  MAX_TOTAL_TEXT = 100 * 1024 * 1024;
32990
34006
  PDF_LOAD_TIMEOUT_MS = 3e4;
@@ -33067,6 +34083,7 @@ __export(src_exports, {
33067
34083
  parseHwpx: () => parseHwpx,
33068
34084
  parseImage: () => parseImage,
33069
34085
  parsePdf: () => parsePdf,
34086
+ parsePptx: () => parsePptx,
33070
34087
  parseXls: () => parseXls,
33071
34088
  parseXlsx: () => parseXlsx,
33072
34089
  patchHwp: () => patchHwp,
@@ -33099,14 +34116,17 @@ init_script_tags();
33099
34116
  init_cjs_shims();
33100
34117
  init_script_tags();
33101
34118
  function toPlainMarkdown(md2) {
33102
- return plainScripts(md2).replace(/!\[[^\]\n]*\]\([^)\n]*\)/g, "").replace(/<img\b[^>]*>/gi, "").replace(/(?<!!)\[([^\]\n]*)\]\((?:https?|mailto|ftp):[^)\s]*\)/g, "$1").replace(/<\/?u>/g, "").replace(/(?<!\\)\*\*(?=\S)([^\n]*?\S)(?<!\\)\*\*/g, "$1").replace(/(<br>)+(?=<\/t[dh]>)/g, "").replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
34119
+ return plainScripts(md2).replace(/!\[[^\]\n]*\]\([^)\n]*\)/g, "").replace(/<img\b[^>]*>/gi, "").replace(/(?<!!)\[([^\]\n]*)\]\((?:https?|mailto|ftp):[^)\s]*\)/g, "$1").replace(/(?<!\\)<\/?u>/g, "").replace(/(?<!\\)\*\*(?=\S)([^\n]*?\S)(?<!\\)\*\*/g, "$1").replace(/(<br>)+(?=<\/t[dh]>)/g, "").replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
33103
34120
  }
33104
34121
 
34122
+ // .kordoc-source/src/index.ts
34123
+ init_page_range();
34124
+
33105
34125
  // .kordoc-source/src/html-tables.ts
33106
34126
  init_cjs_shims();
33107
34127
  var TABLE_TAG = /(<\/?(?:table|tr|th|td)\b[^>]*>)/i;
33108
34128
  function pipeCellToHtml(cell2) {
33109
- return cell2.split(/(<br>|<\/?(?:u|sup|sub)>|<img\b[^>]*>)/).map((part, i) => i % 2 ? part : part.replace(/\\([\\`*_{}[\]()#+\-.!|~<>$])/g, "$1").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")).join("");
34129
+ return cell2.split(/(<br>|(?<!\\)<\/?(?:u|sup|sub)>|<img\b[^>]*>)/).map((part, i) => i % 2 ? part : part.replace(/\\([\\`*_{}[\]()#+\-.!|~<>$])/g, "$1").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")).join("");
33110
34130
  }
33111
34131
  function splitPipeRow(line) {
33112
34132
  const t = line.trim().replace(/^\|/, "").replace(/(?<!\\)\|$/, "");
@@ -33651,7 +34671,8 @@ function createSectionShared() {
33651
34671
  numState: /* @__PURE__ */ new Map(),
33652
34672
  pageText: { headers: [], footers: [] },
33653
34673
  track: { deleteDepth: 0, warned: false, deletedObjects: /* @__PURE__ */ new WeakSet(), deletedImageRefs: /* @__PURE__ */ new Set() },
33654
- pageState: { base: 0, allUsable: true }
34674
+ pageState: { base: 0, allUsable: true },
34675
+ tocTexts: /* @__PURE__ */ new Set()
33655
34676
  };
33656
34677
  }
33657
34678
  function createXmlParser(warnings) {
@@ -33763,6 +34784,24 @@ async function decryptHwpxInPlace(zip, manifestXml, password) {
33763
34784
  init_cjs_shims();
33764
34785
  init_utils();
33765
34786
  init_types();
34787
+
34788
+ // .kordoc-source/src/toc-entry.ts
34789
+ init_cjs_shims();
34790
+ var TOC_LEADER = "";
34791
+ var LEADERS = /\x1F/g;
34792
+ var PAGE_LABEL = /^(?:\d{1,4}|[ivxlc]{1,7}|\d{1,3}\s*[-–]\s*\d{1,4}|[-–]\s*\d{1,4}\s*[-–])$/i;
34793
+ var TOC_ENTRY_BLOCKS = /* @__PURE__ */ new WeakSet();
34794
+ function takeTocLeaders(text2) {
34795
+ if (!text2.includes(TOC_LEADER)) return { text: text2, tocEntry: false };
34796
+ const lines = text2.replace(/\x1E/g, "").split("\n").filter((l) => l.trim());
34797
+ const tocEntry = lines.length > 0 && lines.every((l) => {
34798
+ const at = l.lastIndexOf(TOC_LEADER);
34799
+ return at > 0 && /\S/.test(l.slice(0, at).replace(LEADERS, "")) && PAGE_LABEL.test(l.slice(at + 1).trim());
34800
+ });
34801
+ return { text: text2.replace(LEADERS, " "), tocEntry };
34802
+ }
34803
+
34804
+ // .kordoc-source/src/hwpx/styles.ts
33766
34805
  function isRealStrikeShape(shape) {
33767
34806
  switch (shape) {
33768
34807
  case "SOLID":
@@ -33996,7 +35035,7 @@ function parseParaHeadings(doc, map2) {
33996
35035
  if (map2.size > 0) break;
33997
35036
  }
33998
35037
  }
33999
- function detectHwpxHeadings(blocks, styleMap) {
35038
+ function detectHwpxHeadings(blocks, styleMap, tocTexts) {
34000
35039
  var _a2, _b;
34001
35040
  if (blocks.some((b) => b.type === "heading")) return;
34002
35041
  let baseFontSize = 0;
@@ -34014,7 +35053,7 @@ function detectHwpxHeadings(blocks, styleMap) {
34014
35053
  }
34015
35054
  }
34016
35055
  for (const block2 of blocks) {
34017
- if (block2.type !== "paragraph" || !block2.text) continue;
35056
+ if (block2.type !== "paragraph" || !block2.text || TOC_ENTRY_BLOCKS.has(block2) || (tocTexts == null ? void 0 : tocTexts.has(block2.text.trim()))) continue;
34018
35057
  const text2 = block2.text.trim();
34019
35058
  if (text2.length === 0 || text2.length > 200 || /^\d+$/.test(text2)) continue;
34020
35059
  let level = 0;
@@ -35068,6 +36107,7 @@ function noteAutoNumOf(el) {
35068
36107
  init_cjs_shims();
35069
36108
  init_builder();
35070
36109
  init_script_tags();
36110
+ init_script_tags();
35071
36111
  var KORDOC_CHAR_CODE = "4";
35072
36112
  var KORDOC_PARA_QUOTE = "6";
35073
36113
  function spanModeOf(layout2) {
@@ -35100,7 +36140,7 @@ function extractRunSpans(para2, ctx, mode, requireMixed) {
35100
36140
  const tkids = rc.childNodes;
35101
36141
  for (let k = 0; k < ((_b = tkids == null ? void 0 : tkids.length) != null ? _b : 0); k++) {
35102
36142
  const tk = tkids[k];
35103
- if (tk.nodeType === 3 || tk.nodeType === 4) text2 += escapeLiteralDollar(tk.textContent || "");
36143
+ if (tk.nodeType === 3 || tk.nodeType === 4) text2 += escapeLiteralTags(escapeLiteralDollar(tk.textContent || ""));
35104
36144
  else if (tk.nodeType === 1) {
35105
36145
  const ttag = (tk.tagName || tk.localName || "").replace(/^[^:]+:/, "");
35106
36146
  if (ttag === "tab" || ttag === "fwSpace" || ttag === "hwSpace" || ttag === "nbSpace") text2 += " ";
@@ -35216,13 +36256,13 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
35216
36256
  }
35217
36257
  if (tableCtx) tableStack.push(tableCtx);
35218
36258
  const newTable = { rows: [], currentRow: [], cell: null, sourceId: (_a2 = el.getAttribute("id")) != null ? _a2 : void 0 };
35219
- walkSection(el, blocks, newTable, tableStack, ctx, depth + 1);
36259
+ inIndependentDeletionStory(ctx.shared.track, () => walkSection(el, blocks, newTable, tableStack, ctx, depth + 1));
35220
36260
  tableCtx = completeTable(newTable, tableStack, blocks, ctx);
35221
36261
  break;
35222
36262
  }
35223
36263
  // 표/도표 캡션 — IRTable.caption으로 보존 (v3.0, 기존 무음 드롭 수정)
35224
36264
  case "caption": {
35225
- const cap = collectSubListContent(el, ctx);
36265
+ const cap = inIndependentDeletionStory(ctx.shared.track, () => collectSubListContent(el, ctx));
35226
36266
  if (cap.text) {
35227
36267
  if (tableCtx) {
35228
36268
  tableCtx.caption = (tableCtx.caption ? tableCtx.caption + "\n" : "") + cap.text;
@@ -35275,13 +36315,16 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
35275
36315
  case "p": {
35276
36316
  const paraPg = (_e = ctx.paraPage) == null ? void 0 : _e.get(el);
35277
36317
  if (paraPg !== void 0 && ctx.pageBase !== void 0) ctx.page = ctx.pageBase + paraPg + 1;
35278
- const { text: rawText, href, footnote, style, segments, placeholderSpans } = extractParagraphInfo(el, ctx.styleMap, ctx);
36318
+ const { text: rawText, href, footnote, style, segments, placeholderSpans, tocEntry } = extractParagraphInfo(el, ctx.styleMap, ctx);
35279
36319
  let text2 = rawText;
35280
36320
  let headingLevel;
35281
36321
  const ph = resolveParaHeading(el, ctx);
35282
36322
  if (text2) {
35283
36323
  if (ph == null ? void 0 : ph.prefix) text2 = ph.prefix + " " + text2;
35284
- headingLevel = ph == null ? void 0 : ph.headingLevel;
36324
+ headingLevel = tocEntry ? void 0 : ph == null ? void 0 : ph.headingLevel;
36325
+ if (tocEntry) {
36326
+ for (const line of text2.split("\n")) if (line.trim()) ctx.shared.tocTexts.add(line.trim());
36327
+ }
35285
36328
  }
35286
36329
  if (segments) {
35287
36330
  const cell2 = (_f = tableCtx == null ? void 0 : tableCtx.cell) != null ? _f : null;
@@ -35344,6 +36387,7 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
35344
36387
  }
35345
36388
  const block2 = { type: headingLevel ? "heading" : "paragraph", text: text2, pageNumber: ctx.page };
35346
36389
  if (headingLevel) block2.level = headingLevel;
36390
+ if (tocEntry) TOC_ENTRY_BLOCKS.add(block2);
35347
36391
  if (style) block2.style = style;
35348
36392
  if (href) block2.href = href;
35349
36393
  if (footnote) block2.footnoteText = footnote;
@@ -35367,6 +36411,15 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
35367
36411
  if (spanMode !== "foreign" && el.getAttribute("paraPrIDRef") === KORDOC_PARA_QUOTE) block2.quote = true;
35368
36412
  }
35369
36413
  if (!headingLevel && !block2.spans && placeholderSpans) block2.spans = withPrefixSpan(placeholderSpans, ph == null ? void 0 : ph.prefix);
36414
+ if (headingLevel && placeholderSpans) {
36415
+ const shown = withPrefixSpan(placeholderSpans.filter((s) => !s.placeholder), ph == null ? void 0 : ph.prefix).map((s) => s.text).join("").trim();
36416
+ if (shown) block2.text = shown;
36417
+ else {
36418
+ block2.type = "paragraph";
36419
+ delete block2.level;
36420
+ block2.spans = withPrefixSpan(placeholderSpans, ph == null ? void 0 : ph.prefix);
36421
+ }
36422
+ }
35370
36423
  blocks.push(block2);
35371
36424
  } else {
35372
36425
  blocks.push({ type: "paragraph", text: text2, pageNumber: ctx.page });
@@ -35612,10 +36665,10 @@ function walkParagraphChildren(node, blocks, tableCtx, tableStack, ctx, depth =
35612
36665
  }
35613
36666
  if (tableCtx) tableStack.push(tableCtx);
35614
36667
  const newTable = { rows: [], currentRow: [], cell: null, inline: isInlineTbl(el), sourceId: (_a2 = el.getAttribute("id")) != null ? _a2 : void 0 };
35615
- walkSection(el, blocks, newTable, tableStack, ctx, d + 1);
36668
+ inIndependentDeletionStory(ctx.shared.track, () => walkSection(el, blocks, newTable, tableStack, ctx, d + 1));
35616
36669
  tableCtx = completeTable(newTable, tableStack, blocks, ctx);
35617
36670
  } else if (localTag === "caption" && !inShape) {
35618
- const cap = collectSubListContent(el, ctx);
36671
+ const cap = inIndependentDeletionStory(ctx.shared.track, () => collectSubListContent(el, ctx));
35619
36672
  if (cap.text) {
35620
36673
  if (tableCtx == null ? void 0 : tableCtx.cell) mergeBlocksIntoCell(tableCtx.cell, [{ type: "paragraph", text: cap.text, pageNumber: ctx.page }]);
35621
36674
  else if (tableCtx) {
@@ -35786,7 +36839,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35786
36839
  const open = openFields.pop();
35787
36840
  if ((open == null ? void 0 : open.rangeIdx) !== void 0) linkRanges[open.rangeIdx].end = text2.length;
35788
36841
  if ((open == null ? void 0 : open.guide) !== void 0 && open.start !== void 0) {
35789
- const value = text2.slice(open.start).replace(/\\\$/g, "$");
36842
+ const value = text2.slice(open.start).replace(/\\([$<])/g, "$1");
35790
36843
  if (value && (value === open.guide || value.trimEnd() === open.guide)) {
35791
36844
  text2 = text2.slice(0, open.start) + PH_OPEN + text2.slice(open.start) + PH_CLOSE;
35792
36845
  }
@@ -35818,7 +36871,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35818
36871
  // 아니므로 방출하지 않는다
35819
36872
  case "header":
35820
36873
  case "footer": {
35821
- if (!ctx) break;
36874
+ if (!ctx || isInDeletedRange(ctx)) break;
35822
36875
  const t = collectSubListText(k, ctx);
35823
36876
  if (t && hasPageAutoNum(k) && !/\p{L}/u.test(t)) break;
35824
36877
  if (t) {
@@ -35883,7 +36936,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35883
36936
  }
35884
36937
  };
35885
36938
  const walk = (node, depth = 0) => {
35886
- var _a2, _b, _c;
36939
+ var _a2, _b, _c, _d;
35887
36940
  if (depth > MAX_XML_DEPTH) return;
35888
36941
  const children = node.childNodes;
35889
36942
  if (!children) return;
@@ -35897,7 +36950,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35897
36950
  (_a2 = ctx.warnings) == null ? void 0 : _a2.push({ page: ctx.page, message: "\uBCC0\uACBD\uCD94\uC801 \uC0AD\uC81C \uD14D\uC2A4\uD2B8 \uCD9C\uB825 \uC81C\uC678", code: "HIDDEN_TEXT_FILTERED" });
35898
36951
  }
35899
36952
  } else {
35900
- text2 += escapeLiteralDollar(t.replace(/\x1E/g, ""));
36953
+ text2 += escapeLiteralTags(escapeLiteralDollar(t.replace(/\x1E/g, "")));
35901
36954
  }
35902
36955
  continue;
35903
36956
  }
@@ -35917,8 +36970,9 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35917
36970
  // 점 채움을 탭 하나로 바꾸고 쪽 번호를 남기는 것과 같다). 종전엔 채움 탭 뒤를 쪽 번호로 보고 잘라, 목차 쪽 번호만이 아니라
35918
36971
  // 일정표 "사용자 의견조사 ····· '26년 8~9월"(gate-fill 36646162)의 일정, 줄바꿈 뒤 다음 목차 항목
35919
36972
  // "<참고2> 직종별사업체노동력조사 개요"(rhwp issue6044)까지 사라졌다
36973
+ // (채움 탭은 목차 항목 판정까지 TOC_LEADER 표지로 들고 가다 보통 탭으로 바꾼다 — toc-entry.ts)
35920
36974
  case "tab":
35921
- text2 += " ";
36975
+ text2 += /^(?:|0|NONE)$/i.test((_b = child.getAttribute("leader")) != null ? _b : "") ? " " : TOC_LEADER;
35922
36976
  break;
35923
36977
  case "br":
35924
36978
  if ((child.getAttribute("type") || "line") === "line") text2 += "\n";
@@ -35940,9 +36994,10 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35940
36994
  if (isInlineTbl(child)) text2 += "";
35941
36995
  break;
35942
36996
  // 양식 선택 상자·라디오 단추 — 한컴이 그리는 상자 기호와 캡션 글 (종전엔 통째로 빠졌다: form-002 "원천기술형"·서울 결재 "부분공개")
36997
+ // 지운 구간의 양식 단추·수식은 글처럼 내지 않는다 (최종본)
35943
36998
  case "checkBtn":
35944
36999
  case "radioBtn":
35945
- text2 += formButtonText(child, tag === "radioBtn");
37000
+ if (!isInDeletedRange(ctx)) text2 += formButtonText(child, tag === "radioBtn");
35946
37001
  break;
35947
37002
  // 하이퍼링크
35948
37003
  case "hyperlink": {
@@ -35964,7 +37019,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35964
37019
  // 대체 표현 묶음 — 한컴은 지원하는 hp:case 하나만 그린다(차트, 없으면 hp:default 의 OLE).
35965
37020
  // 둘 다 순회하면 같은 캡션이 두 번 나온다 (1790387 [그림 5] 이중 방출)
35966
37021
  case "switch": {
35967
- const branch = (_b = findChildByLocalName(child, "case")) != null ? _b : findChildByLocalName(child, "default");
37022
+ const branch = (_c = findChildByLocalName(child, "case")) != null ? _c : findChildByLocalName(child, "default");
35968
37023
  if (branch) walk(branch, depth + 1);
35969
37024
  break;
35970
37025
  }
@@ -36012,6 +37067,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
36012
37067
  // 스크립트가 담겨 있음. hml-equation-parser 로 LaTeX 변환 후 `$...$`
36013
37068
  // 로 래핑. 실패/빈 스크립트면 무시 (대체 텍스트 누출 방지).
36014
37069
  case "equation": {
37070
+ if (isInDeletedRange(ctx)) break;
36015
37071
  const script = findChildByLocalName(child, "script");
36016
37072
  const raw = script ? extractTextFromNode(script) : "";
36017
37073
  if (raw.trim()) {
@@ -36036,7 +37092,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
36036
37092
  case "run": {
36037
37093
  const runCharPr = child.getAttribute("charPrIDRef");
36038
37094
  if (tag === "r" && runCharPr && !charPrId) charPrId = runCharPr;
36039
- const script = runCharPr ? (_c = styleMap == null ? void 0 : styleMap.charProperties.get(runCharPr)) == null ? void 0 : _c.script : void 0;
37095
+ const script = runCharPr ? (_d = styleMap == null ? void 0 : styleMap.charProperties.get(runCharPr)) == null ? void 0 : _d.script : void 0;
36040
37096
  const start = text2.length, nLinks = linkRanges.length, nOpen = openFields.length;
36041
37097
  walk(child, depth + 1);
36042
37098
  if (script && linkRanges.length === nLinks && openFields.length === nOpen && runHasOnlyText(child)) {
@@ -36054,8 +37110,8 @@ function extractParagraphInfo(para2, styleMap, ctx) {
36054
37110
  walk(para2);
36055
37111
  {
36056
37112
  const applied = [];
36057
- const closed = linkRanges.filter((r) => r.end !== void 0 && r.end > r.start).sort((a, b) => b.start - a.start);
36058
- for (const r of closed) {
37113
+ const closed2 = linkRanges.filter((r) => r.end !== void 0 && r.end > r.start).sort((a, b) => b.start - a.start);
37114
+ for (const r of closed2) {
36059
37115
  if (applied.some(([s, e]) => r.start < e && r.end > s)) continue;
36060
37116
  const anchor = text2.slice(r.start, r.end);
36061
37117
  if (!anchor.trim() || /[\n\x1E\[\]]/.test(anchor)) continue;
@@ -36065,6 +37121,9 @@ function extractParagraphInfo(para2, styleMap, ctx) {
36065
37121
  if (applied.length) href = void 0;
36066
37122
  }
36067
37123
  text2 = tidyScriptTags(text2);
37124
+ const toc = takeTocLeaders(text2);
37125
+ text2 = toc.text;
37126
+ const tocEntry = toc.tocEntry;
36068
37127
  const cleanParaText = (raw) => {
36069
37128
  let t = raw.replace(/[ \t]+/g, " ").trim();
36070
37129
  if (/^그림입니다\.?\s*원본\s*그림의\s*(이름|크기)/.test(t)) t = "";
@@ -36100,7 +37159,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
36100
37159
  if (!style.fontSize && !style.bold && !style.italic) style = void 0;
36101
37160
  }
36102
37161
  }
36103
- return { text: cleanText, href, footnote, style, segments, placeholderSpans };
37162
+ return { text: cleanText, href, footnote, style, segments, placeholderSpans, ...tocEntry ? { tocEntry } : {} };
36104
37163
  }
36105
37164
  function withPrefixSpan(spans, prefix) {
36106
37165
  return prefix ? [{ text: prefix + " " }, ...spans] : spans;
@@ -36313,6 +37372,11 @@ function parseDocInfo(records) {
36313
37372
  return { charShapes, paraShapes, styles, binData, numberings, bullets, borderEdges };
36314
37373
  }
36315
37374
  var LITERAL_DOLLAR_MARK = "\uFDD0";
37375
+ var LITERAL_LT_MARK = "\uFDD1";
37376
+ var LITERAL_LT_TAG = /\uFDD1(?=\/?(?:u|sup|sub)>)/g;
37377
+ function resolveLiteralLt(text2) {
37378
+ return text2.includes(LITERAL_LT_MARK) ? text2.replace(LITERAL_LT_TAG, "\\<").replaceAll(LITERAL_LT_MARK, "<") : text2;
37379
+ }
36316
37380
  function createParaTextState() {
36317
37381
  return { text: "", ctrlIdx: 0, fieldStack: [], fieldRanges: [] };
36318
37382
  }
@@ -36379,8 +37443,9 @@ function appendParaText(state, data, resolveControl) {
36379
37443
  // ── inline 타입 (2바이트 + 14바이트 확장) ──
36380
37444
  // 확장 u16[7] 중 [2] 의 하위 바이트 = 채움 모양(0 없음·3 점선 …), 상위 = 탭 종류+1 (rhwp tab_extended 실측).
36381
37445
  // 채움 탭도 보통 탭 — 채움선은 글이 아니고 뒤 글(목차 쪽 번호 등)은 남긴다 (HWPX section-walker "tab" 과 같은 정책)
37446
+ // 본문 파서(tocLeaders)는 목차 항목 판정까지 채움 탭을 TOC_LEADER 표지로 받는다 (#121)
36382
37447
  case CHAR_TAB:
36383
- result += " ";
37448
+ result += state.tocLeaders && i + 6 <= data.length && (data.readUInt16LE(i + 4) & 255) !== 0 ? TOC_LEADER : " ";
36384
37449
  if (i + 14 <= data.length) i += 14;
36385
37450
  break;
36386
37451
  default:
@@ -36413,7 +37478,7 @@ function appendParaText(state, data, resolveControl) {
36413
37478
  break;
36414
37479
  }
36415
37480
  }
36416
- result += ch === 36 && state.dollarMark ? LITERAL_DOLLAR_MARK : String.fromCharCode(ch);
37481
+ result += !state.dollarMark ? String.fromCharCode(ch) : ch === 36 ? LITERAL_DOLLAR_MARK : ch === 60 ? LITERAL_LT_MARK : String.fromCharCode(ch);
36417
37482
  }
36418
37483
  break;
36419
37484
  }
@@ -36561,7 +37626,7 @@ function resolveImageBlocks(binDataMap, blocks, warnings, sweepUnreferenced) {
36561
37626
  resolveImageSentinels(blocks, renamed);
36562
37627
  return images;
36563
37628
  }
36564
- function collectHwp5BinData(fileIndex) {
37629
+ function collectHwp5BinData(fileIndex, readStream) {
36565
37630
  const binDataMap = /* @__PURE__ */ new Map();
36566
37631
  if (fileIndex) {
36567
37632
  for (const entry of fileIndex) {
@@ -36569,35 +37634,37 @@ function collectHwp5BinData(fileIndex) {
36569
37634
  const match2 = entry.name.match(BIN_ENTRY_RE);
36570
37635
  if (!match2) continue;
36571
37636
  const idx = parseInt(match2[1], 16);
36572
- const data = normalizeBinPayload(Buffer.from(entry.content));
37637
+ const raw = readStream ? readStream(`/BinData/${entry.name}`) : Buffer.from(entry.content);
37638
+ if (!raw) continue;
37639
+ const data = normalizeBinPayload(raw);
36573
37640
  binDataMap.set(idx, { data, name: entry.name });
36574
37641
  }
36575
37642
  }
36576
37643
  return binDataMap;
36577
37644
  }
36578
- function collectHwp5BinDataLenient(lcfb) {
37645
+ function collectHwp5BinDataLenient(lcfb, readStream = lcfb.findStream) {
36579
37646
  const binDataMap = /* @__PURE__ */ new Map();
36580
37647
  const binRe = /^BIN([0-9A-Fa-f]{4,8})(?:\.|$)/;
36581
37648
  for (const e of lcfb.entries()) {
36582
37649
  const match2 = e.name.match(binRe);
36583
37650
  if (!match2) continue;
36584
37651
  const idx = parseInt(match2[1], 16);
36585
- const raw = lcfb.findStream(e.name);
37652
+ const raw = readStream(e.name);
36586
37653
  if (!raw) continue;
36587
37654
  binDataMap.set(idx, { data: normalizeBinPayload(raw), name: e.name });
36588
37655
  }
36589
37656
  return binDataMap;
36590
37657
  }
36591
- function extractHwp5Images(fileIndex, blocks, warnings, sweepUnreferenced) {
36592
- const binDataMap = collectHwp5BinData(fileIndex);
37658
+ function extractHwp5Images(fileIndex, blocks, warnings, sweepUnreferenced, readStream) {
37659
+ const binDataMap = collectHwp5BinData(fileIndex, readStream);
36593
37660
  if (binDataMap.size === 0) {
36594
37661
  resolveImageSentinels(blocks, /* @__PURE__ */ new Map());
36595
37662
  return [];
36596
37663
  }
36597
37664
  return resolveImageBlocks(binDataMap, blocks, warnings, sweepUnreferenced);
36598
37665
  }
36599
- function extractHwp5ImagesLenient(lcfb, blocks, warnings, sweepUnreferenced) {
36600
- const binDataMap = collectHwp5BinDataLenient(lcfb);
37666
+ function extractHwp5ImagesLenient(lcfb, blocks, warnings, sweepUnreferenced, readStream) {
37667
+ const binDataMap = collectHwp5BinDataLenient(lcfb, readStream);
36601
37668
  if (binDataMap.size === 0) {
36602
37669
  resolveImageSentinels(blocks, /* @__PURE__ */ new Map());
36603
37670
  return [];
@@ -36861,8 +37928,11 @@ async function resolveSectionPaths(zip) {
36861
37928
  function parseSectionPathsFromManifest(xml) {
36862
37929
  const parser = createXmlParser();
36863
37930
  const doc = parser.parseFromString(stripDtd(xml), "text/xml");
36864
- const items = doc.getElementsByTagName("opf:item");
36865
- const spine = doc.getElementsByTagName("opf:itemref");
37931
+ const opf = "http://www.idpf.org/2007/opf/";
37932
+ const namespacedItems = doc.getElementsByTagNameNS(opf, "item");
37933
+ const namespacedSpine = doc.getElementsByTagNameNS(opf, "itemref");
37934
+ const items = namespacedItems.length ? namespacedItems : doc.getElementsByTagName("opf:item");
37935
+ const spine = namespacedSpine.length ? namespacedSpine : doc.getElementsByTagName("opf:itemref");
36866
37936
  const idToHref = /* @__PURE__ */ new Map();
36867
37937
  for (let i = 0; i < items.length; i++) {
36868
37938
  const item = items[i];
@@ -37073,7 +38143,7 @@ async function parseHwpxDocument(buffer, options) {
37073
38143
  applyPageText(blocks, shared);
37074
38144
  const images = await extractImagesFromZip(zip, blocks, decompressed, warnings, !(options == null ? void 0 : options.pages), shared.track.deletedImageRefs);
37075
38145
  const shown = (options == null ? void 0 : options.layoutTables) === "keep" ? blocks : unframeLayoutTables(blocks, !!(options == null ? void 0 : options.keepTrailingEmptyCols));
37076
- detectHwpxHeadings(shown, styleMap);
38146
+ detectHwpxHeadings(shown, styleMap, shared.tocTexts);
37077
38147
  const outline = shown.filter((b) => b.type === "heading" && b.level && b.text).map((b) => ({ level: b.level, text: b.text, pageNumber: b.pageNumber }));
37078
38148
  const markdown = blocksToMarkdown(shown);
37079
38149
  return { markdown, blocks: shown, metadata, outline: outline.length > 0 ? outline : void 0, warnings: warnings.length > 0 ? warnings : void 0, images: images.length > 0 ? images : void 0 };
@@ -38318,6 +39388,7 @@ function emitParagraphBlocks(p) {
38318
39388
  pageNumber
38319
39389
  };
38320
39390
  if (p.headingLevel > 0) block2.level = p.headingLevel;
39391
+ if (p.tocEntry) TOC_ENTRY_BLOCKS.add(block2);
38321
39392
  if (style) {
38322
39393
  block2.style = style;
38323
39394
  if (style.strike || style.underline) block2.text = headMarker ? `${headMarker} ${decorate(trimmed)}` : decorate(trimmed);
@@ -38519,6 +39590,7 @@ function createHwp5DocState() {
38519
39590
  outlineNumberingId: 0,
38520
39591
  autoCounters: /* @__PURE__ */ new Map(),
38521
39592
  headerTexts: /* @__PURE__ */ new Set(),
39593
+ tocTexts: /* @__PURE__ */ new Set(),
38522
39594
  headerBlocks: [],
38523
39595
  footerBlocks: []
38524
39596
  };
@@ -38597,6 +39669,7 @@ function parseParagraph(records, start, end, ctx) {
38597
39669
  }
38598
39670
  const state = createParaTextState();
38599
39671
  state.dollarMark = true;
39672
+ state.tocLeaders = true;
38600
39673
  state.scriptAt = scriptLookup(charShapeRuns, ctx.docInfo);
38601
39674
  const resolver = (idx, id) => {
38602
39675
  var _a3;
@@ -38622,7 +39695,7 @@ function parseParagraph(records, start, end, ctx) {
38622
39695
  const anchor = text2.slice(r.start, r.end);
38623
39696
  if (ctrl.guide !== void 0) {
38624
39697
  if (ctx.doc.includeFieldPlaceholders) continue;
38625
- const plain4 = anchor.replaceAll(LITERAL_DOLLAR_MARK, "$");
39698
+ const plain4 = anchor.replaceAll(LITERAL_DOLLAR_MARK, "$").replaceAll(LITERAL_LT_MARK, "<");
38626
39699
  if (plain4 === ctrl.guide || plain4.trimEnd() === ctrl.guide) {
38627
39700
  text2 = text2.slice(0, r.start) + text2.slice(r.end);
38628
39701
  applied.push([r.start, r.end]);
@@ -38638,13 +39711,16 @@ function parseParagraph(records, start, end, ctx) {
38638
39711
  }
38639
39712
  }
38640
39713
  if (text2.includes(LITERAL_DOLLAR_MARK)) text2 = text2.replaceAll(LITERAL_DOLLAR_MARK, "\\$");
39714
+ text2 = resolveLiteralLt(text2);
38641
39715
  text2 = tidyScriptTags(text2);
39716
+ const toc = takeTocLeaders(text2);
39717
+ text2 = toc.text;
38642
39718
  let headingLevel = 0;
38643
39719
  let headMarker = null;
38644
39720
  const ps = ctx.docInfo && paraShapeId >= 0 && paraShapeId < ctx.docInfo.paraShapes.length ? ctx.docInfo.paraShapes[paraShapeId] : null;
38645
39721
  if (ps && ps.headType > 0) {
38646
39722
  if (ps.headType === 1) {
38647
- headingLevel = Math.min(ps.paraLevel + 1, 6);
39723
+ if (!toc.tocEntry) headingLevel = Math.min(ps.paraLevel + 1, 6);
38648
39724
  }
38649
39725
  if (ps.headType === 1 || ps.headType === 2) {
38650
39726
  const nid = ps.numberingId || (ps.headType === 1 ? ctx.doc.outlineNumberingId : 0);
@@ -38662,10 +39738,17 @@ function parseParagraph(records, start, end, ctx) {
38662
39738
  if (bullet && bullet.char !== "\uFFFF") headMarker = bullet.char;
38663
39739
  }
38664
39740
  }
39741
+ if (toc.tocEntry) {
39742
+ for (const line of text2.split("\n")) if (line.trim()) {
39743
+ ctx.doc.tocTexts.add(line.trim());
39744
+ if (headMarker) ctx.doc.tocTexts.add(`${headMarker} ${line.trim()}`);
39745
+ }
39746
+ }
38665
39747
  return emitParagraphBlocks({
38666
39748
  text: text2,
38667
39749
  headMarker,
38668
39750
  headingLevel,
39751
+ tocEntry: toc.tocEntry,
38669
39752
  style: ctx.docInfo && charShapeIds.length > 0 ? resolveCharStyle(charShapeIds, ctx.docInfo) : void 0,
38670
39753
  footnotes: ctrls.filter((c) => c.footnote).map((c) => c.footnote),
38671
39754
  // 컨트롤 파생 블록 (표/이미지/글상자) — 컨트롤 순서대로
@@ -39131,7 +40214,7 @@ function readHwp5DocInfoRecords(c) {
39131
40214
  }
39132
40215
  }
39133
40216
  function readHwp5SectionStreams(c) {
39134
- return c.distribution ? c.cfb ? findViewTextSections(c.cfb, c.compressed) : findViewTextSectionsLenient(c.lenientCfb, c.compressed) : c.encrypted ? findSectionsVia(c.findStream) : c.cfb ? findSections(c.cfb) : findSectionsLenient(c.lenientCfb, c.compressed);
40217
+ return c.distribution ? c.cfb ? findViewTextSections(c.cfb, c.compressed) : findViewTextSectionsLenient(c.lenientCfb, c.compressed) : c.encrypted ? findSectionsVia(c.findStream) : c.cfb ? findSections(c.cfb) : findSectionsLenient(c.lenientCfb);
39135
40218
  }
39136
40219
  function readHwp5SectionRecords(c, sections, warnings) {
39137
40220
  const out = [];
@@ -39151,7 +40234,8 @@ function readHwp5SectionRecords(c, sections, warnings) {
39151
40234
  return out;
39152
40235
  }
39153
40236
  function readHwp5BinData(c) {
39154
- return c.cfb ? collectHwp5BinData(c.cfb.FileIndex) : collectHwp5BinDataLenient(c.lenientCfb);
40237
+ const readStream = c.encrypted ? c.findStream : void 0;
40238
+ return c.cfb ? collectHwp5BinData(c.cfb.FileIndex, readStream) : collectHwp5BinDataLenient(c.lenientCfb, readStream);
39155
40239
  }
39156
40240
  function parseHwp5Document(buffer, options) {
39157
40241
  var _a2;
@@ -39220,7 +40304,7 @@ function parseHwp5Document(buffer, options) {
39220
40304
  bodyBlocks = bodyBlocks.filter((b) => b.pageNumber != null && pageFilter.has(b.pageNumber));
39221
40305
  }
39222
40306
  const blocks = [...doc.headerBlocks, ...bodyBlocks, ...doc.footerBlocks];
39223
- const images = cfb ? extractHwp5Images(cfb.FileIndex, blocks, warnings, !pageFilter) : extractHwp5ImagesLenient(lenientCfb, blocks, warnings, !pageFilter);
40307
+ const images = cfb ? extractHwp5Images(cfb.FileIndex, blocks, warnings, !pageFilter, encrypted ? findStream : void 0) : extractHwp5ImagesLenient(lenientCfb, blocks, warnings, !pageFilter, encrypted ? findStream : void 0);
39224
40308
  let flatBlocks = flattenLayoutTables(blocks);
39225
40309
  if ((options == null ? void 0 : options.layoutTables) !== "keep") flatBlocks = unframeLayoutTables(flatBlocks, !!(options == null ? void 0 : options.keepTrailingEmptyCols));
39226
40310
  if (options == null ? void 0 : options.dedupeRunningHeaders) {
@@ -39230,7 +40314,7 @@ function parseHwp5Document(buffer, options) {
39230
40314
  flatBlocks = deduped;
39231
40315
  }
39232
40316
  if (docInfo) {
39233
- detectHwp5Headings(flatBlocks, docInfo);
40317
+ detectHwp5Headings(flatBlocks, docInfo, doc.tocTexts);
39234
40318
  }
39235
40319
  const outline = flatBlocks.filter((b) => b.type === "heading" && b.level && b.text).map((b) => ({ level: b.level, text: b.text, pageNumber: b.pageNumber }));
39236
40320
  let markdown = blocksToMarkdown(flatBlocks);
@@ -39263,7 +40347,7 @@ function parseDocInfoFromStream(raw, compressed) {
39263
40347
  return null;
39264
40348
  }
39265
40349
  }
39266
- function detectHwp5Headings(blocks, docInfo) {
40350
+ function detectHwp5Headings(blocks, docInfo, tocTexts) {
39267
40351
  var _a2, _b;
39268
40352
  let baseFontSize = 0;
39269
40353
  const sizeFreq = /* @__PURE__ */ new Map();
@@ -39294,7 +40378,7 @@ function detectHwp5Headings(blocks, docInfo) {
39294
40378
  if (baseFontSize <= 0) return;
39295
40379
  for (const block2 of blocks) {
39296
40380
  if (block2.type === "heading") continue;
39297
- if (block2.type !== "paragraph" || !block2.text) continue;
40381
+ if (block2.type !== "paragraph" || !block2.text || TOC_ENTRY_BLOCKS.has(block2) || (tocTexts == null ? void 0 : tocTexts.has(block2.text.trim()))) continue;
39298
40382
  const text2 = block2.text.trim();
39299
40383
  if (text2.length === 0 || text2.length > 200) continue;
39300
40384
  if (/^\d+$/.test(text2)) continue;
@@ -39431,17 +40515,16 @@ function findSections(cfb) {
39431
40515
  }
39432
40516
  return sections.sort((a, b) => a.idx - b.idx).map((s) => s.content);
39433
40517
  }
39434
- function findSectionsLenient(lcfb, compressed) {
40518
+ function findSectionsLenient(lcfb) {
39435
40519
  var _a2;
39436
40520
  const sections = [];
39437
- let totalDecompressed = 0;
40521
+ let totalBytes = 0;
39438
40522
  for (let i = 0; i < MAX_SECTIONS; i++) {
39439
40523
  const raw = (_a2 = lcfb.findStream(`/BodyText/Section${i}`)) != null ? _a2 : lcfb.findStream(`Section${i}`);
39440
40524
  if (!raw) break;
39441
- const content = compressed ? decompressStream(raw) : raw;
39442
- totalDecompressed += content.length;
39443
- if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
39444
- sections.push({ idx: i, content });
40525
+ totalBytes += raw.length;
40526
+ if (totalBytes > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
40527
+ sections.push({ idx: i, content: raw });
39445
40528
  }
39446
40529
  if (sections.length === 0) {
39447
40530
  for (const e of lcfb.entries()) {
@@ -39450,10 +40533,9 @@ function findSectionsLenient(lcfb, compressed) {
39450
40533
  const idx = parseInt(e.name.replace("Section", ""), 10) || 0;
39451
40534
  const raw = lcfb.findStream(e.name);
39452
40535
  if (raw) {
39453
- const content = compressed ? decompressStream(raw) : raw;
39454
- totalDecompressed += content.length;
39455
- if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
39456
- sections.push({ idx, content });
40536
+ totalBytes += raw.length;
40537
+ if (totalBytes > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
40538
+ sections.push({ idx, content: raw });
39457
40539
  }
39458
40540
  }
39459
40541
  }
@@ -39484,6 +40566,7 @@ init_cjs_shims();
39484
40566
  var import_zlib5 = require("zlib");
39485
40567
  init_utils();
39486
40568
  init_builder();
40569
+ init_script_tags();
39487
40570
 
39488
40571
  // .kordoc-source/src/hwp3/drawing.ts
39489
40572
  init_cjs_shims();
@@ -52225,7 +53308,7 @@ function parseCharStream(reader, charCount, ctx, para2) {
52225
53308
  continue;
52226
53309
  }
52227
53310
  if (ch >= 32) {
52228
- para2.text += escapeLiteralDollar((_a2 = decodeJohabText(ch)) != null ? _a2 : "");
53311
+ para2.text += escapeLiteralTags(escapeLiteralDollar((_a2 = decodeJohabText(ch)) != null ? _a2 : ""));
52229
53312
  continue;
52230
53313
  }
52231
53314
  if (ch === 9) {
@@ -52458,6 +53541,7 @@ var import_jszip4 = __toESM(require_lib3(), 1);
52458
53541
  var import_xmldom2 = __toESM(require_lib4(), 1);
52459
53542
  init_utils();
52460
53543
  init_builder();
53544
+ init_script_tags();
52461
53545
 
52462
53546
  // .kordoc-source/src/xlsx/sheet-blocks.ts
52463
53547
  init_cjs_shims();
@@ -52587,7 +53671,7 @@ function collectRichText(root) {
52587
53671
  const el = children[i];
52588
53672
  const local = el.localName || ((_a2 = el.tagName) == null ? void 0 : _a2.replace(/^[^:]+:/, "")) || "";
52589
53673
  if (local === "rPh") continue;
52590
- if (local === "t") out += (_b = el.textContent) != null ? _b : "";
53674
+ if (local === "t") out += escapeLiteralTags(escapeLiteralDollar((_b = el.textContent) != null ? _b : ""));
52591
53675
  else walk(el);
52592
53676
  }
52593
53677
  };
@@ -53118,6 +54202,8 @@ function decodeSST(records) {
53118
54202
 
53119
54203
  // .kordoc-source/src/xls/cell.ts
53120
54204
  init_cjs_shims();
54205
+ init_script_tags();
54206
+ init_builder();
53121
54207
  function errorCodeToText(code2) {
53122
54208
  switch (code2) {
53123
54209
  case 0:
@@ -53229,14 +54315,14 @@ function extractSheetCells(records, bofIndex, sst, convertNum) {
53229
54315
  const h = readCellHeader(rec.data);
53230
54316
  if (h && rec.data.length >= 10) {
53231
54317
  const isst = rec.data.readUInt32LE(6);
53232
- cells.push({ row: h.row, col: h.col, value: (_a2 = sst[isst]) != null ? _a2 : "" });
54318
+ cells.push({ row: h.row, col: h.col, value: escapeLiteralTags(escapeLiteralDollar((_a2 = sst[isst]) != null ? _a2 : "")) });
53233
54319
  }
53234
54320
  break;
53235
54321
  }
53236
54322
  case OP_LABEL: {
53237
54323
  const h = readCellHeader(rec.data);
53238
54324
  if (h) {
53239
- cells.push({ row: h.row, col: h.col, value: decodeLabelString(rec.data) });
54325
+ cells.push({ row: h.row, col: h.col, value: escapeLiteralTags(escapeLiteralDollar(decodeLabelString(rec.data))) });
53240
54326
  }
53241
54327
  break;
53242
54328
  }
@@ -53252,7 +54338,7 @@ function extractSheetCells(records, bofIndex, sst, convertNum) {
53252
54338
  cells.push({
53253
54339
  row: h.row,
53254
54340
  col: h.col,
53255
- value: decodeFormulaStringRecord(next.data)
54341
+ value: escapeLiteralTags(escapeLiteralDollar(decodeFormulaStringRecord(next.data)))
53256
54342
  });
53257
54343
  i = j;
53258
54344
  } else {
@@ -53980,6 +55066,7 @@ function isDisplayMath(el) {
53980
55066
  // .kordoc-source/src/docx/parser.ts
53981
55067
  var MAX_DECOMPRESS_SIZE5 = unzipLimitBytes(100 * 1024 * 1024);
53982
55068
  var MEDIA_PART_RE = /^word\/(?:media|embeddings)\//;
55069
+ var NEVER_READ_RE = /^word\/(?:embeddings\/.*|media\/.+\.(?:mp4|m4v|mov|avi|wmv|mpe?g|mkv|webm|mp3|wav|m4a|wma|aac|ogg|flac|mid|bin))$/i;
53983
55070
  function matchesLocal(el, localName3) {
53984
55071
  var _a2, _b;
53985
55072
  return el.localName === localName3 || ((_b = (_a2 = el.tagName) == null ? void 0 : _a2.endsWith(`:${localName3}`)) != null ? _b : false);
@@ -54176,7 +55263,7 @@ function parseFootnotes(xml) {
54176
55263
  const runs = findElements(p, "r");
54177
55264
  for (const r of runs) {
54178
55265
  const tElements = getChildElements(r, "t");
54179
- for (const t of tElements) texts.push((_a2 = t.textContent) != null ? _a2 : "");
55266
+ for (const t of tElements) texts.push(escapeLiteralTags(escapeLiteralDollar((_a2 = t.textContent) != null ? _a2 : "")));
54180
55267
  }
54181
55268
  }
54182
55269
  notes.set(id, texts.join("").trim());
@@ -54209,7 +55296,7 @@ function extractRun(r) {
54209
55296
  var _a2;
54210
55297
  let text2 = "";
54211
55298
  for (const el of effectiveChildElements(r)) {
54212
- if (matchesLocal(el, "t")) text2 += (_a2 = el.textContent) != null ? _a2 : "";
55299
+ if (matchesLocal(el, "t")) text2 += escapeLiteralTags(escapeLiteralDollar((_a2 = el.textContent) != null ? _a2 : ""));
54213
55300
  else if (matchesLocal(el, "br") || matchesLocal(el, "cr")) text2 += "\n";
54214
55301
  else if (matchesLocal(el, "tab")) text2 += " ";
54215
55302
  else if (matchesLocal(el, "sym")) text2 += symbolChar(getAttr(el, "font"), getAttr(el, "char"));
@@ -54485,7 +55572,7 @@ function collectCellText(tc2, styles, numbering, footnotes, rels, depth) {
54485
55572
  return parts;
54486
55573
  }
54487
55574
  async function buildImageMap(zip, rels, doc, warnings, readBytes) {
54488
- var _a2, _b, _c, _d;
55575
+ var _a2, _b;
54489
55576
  const imageMap = /* @__PURE__ */ new Map();
54490
55577
  const images = [];
54491
55578
  let imgIdx = 0;
@@ -54509,7 +55596,7 @@ async function buildImageMap(zip, rels, doc, warnings, readBytes) {
54509
55596
  let data = null;
54510
55597
  if (readBytes) data = await imgFile.async("uint8array");
54511
55598
  imgIdx++;
54512
- const ext = (_b = (_a2 = imgPath.split(".").pop()) == null ? void 0 : _a2.toLowerCase()) != null ? _b : "png";
55599
+ const ext = partExtension(imgPath);
54513
55600
  const mimeMap = {
54514
55601
  png: "image/png",
54515
55602
  jpg: "image/jpeg",
@@ -54524,7 +55611,7 @@ async function buildImageMap(zip, rels, doc, warnings, readBytes) {
54524
55611
  };
54525
55612
  const filename = `image_${String(imgIdx).padStart(3, "0")}.${ext}`;
54526
55613
  if (data) {
54527
- const mimeType = (_d = (_c = mimeMap[ext]) != null ? _c : detectImageMime(data)) != null ? _d : "application/octet-stream";
55614
+ const mimeType = (_b = (_a2 = mimeMap[ext]) != null ? _a2 : detectImageMime(data)) != null ? _b : "application/octet-stream";
54528
55615
  images.push({ filename, data, mimeType, source: imgPath });
54529
55616
  }
54530
55617
  imageMap.set(embedId, filename);
@@ -54614,7 +55701,7 @@ async function parseHeaderFooterBlocks(zip, doc, rels, kind, styles, numbering,
54614
55701
  async function parseDocxDocument(buffer, options) {
54615
55702
  var _a2, _b;
54616
55703
  const readImages = (options == null ? void 0 : options.images) !== false;
54617
- precheckZipSize(buffer, MAX_DECOMPRESS_SIZE5, void 0, { re: MEDIA_PART_RE, skip: !readImages });
55704
+ precheckZipSize(buffer, MAX_DECOMPRESS_SIZE5, void 0, { re: MEDIA_PART_RE, skip: !readImages, never: NEVER_READ_RE });
54618
55705
  const zip = await import_jszip5.default.loadAsync(buffer);
54619
55706
  const warnings = [];
54620
55707
  const docFile = zip.file("word/document.xml");
@@ -54734,10 +55821,349 @@ async function parseDocxDocument(buffer, options) {
54734
55821
  };
54735
55822
  }
54736
55823
 
54737
- // .kordoc-source/src/hwpml/parser.ts
55824
+ // .kordoc-source/src/pptx/parser.ts
54738
55825
  init_cjs_shims();
55826
+ var import_jszip6 = __toESM(require_lib3(), 1);
54739
55827
  var import_xmldom4 = __toESM(require_lib4(), 1);
55828
+ init_utils();
55829
+ init_page_range();
55830
+ init_builder();
55831
+ init_script_tags();
55832
+ var MAX_DECOMPRESS_SIZE6 = unzipLimitBytes(100 * 1024 * 1024);
55833
+ var MEDIA_PART_RE2 = /^ppt\/(?:media|embeddings)\//;
55834
+ var NEVER_READ_RE2 = /^ppt\/(?:embeddings\/.*|media\/.+\.(?:mp4|m4v|mov|avi|wmv|mpe?g|mkv|webm|mp3|wav|m4a|wma|aac|ogg|flac|mid|bin))$/i;
55835
+ var MAX_ZIP_ENTRIES2 = 1e4;
55836
+ var MAX_SLIDES = 2e3;
55837
+ var SKIP_PLACEHOLDERS = /* @__PURE__ */ new Set(["sldNum", "dt", "ftr", "hdr", "sldImg"]);
55838
+ var BULLET_PLACEHOLDERS = /* @__PURE__ */ new Set(["body", "obj"]);
55839
+ var REL_NOTES = "/notesSlide";
55840
+ var REL_IMAGE = "/image";
55841
+ var SLIDE_PART_RE = /^ppt\/slides\/slide(\d+)\.xml$/;
55842
+ var IMAGE_MIME = {
55843
+ png: "image/png",
55844
+ jpg: "image/jpeg",
55845
+ jpeg: "image/jpeg",
55846
+ gif: "image/gif",
55847
+ bmp: "image/bmp",
55848
+ wmf: "image/wmf",
55849
+ emf: "image/emf",
55850
+ tif: "image/tiff",
55851
+ tiff: "image/tiff",
55852
+ svg: "image/svg+xml"
55853
+ };
55854
+ function parseXml3(text2) {
55855
+ return new import_xmldom4.DOMParser().parseFromString(stripDtd(text2), "text/xml");
55856
+ }
55857
+ function getAttr2(el, name) {
55858
+ const attrs = el.attributes;
55859
+ for (let i = 0; i < attrs.length; i++) {
55860
+ const attr = attrs[i];
55861
+ if (attr.localName === name || attr.name === name) return attr.value;
55862
+ }
55863
+ return null;
55864
+ }
55865
+ var NS_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
55866
+ function getRelId(el) {
55867
+ const attrs = el.attributes;
55868
+ for (let i = 0; i < attrs.length; i++) {
55869
+ const attr = attrs[i];
55870
+ if (attr.localName === "id" && (attr.namespaceURI === NS_REL || attr.name === "r:id")) return attr.value;
55871
+ }
55872
+ return null;
55873
+ }
55874
+ function findPath(el, ...names) {
55875
+ for (const name of names) {
55876
+ if (!el) return null;
55877
+ el = findChildByLocalName(el, name);
55878
+ }
55879
+ return el;
55880
+ }
55881
+ function resolvePart(baseDir, target) {
55882
+ if (target.startsWith("/")) return target.slice(1);
55883
+ const parts = baseDir ? baseDir.split("/") : [];
55884
+ for (const seg of target.split("/")) {
55885
+ if (seg === "..") parts.pop();
55886
+ else if (seg && seg !== ".") parts.push(seg);
55887
+ }
55888
+ return parts.join("/");
55889
+ }
55890
+ async function readRels(zip, part) {
55891
+ var _a2;
55892
+ const map2 = /* @__PURE__ */ new Map();
55893
+ const slash = part.lastIndexOf("/");
55894
+ const dir = slash >= 0 ? part.slice(0, slash) : "";
55895
+ const file = zip.file(`${dir ? dir + "/" : ""}_rels/${part.slice(slash + 1)}.rels`);
55896
+ if (!file) return map2;
55897
+ const doc = parseXml3(await file.async("text"));
55898
+ for (const rel of childrenByLocalName(doc.documentElement, "Relationship")) {
55899
+ const id = getAttr2(rel, "Id");
55900
+ const target = getAttr2(rel, "Target");
55901
+ if (!id || !target || getAttr2(rel, "TargetMode") === "External") continue;
55902
+ map2.set(id, { type: (_a2 = getAttr2(rel, "Type")) != null ? _a2 : "", target: resolvePart(dir, target) });
55903
+ }
55904
+ return map2;
55905
+ }
55906
+ async function slideParts(zip) {
55907
+ var _a2, _b;
55908
+ const ordered = [];
55909
+ const presFile = zip.file("ppt/presentation.xml");
55910
+ if (presFile) {
55911
+ const pres = parseXml3(await presFile.async("text"));
55912
+ const rels = await readRels(zip, "ppt/presentation.xml");
55913
+ const list2 = findChildByLocalName(pres.documentElement, "sldIdLst");
55914
+ for (const sld of list2 ? childrenByLocalName(list2, "sldId") : []) {
55915
+ const target = (_b = rels.get((_a2 = getRelId(sld)) != null ? _a2 : "")) == null ? void 0 : _b.target;
55916
+ if (target && zip.file(target)) ordered.push(target);
55917
+ }
55918
+ }
55919
+ if (ordered.length === 0) {
55920
+ const names = Object.keys(zip.files).filter((n) => SLIDE_PART_RE.test(n));
55921
+ names.sort((a, b) => Number(SLIDE_PART_RE.exec(a)[1]) - Number(SLIDE_PART_RE.exec(b)[1]));
55922
+ ordered.push(...names);
55923
+ }
55924
+ if (ordered.length > MAX_SLIDES) throw new KordocError(`PPTX \uC2AC\uB77C\uC774\uB4DC \uC218 \uCD08\uACFC: ${ordered.length} (\uCD5C\uB300 ${MAX_SLIDES})`);
55925
+ return ordered;
55926
+ }
55927
+ function paragraphText(p) {
55928
+ var _a2;
55929
+ let text2 = "";
55930
+ for (const child of elementChildren(p)) {
55931
+ const name = localName(child);
55932
+ if (name === "r" || name === "fld") {
55933
+ const t = findChildByLocalName(child, "t");
55934
+ const rPr = findChildByLocalName(child, "rPr");
55935
+ const baseline = Number(rPr ? (_a2 = getAttr2(rPr, "baseline")) != null ? _a2 : 0 : 0);
55936
+ if (t) text2 += wrapScript(escapeLiteralTags(escapeLiteralDollar(rawTextContent(t))), baseline > 0 ? "sup" : baseline < 0 ? "sub" : null);
55937
+ } else if (name === "br") {
55938
+ text2 += " ";
55939
+ }
55940
+ }
55941
+ return tidyScriptTags(text2.replace(/\s+/g, " ").trim());
55942
+ }
55943
+ function bodyParagraphs(txBody) {
55944
+ var _a2;
55945
+ const out = [];
55946
+ for (const p of childrenByLocalName(txBody, "p")) {
55947
+ const text2 = paragraphText(p);
55948
+ if (!text2) continue;
55949
+ const pPr = findChildByLocalName(p, "pPr");
55950
+ let bullet;
55951
+ if (pPr) {
55952
+ if (findChildByLocalName(pPr, "buNone")) bullet = "none";
55953
+ else if (findChildByLocalName(pPr, "buAutoNum")) bullet = "ordered";
55954
+ else if (findChildByLocalName(pPr, "buChar") || findChildByLocalName(pPr, "buBlip")) bullet = "unordered";
55955
+ }
55956
+ const lvl = Math.max(0, parseInt(pPr ? (_a2 = getAttr2(pPr, "lvl")) != null ? _a2 : "0" : "0", 10) || 0);
55957
+ out.push({ text: text2, lvl, bullet });
55958
+ }
55959
+ return out;
55960
+ }
55961
+ function placeholderType(sp) {
55962
+ var _a2;
55963
+ const ph = findPath(sp, "nvSpPr", "nvPr", "ph");
55964
+ return ph ? (_a2 = getAttr2(ph, "type")) != null ? _a2 : "obj" : null;
55965
+ }
55966
+ function pushParagraphs(paras, bulletDefault, page, out) {
55967
+ var _a2, _b;
55968
+ let lastList = null;
55969
+ for (const para2 of paras) {
55970
+ const bullet = (_a2 = para2.bullet) != null ? _a2 : bulletDefault ? "unordered" : "none";
55971
+ if (bullet === "none") {
55972
+ out.push({ type: "paragraph", text: para2.text, pageNumber: page });
55973
+ lastList = null;
55974
+ continue;
55975
+ }
55976
+ const item = { type: "list", text: para2.text, listType: bullet, pageNumber: page };
55977
+ if (para2.lvl > 0 && lastList) {
55978
+ ;
55979
+ ((_b = lastList.children) != null ? _b : lastList.children = []).push(item);
55980
+ } else {
55981
+ out.push(item);
55982
+ lastList = item;
55983
+ }
55984
+ }
55985
+ }
55986
+ function parseTable2(tbl2, page, keepEmptyCols) {
55987
+ const rows = childrenByLocalName(tbl2, "tr");
55988
+ if (rows.length === 0) return null;
55989
+ const cellRows = rows.map((tr, r) => {
55990
+ const cells = [];
55991
+ childrenByLocalName(tr, "tc").forEach((tc2, c) => {
55992
+ var _a2, _b;
55993
+ if (getAttr2(tc2, "hMerge") === "1" || getAttr2(tc2, "vMerge") === "1") return;
55994
+ const txBody = findChildByLocalName(tc2, "txBody");
55995
+ const text2 = txBody ? bodyParagraphs(txBody).map((p) => p.text).join("\n") : "";
55996
+ cells.push({
55997
+ text: text2,
55998
+ colSpan: Math.max(1, parseInt((_a2 = getAttr2(tc2, "gridSpan")) != null ? _a2 : "1", 10) || 1),
55999
+ rowSpan: Math.max(1, parseInt((_b = getAttr2(tc2, "rowSpan")) != null ? _b : "1", 10) || 1),
56000
+ colAddr: c,
56001
+ rowAddr: r
56002
+ });
56003
+ });
56004
+ return cells;
56005
+ });
56006
+ const table3 = buildTable(cellRows, { keepAnchoredEmptyCols: keepEmptyCols });
56007
+ if (table3.rows === 0 || table3.cols === 0) return null;
56008
+ return { type: "table", table: table3, pageNumber: page };
56009
+ }
56010
+ async function pictureBlock(pic, ctx) {
56011
+ var _a2, _b, _c;
56012
+ const blip = findPath(pic, "blipFill", "blip");
56013
+ const embed = blip ? getAttr2(blip, "embed") : null;
56014
+ const rel = embed ? ctx.rels.get(embed) : void 0;
56015
+ if (!rel || !rel.type.endsWith(REL_IMAGE)) return null;
56016
+ let filename = ctx.imageNames.get(rel.target);
56017
+ if (!filename) {
56018
+ const file = ctx.zip.file(rel.target);
56019
+ if (!file) return null;
56020
+ const ext = partExtension(rel.target);
56021
+ filename = `image_${String(ctx.imageNames.size + 1).padStart(3, "0")}.${ext}`;
56022
+ try {
56023
+ if (((_a2 = ctx.options) == null ? void 0 : _a2.images) !== false) {
56024
+ const data = await file.async("uint8array");
56025
+ ctx.images.push({ filename, data, mimeType: (_c = (_b = IMAGE_MIME[ext]) != null ? _b : detectImageMime(data)) != null ? _c : "application/octet-stream", source: rel.target });
56026
+ }
56027
+ } catch (err) {
56028
+ ctx.warnings.push({
56029
+ page: ctx.page,
56030
+ code: "SKIPPED_IMAGE",
56031
+ message: `PPTX \uC774\uBBF8\uC9C0 \uCD94\uCD9C \uC2E4\uD328 (${rel.target}): ${err instanceof Error ? err.message : String(err)}`
56032
+ });
56033
+ return null;
56034
+ }
56035
+ ctx.imageNames.set(rel.target, filename);
56036
+ }
56037
+ return { type: "image", text: filename, pageNumber: ctx.page };
56038
+ }
56039
+ async function walkShapes(tree, ctx, out, depth = 0) {
56040
+ var _a2, _b;
56041
+ if (depth > MAX_XML_DEPTH) return;
56042
+ for (const el of elementChildren(tree)) {
56043
+ switch (localName(el)) {
56044
+ case "grpSp":
56045
+ await walkShapes(el, ctx, out, depth + 1);
56046
+ break;
56047
+ case "AlternateContent": {
56048
+ const choice = findChildByLocalName(el, "Choice");
56049
+ if (choice) await walkShapes(choice, ctx, out, depth + 1);
56050
+ break;
56051
+ }
56052
+ case "sp": {
56053
+ const ph = placeholderType(el);
56054
+ const txBody = findChildByLocalName(el, "txBody");
56055
+ if (ph && SKIP_PLACEHOLDERS.has(ph) || !txBody) break;
56056
+ const paras = bodyParagraphs(txBody);
56057
+ if (paras.length === 0) break;
56058
+ if (ph === "title" || ph === "ctrTitle") {
56059
+ out.push({ type: "heading", level: ph === "ctrTitle" ? 1 : 2, text: paras.map((p) => p.text).join(" "), pageNumber: ctx.page });
56060
+ } else {
56061
+ pushParagraphs(paras, ph !== null && BULLET_PLACEHOLDERS.has(ph), ctx.page, out);
56062
+ }
56063
+ break;
56064
+ }
56065
+ case "graphicFrame": {
56066
+ const data = findPath(el, "graphic", "graphicData");
56067
+ const tbl2 = data ? findChildByLocalName(data, "tbl") : null;
56068
+ if (tbl2) {
56069
+ const block2 = parseTable2(tbl2, ctx.page, (_a2 = ctx.options) == null ? void 0 : _a2.keepTrailingEmptyCols);
56070
+ if (block2) out.push(block2);
56071
+ } else if (data) {
56072
+ const uri = (_b = getAttr2(data, "uri")) != null ? _b : "";
56073
+ const kind = /chart/i.test(uri) ? "\uCC28\uD2B8" : /diagram/i.test(uri) ? "SmartArt" : "\uAC1C\uCCB4";
56074
+ ctx.warnings.push({ page: ctx.page, code: "UNSUPPORTED_ELEMENT", message: `PPTX ${kind}\uC758 \uAE00\uC740 \uC77D\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (${ctx.page}\uCABD)` });
56075
+ }
56076
+ break;
56077
+ }
56078
+ case "pic": {
56079
+ const block2 = await pictureBlock(el, ctx);
56080
+ if (block2) out.push(block2);
56081
+ break;
56082
+ }
56083
+ }
56084
+ }
56085
+ }
56086
+ async function notesText(zip, rels) {
56087
+ const rel = [...rels.values()].find((r) => r.type.endsWith(REL_NOTES));
56088
+ const file = rel ? zip.file(rel.target) : null;
56089
+ if (!file) return "";
56090
+ const tree = findPath(parseXml3(await file.async("text")).documentElement, "cSld", "spTree");
56091
+ const texts = [];
56092
+ for (const sp of tree ? childrenByLocalName(tree, "sp") : []) {
56093
+ const txBody = findChildByLocalName(sp, "txBody");
56094
+ if (placeholderType(sp) === "body" && txBody) texts.push(...bodyParagraphs(txBody).map((p) => p.text));
56095
+ }
56096
+ return texts.join(" ");
56097
+ }
56098
+ async function parsePptxDocument(buffer, options) {
56099
+ precheckZipSize(buffer, MAX_DECOMPRESS_SIZE6, MAX_ZIP_ENTRIES2, { re: MEDIA_PART_RE2, skip: (options == null ? void 0 : options.images) === false, never: NEVER_READ_RE2 });
56100
+ const zip = await import_jszip6.default.loadAsync(buffer);
56101
+ if (!zip.file("ppt/presentation.xml")) {
56102
+ throw new KordocError("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 PPTX \uD30C\uC77C: ppt/presentation.xml\uC774 \uC5C6\uC2B5\uB2C8\uB2E4");
56103
+ }
56104
+ const warnings = [];
56105
+ const blocks = [];
56106
+ const imageNames = /* @__PURE__ */ new Map();
56107
+ const images = [];
56108
+ const slides = await slideParts(zip);
56109
+ const pageFilter = (options == null ? void 0 : options.pages) ? parsePageRange(options.pages, slides.length) : null;
56110
+ for (let i = 0; i < slides.length; i++) {
56111
+ const page = i + 1;
56112
+ if (pageFilter && !pageFilter.has(page)) continue;
56113
+ const root = parseXml3(await zip.file(slides[i]).async("text")).documentElement;
56114
+ if (getAttr2(root, "show") === "0") {
56115
+ warnings.push({ page, code: "HIDDEN_TEXT_FILTERED", message: `PPTX \uC228\uAE34 \uC2AC\uB77C\uC774\uB4DC ${page}\uCABD\uC744 \uAC74\uB108\uB701\uB2C8\uB2E4` });
56116
+ continue;
56117
+ }
56118
+ const rels = await readRels(zip, slides[i]);
56119
+ const tree = findPath(root, "cSld", "spTree");
56120
+ if (tree) await walkShapes(tree, { zip, rels, page, warnings, options, imageNames, images }, blocks);
56121
+ const notes = await notesText(zip, rels);
56122
+ if (notes) blocks.push({ type: "paragraph", text: `\uBC1C\uD45C\uC790 \uB178\uD2B8: ${notes}`, quote: true, pageNumber: page });
56123
+ }
56124
+ const metadata = { pageCount: slides.length, pageMode: "layout" };
56125
+ const coreFile = zip.file("docProps/core.xml");
56126
+ if (coreFile) {
56127
+ try {
56128
+ const coreDoc = parseXml3(await coreFile.async("text"));
56129
+ const getFirst = (tag) => {
56130
+ var _a2;
56131
+ const els = coreDoc.getElementsByTagName(tag);
56132
+ return els.length > 0 ? ((_a2 = els[0].textContent) != null ? _a2 : "").trim() || void 0 : void 0;
56133
+ };
56134
+ metadata.title = getFirst("dc:title") || getFirst("dcterms:title");
56135
+ metadata.author = getFirst("dc:creator");
56136
+ metadata.description = getFirst("dc:description");
56137
+ const created = getFirst("dcterms:created");
56138
+ if (created) metadata.createdAt = created;
56139
+ const modified = getFirst("dcterms:modified");
56140
+ if (modified) metadata.modifiedAt = modified;
56141
+ } catch (err) {
56142
+ warnings.push({
56143
+ code: "PARTIAL_PARSE",
56144
+ message: `PPTX \uBA54\uD0C0\uB370\uC774\uD130(core.xml) \uD30C\uC2F1 \uC2E4\uD328: ${err instanceof Error ? err.message : String(err)}`
56145
+ });
56146
+ }
56147
+ }
56148
+ const outline = blocks.filter((b) => b.type === "heading").map((b) => {
56149
+ var _a2, _b;
56150
+ return { level: (_a2 = b.level) != null ? _a2 : 2, text: (_b = b.text) != null ? _b : "", pageNumber: b.pageNumber };
56151
+ });
56152
+ return {
56153
+ markdown: blocksToMarkdown(blocks),
56154
+ blocks,
56155
+ metadata,
56156
+ outline: outline.length > 0 ? outline : void 0,
56157
+ warnings: warnings.length > 0 ? warnings : void 0,
56158
+ images: images.length > 0 ? images : void 0
56159
+ };
56160
+ }
56161
+
56162
+ // .kordoc-source/src/hwpml/parser.ts
56163
+ init_cjs_shims();
56164
+ var import_xmldom5 = __toESM(require_lib4(), 1);
54740
56165
  init_builder();
56166
+ init_script_tags();
54741
56167
  init_page_range();
54742
56168
  init_utils();
54743
56169
  var MAX_TABLE_ROWS = 5e3;
@@ -54752,7 +56178,7 @@ function parseHwpmlDocument(buffer, options) {
54752
56178
  const normalized = text2.replace(/&nbsp;/g, "&#160;");
54753
56179
  const xml = stripDtd(normalized);
54754
56180
  const warnings = [];
54755
- const parser = new import_xmldom4.DOMParser({
56181
+ const parser = new import_xmldom5.DOMParser({
54756
56182
  onError: (_level, msg2) => {
54757
56183
  warnings.push({ message: `HWPML XML \uD30C\uC2F1 \uACBD\uACE0: ${msg2}`, code: "MALFORMED_XML" });
54758
56184
  }
@@ -54849,7 +56275,7 @@ function walkContent(node, blocks, paraShapeMap, sectionNum, warnings, inHeaderF
54849
56275
  }
54850
56276
  if (tag === "TABLE") {
54851
56277
  if (!inHeaderFooter) {
54852
- parseTable2(el, blocks, paraShapeMap, sectionNum, warnings, keep);
56278
+ parseTable3(el, blocks, paraShapeMap, sectionNum, warnings, keep);
54853
56279
  }
54854
56280
  continue;
54855
56281
  }
@@ -54868,7 +56294,7 @@ function walkTablesInP(node, blocks, paraShapeMap, sectionNum, warnings, keep, d
54868
56294
  if (el.nodeType !== 1) continue;
54869
56295
  const tag = localName(el);
54870
56296
  if (tag === "TABLE") {
54871
- parseTable2(el, blocks, paraShapeMap, sectionNum, warnings, keep);
56297
+ parseTable3(el, blocks, paraShapeMap, sectionNum, warnings, keep);
54872
56298
  continue;
54873
56299
  }
54874
56300
  if (tag === "FOOTNOTE" || tag === "ENDNOTE" || tag === "HEADER" || tag === "FOOTER") continue;
@@ -54903,7 +56329,7 @@ function collectCharText(node, parts, depth = 0) {
54903
56329
  if (tag === "CHAR") {
54904
56330
  for (const c of Array.from(el.childNodes)) {
54905
56331
  const t = c.nodeType === 1 ? localName(c) === "TAB" ? " " : rawTextContent(c) : c.nodeType === 3 || c.nodeType === 4 ? (_a2 = c.nodeValue) != null ? _a2 : "" : "";
54906
- if (t) parts.push(t);
56332
+ if (t) parts.push(escapeLiteralTags(t));
54907
56333
  }
54908
56334
  } else if (tag === "TABLE" || tag === "PICTURE" || tag === "SHAPEOBJECT") {
54909
56335
  } else if (tag === "AUTONUM") {
@@ -54912,7 +56338,7 @@ function collectCharText(node, parts, depth = 0) {
54912
56338
  }
54913
56339
  }
54914
56340
  }
54915
- function parseTable2(el, blocks, _paraShapeMap, sectionNum, warnings, keep) {
56341
+ function parseTable3(el, blocks, _paraShapeMap, sectionNum, warnings, keep) {
54916
56342
  const table3 = buildHmlTable(el, warnings, keep, 0);
54917
56343
  if (!table3) return;
54918
56344
  const caption = extractShapeCaption(el);
@@ -55883,11 +57309,11 @@ function fillInlineFields(text2, values, filled, matchedLabels, blockedLabels) {
55883
57309
 
55884
57310
  // .kordoc-source/src/form/filler-hwpx.ts
55885
57311
  init_cjs_shims();
55886
- var import_jszip7 = __toESM(require_lib3(), 1);
57312
+ var import_jszip8 = __toESM(require_lib3(), 1);
55887
57313
 
55888
57314
  // .kordoc-source/src/form/click-here.ts
55889
57315
  init_cjs_shims();
55890
- var import_jszip6 = __toESM(require_lib3(), 1);
57316
+ var import_jszip7 = __toESM(require_lib3(), 1);
55891
57317
 
55892
57318
  // .kordoc-source/src/roundtrip/source-map.ts
55893
57319
  init_cjs_shims();
@@ -55974,7 +57400,7 @@ function prefixOf(qname) {
55974
57400
  }
55975
57401
  function scanSectionXml(xml, sectionIndex) {
55976
57402
  const stack = [];
55977
- const bodyParagraphs = [];
57403
+ const bodyParagraphs2 = [];
55978
57404
  const tables = [];
55979
57405
  const headerTexts = [];
55980
57406
  const footerTexts = [];
@@ -56097,8 +57523,8 @@ function scanSectionXml(xml, sectionIndex) {
56097
57523
  } else if (local === "cellAddr") {
56098
57524
  const cell2 = cellStack[cellStack.length - 1];
56099
57525
  if (cell2 && insideCurrentTable(stack, tableStack)) {
56100
- const ca = parseInt(getAttr2(attrsRaw, "colAddr") || "", 10);
56101
- const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
57526
+ const ca = parseInt(getAttr3(attrsRaw, "colAddr") || "", 10);
57527
+ const ra = parseInt(getAttr3(attrsRaw, "rowAddr") || "", 10);
56102
57528
  if (!isNaN(ca)) cell2.colAddr = ca;
56103
57529
  if (!isNaN(ra)) cell2.rowAddr = ra;
56104
57530
  cell2.addrTagRange = { start: m.index, end: m.index + full.length };
@@ -56106,8 +57532,8 @@ function scanSectionXml(xml, sectionIndex) {
56106
57532
  } else if (local === "cellSpan") {
56107
57533
  const cell2 = cellStack[cellStack.length - 1];
56108
57534
  if (cell2 && insideCurrentTable(stack, tableStack)) {
56109
- const cs = parseInt(getAttr2(attrsRaw, "colSpan") || "1", 10);
56110
- const rs = parseInt(getAttr2(attrsRaw, "rowSpan") || "1", 10);
57535
+ const cs = parseInt(getAttr3(attrsRaw, "colSpan") || "1", 10);
57536
+ const rs = parseInt(getAttr3(attrsRaw, "rowSpan") || "1", 10);
56111
57537
  cell2.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
56112
57538
  cell2.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
56113
57539
  }
@@ -56136,7 +57562,7 @@ function scanSectionXml(xml, sectionIndex) {
56136
57562
  if (cls.inTextbox) para2.inTextbox = true;
56137
57563
  stack.push({ local, qname, contentStart });
56138
57564
  paraStack.push(para2);
56139
- if (para2.kind === "body" || para2.kind === "draw") bodyParagraphs.push(para2);
57565
+ if (para2.kind === "body" || para2.kind === "draw") bodyParagraphs2.push(para2);
56140
57566
  else if (para2.kind === "cell") {
56141
57567
  const cell2 = cellStack[cellStack.length - 1];
56142
57568
  if (cell2) cell2.paragraphs.push(para2);
@@ -56171,14 +57597,14 @@ function scanSectionXml(xml, sectionIndex) {
56171
57597
  const cell2 = cellStack[cellStack.length - 1];
56172
57598
  if (cell2 && insideCurrentTable(stack, tableStack)) {
56173
57599
  if (local === "cellAddr") {
56174
- const ca = parseInt(getAttr2(attrsRaw, "colAddr") || "", 10);
56175
- const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
57600
+ const ca = parseInt(getAttr3(attrsRaw, "colAddr") || "", 10);
57601
+ const ra = parseInt(getAttr3(attrsRaw, "rowAddr") || "", 10);
56176
57602
  if (!isNaN(ca)) cell2.colAddr = ca;
56177
57603
  if (!isNaN(ra)) cell2.rowAddr = ra;
56178
57604
  cell2.addrTagRange = { start: m.index, end: contentStart };
56179
57605
  } else {
56180
- const cs = parseInt(getAttr2(attrsRaw, "colSpan") || "1", 10);
56181
- const rs = parseInt(getAttr2(attrsRaw, "rowSpan") || "1", 10);
57606
+ const cs = parseInt(getAttr3(attrsRaw, "colSpan") || "1", 10);
57607
+ const rs = parseInt(getAttr3(attrsRaw, "rowSpan") || "1", 10);
56182
57608
  cell2.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
56183
57609
  cell2.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
56184
57610
  }
@@ -56192,7 +57618,7 @@ function scanSectionXml(xml, sectionIndex) {
56192
57618
  if (para2) para2.text += " ";
56193
57619
  }
56194
57620
  }
56195
- for (const para2 of bodyParagraphs) fillRunInsertPos(para2, xml);
57621
+ for (const para2 of bodyParagraphs2) fillRunInsertPos(para2, xml);
56196
57622
  for (const para2 of excludedParagraphs) fillRunInsertPos(para2, xml);
56197
57623
  const fillTableInsertPos = (table3, depth = 0) => {
56198
57624
  if (depth > 16) return;
@@ -56205,9 +57631,9 @@ function scanSectionXml(xml, sectionIndex) {
56205
57631
  };
56206
57632
  for (const table3 of tables) fillTableInsertPos(table3);
56207
57633
  for (const table3 of orphanTables) fillTableInsertPos(table3);
56208
- return { sectionIndex, xml, bodyParagraphs, tables, headerTexts, footerTexts, excludedParagraphs, orphanTables };
57634
+ return { sectionIndex, xml, bodyParagraphs: bodyParagraphs2, tables, headerTexts, footerTexts, excludedParagraphs, orphanTables };
56209
57635
  }
56210
- function getAttr2(attrsRaw, name) {
57636
+ function getAttr3(attrsRaw, name) {
56211
57637
  var _a2;
56212
57638
  const re = new RegExp(`(?:^|\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`);
56213
57639
  const m = attrsRaw.match(re);
@@ -56535,7 +57961,7 @@ function fillClickHereInXml(xml, cursor, blockedLabels) {
56535
57961
  }
56536
57962
  async function extractClickHereFields(hwpxBuffer) {
56537
57963
  precheckZipSize(hwpxBuffer);
56538
- const zip = await import_jszip6.default.loadAsync(hwpxBuffer);
57964
+ const zip = await import_jszip7.default.loadAsync(hwpxBuffer);
56539
57965
  const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
56540
57966
  const fields = [];
56541
57967
  for (let si = 0; si < sectionPaths.length; si++) {
@@ -56770,7 +58196,7 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
56770
58196
  var _a2, _b, _c, _d, _e;
56771
58197
  const u8 = new Uint8Array(hwpxBuffer);
56772
58198
  precheckZipSize(hwpxBuffer);
56773
- const zip = await import_jszip7.default.loadAsync(hwpxBuffer);
58199
+ const zip = await import_jszip8.default.loadAsync(hwpxBuffer);
56774
58200
  const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
56775
58201
  if (sectionPaths.length === 0) {
56776
58202
  throw new KordocError("HWPX\uC5D0\uC11C \uC139\uC158 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
@@ -57252,7 +58678,7 @@ init_page_markdown();
57252
58678
 
57253
58679
  // .kordoc-source/src/hwpx/generator.ts
57254
58680
  init_cjs_shims();
57255
- var import_jszip8 = __toESM(require_lib3(), 1);
58681
+ var import_jszip9 = __toESM(require_lib3(), 1);
57256
58682
 
57257
58683
  // .kordoc-source/src/hwpx/gongmun.ts
57258
58684
  init_cjs_shims();
@@ -60330,7 +61756,7 @@ function parseMarkdownToBlocks(md2) {
60330
61756
  }
60331
61757
  const mathLines = [];
60332
61758
  if (afterOpen.trim()) mathLines.push(afterOpen);
60333
- let closed = false;
61759
+ let closed2 = false;
60334
61760
  let trailing = "";
60335
61761
  let j = i + 1;
60336
61762
  for (; j < lines.length; j++) {
@@ -60341,13 +61767,13 @@ function parseMarkdownToBlocks(md2) {
60341
61767
  const before2 = l.slice(0, end);
60342
61768
  if (before2.trim()) mathLines.push(before2);
60343
61769
  trailing = l.slice(end + 2).trim();
60344
- closed = true;
61770
+ closed2 = true;
60345
61771
  j++;
60346
61772
  break;
60347
61773
  }
60348
61774
  mathLines.push(l);
60349
61775
  }
60350
- if (closed) {
61776
+ if (closed2) {
60351
61777
  const text2 = mathLines.join("\n").trim();
60352
61778
  if (text2) blocks.push({ type: "equation", text: text2 });
60353
61779
  if (trailing) blocks.push({ type: "paragraph", text: trailing });
@@ -60383,7 +61809,7 @@ function parseMarkdownToBlocks(md2) {
60383
61809
  if (/^<table[\s>]/i.test(line.trimStart())) {
60384
61810
  const htmlLines = [];
60385
61811
  let depth = 0;
60386
- let closed = false;
61812
+ let closed2 = false;
60387
61813
  let j = i;
60388
61814
  while (j < lines.length) {
60389
61815
  const l = lines[j];
@@ -60392,11 +61818,11 @@ function parseMarkdownToBlocks(md2) {
60392
61818
  depth -= ((_b = l.match(/<\/table>/gi)) != null ? _b : []).length;
60393
61819
  j++;
60394
61820
  if (depth <= 0) {
60395
- closed = true;
61821
+ closed2 = true;
60396
61822
  break;
60397
61823
  }
60398
61824
  }
60399
- if (closed) {
61825
+ if (closed2) {
60400
61826
  blocks.push({ type: "html_table", text: htmlLines.join("\n") });
60401
61827
  i = j;
60402
61828
  continue;
@@ -61772,7 +63198,7 @@ function sanitizeText2(text2) {
61772
63198
  return result;
61773
63199
  }
61774
63200
  function normForMatch(text2) {
61775
- return sanitizeText2(text2.replace(/\\\$/g, "$")).replace(/\s+/g, " ").trim();
63201
+ return sanitizeText2(text2.replace(/\\\$/g, "$").replace(/\\(?=<\/?(?:u|sup|sub)>)/g, "")).replace(/\s+/g, " ").trim();
61776
63202
  }
61777
63203
  function unescapeGfm(text2) {
61778
63204
  return text2.replace(/\\([~*_`|#<$\\])/g, "$1");
@@ -61795,7 +63221,7 @@ function replicateGfmTable(table3) {
61795
63221
  const cell2 = (_a2 = cells[r]) == null ? void 0 : _a2[c];
61796
63222
  if (!cell2) continue;
61797
63223
  display[r][c] = {
61798
- text: escapeGfm(sanitizeText2(cell2.text)).replace(/(?<!\\)\|/g, "\\|").replace(/\n/g, "<br>"),
63224
+ text: escapeGfm(sanitizeText2(cell2.text)).replace(/(?<!\\)\|/g, "\\|").replace(/\r\n|\r|\n/g, "<br>"),
61799
63225
  gridR: r,
61800
63226
  gridC: c
61801
63227
  };
@@ -62417,6 +63843,7 @@ var ImageRegistry = class {
62417
63843
  this.supplied = supplied;
62418
63844
  this.byUrl = /* @__PURE__ */ new Map();
62419
63845
  this.ids = /* @__PURE__ */ new Set();
63846
+ this.names = /* @__PURE__ */ new Set();
62420
63847
  this.parts = [];
62421
63848
  this.picSeq = 0;
62422
63849
  this.binSeq = 0;
@@ -62438,8 +63865,12 @@ var ImageRegistry = class {
62438
63865
  let n = 1;
62439
63866
  while (this.ids.has(itemId)) itemId = `${m[1].replace(/[^A-Za-z0-9_]/g, "_")}_${n++}`;
62440
63867
  this.ids.add(itemId);
63868
+ let name = `BinData/${url}`;
63869
+ let suffix = 1;
63870
+ while (this.names.has(name)) name = `BinData/${m[1]}_${suffix++}.${m[2]}`;
63871
+ this.names.add(name);
62441
63872
  part = {
62442
- name: `BinData/${url}`,
63873
+ name,
62443
63874
  itemId,
62444
63875
  mime,
62445
63876
  data: m[2].toLowerCase() === "bmp" ? PLACEHOLDER_BMP : PLACEHOLDER_PNG
@@ -62469,8 +63900,9 @@ var ImageRegistry = class {
62469
63900
  const base2 = safe && !url.includes("..") ? safe[1] : `image${++this.binSeq}`;
62470
63901
  let itemId = base2.replace(/[^A-Za-z0-9_]/g, "_");
62471
63902
  let n = 1;
62472
- while (this.ids.has(itemId)) itemId = `${base2.replace(/[^A-Za-z0-9_]/g, "_")}_${n++}`;
63903
+ while (this.ids.has(itemId) || this.names.has(`BinData/${itemId}.${sniffed.ext}`)) itemId = `${base2.replace(/[^A-Za-z0-9_]/g, "_")}_${n++}`;
62473
63904
  this.ids.add(itemId);
63905
+ this.names.add(`BinData/${itemId}.${sniffed.ext}`);
62474
63906
  const dim = probeImageSize(bytes);
62475
63907
  let wHU, hHU;
62476
63908
  if (dim && dim.w > 0 && dim.h > 0) {
@@ -63665,7 +65097,8 @@ function renderListItem(block2, blockIdx, ctx) {
63665
65097
  ctx.prevWasOrdered = false;
63666
65098
  }
63667
65099
  const indentPrefix = " ".repeat(indent);
63668
- return generateParagraph(indentPrefix + marker + (block2.text || ""), PARA_LIST);
65100
+ const markerRun = `<hp:run charPrIDRef="${CHAR_NORMAL}"><hp:t>${escapeTextXml(indentPrefix + marker)}</hp:t></hp:run>`;
65101
+ return `<hp:p paraPrIDRef="${PARA_LIST}" styleIDRef="0">${markerRun}${generateRuns(block2.text || "")}</hp:p>`;
63669
65102
  }
63670
65103
  function renderHr(ctx) {
63671
65104
  return ctx.gongmun ? `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}"><hp:t></hp:t></hp:run></hp:p>` : `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0"><hp:t>\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500</hp:t></hp:run></hp:p>`;
@@ -65208,7 +66641,7 @@ async function markdownToHwpx(markdown, options) {
65208
66641
  if (remap2 && remap2.tables.length > 0 && remap2.tables.every((t) => !t.used)) {
65209
66642
  console.warn(`[kordoc] format profile: \uD504\uB85C\uD544 \uD45C ${remap2.tables.length}\uAC1C\uAC00 \uBB38\uC11C \uD45C\uC640 \uB9E4\uCE6D\uB418\uC9C0 \uC54A\uC544 \uBBF8\uC801\uC6A9 (\uD589\xB7\uC5F4/\uCCAB \uC140 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58)`);
65210
66643
  }
65211
- const zip2 = new import_jszip8.default();
66644
+ const zip2 = new import_jszip9.default();
65212
66645
  zip2.file("mimetype", "application/hwp+zip", { compression: "STORE" });
65213
66646
  zip2.file("META-INF/container.xml", generateContainerXml());
65214
66647
  zip2.file("Contents/content.hpf", generateManifest(chartParts2, images2.manifestItems(), "gongmun"));
@@ -65255,7 +66688,7 @@ async function markdownToHwpx(markdown, options) {
65255
66688
  }
65256
66689
  }
65257
66690
  const extraBorderFills = [...(_n = remap == null ? void 0 : remap.borderFillXmls) != null ? _n : [], ...(_o = bfReg == null ? void 0 : bfReg.emit()) != null ? _o : []];
65258
- const zip = new import_jszip8.default();
66691
+ const zip = new import_jszip9.default();
65259
66692
  zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
65260
66693
  zip.file("META-INF/container.xml", generateContainerXml());
65261
66694
  zip.file("Contents/content.hpf", generateManifest(chartParts, images.manifestItems(), gongmun ? "gongmun" : "default"));
@@ -65489,7 +66922,7 @@ function readBuiltinTemplateSample(t) {
65489
66922
 
65490
66923
  // .kordoc-source/src/form/seal.ts
65491
66924
  init_cjs_shims();
65492
- var import_jszip9 = __toESM(require_lib3(), 1);
66925
+ var import_jszip10 = __toESM(require_lib3(), 1);
65493
66926
  init_utils();
65494
66927
 
65495
66928
  // .kordoc-source/src/render/head-styles.ts
@@ -65847,7 +67280,7 @@ async function placeSealHwpx(hwpxBuffer, ops) {
65847
67280
  if (ops.length === 0) throw new KordocError("place_seal: \uBC30\uCE58\uD560 \uB3C4\uC7A5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4");
65848
67281
  const u8 = new Uint8Array(hwpxBuffer);
65849
67282
  precheckZipSize(hwpxBuffer);
65850
- const zip = await import_jszip9.default.loadAsync(hwpxBuffer);
67283
+ const zip = await import_jszip10.default.loadAsync(hwpxBuffer);
65851
67284
  const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort((a, b) => {
65852
67285
  var _a3, _b2, _c2, _d2;
65853
67286
  return Number((_b2 = (_a3 = a.match(/(\d+)\.xml$/i)) == null ? void 0 : _a3[1]) != null ? _b2 : 0) - Number((_d2 = (_c2 = b.match(/(\d+)\.xml$/i)) == null ? void 0 : _c2[1]) != null ? _d2 : 0);
@@ -66015,7 +67448,7 @@ async function placeSealHwpx(hwpxBuffer, ops) {
66015
67448
 
66016
67449
  // .kordoc-source/src/hwpx/extract-profile.ts
66017
67450
  init_cjs_shims();
66018
- var import_jszip10 = __toESM(require_lib3(), 1);
67451
+ var import_jszip11 = __toESM(require_lib3(), 1);
66019
67452
  init_utils();
66020
67453
  function elemsByLocal(root, name) {
66021
67454
  const all = root.getElementsByTagName("*");
@@ -66103,7 +67536,7 @@ function num(s) {
66103
67536
  const n = parseInt(s, 10);
66104
67537
  return Number.isFinite(n) ? n : void 0;
66105
67538
  }
66106
- function parseTable3(tbl2, tableIndex, borderFills, charPrs) {
67539
+ function parseTable4(tbl2, tableIndex, borderFills, charPrs) {
66107
67540
  var _a2, _b, _c, _d, _e, _f;
66108
67541
  const rows = (_a2 = num(tbl2.getAttribute("rowCnt"))) != null ? _a2 : 0;
66109
67542
  const cols = (_b = num(tbl2.getAttribute("colCnt"))) != null ? _b : 0;
@@ -66228,7 +67661,7 @@ function pick(map2, keys) {
66228
67661
  async function hwpxToProfile(input) {
66229
67662
  var _a2, _b;
66230
67663
  const buf = input instanceof ArrayBuffer ? input : toArrayBuffer(input);
66231
- const zip = await import_jszip10.default.loadAsync(buf);
67664
+ const zip = await import_jszip11.default.loadAsync(buf);
66232
67665
  const parser = createXmlParser();
66233
67666
  const headerFile = (_b = zip.file("Contents/header.xml")) != null ? _b : (_a2 = zip.file(/[Hh]eader\.xml$/)) == null ? void 0 : _a2[0];
66234
67667
  let headerXml = "<root/>";
@@ -66246,7 +67679,7 @@ async function hwpxToProfile(input) {
66246
67679
  const doc = parser.parseFromString(await f.async("text"), "text/xml");
66247
67680
  for (const tbl2 of elemsByLocal(doc, "tbl")) {
66248
67681
  if (!isTopLevelTable(tbl2)) continue;
66249
- tables.push(parseTable3(tbl2, tableIndex++, borderFills, charPrs));
67682
+ tables.push(parseTable4(tbl2, tableIndex++, borderFills, charPrs));
66250
67683
  }
66251
67684
  }
66252
67685
  return { schema_version: "0.3.0", tables };
@@ -66955,7 +68388,7 @@ function muncheLintWarnings(text2, limit = 10) {
66955
68388
 
66956
68389
  // .kordoc-source/src/roundtrip/patcher.ts
66957
68390
  init_cjs_shims();
66958
- var import_jszip11 = __toESM(require_lib3(), 1);
68391
+ var import_jszip12 = __toESM(require_lib3(), 1);
66959
68392
  init_builder();
66960
68393
 
66961
68394
  // .kordoc-source/src/roundtrip/table-patch.ts
@@ -67195,6 +68628,76 @@ function tableSzHeightSplice(xml, scanTable, tblOpenLen, delta) {
67195
68628
  return { start: valStart, end: valStart + hM[1].length, replacement: String(newH) };
67196
68629
  }
67197
68630
 
68631
+ // .kordoc-source/src/roundtrip/embedded-line-patch.ts
68632
+ init_cjs_shims();
68633
+ function buildEmbeddedLineSplices(para2, xml, newLines) {
68634
+ var _a2, _b, _c, _d, _e;
68635
+ const tokens = [];
68636
+ let text2 = "";
68637
+ for (const range of para2.tRanges) {
68638
+ if (range.selfClosing) continue;
68639
+ const raw = xml.slice(range.contentStart, range.contentEnd);
68640
+ if (raw.includes("<")) return null;
68641
+ const base2 = text2.length;
68642
+ let cursor = 0;
68643
+ for (const match2 of raw.matchAll(/&(?:lt|gt|amp|quot|apos|#(?:[0-9]+|x[0-9a-fA-F]+));|[^&]/gu)) {
68644
+ const decoded = decodeXmlEntities(match2[0]);
68645
+ if (match2.index !== cursor || decoded === match2[0] && match2[0].startsWith("&")) return null;
68646
+ cursor += match2[0].length;
68647
+ tokens.push({
68648
+ from: text2.length,
68649
+ to: text2.length + decoded.length,
68650
+ start: range.contentStart + match2.index,
68651
+ end: range.contentStart + match2.index + match2[0].length
68652
+ });
68653
+ text2 += decoded;
68654
+ }
68655
+ if (cursor !== raw.length || decodeXmlEntities(raw) !== text2.slice(base2)) return null;
68656
+ }
68657
+ if (text2 !== para2.text || !/[\r\n]/.test(text2) || /<br\s*\/?\s*>/i.test(text2)) return null;
68658
+ const lines = text2.split(/\r\n|\r|\n/);
68659
+ if (lines.length !== newLines.length || lines.some((line) => !line.trim() || sanitizeText2(line) !== line.trim())) return null;
68660
+ const splices = [];
68661
+ let offset = 0;
68662
+ for (let i = 0; i < lines.length; i++) {
68663
+ const line = lines[i];
68664
+ const orig = line.trim();
68665
+ const next = newLines[i];
68666
+ if (sanitizeText2(next) !== next || /[\r\n]/.test(next) || /[\uD800-\uDFFF]/u.test(next) || decodeXmlEntities(escapeXmlText(next)) !== next) return null;
68667
+ let prefix = 0;
68668
+ while (prefix < orig.length && prefix < next.length && orig[prefix] === next[prefix]) prefix++;
68669
+ if (prefix > 0 && /[\uD800-\uDBFF]/.test(orig[prefix - 1]) && /[\uDC00-\uDFFF]/.test((_a2 = orig[prefix]) != null ? _a2 : "")) prefix--;
68670
+ let suffix = 0;
68671
+ while (suffix < orig.length - prefix && suffix < next.length - prefix && orig[orig.length - 1 - suffix] === next[next.length - 1 - suffix]) suffix++;
68672
+ if (suffix > 0 && /[\uDC00-\uDFFF]/.test(orig[orig.length - suffix]) && /[\uD800-\uDBFF]/.test((_b = orig[orig.length - suffix - 1]) != null ? _b : "")) suffix--;
68673
+ if (orig !== next) {
68674
+ const start = offset + line.length - line.trimStart().length + prefix;
68675
+ const end = offset + line.length - line.trimStart().length + orig.length - suffix;
68676
+ const replacement = escapeXmlText(next.slice(prefix, next.length - suffix));
68677
+ if (tokens.some((t) => t.from < start && start < t.to || t.from < end && end < t.to)) return null;
68678
+ if (start === end) {
68679
+ const token = (_c = tokens.find((t) => t.from === start)) != null ? _c : tokens.find((t) => t.to === start);
68680
+ if (!token) return null;
68681
+ const at = token.from === start ? token.start : token.end;
68682
+ splices.push({ start: at, end: at, replacement });
68683
+ } else {
68684
+ let placed = false;
68685
+ for (const token of tokens) {
68686
+ if (token.to <= start || token.from >= end) continue;
68687
+ const previous = splices[splices.length - 1];
68688
+ if (placed && previous.end === token.start) previous.end = token.end;
68689
+ else splices.push({ start: token.start, end: token.end, replacement: placed ? "" : replacement });
68690
+ placed = true;
68691
+ }
68692
+ if (!placed) return null;
68693
+ }
68694
+ }
68695
+ offset += line.length;
68696
+ offset += (_e = (_d = text2.slice(offset).match(/^(?:\r\n|\r|\n)/)) == null ? void 0 : _d[0].length) != null ? _e : 0;
68697
+ }
68698
+ return splices;
68699
+ }
68700
+
67198
68701
  // .kordoc-source/src/roundtrip/table-patch.ts
67199
68702
  function patchGfmTable(table3, scanTable, orig, edited, ctx, skip) {
67200
68703
  const replica = replicateGfmTable(table3);
@@ -67437,7 +68940,7 @@ function patchTextChunkTable(table3, scanTable, orig, edited, ctx, skip) {
67437
68940
  return skip("\uD45C \uB80C\uB354 \uACBD\uB85C \uC2DD\uBCC4 \uC2E4\uD328");
67438
68941
  }
67439
68942
  function applyCellEdit(table3, scanTable, gridR, gridC, newLines, ctx, before2, after2, origLineCount) {
67440
- var _a2, _b, _c, _d;
68943
+ var _a2, _b, _c, _d, _e;
67441
68944
  const skip = (reason) => {
67442
68945
  ctx.skipped.push({ reason, before: summarize(before2), after: summarize(after2) });
67443
68946
  return 0;
@@ -67460,6 +68963,17 @@ function applyCellEdit(table3, scanTable, gridR, gridC, newLines, ctx, before2,
67460
68963
  }
67461
68964
  const nonEmpty = cell2.paragraphs.filter((p) => normForMatch(p.text) !== "");
67462
68965
  if (origLineCount !== void 0 && nonEmpty.length > 0 && origLineCount !== nonEmpty.length) {
68966
+ const target = nonEmpty.length === 1 ? nonEmpty[0] : void 0;
68967
+ const sourceLines = target == null ? void 0 : target.text.split(/\r\n|\r|\n/).map((line) => line.trim());
68968
+ const renderedLines = unescapeGfmCell(stripCellTokens(before2)).split("\n").map((line) => line.trim());
68969
+ if (target && (sourceLines == null ? void 0 : sourceLines.length) === origLineCount && sourceLines.every((line, i) => line === renderedLines[i]) && !extractCellTokens(before2)) {
68970
+ const xml = (_c = ctx.scans[target.sectionIndex]) == null ? void 0 : _c.xml;
68971
+ const precise = xml === void 0 ? null : buildEmbeddedLineSplices(target, xml, newLines);
68972
+ if (precise == null ? void 0 : precise.length) {
68973
+ ctx.sectionSplices[target.sectionIndex].push(...precise);
68974
+ return 1;
68975
+ }
68976
+ }
67463
68977
  return skip("\uC140 \uC904 \uACBD\uACC4 \uB9E4\uD551 \uBAA8\uD638 (\uB9AC\uD130\uB7F4 <br>/\uBB38\uB2E8 \uB0B4 \uC904\uBC14\uAFC8) \u2014 \uBBF8\uC9C0\uC6D0");
67464
68978
  }
67465
68979
  const splices = [];
@@ -67471,7 +68985,7 @@ function applyCellEdit(table3, scanTable, gridR, gridC, newLines, ctx, before2,
67471
68985
  const target = cell2.paragraphs[0];
67472
68986
  if (!target) return skip("\uBE48 \uC140\uC5D0 \uBB38\uB2E8\uC774 \uC5C6\uC5B4 \uD14D\uC2A4\uD2B8 \uC0BD\uC785 \uBD88\uAC00");
67473
68987
  const value = newLines.join(" ");
67474
- const xml = (_c = ctx.scans[target.sectionIndex]) == null ? void 0 : _c.xml;
68988
+ const xml = (_d = ctx.scans[target.sectionIndex]) == null ? void 0 : _d.xml;
67475
68989
  const rawT = xml ? paraTText(target, xml) : null;
67476
68990
  let sp;
67477
68991
  if (xml && rawT === null) {
@@ -67505,7 +69019,7 @@ function applyCellEdit(table3, scanTable, gridR, gridC, newLines, ctx, before2,
67505
69019
  }
67506
69020
  for (let i = 0; i < nonEmpty.length; i++) {
67507
69021
  if (assigned[i] === nonEmpty[i].text || normForMatch(assigned[i]) === normForMatch(nonEmpty[i].text)) continue;
67508
- const sp = buildParagraphSplices(nonEmpty[i], assigned[i], (_d = ctx.scans[nonEmpty[i].sectionIndex]) == null ? void 0 : _d.xml);
69022
+ const sp = buildParagraphSplices(nonEmpty[i], assigned[i], (_e = ctx.scans[nonEmpty[i].sectionIndex]) == null ? void 0 : _e.xml);
67509
69023
  if (sp === null) return skip("\uC140 \uBB38\uB2E8\uC5D0 \uD14D\uC2A4\uD2B8 \uB178\uB4DC\uB97C \uB9CC\uB4E4 \uC218 \uC5C6\uC74C");
67510
69024
  splices.push(...sp);
67511
69025
  sectionIndex = nonEmpty[i].sectionIndex;
@@ -67586,31 +69100,11 @@ async function resolveSectionEntryNames(zip) {
67586
69100
  const f = zip.file(mp);
67587
69101
  if (!f) continue;
67588
69102
  const xml = await f.async("text");
67589
- const paths = sectionPathsFromManifest(xml).filter((p) => zip.file(p) !== null);
69103
+ const paths = parseSectionPathsFromManifest(xml).filter((p) => zip.file(p) !== null);
67590
69104
  if (paths.length > 0) return paths;
67591
69105
  }
67592
69106
  return Object.keys(zip.files).filter((n) => /[Ss]ection\d+\.xml$/.test(n)).sort(compareSectionPaths);
67593
69107
  }
67594
- function sectionPathsFromManifest(xml) {
67595
- const attr = (tag, name) => {
67596
- var _a2;
67597
- const m = tag.match(new RegExp(`(?:^|\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`));
67598
- return m ? (_a2 = m[1]) != null ? _a2 : m[2] : "";
67599
- };
67600
- const idToHref = /* @__PURE__ */ new Map();
67601
- for (const m of xml.matchAll(/<opf:item(\s(?:"[^"]*"|'[^']*'|[^>"'])*?)\/?>/g)) {
67602
- const id = attr(m[1], "id");
67603
- const href = normalizeSectionHref(attr(m[1], "href"));
67604
- if (id && href) idToHref.set(id, href);
67605
- }
67606
- const ordered = [];
67607
- for (const m of xml.matchAll(/<opf:itemref(\s(?:"[^"]*"|'[^']*'|[^>"'])*?)\/?>/g)) {
67608
- const href = idToHref.get(attr(m[1], "idref"));
67609
- if (href) ordered.push(href);
67610
- }
67611
- if (ordered.length > 0) return ordered;
67612
- return Array.from(idToHref.values()).sort(compareSectionPaths);
67613
- }
67614
69108
 
67615
69109
  // .kordoc-source/src/roundtrip/hwp5-patch.ts
67616
69110
  init_cjs_shims();
@@ -68169,7 +69663,12 @@ async function patchHwp(original, editedMarkdown, options) {
68169
69663
  try {
68170
69664
  const kept = parseHwp5Document(originalBuf, { layoutTables: "keep" });
68171
69665
  origBlocks = kept.blocks;
68172
- if (editedFromVisual(kept.markdown, parseHwp5Document(originalBuf).markdown, editedMarkdown)) return fail(LAYOUT_MODE_MISMATCH);
69666
+ const visual = parseHwp5Document(originalBuf).markdown;
69667
+ if (kept.markdown !== visual && editedMarkdown === visual) {
69668
+ const verification2 = (options == null ? void 0 : options.verify) === false ? void 0 : diffUnitLists(splitMarkdownUnits(visual), splitMarkdownUnits(editedMarkdown));
69669
+ return { success: true, data: new Uint8Array(original), applied: 0, skipped, verification: verification2 };
69670
+ }
69671
+ if (editedFromVisual(kept.markdown, visual, editedMarkdown)) return fail(LAYOUT_MODE_MISMATCH);
68173
69672
  } catch (err) {
68174
69673
  return fail(`\uC6D0\uBCF8 HWP \uD30C\uC2F1 \uC2E4\uD328: ${msg(err)}`);
68175
69674
  }
@@ -68840,13 +70339,17 @@ async function patchHwpx(original, editedMarkdown, options) {
68840
70339
  const parsed = await parseHwpxDocument(u8ToArrayBuffer(original), { layoutTables: "keep" });
68841
70340
  origBlocks = parsed.blocks;
68842
70341
  const visual = await parseHwpxDocument(u8ToArrayBuffer(original));
70342
+ if (parsed.markdown !== visual.markdown && editedMarkdown === visual.markdown) {
70343
+ const verification2 = (options == null ? void 0 : options.verify) === false ? void 0 : diffUnitLists(splitMarkdownUnits(visual.markdown), splitMarkdownUnits(editedMarkdown));
70344
+ return { success: true, data: new Uint8Array(original), applied: 0, skipped, verification: verification2 };
70345
+ }
68843
70346
  if (editedFromVisual(parsed.markdown, visual.markdown, editedMarkdown)) return { success: false, applied: 0, skipped, error: LAYOUT_MODE_MISMATCH };
68844
70347
  } catch (err) {
68845
70348
  return { success: false, applied: 0, skipped, error: `\uC6D0\uBCF8 HWPX \uD30C\uC2F1 \uC2E4\uD328: ${err instanceof Error ? err.message : String(err)}` };
68846
70349
  }
68847
70350
  let zip;
68848
70351
  try {
68849
- zip = await import_jszip11.default.loadAsync(original);
70352
+ zip = await import_jszip12.default.loadAsync(original);
68850
70353
  } catch {
68851
70354
  return { success: false, applied: 0, skipped, error: "ZIP \uB85C\uB4DC \uC2E4\uD328" };
68852
70355
  }
@@ -69296,8 +70799,8 @@ async function resolveHeaderEntryName(zip) {
69296
70799
 
69297
70800
  // .kordoc-source/src/validate.ts
69298
70801
  init_cjs_shims();
69299
- var import_jszip12 = __toESM(require_lib3(), 1);
69300
- var import_xmldom5 = __toESM(require_lib4(), 1);
70802
+ var import_jszip13 = __toESM(require_lib3(), 1);
70803
+ var import_xmldom6 = __toESM(require_lib4(), 1);
69301
70804
  var REQUIRED_FILES = [
69302
70805
  "mimetype",
69303
70806
  "META-INF/container.xml",
@@ -69314,7 +70817,7 @@ async function validateHwpx(buffer) {
69314
70817
  const issues = [];
69315
70818
  let zip;
69316
70819
  try {
69317
- zip = await import_jszip12.default.loadAsync(buffer);
70820
+ zip = await import_jszip13.default.loadAsync(buffer);
69318
70821
  } catch (err) {
69319
70822
  return {
69320
70823
  ok: false,
@@ -69343,7 +70846,7 @@ async function validateHwpx(buffer) {
69343
70846
  const text2 = await zip.files[name].async("string");
69344
70847
  let firstError = null;
69345
70848
  try {
69346
- new import_xmldom5.DOMParser({
70849
+ new import_xmldom6.DOMParser({
69347
70850
  onError(level, msg2) {
69348
70851
  if (level !== "warning" && firstError === null) firstError = String(msg2);
69349
70852
  }
@@ -71886,12 +73389,12 @@ function blocksToChunks(blocks, options) {
71886
73389
 
71887
73390
  // .kordoc-source/src/roundtrip/session.ts
71888
73391
  init_cjs_shims();
71889
- var import_jszip13 = __toESM(require_lib3(), 1);
73392
+ var import_jszip14 = __toESM(require_lib3(), 1);
71890
73393
  async function buildState(bytes) {
71891
73394
  const format3 = detectFormat(new Uint8Array(bytes.subarray(0, 512)).buffer);
71892
73395
  if (format3 !== "hwpx") throw new Error(`HWPX \uC138\uC158\uC740 HWPX \uBB38\uC11C\uB9CC \uC5FD\uB2C8\uB2E4 (\uAC10\uC9C0\uB41C \uD3EC\uB9F7: ${format3}) \u2014 HWP 5.x \uB294 patchHwp \uB85C \uD328\uCE58\uD558\uC138\uC694`);
71893
73396
  const parsed = await parseHwpxDocument(u8ToArrayBuffer2(bytes), { layoutTables: "keep" });
71894
- const zip = await import_jszip13.default.loadAsync(bytes);
73397
+ const zip = await import_jszip14.default.loadAsync(bytes);
71895
73398
  const sectionPaths = await resolveSectionEntryNames(zip);
71896
73399
  if (sectionPaths.length === 0) {
71897
73400
  throw new Error("HWPX \uC139\uC158 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
@@ -78035,7 +79538,7 @@ init_cjs_shims();
78035
79538
 
78036
79539
  // .kordoc-source/src/render/svg-render.ts
78037
79540
  init_cjs_shims();
78038
- var import_jszip14 = __toESM(require_lib3(), 1);
79541
+ var import_jszip15 = __toESM(require_lib3(), 1);
78039
79542
  init_utils();
78040
79543
 
78041
79544
  // .kordoc-source/src/render/layout.ts
@@ -78148,7 +79651,7 @@ var CHAR_CTRL_1SLOT = /* @__PURE__ */ new Set(["lineBreak", "hyphen", "nbSpace",
78148
79651
  function pushFillers(chars, n, prId) {
78149
79652
  for (let i = 0; i < n; i++) chars.push({ ch: "", prId });
78150
79653
  }
78151
- function pushTextSlots(t, chars, prId, depth) {
79654
+ function pushTextSlots(t, chars, prId, depth, del = { deleted: 0 }) {
78152
79655
  var _a2;
78153
79656
  if (depth > 32) return;
78154
79657
  const kids = t.childNodes;
@@ -78157,19 +79660,24 @@ function pushTextSlots(t, chars, prId, depth) {
78157
79660
  const c = kids[i];
78158
79661
  if (c.nodeType === 3 || c.nodeType === 4) {
78159
79662
  for (const cp of (_a2 = c.textContent) != null ? _a2 : "") {
78160
- chars.push({ ch: cp, prId });
79663
+ chars.push({ ch: del.deleted ? "" : cp, prId });
78161
79664
  if (cp.length === 2) chars.push({ ch: "", prId });
78162
79665
  }
78163
79666
  } else if (c.nodeType === 1) {
78164
79667
  const el = c;
78165
79668
  const tag = ln(el);
78166
- if (tag === "tab") {
78167
- chars.push({ ch: "", prId, tab: true, tabW: num2(el, "width") });
78168
- pushFillers(chars, 7, prId);
79669
+ if (tag === "deleteBegin" || tag === "deleteEnd") {
79670
+ del.deleted = deletionDelta(el, del.deleted);
79671
+ } else if (tag === "tab") {
79672
+ if (del.deleted) pushFillers(chars, 8, prId);
79673
+ else {
79674
+ chars.push({ ch: "", prId, tab: true, tabW: num2(el, "width") });
79675
+ pushFillers(chars, 7, prId);
79676
+ }
78169
79677
  } else if (CHAR_CTRL_1SLOT.has(tag)) {
78170
- chars.push(tag === "nbSpace" ? { ch: " ", prId, nb: true } : { ch: tag === "fwSpace" ? " " : "", prId });
79678
+ chars.push(del.deleted ? { ch: "", prId } : tag === "nbSpace" ? { ch: " ", prId, nb: true } : { ch: tag === "fwSpace" ? " " : "", prId });
78171
79679
  } else {
78172
- pushTextSlots(el, chars, prId, depth + 1);
79680
+ pushTextSlots(el, chars, prId, depth + 1, del);
78173
79681
  }
78174
79682
  }
78175
79683
  }
@@ -78194,7 +79702,7 @@ function prepareDeletedRanges(root, depth = 0) {
78194
79702
  deletedStarts.set(p, deleted);
78195
79703
  const scan = (el, xmlDepth) => {
78196
79704
  if (xmlDepth > 64) return;
78197
- if (ln(el) === "ctrl") for (const ch of elements(el)) scan(ch, xmlDepth + 1);
79705
+ if (ln(el) === "ctrl" || ln(el) === "t") for (const ch of elements(el)) scan(ch, xmlDepth + 1);
78198
79706
  else {
78199
79707
  if (ln(el) === "deleteBegin" || ln(el) === "deleteEnd") deleted = deletionDelta(el, deleted);
78200
79708
  deletedControls.set(el, deleted > 0);
@@ -78227,9 +79735,9 @@ function buildPara(p) {
78227
79735
  for (const ch of elements(runEl)) {
78228
79736
  const cn = ln(ch);
78229
79737
  if (cn === "t") {
78230
- const start = chars.length;
78231
- pushTextSlots(ch, chars, prId, 0);
78232
- if (deleted) for (let i = start; i < chars.length; i++) chars[i] = { ch: "", prId };
79738
+ const del = { deleted };
79739
+ pushTextSlots(ch, chars, prId, 0, del);
79740
+ deleted = del.deleted;
78233
79741
  } else if (OBJ_TAGS.has(cn)) {
78234
79742
  const sz = findChildByLocalName(ch, "sz");
78235
79743
  const pos = findChildByLocalName(ch, "pos");
@@ -78664,22 +80172,48 @@ function rotatedBounds(box, rotations) {
78664
80172
  if (!rotations.length) return box;
78665
80173
  let points = [[box.x, box.y], [box.x + box.w, box.y], [box.x + box.w, box.y + box.h], [box.x, box.y + box.h]];
78666
80174
  for (let i = rotations.length - 1; i >= 0; i--) {
78667
- const { angle, cx, cy } = rotations[i];
80175
+ const r = rotations[i];
80176
+ if (Array.isArray(r)) {
80177
+ points = points.map(([x2, y2]) => [r[0] * x2 + r[2] * y2 + r[4], r[1] * x2 + r[3] * y2 + r[5]]);
80178
+ continue;
80179
+ }
80180
+ const { angle, cx, cy } = r;
78668
80181
  const a = angle * Math.PI / 180, c = Math.cos(a), s = Math.sin(a);
78669
80182
  points = points.map(([x2, y2]) => [cx + c * (x2 - cx) - s * (y2 - cy), cy + s * (x2 - cx) + c * (y2 - cy)]);
78670
80183
  }
78671
80184
  const x = Math.min(...points.map((p) => p[0])), y = Math.min(...points.map((p) => p[1]));
78672
80185
  return { x, y, w: Math.max(...points.map((p) => p[0])) - x, h: Math.max(...points.map((p) => p[1])) - y };
78673
80186
  }
78674
- function objectGeometry(el, x, y, w, h) {
80187
+ function mulAffine(m, n) {
80188
+ return [
80189
+ m[0] * n[0] + m[2] * n[1],
80190
+ m[1] * n[0] + m[3] * n[1],
80191
+ m[0] * n[2] + m[2] * n[3],
80192
+ m[1] * n[2] + m[3] * n[3],
80193
+ m[0] * n[4] + m[2] * n[5] + m[4],
80194
+ m[1] * n[4] + m[3] * n[5] + m[5]
80195
+ ];
80196
+ }
80197
+ function renderingMatrix(el) {
80198
+ const info = findChildByLocalName(el, "renderingInfo");
80199
+ if (!info) return null;
80200
+ let m = null;
80201
+ for (const c of elements(info)) {
80202
+ const tag = ln(c);
80203
+ if (tag !== "transMatrix" && tag !== "scaMatrix" && tag !== "rotMatrix") continue;
80204
+ const n = [num2(c, "e1", 1), num2(c, "e4"), num2(c, "e2"), num2(c, "e5", 1), num2(c, "e3"), num2(c, "e6")];
80205
+ m = m ? mulAffine(m, n) : n;
80206
+ }
80207
+ return m;
80208
+ }
80209
+ function objectGeometry(el, x, y, w, h, boxW = w, boxH = h) {
78675
80210
  const rot = findChildByLocalName(el, "rotationInfo");
78676
80211
  const angle = num2(rot, "angle") % 360;
78677
80212
  if (!angle) return { x, y, w, h, bbox: { x, y, w, h }, transform: "" };
78678
- const org = findChildByLocalName(el, "orgSz");
78679
- const cx = x + num2(rot, "centerX", num2(org, "width", w) / 2) * (w / (num2(org, "width") || w || 1));
78680
- const cy = y + num2(rot, "centerY", num2(org, "height", h) / 2) * (h / (num2(org, "height") || h || 1));
80213
+ const cx = x + boxW / 2, cy = y + boxH / 2;
80214
+ const fx = cx - w / 2, fy = cy - h / 2;
78681
80215
  const rotation = { angle, cx: Math.round(cx), cy: Math.round(cy) };
78682
- return { x, y, w, h, bbox: rotatedBounds({ x, y, w, h }, [rotation]), rotation, transform: `rotate(${angle} ${pt(cx)} ${pt(cy)})` };
80216
+ return { x: fx, y: fy, w, h, bbox: rotatedBounds({ x: fx, y: fy, w, h }, [rotation]), rotation, transform: `rotate(${angle} ${pt(cx)} ${pt(cy)})` };
78683
80217
  }
78684
80218
  function shapeFill(el, defs, images, warn) {
78685
80219
  var _a2, _b, _c;
@@ -78728,31 +80262,34 @@ function shapeFill(el, defs, images, warn) {
78728
80262
  }
78729
80263
  return "none";
78730
80264
  }
78731
- function shapeGeometry(o, x, y, defs, images, warn) {
80265
+ function shapeGeometry(o, boxX, boxY, defs, images, warn, local = false) {
78732
80266
  var _a2;
78733
80267
  const el = o.el, org = findChildByLocalName(el, "orgSz"), cur = findChildByLocalName(el, "curSz");
78734
80268
  const ow = num2(org, "width"), oh = num2(org, "height");
78735
- const w = num2(cur, "width") || ow || o.width, h = num2(cur, "height") || oh || o.height;
80269
+ const w = (local ? ow : num2(cur, "width")) || ow || num2(cur, "width") || o.width;
80270
+ const h = (local ? oh : num2(cur, "height")) || oh || num2(cur, "height") || o.height;
80271
+ const geometry = local ? { x: boxX, y: boxY, w, h, bbox: { x: boxX, y: boxY, w, h }, transform: "" } : objectGeometry(el, boxX, boxY, w, h, o.width || w, o.height || h);
80272
+ const { x, y } = geometry;
78736
80273
  const sx = ow > 0 ? w / ow : 1, sy = oh > 0 ? h / oh : 1;
78737
80274
  const line = findChildByLocalName(el, "lineShape"), style = (_a2 = line == null ? void 0 : line.getAttribute("style")) != null ? _a2 : "SOLID";
78738
80275
  const color = esc((line == null ? void 0 : line.getAttribute("color")) || "#000000");
78739
80276
  const strokeW = style === "NONE" ? 0 : Math.max(0.2, num2(line, "width", 33) / 100 * 2.834645);
78740
80277
  const dash = /DASH|DOT/.test(style) ? ` stroke-dasharray="${style.includes("DOT") ? "1,1.5" : "3,1.5"}"` : "";
78741
- const stroke = strokeW ? ` stroke="${color}" stroke-width="${strokeW.toFixed(2)}"${dash}` : "";
80278
+ const keepWidth = local ? ` vector-effect="non-scaling-stroke"` : "";
80279
+ const stroke = strokeW ? ` stroke="${color}" stroke-width="${strokeW.toFixed(2)}"${dash}${keepWidth}` : "";
78742
80280
  const fill = ` fill="${shapeFill(el, defs, images, warn)}"`;
78743
80281
  let svg = "";
78744
80282
  if (o.tag === "rect") svg = `<rect x="${pt(x)}" y="${pt(y)}" width="${pt(w)}" height="${pt(h)}"${fill}${stroke}/>`;
78745
80283
  else if (o.tag === "ellipse") svg = `<ellipse cx="${pt(x + w / 2)}" cy="${pt(y + h / 2)}" rx="${pt(w / 2)}" ry="${pt(h / 2)}"${fill}${stroke}/>`;
78746
80284
  else if (o.tag === "line") {
78747
80285
  const s = findChildByLocalName(el, "startPt"), e = findChildByLocalName(el, "endPt");
78748
- svg = `<line x1="${pt(x + num2(s, "x") * sx)}" y1="${pt(y + num2(s, "y") * sy)}" x2="${pt(x + num2(e, "x") * sx)}" y2="${pt(y + num2(e, "y") * sy)}" stroke="${color}" stroke-width="${(strokeW || 0.3).toFixed(2)}"${dash}/>`;
80286
+ svg = `<line x1="${pt(x + num2(s, "x") * sx)}" y1="${pt(y + num2(s, "y") * sy)}" x2="${pt(x + num2(e, "x") * sx)}" y2="${pt(y + num2(e, "y") * sy)}" stroke="${color}" stroke-width="${(strokeW || 0.3).toFixed(2)}"${dash}${keepWidth}/>`;
78749
80287
  } else if (o.tag === "polygon" || o.tag === "curv") {
78750
80288
  const pts = elements(el).filter((c) => ln(c) === "pt").map((c) => `${pt(x + num2(c, "x") * sx)},${pt(y + num2(c, "y") * sy)}`);
78751
80289
  if (pts.length >= 2) svg = `<polygon points="${pts.join(" ")}"${fill}${stroke}/>`;
78752
80290
  } else if (o.tag === "curve") {
78753
80291
  const segs = elements(el).filter((c) => ln(c) === "seg");
78754
- if (segs.some((s) => s.getAttribute("type") !== "LINE")) warn("curve:bezier", "\uBE44\uC120\uD615 \uACE1\uC120 \uB80C\uB354 \uBBF8\uC9C0\uC6D0 \u2014 \uC0DD\uB7B5");
78755
- else if (segs.length) {
80292
+ if (segs.length) {
78756
80293
  let path = "", lastX, lastY;
78757
80294
  for (const s of segs) {
78758
80295
  const x1 = num2(s, "x1"), y1 = num2(s, "y1"), x2 = num2(s, "x2"), y2 = num2(s, "y2");
@@ -78764,7 +80301,7 @@ function shapeGeometry(o, x, y, defs, images, warn) {
78764
80301
  svg = `<path d="${path}"${fill}${stroke}/>`;
78765
80302
  }
78766
80303
  } else if (o.tag === "arc") svg = `<ellipse cx="${pt(x + w / 2)}" cy="${pt(y + h / 2)}" rx="${pt(w / 2)}" ry="${pt(h / 2)}" fill="none"${stroke || ` stroke="${color}" stroke-width="0.3"`}/>`;
78767
- return { ...objectGeometry(el, x, y, w, h), svg };
80304
+ return { ...geometry, svg };
78768
80305
  }
78769
80306
 
78770
80307
  // .kordoc-source/src/render/svg-render.ts
@@ -79063,6 +80600,7 @@ function drawObject(o, x, y, baseV, areaW, ctx, depth) {
79063
80600
  if (o.tag === "tbl") drawTable(o.el, x, y, ctx, depth + 1);
79064
80601
  else if (o.tag === "pic") drawPic(o.el, x, y, ctx);
79065
80602
  else if (o.tag === "container") {
80603
+ if (drawGroupByMatrix(o, x, y, baseV, areaW, ctx, depth)) return;
79066
80604
  for (const ch of elements(o.el)) {
79067
80605
  const tag = ln(ch);
79068
80606
  if (!OBJ_TAGS.has(tag)) continue;
@@ -79079,8 +80617,42 @@ function drawObject(o, x, y, baseV, areaW, ctx, depth) {
79079
80617
  warnOnce(ctx, `shape:${o.tag}`, `\uAC1C\uCCB4(${o.tag}) \uB80C\uB354 \uBBF8\uC9C0\uC6D0 \u2014 \uC0DD\uB7B5`);
79080
80618
  }
79081
80619
  }
79082
- function drawShape(o, x, y, ctx, depth) {
79083
- const geometry = shapeGeometry(o, x, y, ctx.defs, ctx.images, (key, msg2) => warnOnce(ctx, key, msg2));
80620
+ function drawGroupByMatrix(o, x, y, baseV, areaW, ctx, depth) {
80621
+ const top = renderingMatrix(o.el);
80622
+ const leaves = [];
80623
+ const collect = (el) => {
80624
+ for (const ch of elements(el)) {
80625
+ const tag = ln(ch);
80626
+ if (!OBJ_TAGS.has(tag)) continue;
80627
+ if (tag === "container") {
80628
+ if (!collect(ch)) return false;
80629
+ } else if (renderingMatrix(ch)) leaves.push(ch);
80630
+ else return false;
80631
+ }
80632
+ return true;
80633
+ };
80634
+ if (!top || !collect(o.el)) return false;
80635
+ const org = findChildByLocalName(o.el, "orgSz");
80636
+ const box = rotatedBounds({ x: 0, y: 0, w: num2(org, "width"), h: num2(org, "height") }, [top]);
80637
+ const base2 = [1, 0, 0, 1, x - box.x, y - box.y];
80638
+ for (const leaf2 of leaves) {
80639
+ const m = mulAffine(base2, renderingMatrix(leaf2));
80640
+ const tag = ln(leaf2), lorg = findChildByLocalName(leaf2, "orgSz");
80641
+ const w = num2(lorg, "width") || num2(findChildByLocalName(leaf2, "curSz"), "width");
80642
+ const h = num2(lorg, "height") || num2(findChildByLocalName(leaf2, "curSz"), "height");
80643
+ ctx.regionRotations.push(m);
80644
+ emit(ctx, `<g transform="matrix(${m.slice(0, 4).map((v) => Math.round(v * 1e6) / 1e6).join(" ")} ${pt2(m[4])} ${pt2(m[5])})">`);
80645
+ const sub = { el: leaf2, tag, index: 0, inline: true, width: w, height: h, omL: 0, omR: 0 };
80646
+ if (tag === "pic") drawPicFrame(leaf2, 0, 0, w, h, "", ctx);
80647
+ else if (SHAPE_TAGS.has(tag)) drawShape(sub, 0, 0, ctx, depth + 1, [Math.hypot(m[0], m[1]) || 1, Math.hypot(m[2], m[3]) || 1]);
80648
+ else drawObject(sub, 0, 0, baseV, areaW, ctx, depth + 1);
80649
+ emit(ctx, "</g>");
80650
+ ctx.regionRotations.pop();
80651
+ }
80652
+ return true;
80653
+ }
80654
+ function drawShape(o, x, y, ctx, depth, groupScale) {
80655
+ const geometry = shapeGeometry(o, x, y, ctx.defs, ctx.images, (key, msg2) => warnOnce(ctx, key, msg2), !!groupScale);
79084
80656
  const b = geometry;
79085
80657
  if (geometry.rotation) ctx.regionRotations.push(geometry.rotation);
79086
80658
  ctx.stats.shapes++;
@@ -79092,7 +80664,17 @@ function drawShape(o, x, y, ctx, depth) {
79092
80664
  const dt = findChildByLocalName(o.el, "drawText");
79093
80665
  const sub = dt ? findChildByLocalName(dt, "subList") : null;
79094
80666
  if (sub) {
79095
- for (const p of elements(sub)) if (ln(p) === "p") drawPara(p, x, y, geometry.w, ctx, depth + 1);
80667
+ const [sx, sy] = groupScale != null ? groupScale : [1, 1];
80668
+ const unscale = sx !== 1 || sy !== 1;
80669
+ if (unscale) {
80670
+ emit(ctx, `<g transform="scale(${1 / sx} ${1 / sy})">`);
80671
+ ctx.regionRotations.push([1 / sx, 0, 0, 1 / sy, 0, 0]);
80672
+ }
80673
+ for (const p of elements(sub)) if (ln(p) === "p") drawPara(p, geometry.x * sx, geometry.y * sy, geometry.w * sx, ctx, depth + 1);
80674
+ if (unscale) {
80675
+ ctx.regionRotations.pop();
80676
+ emit(ctx, "</g>");
80677
+ }
79096
80678
  }
79097
80679
  if (geometry.rotation) ctx.regionRotations.pop();
79098
80680
  if (geometry.transform) emit(ctx, "</g>");
@@ -79175,16 +80757,31 @@ function imageSymbol(loaded, ctx) {
79175
80757
  }
79176
80758
  function drawPic(pic, x, y, ctx) {
79177
80759
  const sz = findChildByLocalName(pic, "sz");
79178
- const w = num2(sz, "width", 5669), h = num2(sz, "height", 5669);
80760
+ let w = num2(sz, "width", 5669), h = num2(sz, "height", 5669);
80761
+ const cur = findChildByLocalName(pic, "curSz");
80762
+ const rotated = objectGeometry(pic, x, y, num2(cur, "width") || w, num2(cur, "height") || h, w, h);
80763
+ if (rotated.rotation) {
80764
+ x = rotated.x;
80765
+ y = rotated.y;
80766
+ w = rotated.w;
80767
+ h = rotated.h;
80768
+ ctx.regionRotations.push(rotated.rotation);
80769
+ }
80770
+ drawPicFrame(pic, x, y, w, h, rotated.transform, ctx);
80771
+ if (rotated.rotation) ctx.regionRotations.pop();
80772
+ }
80773
+ function drawPicFrame(pic, x, y, w, h, transform, ctx) {
79179
80774
  const img = findFirst(pic, "img");
79180
80775
  const ref = img == null ? void 0 : img.getAttribute("binaryItemIDRef");
79181
80776
  const loaded = ref != null ? ctx.images.get(ref) : void 0;
79182
80777
  const imgId = ctx.regions.add("image", bboxOf(ctx, x, y, w, h), { sourceId: ref != null ? ref : void 0, parentId: parentId(ctx) });
79183
80778
  emit(ctx, regionOpenTag(imgId, "image", pageNo(ctx)));
80779
+ const close = transform ? "</g></g>" : "</g>";
80780
+ if (transform) emit(ctx, `<g transform="${transform}">`);
79184
80781
  if (!loaded) {
79185
80782
  emit(ctx, `<rect x="${pt2(x)}" y="${pt2(y)}" width="${pt2(w)}" height="${pt2(h)}" fill="#eee" stroke="#c00" stroke-width="0.5"/>`);
79186
80783
  warnOnce(ctx, `img:${ref}`, `\uC774\uBBF8\uC9C0 \uBC14\uC774\uB108\uB9AC \uB204\uB77D: ${ref != null ? ref : "(ref \uC5C6\uC74C)"}`);
79187
- emit(ctx, "</g>");
80784
+ emit(ctx, close);
79188
80785
  return;
79189
80786
  }
79190
80787
  ctx.stats.images++;
@@ -79206,7 +80803,7 @@ function drawPic(pic, x, y, ctx) {
79206
80803
  } else {
79207
80804
  emit(ctx, `<use href="#${symId}" x="${pt2(x)}" y="${pt2(y)}" width="${pt2(w)}" height="${pt2(h)}"/>`);
79208
80805
  }
79209
- emit(ctx, "</g>");
80806
+ emit(ctx, close);
79210
80807
  }
79211
80808
  function sniffMime(name, bytes) {
79212
80809
  const lower = name.toLowerCase();
@@ -79336,7 +80933,7 @@ async function renderHwpxInternal(input, options) {
79336
80933
  precheckZipSize(ab, MAX_DECOMPRESS_SIZE, MAX_ZIP_ENTRIES);
79337
80934
  let zip;
79338
80935
  try {
79339
- zip = await import_jszip14.default.loadAsync(input);
80936
+ zip = await import_jszip15.default.loadAsync(input);
79340
80937
  } catch {
79341
80938
  throw new KordocError("HWPX(ZIP) \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4 \u2014 \uB80C\uB354\uB294 HWPX\uB9CC \uC9C0\uC6D0");
79342
80939
  }
@@ -80373,6 +81970,7 @@ init_builder();
80373
81970
  init_page_markdown();
80374
81971
  init_utils();
80375
81972
  async function parse(input, options) {
81973
+ var _a2;
80376
81974
  let buffer;
80377
81975
  const opts = typeof input === "string" && !(options == null ? void 0 : options.filePath) ? { ...options, filePath: input } : options;
80378
81976
  if (typeof input === "string") {
@@ -80381,7 +81979,7 @@ async function parse(input, options) {
80381
81979
  buffer = toArrayBuffer(buf);
80382
81980
  } catch (err) {
80383
81981
  const msg2 = err instanceof Error && "code" in err && err.code === "ENOENT" ? `\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input}` : `\uD30C\uC77C \uC77D\uAE30 \uC2E4\uD328: ${input}`;
80384
- return { success: false, fileType: "unknown", error: msg2, code: "PARSE_ERROR" };
81982
+ return { success: false, fileType: "unknown", error: msg2, code: classifyError(err) };
80385
81983
  }
80386
81984
  } else if (Buffer.isBuffer(input)) {
80387
81985
  buffer = toArrayBuffer(input);
@@ -80399,9 +81997,12 @@ async function parse(input, options) {
80399
81997
  }
80400
81998
  if (result.success && (opts == null ? void 0 : opts.classifyTables)) classifyTableTree(result.blocks);
80401
81999
  let out = result;
80402
- if (result.success && !result.pages) {
80403
- const pages = blocksToPages(result.blocks);
80404
- if (pages) out = { ...result, pages };
82000
+ if (result.success && (opts == null ? void 0 : opts.pages) && result.pageCount && parsePageRange(opts.pages, result.pageCount).size === 0) {
82001
+ out = { ...result, warnings: [...(_a2 = result.warnings) != null ? _a2 : [], { code: "PARTIAL_PARSE", message: `\uC694\uCCAD\uD55C \uCABD \uBC94\uC704(${opts.pages})\uAC00 \uBB38\uC11C \uCABD(1~${result.pageCount})\uACFC \uACB9\uCE58\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4` }] };
82002
+ }
82003
+ if (out.success && !out.pages) {
82004
+ const pages = blocksToPages(out.blocks);
82005
+ if (pages) out = { ...out, pages };
80405
82006
  }
80406
82007
  if (out.success && (opts == null ? void 0 : opts.plain)) {
80407
82008
  out = { ...out, markdown: toPlainMarkdown(out.markdown), ...out.pages ? { pages: out.pages.map((p) => ({ ...p, markdown: toPlainMarkdown(p.markdown) })) } : {} };
@@ -80428,9 +82029,7 @@ async function dispatch(format3, buffer, opts) {
80428
82029
  const zipFormat = await detectZipFormat(buffer);
80429
82030
  if (zipFormat === "xlsx") return parseXlsx(buffer, opts);
80430
82031
  if (zipFormat === "docx") return parseDocx(buffer, opts);
80431
- if (zipFormat === "pptx") {
80432
- return { success: false, fileType: "pptx", error: "PPTX \uD30C\uC77C\uC740 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD\uC785\uB2C8\uB2E4.", code: "UNSUPPORTED_FORMAT" };
80433
- }
82032
+ if (zipFormat === "pptx") return parsePptx(buffer, opts);
80434
82033
  return parseHwpx(buffer, opts);
80435
82034
  }
80436
82035
  case "hwp": {
@@ -80557,6 +82156,14 @@ async function parseDocx(buffer, options) {
80557
82156
  return { success: false, fileType: "docx", error: sanitizeError(err), code: classifyError(err) };
80558
82157
  }
80559
82158
  }
82159
+ async function parsePptx(buffer, options) {
82160
+ try {
82161
+ const { markdown, blocks, metadata, outline, warnings, images } = await parsePptxDocument(buffer, options);
82162
+ return scriptsOff({ success: true, fileType: "pptx", markdown, blocks, metadata, outline, warnings, images: (images == null ? void 0 : images.length) ? images : void 0, pageCount: metadata == null ? void 0 : metadata.pageCount }, (options == null ? void 0 : options.scriptTags) === false);
82163
+ } catch (err) {
82164
+ return { success: false, fileType: "pptx", error: sanitizeError(err), code: classifyError(err) };
82165
+ }
82166
+ }
80560
82167
  async function parseHwpml(buffer, options) {
80561
82168
  try {
80562
82169
  const { markdown, blocks, metadata, outline, warnings } = parseHwpmlDocument(buffer, options);
@@ -80670,6 +82277,7 @@ async function fillForm(input, values, outputFormat = "markdown") {
80670
82277
  parseHwpx,
80671
82278
  parseImage,
80672
82279
  parsePdf,
82280
+ parsePptx,
80673
82281
  parseXls,
80674
82282
  parseXlsx,
80675
82283
  patchHwp,