Skip to main content

hwp-ingest

CI PyPI Python versions License

Rust-backed Python package for Korean HWP/HWPX ingestion.
Convert HWP documents to PDF or page-level SVG artifacts through a typed Python facade.

hwp-ingest uses a vendored rhwp subset as its current HWP parsing, layout, and rendering backend. The vendored backend can carry hwp-ingest-local compatibility patches, while product-facing conversion policy stays in the hwp-ingest Rust/Python layers.

Features

  • Convert HWP files to PDF bytes or PDF files.
  • Render page-level SVG artifacts for inspection and downstream pipelines.
  • Read basic document metadata such as renderable page count.
  • Keep conversion orchestration in Rust while Python handles paths, overwrite policy, and typed facade ergonomics.

Install from PyPI:

uv pip install hwp-ingest
# or
python -m pip install hwp-ingest

Runtime PDF dependency

PDF conversion requires the rsvg-convert executable from librsvg at runtime. The Python wheel does not bundle this executable. SVG output does not require rsvg-convert; that executable is only needed for PDF conversion.

Check availability:

rsvg-convert --version

Install examples:

# Debian/Ubuntu
sudo apt-get install librsvg2-bin

# Fedora/RHEL
sudo dnf install librsvg2-tools

# Arch Linux
sudo pacman -S librsvg

# macOS
brew install librsvg

On Windows, install librsvg/rsvg-convert and ensure rsvg-convert.exe is on PATH. If rsvg-convert is missing, PDF conversion raises hwp_ingest.HwpIngestError with a clear message. svg2pdf is not used as an automatic fallback because it is known to drop clipped table text in some HWP documents.

Font fallback and PUA glyphs

hwp-ingest does not bundle Hancom or Microsoft fonts. PDF conversion asks rsvg-convert/fontconfig to resolve the SVG font-family chain from fonts installed on the system. If a document contains visible Private Use Area (PUA) characters, such as Hancom symbol slots, a generic Unicode font is not enough: PUA codepoints do not define a standard glyph shape. They render correctly only when the owning document font is installed, or when the project adds a source-backed codepoint mapping for that specific symbol set.

The current renderer preserves the document font name first, then appends Korean-compatible fallback families:

Text family in the document Fallback order
Batang/Myeongjo/serif text Document font → Batang/바탕 → Nanum Myeongjo → AppleMyungjo → Noto Serif KR / Noto Serif CJK KR → HCR Batang Ext-B / 함초롬바탕 확장B → HCR Batang Ext / 함초롬바탕 확장 → HCR Batang / 함초롬바탕 → Source Han Serif K Old Hangul → serif
Dotum/Gothic/Gulim/sans-serif text Document font → Malgun Gothic / 맑은 고딕 → Apple SD Gothic Neo → Noto Sans KR ExtraLight → Noto Sans KR → Pretendard → HCR Batang Ext-B / 함초롬바탕 확장B → HCR Batang Ext / 함초롬바탕 확장 → HCR Batang / 함초롬바탕 → Source Han Serif K Old Hangul → sans-serif

For Hancom-origin documents with PUA symbols, install the matching licensed font on the machine running conversion:

Document/font origin Families to check first
Hancom/HCR body or PUA symbols HCR Batang / 함초롬바탕, HCR Dotum / 함초롬돋움
Windows-origin documents Batang, Dotum, Gulim, Gungsuh, Malgun Gothic
Older HY/Hanyang documents HY울릉도L, HY헤드라인M, HY견고딕, HY그래픽, HY견명조, HY신명조

Linux/fontconfig check:

fc-match "HCR Batang"
fc-match "함초롬바탕"
fc-match "HCR Dotum"

If these commands resolve to a fallback like Noto or DejaVu instead of the expected Hancom/HCR family, install the licensed TTF/OTF files into a system or user font directory and refresh fontconfig:

