### Successful Build Output Source: https://github.com/ai-screams/hwpforge/blob/main/docs/getting-started/installation.md Example output indicating a successful build after adding HwpForge. This confirms the installation is complete. ```text Compiling hwpforge v0.1.0 Finished `dev` profile [unoptimized + debuginfo] target(s) in ... ``` -------------------------------- ### Create HwpxStyleStore with Default Fonts Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/style-templates.md Initialize an `HwpxStyleStore` using the 'Modern' Hancom style set and a specified default font. This is a convenient way to get a pre-configured style store. ```rust use hwpforge_smithy_hwpx::{HwpxStyleStore, HancomStyleSet}; // 기본값 (간단한 방법) let modern = HwpxStyleStore::with_default_fonts("함초롬바탕"); // 특정 스타일셋 지정 // from_registry_with()로 커스텀 레지스트리 + 스타일셋 조합 가능 ``` -------------------------------- ### Install HwpForge CLI (Hammer) Source: https://github.com/ai-screams/hwpforge/blob/main/README.md Install the HwpForge command-line interface tool, named 'Hammer', to manage HWP/HWPX documents directly from the terminal. ```bash cargo install hwpforge-bindings-cli ``` -------------------------------- ### Full Pipeline: Markdown String to HWPX File Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/markdown-bridge.md This example demonstrates the complete process of converting a Markdown string to an HWPX file. It includes decoding Markdown, validating the document, applying default styles, and encoding to HWPX bytes, which are then written to a file. ```rust use hwpforge::md::{MdDecoder, MdDocument}; use hwpforge::hwpx::{HwpxEncoder, HwpxStyleStore}; fn markdown_to_hwpx(markdown: &str, output_path: &str) { // 1. Markdown 파싱 → Core DOM let MdDocument { document, .. } = MdDecoder::decode_with_default(markdown).unwrap(); // 2. 문서 검증 let validated = document.validate().unwrap(); // 3. 한컴 기본 스타일 적용 후 HWPX 인코딩 let style_store = HwpxStyleStore::with_default_fonts("함초롬바탕"); let image_store = Default::default(); let bytes = HwpxEncoder::encode(&validated, &style_store, &image_store).unwrap(); // 4. 파일 저장 std::fs::write(output_path, &bytes).unwrap(); println!("저장 완료: {output_path}"); } fn main() { let md = r#"--- title: AI 활용 정책 제안서 author: 정책팀 date: 2026-03-06 --- # 제안 배경 인공지능 기술의 급속한 발전에 대응하여 정책 수립이 필요합니다. ## 현황 분석 국내외 AI 활용 사례를 분석하였습니다. ## 정책 방향 단계적 도입과 윤리적 기준 마련을 제안합니다. "#; markdown_to_hwpx(md, "proposal.hwpx"); } ``` -------------------------------- ### Register HWPForge with Claude Code (npm) Source: https://github.com/ai-screams/hwpforge/blob/main/README.md Install and register the HWPForge MCP server using npm. This is the recommended method as it automatically downloads the binary without requiring a Rust toolchain. ```bash claude mcp add hwpforge -- npx -y @hwpforge/mcp ``` -------------------------------- ### Process Legacy HWP5 Files Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/text-extraction.md Handle legacy HWP5 (.hwp) files using the dedicated crate. This example iterates through sections, paragraphs, and runs to extract text content from a legacy HWP5 document. ```rust use hwpforge_smithy_hwp5::Hwp5Decoder; use hwpforge_core::run::RunContent; let result = Hwp5Decoder::decode_file("legacy.hwp").unwrap(); let doc = &result.document; for section in doc.sections() { for paragraph in §ion.paragraphs { for run in ¶graph.runs { if let RunContent::Text(ref text) = run.content { print!("{}", text); } } println!(); } } ``` -------------------------------- ### GitHub README Banner Example Source: https://github.com/ai-screams/hwpforge/blob/main/branding/BRANDING.md Markdown snippet for displaying the main banner image in a GitHub README. Ensure the image path is correct. ```markdown
HwpForge Banner
한글 문서를 코드로 벼려내다
Forge Korean Documents with Code
``` -------------------------------- ### HWPX Formula Example (HancomEQN) Source: https://github.com/ai-screams/hwpforge/blob/main/examples/interop/hwpx_md_convert/hwpx2md/full_report.md Illustrates a mathematical formula using the HancomEQN format, which is specific to HWPX documents. Note that this format does not use standard MathML. ```text x=\frac{-b+-root{2}of{b^{2}-4 ac}}{2 a} ``` -------------------------------- ### Badge Combination Example for Crates.io and License Source: https://github.com/ai-screams/hwpforge/blob/main/branding/BRANDING.md Markdown snippet for creating badges to display on project pages, linking to the crates.io page and the license file. The colors are derived from the project's color palette. ```markdown [![Crates.io](https://img.shields.io/crates/v/hwpforge?color=B7410E)](https://crates.io/crates/hwpforge) [![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-E8A832)](LICENSE) ``` -------------------------------- ### Complete HWPX Document Read-Modify-Save Example Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/hwpx-codec.md Demonstrates a full workflow: decoding an HWPX file, modifying existing text (e.g., replacing '초안' with '최종본'), adding a new paragraph, validating the document, encoding it, and saving to a specified output file. This function handles potential errors during decoding, validation, and encoding. ```rust use hwpforge_smithy_hwpx::{HwpxDecoder, HwpxEncoder}; use hwpforge_core::run::{Run, RunContent}; use hwpforge_core::paragraph::Paragraph; use hwpforge_foundation::{CharShapeIndex, ParaShapeIndex}; fn modify_document( input: &str, output: &str, ) -> Result<(), Box> { // 읽기 let mut result = HwpxDecoder::decode_file(input) .map_err(|e| format!("디코딩 실패: {e}"))?; let sections = result.document.sections_mut(); // 기존 텍스트 수정 for section in sections.iter_mut() { for paragraph in &mut section.paragraphs { for run in &mut paragraph.runs { if let RunContent::Text(ref mut text) = run.content { *text = text.replace("초안", "최종본"); } } } } // 새 문단 추가 if let Some(first_section) = result.document.sections_mut().first_mut() { first_section.paragraphs.push(Paragraph::with_runs( vec![Run::text("— 이 문서는 자동으로 수정되었습니다.", CharShapeIndex::new(0))], ParaShapeIndex::new(0), )); } // 저장 let validated = result.document.validate() .map_err(|e| format!("검증 실패: {e}"))?; let bytes = HwpxEncoder::encode(&validated, &result.style_store, &result.image_store) .map_err(|e| format!("인코딩 실패: {e}"))?; std::fs::write(output, &bytes)?; Ok(()) } ``` -------------------------------- ### Create a New HWP Document Source: https://github.com/ai-screams/hwpforge/blob/main/README.md Demonstrates creating a new HWP document with a simple text run using the HWPForge Rust library. Ensure necessary imports are included. ```rust use hwpforge::core::{Document, Draft, Paragraph, Run, Section, PageSettings}; use hwpforge::foundation::{CharShapeIndex, ParaShapeIndex}; let mut doc = Document::::new(); doc.add_section(Section::with_paragraphs( vec![Paragraph::with_runs( vec![Run::text("Hello, 한글!", CharShapeIndex::new(0))], ParaShapeIndex::new(0), )], PageSettings::a4(), )); ``` -------------------------------- ### Update Rust Toolchain Source: https://github.com/ai-screams/hwpforge/blob/main/docs/getting-started/installation.md Update your Rust installation using rustup if your current version is below the minimum requirement. ```bash rustup update stable ``` -------------------------------- ### Build Project Source: https://github.com/ai-screams/hwpforge/blob/main/docs/getting-started/installation.md Compile your project to ensure the HwpForge dependency is correctly integrated and the build is successful. ```bash cargo build ``` -------------------------------- ### Update/Delete HWPForge (Cargo) Source: https://github.com/ai-screams/hwpforge/blob/main/README.md Instructions for updating or uninstalling HWPForge when installed via Cargo. npm users do not need separate update commands. ```bash cargo install hwpforge-bindings-mcp --force ``` ```bash cargo uninstall hwpforge-bindings-mcp ``` -------------------------------- ### Register HWPForge with Claude Code (Cargo) Source: https://github.com/ai-screams/hwpforge/blob/main/README.md Install HWPForge using Cargo and register it with Claude Code. This method is suitable for Rust developers. ```bash cargo install hwpforge-bindings-mcp && claude mcp add hwpforge hwpforge-mcp ``` -------------------------------- ### Add HwpForge with All Features Source: https://github.com/ai-screams/hwpforge/blob/main/docs/getting-started/installation.md Enable all available features of the HwpForge library by specifying the 'full' feature flag. ```toml [dependencies] hwpforge = { version = "0.1", features = ["full"] } ``` -------------------------------- ### Create HwpxStyleStore with Default Fonts Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/hwpx-codec.md Quickly create a `HwpxStyleStore` using a single font name. This is the simplest method for basic styling. ```rust use hwpforge::hwpx::HwpxStyleStore; let style_store = HwpxStyleStore::with_default_fonts("함초롬바탕"); ``` -------------------------------- ### CLI Format Conversion and Inspection Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/format-pipeline.md Demonstrates CLI commands for converting Markdown to HWPX, inspecting HWPX documents with JSON output, and performing a roundtrip conversion from HWPX to JSON and back. ```bash # Markdown → HWPX 변환 hwpforge convert report.md -o report.hwpx # HWPX 문서 검사 (메타데이터 포함) hwpforge inspect report.hwpx --json # HWPX → JSON → 편집 → HWPX 라운드트립 hwpforge to-json report.hwpx -o report.json # (AI 에이전트가 JSON 편집) hwpforge from-json report.json -o updated.hwpx # HWPX → Markdown (읽기용) # Rust API: MdEncoder::encode_lossy(&validated) ``` -------------------------------- ### Create and Save HWPX Document in Rust Source: https://github.com/ai-screams/hwpforge/blob/main/docs/README.md Demonstrates the basic workflow of creating a new HWPX document, adding text, validating it, and saving it to a file using the HwpForge library. Ensure you have the necessary dependencies added to your Cargo.toml. ```rust use hwpforge::core::{Document, Draft, Paragraph, Run, Section, PageSettings}; use hwpforge::foundation::{CharShapeIndex, ParaShapeIndex}; use hwpforge::hwpx::{HwpxEncoder, HwpxStyleStore}; use hwpforge::core::ImageStore; // 1. 문서 생성 let mut doc = Document::::new(); doc.add_section(Section::with_paragraphs( vec![Paragraph::with_runs( vec![Run::text("안녕하세요, HwpForge!", CharShapeIndex::new(0))], ParaShapeIndex::new(0), )], PageSettings::a4(), )); // 2. 검증 + 인코딩 let validated = doc.validate().unwrap(); let style_store = HwpxStyleStore::with_default_fonts("함초롬바탕"); let image_store = ImageStore::new(); let bytes = HwpxEncoder::encode(&validated, &style_store, &image_store).unwrap(); // 3. 파일 저장 std::fs::write("output.hwpx", &bytes).unwrap(); ``` -------------------------------- ### HWPX and Markdown to Core DOM Conversion and Processing Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/format-pipeline.md Demonstrates converting HWPX and Markdown files into a common Core DOM representation for independent processing. Shows how to access document metadata and content structure. ```rust use hwpforge::hwpx::{HwpxDecoder, HwpxEncoder, HwpxRegistryBridge}; use hwpforge::md::{MdDecoder, MdDocument, MdEncoder}; use hwpforge::core::{Document, Draft, ImageStore}; // === 1. HWPX → Core DOM === let hwpx_result = HwpxDecoder::decode_file("input.hwpx").unwrap(); let doc_from_hwpx: Document = hwpx_result.document; // === 2. Markdown → Core DOM === let markdown = "# 제목\n\n본문 내용입니다."; let MdDocument { document: doc_from_md, style_registry } = MdDecoder::decode_with_default(markdown).unwrap(); // === 3. 포맷 독립 처리 (어느 소스에서 왔든 동일) === fn process_document(doc: &Document) { // 메타데이터 접근 let meta = doc.metadata(); println!("제목: {:?}", meta.title); println!("작성자: {:?}", meta.author); // 섹션/문단 순회 for section in doc.sections() { println!("문단 수: {}", section.paragraphs.len()); let counts = section.content_counts(); println!("표: {}, 이미지: {}", counts.tables, counts.images); } } process_document(&doc_from_hwpx); process_document(&doc_from_md); // === 4. Core DOM → 다른 포맷으로 출력 === // HWPX로 저장 let bridge = HwpxRegistryBridge::from_registry(&style_registry).unwrap(); let rebound = bridge.rebind_draft_document(doc_from_md).unwrap(); let validated = rebound.validate().unwrap(); let bytes = HwpxEncoder::encode(&validated, bridge.style_store(), &ImageStore::new()).unwrap(); std::fs::write("output.hwpx", &bytes).unwrap(); // Markdown으로 저장 let markdown_out = MdEncoder::encode_lossy(&validated).unwrap(); std::fs::write("output.md", &markdown_out).unwrap(); ``` -------------------------------- ### Handling Unicode Characters in HWPForge Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/hwpx-codec.md Demonstrates that HWPForge internally uses UTF-8 and fully supports all Unicode characters, including Korean text, emojis, and special symbols. Examples show the creation of `Run` objects with various types of Unicode text. ```rust use hwpforge::core::run::Run; use hwpforge::foundation::CharShapeIndex; // 모두 정상 동작 let run1 = Run::text("한글 텍스트 테스트", CharShapeIndex::new(0)); let run2 = Run::text("특수문자: ©®™ §¶ ±×÷", CharShapeIndex::new(0)); let run3 = Run::text("수학 기호: α β γ δ ∑ ∫", CharShapeIndex::new(0)); ``` -------------------------------- ### Ensuring Document Validity with Sections Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/hwpx-codec.md Explains that a `Document` requires at least one section to pass validation. The example demonstrates creating a new document, showing that validation fails for an empty document, but succeeds after adding a section containing an empty paragraph. ```rust use hwpforge::core::{Document, Draft, PageSettings, Paragraph, Section}; use hwpforge::foundation::ParaShapeIndex; let mut doc = Document::::new(); // ❌ 빈 문서 — validate() 실패 // let validated = doc.validate(); // Err: 섹션 없음 // ✅ 빈 문단이라도 하나 추가 doc.add_section(Section::with_paragraphs( vec![Paragraph::new(ParaShapeIndex::new(0))], PageSettings::a4(), )); let validated = doc.validate().unwrap(); // OK ``` -------------------------------- ### Process Legacy HWP5 Files Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/migration-strategy.md Handles legacy HWP5 files by either using the HwpForge CLI for direct conversion/auditing or by integrating with the `hwpforge-smithy-hwp5` crate to decode HWP5 files and reuse the existing Core/HWPX pipeline. Separating HWP5 files into a distinct queue is recommended for large-scale migrations. ```rust // 현재 — HWP5 직접 decode 후 기존 pipeline에 연결 // use hwpforge_smithy_hwp5::Hwp5Decoder; // // let result = Hwp5Decoder::decode_file("legacy.hwp")?; // let validated = result.document.validate()?; // let markdown = MdEncoder::encode_lossy(&validated)?; ``` -------------------------------- ### Run HwpForge Benchmarks Source: https://github.com/ai-screams/hwpforge/blob/main/benches/README.md Execute the benchmarks using Cargo. Results are generated in the target/criterion/ directory. ```bash cargo bench ``` -------------------------------- ### Error Handling with HwpxResult Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/hwpx-codec.md Illustrates how to handle potential errors returned by HWPForge functions, which typically return `HwpxResult`. The example shows a `match` statement to differentiate between successful decoding (`Ok`) and failure (`Err`), printing appropriate messages to standard output or standard error. ```rust use hwpforge::hwpx::HwpxDecoder; match HwpxDecoder::decode_file("missing.hwpx") { Ok(_result) => println!("디코딩 성공"), Err(e) => eprintln!("디코딩 실패: {e}"), } ``` -------------------------------- ### HWP5 Conversion using CLI Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/format-pipeline.md Command-line interface commands for converting HWP5 files to HWPX, auditing HWP5 files, and performing a census of HWP5 files. ```bash hwpforge convert-hwp5 legacy.hwp -o converted.hwpx hwpforge audit-hwp5 legacy.hwp converted.hwpx hwpforge census-hwp5 legacy.hwp --json ``` -------------------------------- ### Create HwpxStyleStore from Blueprint Template Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/hwpx-codec.md Generate a `HwpxStyleStore` by converting a custom YAML style template using `StyleRegistry` and `HwpxRegistryBridge`. This is for advanced custom styling. ```rust use hwpforge::blueprint::builtins::builtin_default; use hwpforge::blueprint::registry::StyleRegistry; use hwpforge::hwpx::HwpxRegistryBridge; let template = builtin_default().unwrap(); let registry = StyleRegistry::from_template(&template).unwrap(); let bridge = HwpxRegistryBridge::from_registry(®istry).unwrap(); let style_store = bridge.style_store(); ``` -------------------------------- ### Programmatically Setting Metadata Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/metadata.md Illustrates how to programmatically set metadata for a document in the `Document` state using `metadata_mut()` or `set_metadata()`. Also shows adding content and validating the document. ```rust use hwpforge::core::{Document, Draft, Metadata, PageSettings, Paragraph, Run, Section}; use hwpforge::foundation::{CharShapeIndex, ParaShapeIndex}; let mut doc = Document::::new(); doc.metadata_mut().title = Some("제안서".to_string()); doc.metadata_mut().author = Some("홍길동".to_string()); doc.metadata_mut().created = Some("2026-03-06".to_string()); doc.metadata_mut().subject = Some("신규 사업 제안".to_string()); doc.metadata_mut().keywords = vec!["사업".to_string(), "제안".to_string()]; let meta = Metadata { title: Some("제안서".to_string()), author: Some("홍길동".to_string()), created: Some("2026-03-06".to_string()), ..Metadata::default() }; doc.set_metadata(meta); doc.add_section(Section::with_paragraphs( vec![Paragraph::with_runs( vec![Run::text("본문 내용", CharShapeIndex::new(0))], ParaShapeIndex::new(0), )], PageSettings::a4(), )); let validated = doc.validate().unwrap(); ``` -------------------------------- ### Create Column Chart in HWP Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/charts.md Generates a column chart with sales data and saves it as an HWPX file. Ensure to use default fonts for compatibility. ```rust use hwpforge_core::control::Control; use hwpforge_core::chart::{ChartType, ChartData, ChartGrouping, LegendPosition}; use hwpforge_core::run::Run; use hwpforge_core::paragraph::Paragraph; use hwpforge_core::{Document, Section, PageSettings}; use hwpforge_smithy_hwpx::{HwpxEncoder, HwpxStyleStore}; use hwpforge_foundation::{CharShapeIndex, ParaShapeIndex, HwpUnit}; let data = ChartData::category( &["2022", "2023", "2024", "2025"], &[ ("국내 매출", &[3200.0, 4100.0, 5300.0, 6800.0]), ("해외 매출", &[1100.0, 1800.0, 2700.0, 3900.0]), ], ); let chart = Control::Chart { chart_type: ChartType::Column, data, title: Some("연도별 매출 현황 (단위: 백만원)".to_string()), legend: LegendPosition::Bottom, grouping: ChartGrouping::Clustered, width: HwpUnit::from_mm(140.0).unwrap(), height: HwpUnit::from_mm(90.0).unwrap(), }; let mut doc = Document::new(); doc.add_section(Section::with_paragraphs( vec![Paragraph::with_runs( vec![Run::control(chart, CharShapeIndex::new(0))], ParaShapeIndex::new(0), )], PageSettings::a4(), )); let validated = doc.validate().unwrap(); let bytes = HwpxEncoder::encode( &validated, &HwpxStyleStore::with_default_fonts("함초롬바탕"), &Default::default(), ).unwrap(); std::fs::write("bar_chart.hwpx", &bytes).unwrap(); ``` -------------------------------- ### HwpForge Architecture Overview Source: https://github.com/ai-screams/hwpforge/blob/main/CONTRIBUTING.md This diagram illustrates the layered architecture of HwpForge, from foundational primitives to user-facing bindings. Structure and Style are kept separate, similar to HTML and CSS. ```text foundation (primitives: HwpUnit, Color, Index) | core (format-independent document model, style references only) | blueprint (YAML style templates, Figma Design Token pattern) | smithy-hwpx / smithy-md (format-specific compilers) | bindings-py / bindings-cli (user interfaces) ``` -------------------------------- ### Register HWPForge with Claude Desktop Source: https://github.com/ai-screams/hwpforge/blob/main/README.md Configure HWPForge for Claude Desktop by editing the `claude_desktop_config.json` file. ```json { "mcpServers": { "hwpforge": { "command": "npx", "args": ["-y", "@hwpforge/mcp"] } } } ``` -------------------------------- ### Essential Development Commands Source: https://github.com/ai-screams/hwpforge/blob/main/CONTRIBUTING.md Run these commands to maintain code quality and ensure compatibility. `make ci` runs the full CI pipeline. ```bash make ci # Full CI pipeline: fmt + clippy + test + deny + lint make test # cargo nextest run (parallel, all features) make clippy # cargo clippy (all targets, all features, -D warnings) make fmt-fix # Auto-format with rustfmt make doc # Generate rustdoc (opens in browser) make cov # Coverage report with 90% gate (llvm-cov) mdbook build # Build the project book ``` -------------------------------- ### Load Built-in Default Template Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/style-templates.md Instantiate the default HWPX template without needing a separate YAML file. Verify the template metadata and default styles. ```rust use hwpforge_blueprint::builtins::builtin_default; use hwpforge_blueprint::registry::StyleRegistry; let template = builtin_default().unwrap(); assert_eq!(template.meta.name, "default"); let registry = StyleRegistry::from_template(&template).unwrap(); let body = registry.get_style("body").unwrap(); let cs = registry.char_shape(body.char_shape_id).unwrap(); assert_eq!(cs.font, "한컴바탕"); ``` -------------------------------- ### Markdown to HWPX Pipeline Overview Source: https://github.com/ai-screams/hwpforge/blob/main/docs/guide/markdown-bridge.md This diagram illustrates the Markdown to HWPX conversion pipeline, showing the flow from Markdown string to HWPX file through intermediate Core DOM representations. ```text Markdown 문자열 | v (MdDecoder::decode) Document + StyleRegistry | v (doc.validate()) Document | v (HwpxEncoder::encode) HWPX 바이트 → .hwpx 파일 ```