kordoc 4.0.2 → 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +792 -768
  2. package/dist/{-XMKVL3NX.js → -QSF64HNK.js} +8 -8
  3. package/dist/{chunk-STMLZDKR.js → chunk-6JSZBSOD.js} +2 -2
  4. package/dist/chunk-6JSZBSOD.js.map +1 -0
  5. package/dist/{chunk-IKBIIEVJ.js → chunk-AUJICYJG.js} +3 -3
  6. package/dist/chunk-AUJICYJG.js.map +1 -0
  7. package/dist/chunk-DCZVOIEO.cjs.map +1 -1
  8. package/dist/chunk-GS7T56RP.cjs.map +1 -1
  9. package/dist/{chunk-AHWRAGXN.js → chunk-K2SETHJ6.js} +162 -75
  10. package/dist/chunk-K2SETHJ6.js.map +1 -0
  11. package/dist/{chunk-5CJGKKMZ.js → chunk-MEPHGCPQ.js} +1 -1
  12. package/dist/chunk-MEPHGCPQ.js.map +1 -0
  13. package/dist/chunk-MOL7MDBG.js +0 -0
  14. package/dist/{chunk-6SD4X5PT.js → chunk-MQLKSRIK.js} +3 -3
  15. package/dist/chunk-MQLKSRIK.js.map +1 -0
  16. package/dist/{chunk-WN7LZHII.cjs → chunk-OVESZY5R.cjs} +2 -2
  17. package/dist/chunk-OVESZY5R.cjs.map +1 -0
  18. package/dist/{chunk-6YIYFWO2.js → chunk-PNQDQ3SM.js} +2 -2
  19. package/dist/chunk-PNQDQ3SM.js.map +1 -0
  20. package/dist/{chunk-67RANGFQ.js → chunk-RO2GVZ3I.js} +3 -3
  21. package/dist/chunk-RO2GVZ3I.js.map +1 -0
  22. package/dist/{chunk-3IYQYBUF.js → chunk-TQYX5E32.js} +2 -2
  23. package/dist/chunk-TQYX5E32.js.map +1 -0
  24. package/dist/cli.js +14 -14
  25. package/dist/cli.js.map +1 -1
  26. package/dist/{detect-PJZMUL2Z.js → detect-RI2MQ33K.js} +2 -2
  27. package/dist/formula-5NKVS2LR.cjs.map +1 -1
  28. package/dist/formula-JCNF43NE.js +0 -0
  29. package/dist/index.cjs +461 -374
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +5 -4
  32. package/dist/index.d.ts +5 -4
  33. package/dist/index.js +157 -70
  34. package/dist/index.js.map +1 -1
  35. package/dist/mcp.js +17 -17
  36. package/dist/mcp.js.map +1 -1
  37. package/dist/page-range-737B4EZW.js +0 -0
  38. package/dist/page-range-P7SDW6LR.cjs.map +1 -1
  39. package/dist/{parser-3HM2VYKK.js → parser-AODAQQLQ.js} +5 -5
  40. package/dist/parser-AODAQQLQ.js.map +1 -0
  41. package/dist/{parser-6AYYGX6J.cjs → parser-FMONFTAN.cjs} +16 -16
  42. package/dist/parser-FMONFTAN.cjs.map +1 -0
  43. package/dist/{parser-2Q2YKEJG.js → parser-J7YREDNS.js} +4 -4
  44. package/dist/parser-J7YREDNS.js.map +1 -0
  45. package/dist/{provider-H4WWSPOV.js → provider-4ZJKV3DC.js} +1 -1
  46. package/dist/provider-4ZJKV3DC.js.map +1 -0
  47. package/dist/{provider-7H4CPZYS.js → provider-AKROB7WQ.js} +1 -1
  48. package/dist/provider-AKROB7WQ.js.map +1 -0
  49. package/dist/{provider-5K7O3Z2O.cjs → provider-G4C2V2PD.cjs} +1 -1
  50. package/dist/provider-G4C2V2PD.cjs.map +1 -0
  51. package/dist/render-JPP7YTV3.js +10 -0
  52. package/dist/seal-MDE4DXZQ.js +10 -0
  53. package/dist/setup-57FB3LSP.js +0 -0
  54. package/dist/{watch-6OHF727O.js → watch-P65Z24AL.js} +8 -8
  55. package/dist/watch-P65Z24AL.js.map +1 -0
  56. package/package.json +4 -4
  57. package/dist/chunk-3IYQYBUF.js.map +0 -1
  58. package/dist/chunk-5CJGKKMZ.js.map +0 -1
  59. package/dist/chunk-67RANGFQ.js.map +0 -1
  60. package/dist/chunk-6SD4X5PT.js.map +0 -1
  61. package/dist/chunk-6YIYFWO2.js.map +0 -1
  62. package/dist/chunk-AHWRAGXN.js.map +0 -1
  63. package/dist/chunk-IKBIIEVJ.js.map +0 -1
  64. package/dist/chunk-STMLZDKR.js.map +0 -1
  65. package/dist/chunk-WN7LZHII.cjs.map +0 -1
  66. package/dist/parser-2Q2YKEJG.js.map +0 -1
  67. package/dist/parser-3HM2VYKK.js.map +0 -1
  68. package/dist/parser-6AYYGX6J.cjs.map +0 -1
  69. package/dist/provider-5K7O3Z2O.cjs.map +0 -1
  70. package/dist/provider-7H4CPZYS.js.map +0 -1
  71. package/dist/provider-H4WWSPOV.js.map +0 -1
  72. package/dist/render-W4VCJE6N.js +0 -10
  73. package/dist/seal-DRPTNHOP.js +0 -10
  74. package/dist/watch-6OHF727O.js.map +0 -1
  75. /package/dist/{-XMKVL3NX.js.map → -QSF64HNK.js.map} +0 -0
  76. /package/dist/{detect-PJZMUL2Z.js.map → detect-RI2MQ33K.js.map} +0 -0
  77. /package/dist/{render-W4VCJE6N.js.map → render-JPP7YTV3.js.map} +0 -0
  78. /package/dist/{seal-DRPTNHOP.js.map → seal-MDE4DXZQ.js.map} +0 -0
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  sanitizeHref,
21
21
  stripDtd,
22
22
  toArrayBuffer
23
- } from "./chunk-3IYQYBUF.js";
23
+ } from "./chunk-TQYX5E32.js";
24
24
  import {
25
25
  parsePageRange
26
26
  } from "./chunk-GE43BE46.js";