# user-local example
mkdir -p ~/.local/share/fonts/hancom
cp HCRBatang.ttf HCRBatang-Bold.ttf ~/.local/share/fonts/hancom/
fc-cache -f ~/.local/share/fonts/hancom

Do not commit restricted font files into this repository.

Quick start

Convert an HWP file to a PDF next to the input file:

from pathlib import Path

import hwp_ingest

input_path = Path("document.hwp")
output_path = hwp_ingest.to_pdf_file(input_path, overwrite=True)
print(output_path)

Convert one zero-based page to bytes:

from pathlib import Path

import hwp_ingest

pdf_bytes = hwp_ingest.to_pdf_bytes(
    Path("document.hwp").read_bytes(),
    page_index=0,
)
Path("page-1.pdf").write_bytes(pdf_bytes)

Render SVG page artifacts without the PDF backend:

from pathlib import Path

import hwp_ingest

svg_pages = hwp_ingest.to_svg_pages(Path("document.hwp").read_bytes())
Path("page-1.svg").write_bytes(svg_pages[0])

Read basic document metadata:

from pathlib import Path

import hwp_ingest

info = hwp_ingest.analyze_bytes(Path("document.hwp").read_bytes())
print(info.page_count)

Python API

The package is typed and ships py.typed plus checked-in .pyi stubs.

hwp_ingest.analyze_bytes(data: bytes) -> hwp_ingest.DocumentInfo

Returns a DocumentInfo object. DocumentInfo.page_count is the number of renderable pages discovered in the HWP bytes.

hwp_ingest.to_pdf_bytes(
    data: bytes,
    *,
    page_index: int | None = None,
) -> bytes

Returns PDF bytes. page_index is zero-based. Pass None to convert the full document.

hwp_ingest.to_svg_pages(
    data: bytes,
    *,
    page_index: int | None = None,
) -> list[bytes]

Returns one SVG document per selected page as bytes. page_index is zero-based. Pass None to render all pages in document order. SVG output does not require rsvg-convert.

hwp_ingest.to_pdf_file(
    input_path: str | os.PathLike[str],
    output_path: str | os.PathLike[str] | None = None,
    *,
    page_index: int | None = None,
    overwrite: bool = False,
) -> pathlib.Path

Writes a PDF and returns the output path. If output_path is None, the output uses the input path with a .pdf suffix. Existing output files are protected unless overwrite=True.

hwp_ingest.to_svg_files(
    input_path: str | os.PathLike[str],
    output_dir: str | os.PathLike[str] | None = None,
    *,
    page_index: int | None = None,
    overwrite: bool = False,
) -> list[pathlib.Path]

Writes one SVG file per selected page and returns paths in page order. If output_dir is None, SVG files are written beside the input file. Generated filenames are stable and use one-based visible page numbers: <stem>.page-0001.svg, <stem>.page-0002.svg, and so on. Existing output files are protected unless overwrite=True.

Errors

  • ValueError: negative page_index, empty documents, or out-of-range pages.
  • FileExistsError: output exists and overwrite=False.
  • FileNotFoundError: input file path does not exist.
  • hwp_ingest.HwpIngestError: parse, render, PDF backend, or output write failures.

Local development

cargo test --workspace
uv run maturin develop
uv run pytest

Build distributable artifacts locally:

uv run maturin sdist --out dist
uv run --with ziglang maturin build --release --locked --out dist --compatibility pypi --zig

Notices

This project includes vendored portions of rhwp.

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

"한글", "한컴", "HWP", and "HWPX" are registered trademarks of Hancom Inc. hwp-ingest is an independent open-source project and is not affiliated with, sponsored by, or endorsed by Hancom Inc.

See NOTICE, THIRD_PARTY_LICENSES.md, and vendor/rhwp-subset/NOTICE for vendored source attribution and license details.

Project direction

See docs/rhwp-python-binding-plan.md for batch engine, semantic output, vendor/upstream sync, and production pipeline direction.

Metadata

