/** * HWP 문서 IR (Intermediate Representation) 타입. * rhwp 의 model 모듈을 단순화하여 HWPX 변환에 필요한 정보만 정의. */ import type { FileHeader } from "./fileHeader.js"; /** * 이미지 src(데이터 URI 가 아닌 file://·로컬/상대 경로)를 바이트로 해석하는 resolver. * 코어는 이를 주입받기만 한다(브라우저 안전). Node(CLI) 측에서 fs 기반 구현을 제공한다. * null 을 반환하면 해당 이미지는 스킵된다. */ export type ImageResolver = (src: string) => { data: Uint8Array; extension: string; } | null; /** 지원 용지 종류 이름(일반 세트). 그 외는 커스텀 치수로 지정. */ export type PaperSizeName = "A4" | "A3" | "A5" | "B4" | "B5" | "Letter" | "Legal"; /** * HTML→HWPX 페이지 설정 명시 제어 옵션. 미지정 필드는 컨테이너 CSS > 기본값 순으로 자동 귀결. * 용지 치수는 한글 네이티브 방식대로 물리값(세로 기준) 고정이며, 방향은 orientation 으로 표현한다. */ export interface PageSetupOption { /** 용지 종류 이름 또는 커스텀 치수({width,height,unit}). 미지정 시 A4. */ size?: PaperSizeName | { width: number; height: number; unit?: "mm" | "hwpunit"; }; /** 'auto'(기본): 본문폭이 세로 가용폭을 넘으면 가로. 'portrait'/'landscape': 명시 고정. */ orientation?: "auto" | "portrait" | "landscape"; /** 페이지 여백(mm). 지정 면만 반영, 나머지는 컨테이너 padding > 한글 기본. */ margins?: { left?: number; right?: number; top?: number; bottom?: number; header?: number; footer?: number; gutter?: number; }; } /** md/html → HwpDocument 변환 옵션. */ export interface ConvertOptions { imageResolver?: ImageResolver; /** HTML→HWPX 용지/방향/여백 명시 제어(p1x 자동동작 오버라이드). */ page?: PageSetupOption; } export interface HwpRun { /** 글자 모양 ID (DocInfo의 CHAR_SHAPE 인덱스) */ charShapeId: number; /** 텍스트 — 일반 문자만 (컨트롤 문자는 별도 controls 에 표시) */ text: string; } export interface HwpParagraph { paraShapeId: number; styleId: number; /** 문단 텍스트 (모든 run을 이은 평문) */ text: string; /** 글자 모양 변화점 기준 run 분할 */ runs: HwpRun[]; /** 인라인 컨트롤들 (표/그림/필드/머리말 등) */ controls: HwpControl[]; /** * 표만 든 앵커 문단의 빈 lineseg 를 최소 높이(1pt 센티넬)로 줄여 표 위 빈 줄을 제거한다. * HTML 경로(htmlReader 의 표 생성기)만 설정 — md/HWP 바이너리 경로는 미설정(무영향). * 완전 생략이 아니라 최소값이라 인접 표 경계 붕괴를 막는다(docx-convert 미러). */ tightTableAnchor?: boolean; } export interface HwpSection { paragraphs: HwpParagraph[]; /** 섹션 페이지 설정(용지/여백/방향). secd→PAGE_DEF 에서 추출. 미설정 시 빌더 기본값 폴백 */ pageDef?: HwpPageDef; } /** * 섹션 페이지 설정 — HWP `secd` 컨트롤 자식 `HWPTAG_PAGE_DEF` 레코드에서 추출. * 모든 치수는 HWPUNIT(1/7200 inch) — OWPML `pagePr`/`margin` 과 동일 단위라 변환 없이 매핑. */ export interface HwpPageDef { /** 용지 가로/세로 크기 */ width: number; height: number; /** 본문 여백 */ left: number; right: number; top: number; bottom: number; /** 머리말/꼬리말/제본 여백 */ header: number; footer: number; gutter: number; /** attr bit0 — 가로 방향. (1차 보존 범위: IR 에만 기록, 빌더는 width/height 로 자연 표현) */ landscape: boolean; } export type HwpControl = HwpTableControl | HwpPictureControl | HwpHeaderControl | HwpFooterControl | HwpFootnoteControl | HwpFieldControl | HwpShapeControl | HwpEquationControl | HwpSectionDefControl | HwpColumnDefControl | HwpUnknownControl; export interface HwpSectionDefControl { kind: "sectionDef"; /** secd 자식 PAGE_DEF 에서 디코드한 페이지 설정 */ pageDef: HwpPageDef; } export interface HwpColumnDefControl { kind: "columnDef"; /** 단(컬럼) 수. 1=단일. cold 컨트롤(본문 단 정의/단 바꿈)에서 디코드. */ colCount: number; } export interface HwpShapeControl { kind: "shape"; /** "line" | "rectangle" | "ellipse" | "arc" | "polygon" | "curve" */ shapeType: "line" | "rectangle" | "ellipse" | "arc" | "polygon" | "curve"; /** 시작 좌표 (HWPUNIT) */ x1?: number; y1?: number; /** 끝 좌표 (HWPUNIT) */ x2?: number; y2?: number; } export interface HwpEquationControl { kind: "equation"; /** 수식 스크립트 (HWP 자체 수식 언어, LaTeX 와 비슷하지만 다름) */ script: string; } export interface HwpTableControl { kind: "table"; rowCount: number; colCount: number; cells: HwpTableCell[]; /** 컬럼별 너비(HWPUNIT). 미설정 시 균등분할. div 다단 레이아웃 표가 grid-template-columns 반영 */ colWidths?: number[]; /** 테두리 없는 레이아웃 표(div grid/flex 합성). 미설정 시 일반 데이터 표(격자 테두리) */ borderless?: boolean; /** 셀 간격(HWPUNIT) — CSS grid gap. 미설정 시 0 */ cellSpacing?: number; /** 콘텐츠 폭 유지(레이아웃 표 전폭 스케일 회피). 미설정 시 false=기존 본문 전폭 스케일. * 인라인 width span flex 행 승격 표가 우측정렬을 실효화하려면 true. */ fitContent?: boolean; } export interface HwpTableCell { col: number; row: number; colSpan: number; rowSpan: number; paragraphs: HwpParagraph[]; /** 셀 실폭(HWPUNIT) — HWP 표 셀 list-header. 미설정 시 빌더가 colWidths 로 산정(HTML/md). */ width?: number; /** 셀 실높이(HWPUNIT) — HWP 표 셀 list-header. 미설정 시 빌더 DEFAULT_ROW_HEIGHT(HTML/md). */ height?: number; /** 셀 배경/테두리 — docInfo.borderFills 인덱스. 미설정 시 기본(0) */ borderFillId?: number; /** 셀 안쪽 여백(HWPUNIT) — CSS padding. 미설정 시 빌더 기본 */ cellMargin?: { left: number; right: number; top: number; bottom: number; }; /** 셀 세로 정렬 — CSS vertical-align. 미설정 시 빌더 기본(데이터셀 CENTER) */ vertAlign?: "TOP" | "CENTER" | "BOTTOM"; } export interface HwpPictureControl { kind: "picture"; /** DocInfo BIN_DATA 의 storageId */ binDataId: number; /** CSS 표시 너비 — px 또는 % (pct=true). 미설정 시 원본 px(축소만) */ width?: { v: number; pct: boolean; }; /** CSS 표시 높이 — px 또는 %. 미설정 시 너비·원본 비율로 보완 */ height?: { v: number; pct: boolean; }; } export interface HwpHeaderControl { kind: "header"; paragraphs: HwpParagraph[]; } export interface HwpFooterControl { kind: "footer"; paragraphs: HwpParagraph[]; } export interface HwpFootnoteControl { kind: "footnote"; paragraphs: HwpParagraph[]; } export interface HwpFieldControl { kind: "field"; /** "%hlk", "%clk", "%dte" 등 */ ctrlId: string; /** 필드 명령 (UTF-16) */ command?: string; } export interface HwpUnknownControl { kind: "unknown"; /** 4글자 ctrl_id ("tbl ", "secd", "cold", "$pic" 등) */ ctrlId: string; } export interface HwpDocInfo { /** 언어별 폰트 그룹 [HANGUL, LATIN, HANJA, JAPANESE, OTHER, SYMBOL, USER] */ fontFaces: HwpFaceName[][]; charShapes: HwpCharShape[]; paraShapes: HwpParaShape[]; styles: HwpStyle[]; binData: HwpBinDataRef[]; /** 테두리/채우기 정의 — paraShape 의 borderFillIDRef 가 참조 */ borderFills: HwpBorderFill[]; /** 번호 매기기 — paraShape 의 numberingIDRef 가 참조 */ numberings: HwpNumbering[]; /** 글머리표 */ bullets: HwpBullet[]; /** 탭 정의 — paraShape 의 tabPrIDRef 가 참조 */ tabDefs: HwpTabDef[]; } export interface HwpBorderLine { /** 0=NONE, 1=SOLID, 2=DASH, 3=DOT, 4=DASH_DOT, 5=DASH_DOT_DOT, 6=LONG_DASH, 7=CIRCLE, * 8=DOUBLE, 9=THIN_THICK_DOUBLE, 10=THICK_THIN_DOUBLE, 11=THIN_THICK_THIN_TRIPLE, * 12=WAVE, 13=DOUBLE_WAVE, 14=THICK_3D, 15=THICK_3D_REVERSE, 16=THIN_3D, 17=THIN_3D_REVERSE */ lineType: number; /** HWP 너비 인덱스 (0..15). mm 변환은 BORDER_WIDTH_MM 표 참조. */ widthIndex: number; /** 0xAABBGGRR */ color: number; } export interface HwpDiagonalLine { /** 0=NONE, 1=FORWARD, 2=BACKWARD, 3=CROSS */ diagonalType: number; widthIndex: number; color: number; } export interface HwpSolidFill { /** 0xAABBGGRR */ backgroundColor: number; patternColor: number; /** -1=NONE, 0=HORIZONTAL, 1=VERTICAL, ... */ patternType: number; } export interface HwpBorderFill { /** 비트필드 속성 (3D, shadow, centerLine 등) */ attr: number; /** [left, right, top, bottom] */ borders: [HwpBorderLine, HwpBorderLine, HwpBorderLine, HwpBorderLine]; diagonal: HwpDiagonalLine; /** 채우기. solid 만 보존 (gradient/image 는 미보존) */ fill?: HwpSolidFill; } export interface HwpNumbering { startNumber: number; /** 수준별 (1~7) 번호 형식 문자열 (예: "^1.", "^1.^2.", "^1)") */ levelFormats: string[]; } export interface HwpBullet { /** 글머리 문자 (예: ●, ○, ■, …) */ bulletChar: string; } export interface HwpTabDef { attr: number; autoTabLeft: boolean; autoTabRight: boolean; } export interface HwpFaceName { name: string; substituteName?: string; } export interface HwpCharShape { faceNameIds: { hangul: number; latin: number; hanja: number; japanese: number; other: number; symbol: number; user: number; }; baseSize: number; property: number; textColor: number; shadeColor: number; underlineColor: number; shadowColor: number; outlineColor?: number; bold: boolean; italic: boolean; underline: boolean; strikeout: boolean; /** 글자 테두리 — docInfo.borderFills 인덱스(인라인 span border). 미설정 시 없음 */ borderFillId?: number; /** * 자간(letter-spacing) — per-script 균일 percent(HWPX ``). 미설정 시 0. * CSS letter-spacing(px/em)을 글자크기 기준 %로 환산해 담는다(htmlReader). md/HWP 미설정→0. */ letterSpacing?: number; } export interface HwpParaShape { alignment: "left" | "right" | "center" | "justify" | "distribute" | "distributeSpace" | "unknown"; property: number; leftMargin: number; rightMargin: number; indent: number; prevSpacing: number; nextSpacing: number; lineSpacing: number; /** 문단 배경/테두리 — docInfo.borderFills 인덱스. 미설정 시 문단 채우기 없음 */ borderFillIDRef?: number; } export interface HwpStyle { name: string; engName?: string; paraShapeId: number; charShapeId: number; } export interface HwpBinDataRef { storageId: number; extension?: string; type: "embedding" | "storage" | "link"; } export interface HwpDocument { header: FileHeader; docInfo: HwpDocInfo; sections: HwpSection[]; binData: Map; }