# hwpx-js

한글(Hancom) 워드프로세서의 HWPX/HWP 문서를 읽고 쓰는 JavaScript 라이브러리.

- **HWPX** (.hwpx) 읽기/쓰기
- **HWP 5.0** (.hwp) 읽기
- prod 의존성 **fflate 1개** (~8KB)
- CJS/ESM dual export, TypeScript 타입 포함
- Node.js + 브라우저 지원

> 본 제품은 한글과컴퓨터의 글 문서 파일(.hwp) 공개 문서를 참고하여 개발하였습니다.

## 설치

```bash
npm install hwpx-js
```

## 문서 생성

```typescript
import { writeFileSync } from 'fs';
import { write, HWPXBuilder } from 'hwpx-js';

const doc = new HWPXBuilder()
  .addParagraph('제목', { fontSize: 20, bold: true })
  .addParagraph('본문입니다.')
  .addStyledText([
    { text: '굵게', style: { bold: true } },
    { text: ' / ' },
    { text: '빨강', style: { color: '#FF0000' } },
  ])
  .build();

writeFileSync('output.hwpx', write(doc));
```

## 문서 읽기

```typescript
import { readFileSync } from 'fs';
import { read } from 'hwpx-js';

// .hwpx / .hwp 자동 감지
const doc = read(new Uint8Array(readFileSync('document.hwpx')));

for (const section of doc.sections) {
  for (const para of section.paragraphs) {
    for (const run of para.runs) {
      if (run.t === 'text') console.log(run.text);
    }
  }
}
```

## HWPXBuilder API

| 메서드 | 설명 |
|--------|------|
| `addParagraph(text, style?)` | 텍스트 문단 추가 |
| `addStyledText(segments[])` | 복수 스타일 문단 |
| `addEmptyParagraph()` | 빈 줄 |
| `addTable(data[][], opts?)` | 테이블 (셀 병합 지원) |
| `addImage(data, format, opts)` | 이미지 삽입 |
| `setPageSettings(opts)` | 페이지 크기/여백 |
| `setHeaderFooter(opts)` | 머리글/바닥글 |
| `setColumns(opts)` | 다단 |
| `addSection()` | 새 섹션 시작 |
| `build()` | `HWPXDocument` 반환 |

### 텍스트 스타일 옵션

```typescript
{
  fontSize: 12,        // pt
  bold: true,
  italic: true,
  color: '#FF0000',
  underline: true,
  strikeout: true,
  fontName: '맑은 고딕',
}
```

### 테이블

```typescript
builder.addTable(
  [
    ['이름', '나이'],
    ['홍길동', '30'],
  ],
  {
    borderStyle: 'SOLID',
    colWidths: [40, 30],        // mm
    merges: [                    // 셀 병합
      { row: 0, col: 0, rowSpan: 1, colSpan: 2 },
    ],
  }
);
```

### 이미지

```typescript
const png = new Uint8Array(readFileSync('photo.png'));
builder.addImage(png, 'png', { width: 50, height: 40 }); // mm
```

### 페이지 설정

```typescript
builder
  .setPageSettings({
    width: 297, height: 210,   // A4 가로 (mm)
    landscape: true,
    marginLeft: 20,
    marginRight: 20,
  })
  .setHeaderFooter({ header: '보고서', footer: '페이지' })
  .setColumns({ count: 2, gap: 10 });
```

## 유틸리티

```typescript
import { utils } from 'hwpx-js';

utils.mmToHwpunit(210);          // mm → HWPUNIT (1/7200 inch)
utils.hwpunitToMm(59528);       // HWPUNIT → mm
utils.ptToCharHeight(12);        // pt → 글자크기 단위
utils.hexToColorref('#FF0000');  // hex → COLORREF (BGR)
utils.detectFormat(data);        // 'hwpx' | 'hwp5' | 'unknown'
```

## HWPXDocument 구조

```
HWPXDocument
├── meta          { hwpVersion, title?, creator?, ... }
├── head
│   ├── fontFaces[]
│   ├── charProperties[]
│   ├── paraProperties[]
│   ├── styles[]
│   └── borderFills[]
├── sections[]
│   ├── def       { pageWidth, pageHeight, pageMargin, columns?, headerFooter? }
│   └── paragraphs[]
│       └── runs[]   (discriminated union: t = 'text' | 'table' | 'picture' | 'break')
└── binData[]     { id, format, name, data: Uint8Array }
```

모든 치수는 HWPUNIT (1/7200 inch). `utils.mmToHwpunit()` / `utils.ptToHwpunit()`로 변환.

## 라이선스

Apache-2.0