@@ -404,7 +404,7 @@ function createXmlParser(warnings) {
404
404
  return new DOMParser({
405
405
  onError(level, msg2) {
406
406
  if (level === "fatalError") throw new KordocError(`XML \uD30C\uC2F1 \uC2E4\uD328: ${msg2}`);
407
- warnings?.push({ code: "MALFORMED_XML", message: `XML ${level === "warn" ? "\uACBD\uACE0" : "\uC624\uB958"}: ${msg2}` });
407
+ warnings?.push({ code: "MALFORMED_XML", message: `XML ${level === "warning" ? "\uACBD\uACE0" : "\uC624\uB958"}: ${msg2}` });
408
408
  }
409
409
  });
410
410
  }
@@ -463,9 +463,9 @@ async function extractHwpxStyles(zip, decompressed) {
463
463
  const parser = createXmlParser();
464
464
  const doc = parser.parseFromString(stripDtd(xml), "text/xml");
465
465
  if (!doc.documentElement) continue;
466
- parseCharProperties(doc, result.charProperties);
467
- parseStyleElements(doc, result.styles);
468
466
  const domDoc = doc;
467
+ parseCharProperties(domDoc, result.charProperties);
468
+ parseStyleElements(domDoc, result.styles);
469
469
  parseNumberings(domDoc, result.numberings);
470
470
  parseBullets(domDoc, result.bullets);
471
471
  parseParaHeadings(domDoc, result.paraHeadings);
@@ -1333,12 +1333,17 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
1333
1333
  break;
1334
1334
  }
1335
1335
  // 표/도표 캡션 — IRTable.caption으로 보존 (v3.0, 기존 무음 드롭 수정)