Release files for hwp-ingest 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hwp-ingest 0.1.1
File Size Uploaded
hwp_ingest-0.1.1.tar.gz 2.5 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for hwp-ingest 0.1.1
File
hwp_ingest-0.1.1-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
hwp_ingest-0.1.1-cp310-abi3-manylinux_2_28_x86_64.whl CPython 3.10 abi3 Linux glibc 2.28+ x86-64 Details
hwp_ingest-0.1.1-cp310-abi3-manylinux_2_28_aarch64.whl CPython 3.10 abi3 Linux glibc 2.28+ ARM64 Details
hwp_ingest-0.1.1-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details
hwp_ingest-0.1.1-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details

Total release size: 16.2 MB

Release files / hwp_ingest-0.1.1.tar.gz

Download URL hwp_ingest-0.1.1.tar.gz
Size 2.5 MB
Tags Source
SHA-256 checksum
How to use checksums
87a424c13a7d9e67c1a4cc0dba6925eb53a950479a78989bc78f1aed01cdc4bc
BLAKE2b-256 checksum
How to use checksums
f06b4d1aae017377accb88c84983157852f813de7e3af38e7d59288d469a7bb2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 6, 2026.

Transparency log

Release files / hwp_ingest-0.1.1-cp310-abi3-win_amd64.whl

Download URL hwp_ingest-0.1.1-cp310-abi3-win_amd64.whl
Size 2.8 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
674b15133e67c26203857afb28c8efab1a4172a90d55637daabe0d9fdebb608b
BLAKE2b-256 checksum
How to use checksums
056f69939afbbd08ee195b2eeb1f172fd0e197f57c553d33db54de5a7ad6aa64
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 6, 2026.

Transparency log

Release files / hwp_ingest-0.1.1-cp310-abi3-manylinux_2_28_x86_64.whl

Download URL hwp_ingest-0.1.1-cp310-abi3-manylinux_2_28_x86_64.whl
Size 3.0 MB
Tags CPython 3.10 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
d94da40a840713fa79ddfed70c376d97810705070a4e217c3001070cd33877bb
BLAKE2b-256 checksum
How to use checksums
15b87547795834076a342eb1f989fec82779dcc8f47d5d2d0e5a0765ac03f974
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 6, 2026.

Transparency log

Release files / hwp_ingest-0.1.1-cp310-abi3-manylinux_2_28_aarch64.whl

Download URL hwp_ingest-0.1.1-cp310-abi3-manylinux_2_28_aarch64.whl
Size 2.7 MB
Tags CPython 3.10 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
7d6303fab5df6d080b464e946d86f1f70cea049e5790e73f6c3d544e23ed430b
BLAKE2b-256 checksum
How to use checksums
83ac47e5ea379b55504496084a19840c44ff12514ac2a273e5f3dd611c30ac4a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 6, 2026.

Transparency log

Release files / hwp_ingest-0.1.1-cp310-abi3-macosx_11_0_arm64.whl

Download URL hwp_ingest-0.1.1-cp310-abi3-macosx_11_0_arm64.whl
Size 2.6 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
1a9b249fd197d3f38343ff34cd25e8c0ebf31c2dad551dd5223cc5777ff7ac3f
BLAKE2b-256 checksum
How to use checksums
42ac52bf6124b724844af08cc9f007071fb9bde7dddbe6d771c9be0f264beeb1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 6, 2026.

Transparency log

Release files / hwp_ingest-0.1.1-cp310-abi3-macosx_10_12_x86_64.whl

Download URL hwp_ingest-0.1.1-cp310-abi3-macosx_10_12_x86_64.whl
Size 2.7 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
5549e19f7a88fc8386493dd64e3533ec35892374e5262da030cb8a1551a23afd
BLAKE2b-256 checksum
How to use checksums
5206cd9a8d3febebedd25e8c7c9a45372156e8b1e7f568132e35b3a04365c643
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 6, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

6 release files

0.1.0

6 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page