1336
- case "caption":
1337
- if (tableCtx) {
1338
- const capText = collectSubListText(el, ctx);
1339
- if (capText) tableCtx.caption = (tableCtx.caption ? tableCtx.caption + "\n" : "") + capText;
1336
+ case "caption": {
1337
+ const capText = collectSubListText(el, ctx);
1338
+ if (capText) {
1339
+ if (tableCtx) {
1340
+ tableCtx.caption = (tableCtx.caption ? tableCtx.caption + "\n" : "") + capText;
1341
+ } else {
1342
+ blocks.push({ type: "paragraph", text: capText, pageNumber: ctx.sectionNum });
1343
+ }
1340
1344
  }
1341
1345
  break;
1346
+ }
1342
1347
  case "tr":
1343
1348
  if (tableCtx) {
1344
1349
  tableCtx.currentRow = [];
@@ -1503,7 +1508,7 @@ function walkParagraphChildren(node, blocks, tableCtx, tableStack, ctx, depth =
1503
1508
  if (depth > MAX_XML_DEPTH) return tableCtx;
1504
1509
  const children = node.childNodes;
1505
1510
  if (!children) return tableCtx;
1506
- const walkChildren = (parent, d) => {
1511
+ const walkChildren = (parent, d, inShape = false) => {
1507
1512
  if (d > MAX_XML_DEPTH) return;
1508
1513
  const kids2 = parent.childNodes;
1509
1514
  if (!kids2) return;
@@ -1517,6 +1522,13 @@ function walkParagraphChildren(node, blocks, tableCtx, tableStack, ctx, depth =
1517
1522
  const newTable = { rows: [], currentRow: [], cell: null };
1518
1523
  walkSection(el, blocks, newTable, tableStack, ctx, d + 1);
1519
1524
  tableCtx = completeTable(newTable, tableStack, blocks, ctx);
1525
+ } else if (localTag === "caption" && !inShape) {
1526
+ const capText = collectSubListText(el, ctx);
1527
+ if (capText) {
1528
+ if (tableCtx?.cell) mergeBlocksIntoCell(tableCtx.cell, [{ type: "paragraph", text: capText, pageNumber: ctx.sectionNum }]);
1529
+ else if (tableCtx) tableCtx.caption = (tableCtx.caption ? tableCtx.caption + "\n" : "") + capText;
1530
+ else blocks.push({ type: "paragraph", text: capText, pageNumber: ctx.sectionNum });
1531
+ }
1520
1532
  } else if (localTag === "pic" || localTag === "shape" || localTag === "drawingObject") {
1521
1533
  if (tableCtx?.cell) {
1522
1534
  const sink = [];
@@ -1533,8 +1545,10 @@ function walkParagraphChildren(node, blocks, tableCtx, tableStack, ctx, depth =
1533
1545
  } else {
1534
1546
  extractDrawTextBlocks(el, blocks, ctx);
1535
1547
  }
1536
- } else if (localTag === "r" || localTag === "run" || localTag === "ctrl" || localTag === "rect" || localTag === "ellipse" || localTag === "polygon" || localTag === "line" || localTag === "arc" || localTag === "curve" || localTag === "connectLine" || localTag === "container") {
1537
- walkChildren(el, d + 1);
1548
+ } else if (localTag === "r" || localTag === "run" || localTag === "ctrl") {
1549
+ walkChildren(el, d + 1, inShape);
1550
+ } else if (localTag === "rect" || localTag === "ellipse" || localTag === "polygon" || localTag === "line" || localTag === "arc" || localTag === "curve" || localTag === "connectLine" || localTag === "container") {
1551
+ walkChildren(el, d + 1, true);
1538
1552
  }
1539
1553
  }
1540
1554
  };
@@ -1670,6 +1684,9 @@ function extractParagraphInfo(para2, styleMap, ctx) {
1670
1684
  case "indexmark":
1671
1685
  case "colPr":
1672
1686
  break;
1687
+ // 캡션 — walkParagraphChildren의 caption 분기가 보존하므로 손실 경고 대상 아님
1688
+ case "caption":
1689
+ break;
1673
1690
  // 미지원 요소 — 텍스트를 가졌으면 무음 손실 대신 경고
1674
1691
  default: {
1675
1692
  if (ctx?.warnings && extractTextFromNode(k)) {
@@ -21064,9 +21081,11 @@ var OFFICIAL_MARGINS = { top: 20, bottom: 15, left: 20, right: 15 };
21064
21081
  var GAEJOSIK_MARGINS = { top: 15, bottom: 15, left: 20, right: 20 };
21065
21082
  var GAEJOSIK_HEADER_FOOTER = 4251;
21066
21083
  var PRESET_DEFAULTS = {
21067
- official: { bodyPt: 15, lineSpacing: 160, numbering: "standard" },
21084
+ // 서울시 실결재 104건 12pt 64건(13pt 30, 15pt 5) — 지배값을 기본으로 사용.
21085
+ official: { bodyPt: 12, lineSpacing: 160, numbering: "standard" },
21068
21086
  report: { bodyPt: 15, lineSpacing: 160, numbering: "report" },
21069
- plan: { bodyPt: 15, lineSpacing: 160, numbering: "standard" },
21087
+ // 실측 추진계획안: * 계층.
21088
+ plan: { bodyPt: 15, lineSpacing: 160, numbering: "report" },
21070
21089
  notice: { bodyPt: 15, lineSpacing: 160, numbering: "standard" },
21071
21090
  minutes: { bodyPt: 14, lineSpacing: 130, numbering: "standard" },
21072
21091
  gaejosik: { bodyPt: 15, lineSpacing: 160, numbering: "gaejosik" },
@@ -21105,7 +21124,46 @@ function normalizeGongmunPreset(preset) {
21105
21124
  function usesReportFonts(preset) {
21106
21125
  return preset === "gaejosik" || preset === "report" || preset === "plan";
21107
21126
  }
21127
+ function usesAsteriskThird(preset) {
21128
+ return preset === "plan" || preset === "press";
21129
+ }
21130
+ function needsGaejosikAssets(gongmun) {
21131
+ return usesReportFonts(gongmun.preset) || gongmun.cover !== null || gongmun.toc;
21132
+ }
21133
+ function assertFiniteRange(name, value, min, max) {
21134
+ if (!Number.isFinite(value) || value < min || value > max) {
21135
+ throw new KordocError(`${name} must be a finite number between ${min} and ${max}`);
21136
+ }
21137
+ }
21138
+ function validateGongmunOptions(opts) {
21139
+ if (opts.bodyPt !== void 0) assertFiniteRange("bodyPt", opts.bodyPt, 6, 40);
21140
+ if (opts.lineSpacing !== void 0) assertFiniteRange("lineSpacing", opts.lineSpacing, 50, 300);
21141
+ if (typeof opts.autoFit === "object" && opts.autoFit.minRatio !== void 0) {
21142
+ assertFiniteRange("autoFit.minRatio", opts.autoFit.minRatio, 50, 99);
21143
+ }
21144
+ if (opts.margins) {
21145
+ for (const side of ["top", "bottom", "left", "right"]) {
21146
+ const value = opts.margins[side];
21147
+ assertFiniteRange(`margins.${side}`, value, 0, 200);
21148
+ }
21149
+ if (opts.margins.left + opts.margins.right >= 210) {
21150
+ throw new KordocError("margins.left + margins.right must be less than 210");
21151
+ }
21152
+ if (opts.margins.top + opts.margins.bottom >= 297) {
21153
+ throw new KordocError("margins.top + margins.bottom must be less than 297");
21154
+ }
21155
+ }
21156
+ if (opts.sizes) {
21157
+ for (const [key, value] of Object.entries(opts.sizes)) {
21158
+ if (value !== void 0) assertFiniteRange(`sizes.${key}`, value, 6, 60);
21159
+ }
21160
+ }
21161
+ if (opts.approval && opts.approval.length > 6) {
21162
+ throw new KordocError("approval must contain at most 6 labels");
21163
+ }
21164
+ }
21108
21165
  function resolveGongmun(opts) {
21166
+ validateGongmunOptions(opts);
21109
21167
  const preset = normalizeGongmunPreset(opts.preset);
21110
21168
  const d = PRESET_DEFAULTS[preset];
21111
21169
  const bodyPt = opts.bodyPt ?? d.bodyPt;
@@ -21123,8 +21181,10 @@ function resolveGongmun(opts) {
21123
21181
  margins: opts.margins ?? (reportFamily ? GAEJOSIK_MARGINS : OFFICIAL_MARGINS),
21124
21182
  centerTitle: opts.centerTitle ?? true,
21125
21183
  autoFitMinRatio,
21126
- cover: coverOn ? { date: coverOpts.date ?? null, org: coverOpts.org ?? "" } : null,
21127
- toc: opts.toc ?? gaejosik,
21184
+ // 보도자료는 머리박스가 1페이지 최상단을 차지하는 서식이라 표지·목차와 양립 불가
21185
+ // 켜면 머리박스가 표지에 얹히고 25pt 제목·부제가 유실된다 (docHead 프리셋 게이팅과 동일 관례)
21186
+ cover: coverOn && preset !== "press" ? { date: coverOpts.date ?? null, org: coverOpts.org ?? "" } : null,
21187
+ toc: preset !== "press" && (opts.toc ?? gaejosik),
21128
21188
  fonts: opts.fonts ?? {},
21129
21189
  sizes: opts.sizes ?? {},
21130
21190
  // 쪽번호 — 보고서 계열 관행(실측: 2_보고서 양식·추진계획·공고문 전부 하단 중앙)
@@ -21140,7 +21200,7 @@ function resolveGongmun(opts) {
21140
21200
  // h2 말머리 — 실측: 보고서 양식 □ 대항목(QA-2), 공고문 아라비아("1. 사업개요", 바이오헬스 실측)
21141
21201
  h2Marker: opts.h2Marker ?? (preset === "report" || preset === "plan" ? "box" : preset === "notice" ? "number" : "none"),
21142
21202
  // 2단계 부호 — 실결재 기안문·공고문 ㅇ 지배(60건 중 ㅇ134:○5), 보고서 양식 계열 ○
21143
- bullet2: opts.bullet2 ?? (preset === "notice" || preset === "press" ? "\u3147" : "\u25CB"),
21203
+ bullet2: opts.bullet2 ?? (preset === "plan" || preset === "notice" || preset === "press" ? "\u3147" : "\u25CB"),
21144
21204
  // 단일 형제 부호 생략 — 규정이지만 부호 없는 계단이 실무 눈에 어색 (실무자 QA)
21145
21205
  suppressSingle: opts.suppressSingle ?? false,
21146
21206
  docHead: preset === "official" && opts.docHead ? opts.docHead : null,
@@ -21166,7 +21226,7 @@ function circledHangul(n) {
21166
21226
  return String.fromCodePoint(12910 + n % 14);
21167
21227
  }
21168
21228
  var REPORT_BULLETS = ["\u25A1", "\u25CB", "-", "\u318D"];
21169
- var PRESS_BULLETS = ["\u25A1", "\u3147", "*", "\u318D"];
21229
+ var ASTERISK_BULLETS = ["\u25A1", "\u25CB", "*", "\u318D"];
21170
21230
  function standardMarker(depth, n) {
21171
21231
  switch (depth) {
21172
21232
  case 0:
@@ -21189,19 +21249,19 @@ function standardMarker(depth, n) {
21189
21249
  return circledHangul(n);
21190
21250
  }
21191
21251
  }
21192
- function reportMarker(depth, bullet2 = "\u25CB", press = false) {
21193
- const bullets = press ? PRESS_BULLETS : REPORT_BULLETS;
21252
+ function reportMarker(depth, bullet2 = "\u25CB", asteriskThird = false) {
21253
+ const bullets = asteriskThird ? ASTERISK_BULLETS : REPORT_BULLETS;
21194
21254
  const m = bullets[Math.min(depth, bullets.length - 1)];
21195
- return depth === 1 && !press ? bullet2 : m;
21255
+ return depth === 1 ? bullet2 : m;
21196
21256
  }
21197
21257
  function markerWidth(marker, bodyHeight) {
21198
21258
  let em = SPACE_EM_FIXED;
21199
21259
  for (const c of marker) em += charWidthEm1000(c.codePointAt(0));
21200
21260
  return Math.round(em / 1e3 * bodyHeight);
21201
21261
  }
21202
- function levelIndent(depth, bodyHeight, numbering, sizes = {}, bullet2 = "\u25CB", press = false) {
21262
+ function levelIndent(depth, bodyHeight, numbering, sizes = {}, bullet2 = "\u25CB", asteriskThird = false) {
21203
21263
  if (numbering === "gaejosik") return gaejosikLevelIndent(depth, bodyHeight, sizes, bullet2);
21204
- const marker = numbering === "report" ? reportMarker(depth, bullet2, press) : standardMarker(depth, 0);
21264
+ const marker = numbering === "report" ? reportMarker(depth, bullet2, asteriskThird) : standardMarker(depth, 0);
21205
21265
  return { left: Math.round(depth * bodyHeight), indent: -markerWidth(marker, bodyHeight) };
21206
21266
  }
21207
21267
  function computeSuppression(depths) {
@@ -21218,10 +21278,10 @@ function computeSuppression(depths) {
21218
21278
  return keys.map((k) => (counts.get(k) ?? 0) <= 1);
21219
21279
  }
21220
21280
  var GongmunNumberer = class {
21221
- constructor(numbering, bullet2 = "\u25CB", press = false) {
21281
+ constructor(numbering, bullet2 = "\u25CB", asteriskThird = false) {
21222
21282
  this.numbering = numbering;
21223
21283
  this.bullet2 = bullet2;
21224
- this.press = press;
21284
+ this.asteriskThird = asteriskThird;
21225
21285
  }
21226
21286
  counts = [];
21227
21287
  /** depth 항목 하나에 대한 마커. suppress=true면 빈 문자열(부호 없음) */
@@ -21231,7 +21291,7 @@ var GongmunNumberer = class {
21231
21291
  this.counts[depth] = n + 1;
21232
21292
  if (suppress) return "";
21233
21293
  if (this.numbering === "gaejosik") return gaejosikMarker(depth, this.bullet2);
21234
- return this.numbering === "report" ? reportMarker(depth, this.bullet2, this.press) : standardMarker(depth, n);
21294
+ return this.numbering === "report" ? reportMarker(depth, this.bullet2, this.asteriskThird) : standardMarker(depth, n);
21235
21295
  }
21236
21296
  reset() {
21237
21297
  this.counts = [];
@@ -21347,13 +21407,16 @@ var GJ_CHAR_TABLE = 22;
21347
21407
  var GJ_CHAR_TABLE_BOLD = 23;
21348
21408
  var GJ_CHAR_BAR = 24;
21349
21409
  var GJ_CHAR_BODY_TITLE = 25;
21350
- var GJ_CHAR_COUNT = 15;
21410
+ var GJ_CHAR_TITLE_BAR = 26;
21411
+ var GJ_CHAR_APPROVAL = 27;
21412
+ var GJ_CHAR_COUNT = 17;
21351
21413
  var GJ_PARA_CHAM = 20;
21352
21414
  var GJ_PARA_COVER = 21;
21353
21415
  var GJ_PARA_TOC_ITEM = 22;
21354
21416
  var GJ_PARA_CHAPTER = 23;
21355
21417
  var GJ_PARA_BAR = 24;
21356
21418
  var GONGMUN_LIST_PLAIN_BASE = 25;
21419
+ var GONGMUN_PARA_APPROVAL = GONGMUN_LIST_PLAIN_BASE + GONGMUN_LIST_LEVELS;
21357
21420
  var GJ_BF_CHAPTER_NUM = 3;
21358
21421
  var GJ_BF_CHAPTER_GAP = 4;
21359
21422
  var GJ_BF_CHAPTER_TITLE = 5;
@@ -21361,8 +21424,8 @@ var GJ_BF_BAR_DARK = 6;
21361
21424
  var GJ_BF_BAR_LIGHT = 7;
21362
21425
  var GJ_BF_TOC_BOX = 8;
21363
21426
  var GJ_BF_TOC_STRIPE = 9;
21364
- function gongmunTableHeaderBf(gaejosik) {
21365
- return gaejosik ? 10 : 3;
21427
+ function gongmunTableHeaderBf(richAssets) {
21428
+ return richAssets ? 10 : 3;
21366
21429
  }
21367
21430
  function borderFillEntry(id, b, fill) {
21368
21431
  const side = (name, v) => v ? ` <hh:${name} type="${v[2] ?? "SOLID"}" width="${v[0]}" color="${v[1]}"/>` : ` <hh:${name} type="NONE" width="0.1 mm" color="#000000"/>`;
@@ -21395,10 +21458,12 @@ function pageHidingCtrl(hideHeader = false) {
21395
21458
  var GONGMUN_TBL_CHAR = 11;
21396
21459
  var GONGMUN_TBL_CHAR_BOLD = 12;
21397
21460
  var GONGMUN_TBL_PT = 1200;
21461
+ var GONGMUN_TITLE_BAR_CHAR = 13;
21462
+ var GONGMUN_APPROVAL_CHAR = 14;
21398
21463
  var CHAR_VARIANT_BASE = 11;
21399
- function charVariantBase(measured, isGongmun = true) {
21464
+ function charVariantBase(richAssets, isGongmun = true) {
21400
21465
  if (!isGongmun) return CHAR_VARIANT_BASE;
21401
- return measured ? 11 + GJ_CHAR_COUNT : 11 + 2;
21466
+ return richAssets ? 11 + GJ_CHAR_COUNT : 11 + 4;
21402
21467
  }
21403
21468
  var GONGMUN_BODY_RATIO = 95;
21404
21469
 
@@ -21647,6 +21712,7 @@ function generateManifest(chartParts = []) {
21647
21712
  }
21648
21713
  function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls = []) {
21649
21714
  const measured = !!gongmun && usesReportFonts(gongmun.preset);
21715
+ const richAssets = !!gongmun && needsGaejosikAssets(gongmun);
21650
21716
  let body = 1e3, code = 900, h1 = 1800, h2 = 1400, h3 = 1200, h4 = 1100;
21651
21717
  if (gongmun) {
21652
21718
  body = gongmun.bodyHeight;
@@ -21654,9 +21720,9 @@ function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls
21654
21720
  h1 = gongmun.preset === "report" || gongmun.preset === "plan" ? 2e3 : 1700;
21655
21721
  h2 = 1600;
21656
21722
  h3 = body;
21657
- h4 = Math.max(body - 100, 1300);
21723
+ h4 = Math.min(h3, Math.max(body - 100, 1300));
21658
21724
  }
21659
- const bodyFont = measured ? 4 : 0;
21725
+ const bodyFont = richAssets ? 4 : 0;
21660
21726
  const hFont = measured ? 3 : 1;
21661
21727
  const hBold = !measured;
21662
21728
  const bodyRatio = gongmun ? GONGMUN_BODY_RATIO : 100;
@@ -21673,13 +21739,15 @@ function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls
21673
21739
  charPr(CHAR_TABLE_HEADER, body, theme.tableHeaderBold, false, bodyFont, theme.tableHeader),
21674
21740
  charPr(CHAR_QUOTE, body, false, true, bodyFont, theme.quote)
21675
21741
  ];
21676
- if (gongmun && !measured) {
21742
+ if (gongmun && !richAssets) {
21677
21743
  rows.push(
21678
21744
  charPr(11, GONGMUN_TBL_PT, false, false, bodyFont, theme.body),
21679
- charPr(12, GONGMUN_TBL_PT, true, false, bodyFont, theme.body)
21745
+ charPr(12, GONGMUN_TBL_PT, true, false, bodyFont, theme.body),
21746
+ charPr(GONGMUN_TITLE_BAR_CHAR, 100, false, false, bodyFont, theme.body),
21747
+ charPr(GONGMUN_APPROVAL_CHAR, 1e3, false, false, bodyFont, theme.body)
21680
21748
  );
21681
21749
  }
21682
- if (measured) {
21750
+ if (richAssets) {
21683
21751
  const sz = gaejosikSizes(body, gongmun.sizes);
21684
21752
  rows.push(
21685
21753
  charPr(11, sz.dae, false, false, 3),
@@ -21710,8 +21778,12 @@ function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls
21710
21778
  // 표 셀 bold
21711
21779
  charPr(24, sz.bar, false, false, 4),
21712
21780
  // 표지 바 셀 빈 문단(6pt)
21713
- charPr(25, sz.bodyTitle, false, false, 3)
21781
+ charPr(25, sz.bodyTitle, false, false, 3),
21714
21782
  // 본문 제목박스(HY헤드라인M 22pt, 실측 GT3 표④)
21783
+ charPr(GJ_CHAR_TITLE_BAR, 100, false, false, 4),
21784
+ // 1페이지형 제목박스 바(1pt)
21785
+ charPr(GJ_CHAR_APPROVAL, 1e3, false, false, 7)
21786
+ // 결재란 라벨(맑은 고딕 10pt)
21715
21787
  );
21716
21788
  }
21717
21789
  for (const r of ratioVariants) {
@@ -21757,7 +21829,7 @@ ${base2.join("\n")}
21757
21829
  paraPr(7, { align: "LEFT", lineSpacing: ls, indent: 600, keepWord: true })
21758
21830
  ];
21759
21831
  for (let d = 0; d < GONGMUN_LIST_LEVELS; d++) {
21760
- const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, gongmun.preset === "press");
21832
+ const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset));
21761
21833
  const sectionGap = gongmun.numbering === "gaejosik" || gongmun.numbering === "report" ? gaejosikSpaceBefore(d, gongmun.bodyHeight) : 0;
21762
21834
  const keepNext = (gongmun.numbering === "gaejosik" || gongmun.numbering === "report") && d === 0;
21763
21835
  base.push(paraPr(GONGMUN_LIST_BASE + d, { align: "JUSTIFY", lineSpacing: ls, left, indent, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext }));
@@ -21780,10 +21852,11 @@ ${base2.join("\n")}
21780
21852
  );
21781
21853
  }
21782
21854
  for (let d = 0; d < GONGMUN_LIST_LEVELS; d++) {
21783
- const { left } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, gongmun.preset === "press");
21855
+ const { left } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset));
21784
21856
  const sectionGap = gongmun.numbering === "gaejosik" || gongmun.numbering === "report" ? gaejosikSpaceBefore(d, gongmun.bodyHeight) : 0;
21785
21857
  base.push(paraPr(GONGMUN_LIST_PLAIN_BASE + d, { align: "JUSTIFY", lineSpacing: ls, left, indent: 0, spaceBefore: sectionGap, keepWord: true }));
21786
21858
  }
21859
+ base.push(paraPr(GONGMUN_PARA_APPROVAL, { align: "CENTER", lineSpacing: 100, keepWord: true }));
21787
21860
  return `<hh:paraProperties itemCnt="${base.length}">
21788
21861
  ${base.join("\n")}
21789
21862
  </hh:paraProperties>`;
@@ -21800,14 +21873,14 @@ ${heads}
21800
21873
  </hh:numberings>`;
21801
21874
  }
21802
21875
  function fontEntry(id, face, weight = 6) {
21803
- return ` <hh:font id="${id}" face="${face}" type="TTF" isEmbedded="0">
21876
+ return ` <hh:font id="${id}" face="${escapeXml(face)}" type="TTF" isEmbedded="0">
21804
21877
  <hh:typeInfo familyType="FCAT_GOTHIC" weight="${weight}" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
21805
21878
  </hh:font>`;
21806
21879
  }
21807
21880
  function buildFontFaces(gongmun, bodyFace) {
21808
- if (gongmun && usesReportFonts(gongmun.preset)) {
21881
+ if (gongmun && needsGaejosikAssets(gongmun)) {
21809
21882
  const ov = gongmun.fonts;
21810
- const bodyDefault = gongmun.preset !== "gaejosik" && gongmun.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD734\uBA3C\uBA85\uC870";
21883
+ const bodyDefault = usesReportFonts(gongmun.preset) ? gongmun.preset !== "gaejosik" && gongmun.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD734\uBA3C\uBA85\uC870" : bodyFace;
21811
21884
  const faces = [
21812
21885
  "\uD568\uCD08\uB86C\uBC14\uD0D5",
21813
21886
  "\uD568\uCD08\uB86C\uB3CB\uC6C0",
@@ -21866,7 +21939,7 @@ function buildBorderFills(gongmun, extra = []) {
21866
21939
  borderFillEntry(1, {}),
21867
21940
  borderFillEntry(2, { l: thin, r: thin, t: thin, b: thin })
21868
21941
  ];
21869
- if (gongmun?.preset === "gaejosik") {
21942
+ if (gongmun && needsGaejosikAssets(gongmun)) {
21870
21943
  const c = GAEJOSIK_COLORS;
21871
21944
  const edge = ["0.12 mm", c.border];
21872
21945
  const grayLine = ["0.1 mm", c.titleLine];
@@ -22163,7 +22236,7 @@ function computeGongmunFitPlan(blocks, gongmun, gongmunList) {
22163
22236
  if (gongmun.numbering === "gaejosik" && (depth === 0 || (block.text || "").trimStart().startsWith("\u203B"))) continue;
22164
22237
  const content = plainRenderText(block.text || "");
22165
22238
  text = marker ? `${marker} ${content}` : content;
22166
- const li = levelIndent(depth, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, gongmun.preset === "press");
22239
+ const li = levelIndent(depth, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset));
22167
22240
  const left = li.left;
22168
22241
  const indent = marker ? li.indent : 0;
22169
22242
  firstW = pageW - left - Math.max(indent, 0);
@@ -22221,7 +22294,7 @@ function precomputeGongmunList(blocks, gongmun) {
22221
22294
  }
22222
22295
  const depths = run.map((bi) => Math.min(Math.max((blocks[bi].indent || 0) + depthOffset, 0), GONGMUN_LIST_LEVELS - 1));
22223
22296
  const suppress = gongmun.suppressSingle && gongmun.numbering === "standard" ? computeSuppression(depths) : depths.map(() => false);
22224
- const numberer = new GongmunNumberer(gongmun.numbering, gongmun.bullet2, gongmun.preset === "press");
22297
+ const numberer = new GongmunNumberer(gongmun.numbering, gongmun.bullet2, usesAsteriskThird(gongmun.preset));
22225
22298
  run.forEach((bi, k) => {
22226
22299
  const marker = numberer.next(depths[k], suppress[k]);
22227
22300
  result.set(bi, { marker, depth: depths[k] });
@@ -23110,6 +23183,7 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, r
23110
23183
  const reg = style?.bfRegistry ?? null;
23111
23184
  let htmlHeaderRows = 0;
23112
23185
  while (htmlHeaderRows < rows.length && rows[htmlHeaderRows].tag === "th") htmlHeaderRows++;
23186
+ const tableRowHeights = Array(rowCnt).fill(cellH);
23113
23187
  const tcXmls = placed.map((cell2, i) => {
23114
23188
  const k = `${cell2.r},${cell2.c}`;
23115
23189
  const isHeader = cell2.isHeader;
@@ -23137,6 +23211,10 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, r
23137
23211
  }
23138
23212
  const contentH = Math.max(cellH * cell2.rowSpan, Math.max(lines.length, 1) * (style ? Math.round(measureH * 1.6) : 800) + nestedH);
23139
23213
  const cellHeight = Math.max(prof?.cellH.get(k) ?? 0, contentH);
23214
+ const perRow = Math.ceil(cellHeight / cell2.rowSpan);
23215
+ for (let r = cell2.r; r < Math.min(cell2.r + cell2.rowSpan, rowCnt); r++) {
23216
+ tableRowHeights[r] = Math.max(tableRowHeights[r], perRow);
23217
+ }
23140
23218
  const bf = prof?.cellBf.get(k) ?? (reg ? reg.get(dataCellSpec({
23141
23219
  row: cell2.r,
23142
23220
  rowEnd: cell2.r + cell2.rowSpan - 1,
@@ -23154,7 +23232,8 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, r
23154
23232
  const rowTcs = tcXmls.filter((_, i) => placed[i].r === r);
23155
23233
  trXmls.push(`<hp:tr>${rowTcs.join("")}</hp:tr>`);
23156
23234
  }
23157
- return `<hp:tbl id="${tblId}" zOrder="0" numberingType="TABLE" pageBreak="CELL" repeatHeader="${style ? 1 : 0}" rowCnt="${rowCnt}" colCnt="${colCnt}" cellSpacing="0" borderFillIDRef="2" noShading="0"><hp:sz width="${tblW}" widthRelTo="ABSOLUTE" height="${cellH * rowCnt}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="0" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="0" right="0" top="0" bottom="0"/><hp:inMargin left="510" right="510" top="141" bottom="141"/>` + trXmls.join("") + `</hp:tbl>`;
23235
+ const tableH = tableRowHeights.reduce((sum, height) => sum + height, 0);
23236
+ return `<hp:tbl id="${tblId}" zOrder="0" numberingType="TABLE" pageBreak="CELL" repeatHeader="${style ? 1 : 0}" rowCnt="${rowCnt}" colCnt="${colCnt}" cellSpacing="0" borderFillIDRef="2" noShading="0"><hp:sz width="${tblW}" widthRelTo="ABSOLUTE" height="${tableH}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="0" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="0" right="0" top="0" bottom="0"/><hp:inMargin left="510" right="510" top="141" bottom="141"/>` + trXmls.join("") + `</hp:tbl>`;
23158
23237
  }
23159
23238
 
23160
23239
  // src/hwpx/gen-gongmun-extra.ts
@@ -23169,9 +23248,9 @@ function para(text, paraPrId, charPrId) {
23169
23248
  return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t>${escapeXml(text)}</hp:t></hp:run></hp:p>`;
23170
23249
  }
23171
23250
  var APPROVAL_COL_W = 7085;
23172
- var APPROVAL_LABEL_H = 1100;
23251
+ var APPROVAL_LABEL_H = 1300;
23173
23252
  var APPROVAL_SIGN_H = 4200;
23174
- function buildApprovalTable(labels, gongmun, reg) {
23253
+ function buildApprovalTable(labels, reg, approvalCharPr) {
23175
23254
  const n = labels.length;
23176
23255
  const w = APPROVAL_COL_W * n;
23177
23256
  const bfAt = (row, col) => reg.get({
@@ -23181,10 +23260,10 @@ function buildApprovalTable(labels, gongmun, reg) {
23181
23260
  r: col === n - 1 ? "thick" : "thin"
23182
23261
  });
23183
23262
  const labelRow = labels.map(
23184
- (label, c) => tc({ bf: bfAt(0, c), row: 0, col: c, w: APPROVAL_COL_W, h: APPROVAL_LABEL_H, paras: para(label, GONGMUN_TBL_CENTER, CHAR_NORMAL) })
23263
+ (label, c) => tc({ bf: bfAt(0, c), row: 0, col: c, w: APPROVAL_COL_W, h: APPROVAL_LABEL_H, paras: para(label, GONGMUN_PARA_APPROVAL, approvalCharPr) })
23185
23264
  ).join("");
23186
23265
  const signRow = labels.map(
23187
- (_, c) => tc({ bf: bfAt(1, c), row: 1, col: c, w: APPROVAL_COL_W, h: APPROVAL_SIGN_H, paras: para("", GONGMUN_TBL_CENTER, CHAR_NORMAL) })
23266
+ (_, c) => tc({ bf: bfAt(1, c), row: 1, col: c, w: APPROVAL_COL_W, h: APPROVAL_SIGN_H, paras: para("", GONGMUN_PARA_APPROVAL, approvalCharPr) })
23188
23267
  ).join("");
23189
23268
  const table2 = tbl([labelRow, signRow], w, APPROVAL_LABEL_H + APPROVAL_SIGN_H, n);
23190
23269
  return `<hp:p paraPrIDRef="${GONGMUN_RIGHT}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${table2}</hp:run></hp:p>`;
@@ -23196,13 +23275,13 @@ function buildEndMark() {
23196
23275
  return para(" \uB05D.", PARA_NORMAL, CHAR_NORMAL);
23197
23276
  }
23198
23277
  var TITLE_BOX = { barH: 382, titleH: 2850, color: "#0080C0", gradient: ["#0080C0", "#3CBFFF"] };
23199
- function buildTitleBox(title, titleCharPr, bodyWidth, reg) {
23278
+ function buildTitleBox(title, titleCharPr, barCharPr, bodyWidth, reg) {
23200
23279
  const w = bodyWidth - 280;
23201
23280
  const outer = { t: "thin", b: "thin", l: "thin", r: "thin" };
23202
23281
  const barTop = reg.get({ ...outer, fill: TITLE_BOX.color });
23203
23282
  const barBottom = reg.get({ ...outer, fill: { gradient: TITLE_BOX.gradient } });
23204
23283
  const mid = reg.get(outer);
23205
- const barPara = `<hp:p paraPrIDRef="${GONGMUN_TBL_CENTER}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}"><hp:t></hp:t></hp:run></hp:p>`;
23284
+ const barPara = para("", GJ_PARA_BAR, barCharPr);
23206
23285
  const rows = [
23207
23286
  tc({ bf: barTop, row: 0, col: 0, w, h: TITLE_BOX.barH, paras: barPara }),
23208
23287
  tc({ bf: mid, row: 1, col: 0, w, h: TITLE_BOX.titleH, paras: para(title, GONGMUN_TBL_CENTER, titleCharPr) }),
@@ -23219,8 +23298,8 @@ function docframeIds(base) {
23219
23298
  function docframeActive(g) {
23220
23299
  return !!(g.docHead || g.docFoot || g.reportInfo || g.noticeHead || g.press);
23221
23300
  }
23222
- function docframeCharPrXmls(base, measured) {
23223
- const body = measured ? 4 : 0;
23301
+ function docframeCharPrXmls(base, richAssets) {
23302
+ const body = richAssets ? 4 : 0;
23224
23303
  const ids = docframeIds(base);
23225
23304
  return [
23226
23305
  charPr(ids.org, 1800, true, false, body),
@@ -23627,15 +23706,16 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
23627
23706
  let prevWasOrdered = false;
23628
23707
  const gaejosik = gongmun?.preset === "gaejosik";
23629
23708
  const measured = !!gongmun && usesReportFonts(gongmun.preset);
23630
- const vBase = charVariantBase(measured, !!gongmun);
23709
+ const richAssets = !!gongmun && needsGaejosikAssets(gongmun);
23710
+ const vBase = charVariantBase(richAssets, !!gongmun);
23631
23711
  const tableStyle = gongmun ? {
23632
23712
  totalWidth: mmToHwpunit(210 - gongmun.margins.left - gongmun.margins.right),
23633
23713
  // 표 셀 크기 — 실측: 실측 프리셋 맑은 고딕 12pt(22·23), 비실측도 12pt(11·12,
23634
23714
  // 실결재 지배값 — 본문 크기 셀은 열폭 부족으로 서술 열 세로 신장, v4.0.2 QA)
23635
- charPr: measured ? GJ_CHAR_TABLE : GONGMUN_TBL_CHAR,
23636
- boldCharPr: measured ? GJ_CHAR_TABLE_BOLD : GONGMUN_TBL_CHAR_BOLD,
23637
- charHeight: measured ? gaejosikSizes(gongmun.bodyHeight, gongmun.sizes).table : GONGMUN_TBL_PT,
23638
- headerBf: gongmunTableHeaderBf(gaejosik),
23715
+ charPr: richAssets ? GJ_CHAR_TABLE : GONGMUN_TBL_CHAR,
23716
+ boldCharPr: richAssets ? GJ_CHAR_TABLE_BOLD : GONGMUN_TBL_CHAR_BOLD,
23717
+ charHeight: richAssets ? gaejosikSizes(gongmun.bodyHeight, gongmun.sizes).table : GONGMUN_TBL_PT,
23718
+ headerBf: gongmunTableHeaderBf(richAssets),
23639
23719
  centerParaPr: GONGMUN_CENTER,
23640
23720
  tblCenterParaPr: GONGMUN_TBL_CENTER,
23641
23721
  tblLeftParaPr: GONGMUN_TBL_LEFT,
@@ -23656,7 +23736,7 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
23656
23736
  preamble.push(buildReportInfo(gongmun, dfIds));
23657
23737
  }
23658
23738
  if (gongmun?.approval && bfReg) {
23659
- preamble.push(buildApprovalTable(gongmun.approval, gongmun, bfReg));
23739
+ preamble.push(buildApprovalTable(gongmun.approval, bfReg, richAssets ? GJ_CHAR_APPROVAL : GONGMUN_APPROVAL_CHAR));
23660
23740
  }
23661
23741
  if (gongmun?.docHead && dfIds) {
23662
23742
  preamble.push(...buildDocHead(gongmun, dfIds));
@@ -23667,7 +23747,7 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
23667
23747
  if (gongmun?.press && dfIds && bfReg && tableStyle) {
23668
23748
  preamble.push(...buildPressHead(gongmun, dfIds, tableStyle.totalWidth, bfReg));
23669
23749
  }
23670
- if (gaejosik && gongmun) {
23750
+ if (gongmun && (gongmun.cover || gongmun.toc)) {
23671
23751
  const h1Idx = blocks.findIndex((b) => b.type === "heading" && (b.level ?? 1) === 1);
23672
23752
  const chapters = blocks.filter((b) => b.type === "heading" && b.level === 2).map((b) => stripChapterNumber(b.text || ""));
23673
23753
  let coverTitle = "";
@@ -23689,9 +23769,10 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
23689
23769
  if (gongmun.bodyTitleBox && coverTitle && hasFrontPages) {
23690
23770
  preamble.push(buildGaejosikBodyTitle(coverTitle, gongmun).replace(/^<hp:p /, `<hp:p pageBreak="1" `));
23691
23771
  }
23692
- } else if (gongmun && !gaejosik && bfReg && (gongmun.preset === "report" || gongmun.preset === "plan" || gongmun.preset === "notice")) {
23772
+ }
23773
+ if (gongmun && !gaejosik && coverH1Idx < 0 && bfReg && (gongmun.preset === "report" || gongmun.preset === "plan" || gongmun.preset === "notice")) {
23693
23774
  titleBoxH1Idx = blocks.findIndex((b) => b.type === "heading" && (b.level ?? 1) === 1);
23694
- } else if (gongmun?.press && dfIds) {
23775
+ } else if (gongmun?.press && coverH1Idx < 0 && dfIds) {
23695
23776
  pressH1Idx = blocks.findIndex((b) => b.type === "heading" && (b.level ?? 1) === 1);
23696
23777
  }
23697
23778
  if (preamble.length > 0) {
@@ -23712,6 +23793,7 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
23712
23793
  }
23713
23794
  switch (block.type) {
23714
23795
  case "heading": {
23796
+ if (gongmun && blockIdx === coverH1Idx) break;
23715
23797
  if (gongmun && blockIdx === pressH1Idx && dfIds) {
23716
23798
  const parts = [generateParagraph((block.text || "").trim(), GONGMUN_CENTER, dfIds.pressTitle)];
23717
23799
  for (const s of gongmun.press?.sub ?? []) {
@@ -23721,12 +23803,17 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
23721
23803
  break;
23722
23804
  }
23723
23805
  if (gongmun && blockIdx === titleBoxH1Idx && tableStyle && bfReg) {
23724
- xml = buildTitleBox((block.text || "").trim(), measured ? GJ_CHAR_BODY_TITLE : CHAR_H1, tableStyle.totalWidth, bfReg);
23806
+ xml = buildTitleBox(
23807
+ (block.text || "").trim(),
23808
+ measured ? GJ_CHAR_BODY_TITLE : CHAR_H1,
23809
+ richAssets ? GJ_CHAR_TITLE_BAR : GONGMUN_TITLE_BAR_CHAR,
23810
+ tableStyle.totalWidth,
23811
+ bfReg
23812
+ );
23725
23813
  break;
23726
23814
  }
23727
23815
  if (gaejosik) {
23728
23816
  const lvl = block.level || 1;
23729
- if (blockIdx === coverH1Idx) break;
23730
23817
  if (lvl <= 2) {
23731
23818
  chapterNo++;
23732
23819
  xml = buildGaejosikChapter(chapterNo, stripChapterNumber(block.text || ""), gongmun);
@@ -23941,16 +24028,16 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
23941
24028
  async function markdownToHwpx(markdown, options) {
23942
24029
  const theme = resolveTheme(options?.theme);
23943
24030
  const gongmun = options?.gongmun ? resolveGongmun(options.gongmun) : null;
23944
- const gaejosik = gongmun?.preset === "gaejosik";
23945
24031
  const measured = !!gongmun && usesReportFonts(gongmun.preset);
24032
+ const richAssets = !!gongmun && needsGaejosikAssets(gongmun);
23946
24033
  const blocks = parseMarkdownToBlocks(markdown);
23947
24034
  const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
23948
24035
  const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null;
23949
- const staticBfEnd = gongmun ? gaejosik ? 11 : 4 : 3;
23950
- const remap = options?.profile ? buildProfileRemap(options.profile, charVariantBase(measured, !!gongmun) + (fit?.variants?.length ?? 0) * 4, staticBfEnd) : null;
24036
+ const staticBfEnd = gongmun ? richAssets ? 11 : 4 : 3;
24037
+ const remap = options?.profile ? buildProfileRemap(options.profile, charVariantBase(richAssets, !!gongmun) + (fit?.variants?.length ?? 0) * 4, staticBfEnd) : null;
23951
24038
  const bfReg = gongmun ? new TableBfRegistry(staticBfEnd + (remap?.borderFillXmls.length ?? 0)) : null;
23952
24039
  const dfActive = !!gongmun && docframeActive(gongmun);
23953
- const dfBase = charVariantBase(measured, !!gongmun) + (fit?.variants?.length ?? 0) * 4 + (remap?.charPrXmls.length ?? 0);
24040
+ const dfBase = charVariantBase(richAssets, !!gongmun) + (fit?.variants?.length ?? 0) * 4 + (remap?.charPrXmls.length ?? 0);
23954
24041
  const dfIds = dfActive ? docframeIds(dfBase) : null;
23955
24042
  const chartParts = [];
23956
24043
  const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts, bfReg, remap, dfIds);
@@ -23970,7 +24057,7 @@ async function markdownToHwpx(markdown, options) {
23970
24057
  gongmun,
23971
24058
  fit?.variants ?? [],
23972
24059
  extraBorderFills,
23973
- [...remap?.charPrXmls ?? [], ...dfActive ? docframeCharPrXmls(dfBase, measured) : []]
24060
+ [...remap?.charPrXmls ?? [], ...dfActive ? docframeCharPrXmls(dfBase, richAssets) : []]
23974
24061
  ));
23975
24062
  zip.file("Contents/section0.xml", sectionXml);
23976
24063
  for (const part of chartParts) zip.file(part.name, part.xml);
@@ -28779,7 +28866,7 @@ async function parseHwp(buffer, options) {
28779
28866
  async function parsePdf(buffer, options) {
28780
28867
  let parsePdfDocument;
28781
28868
  try {
28782
- const mod = await import("./parser-2Q2YKEJG.js");
28869
+ const mod = await import("./parser-J7YREDNS.js");
28783
28870
  parsePdfDocument = mod.parsePdfDocument;
28784
28871
  } catch {
28785
28872
  return {