Skip to main content

Python bindings for native rhwp HWP to PDF conversion

Project description

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 MyeongjoAppleMyungjoNoto Serif KR / Noto Serif CJK KRHCR Batang Ext-B / 함초롬바탕 확장BHCR Batang Ext / 함초롬바탕 확장HCR Batang / 함초롬바탕Source Han Serif K Old Hangulserif
Dotum/Gothic/Gulim/sans-serif text Document font → Malgun Gothic / 맑은 고딕Apple SD Gothic NeoNoto Sans KR ExtraLightNoto Sans KRPretendardHCR Batang Ext-B / 함초롬바탕 확장BHCR Batang Ext / 함초롬바탕 확장HCR Batang / 함초롬바탕Source Han Serif K Old Hangulsans-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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hwp_ingest-0.1.0.tar.gz (2.5 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

hwp_ingest-0.1.0-cp310-abi3-win_amd64.whl (2.8 MB view details)

Uploaded CPython 3.10+Windows x86-64

hwp_ingest-0.1.0-cp310-abi3-manylinux_2_28_x86_64.whl (3.0 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.28+ x86-64

hwp_ingest-0.1.0-cp310-abi3-manylinux_2_28_aarch64.whl (2.7 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.28+ ARM64

hwp_ingest-0.1.0-cp310-abi3-macosx_11_0_arm64.whl (2.6 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

hwp_ingest-0.1.0-cp310-abi3-macosx_10_12_x86_64.whl (2.7 MB view details)

Uploaded CPython 3.10+macOS 10.12+ x86-64

File details

Details for the file hwp_ingest-0.1.0.tar.gz.

File metadata

  • Download URL: hwp_ingest-0.1.0.tar.gz
  • Upload date:
  • Size: 2.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for hwp_ingest-0.1.0.tar.gz
Algorithm Hash digest
SHA256 45bc42693315ea26bea38c2333affe42436a4a25ce6e97ea4bdba6cb8073e472
MD5 f704b89d4971216d99dd274ebe2ae868
BLAKE2b-256 2e20936b0db9c8fe953fc12c3ad6ea2a765775e95dd9927c384e2a57bddabeee

See more details on using hashes here.

Provenance

The following attestation bundles were made for hwp_ingest-0.1.0.tar.gz:

Publisher: publish.yml on iosif2/hwp-ingest

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hwp_ingest-0.1.0-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: hwp_ingest-0.1.0-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 2.8 MB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for hwp_ingest-0.1.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 e22cc6972ff0bc2e43b154ca5c7ad631c6708f549525ba1ec13629cb752aad47
MD5 c3084d3958bbc6a1fc64a460284456d0
BLAKE2b-256 0bb5b40dc8201ae95ef06dbf03862ccf35d4c4b801a26da7e4694dbb4cf6192d

See more details on using hashes here.

Provenance

The following attestation bundles were made for hwp_ingest-0.1.0-cp310-abi3-win_amd64.whl:

Publisher: publish.yml on iosif2/hwp-ingest

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hwp_ingest-0.1.0-cp310-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for hwp_ingest-0.1.0-cp310-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 17a34e3edc5c9e3222f90b1bd62a352545b3cfada00682de2ae1870bb1f955ca
MD5 5eacb1f91c665f636330d30e409e4b42
BLAKE2b-256 64f90d94135281ae533e29129fd2a65766183890f4ab3bb194eaee48d4c8de77

See more details on using hashes here.

Provenance

The following attestation bundles were made for hwp_ingest-0.1.0-cp310-abi3-manylinux_2_28_x86_64.whl:

Publisher: publish.yml on iosif2/hwp-ingest

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hwp_ingest-0.1.0-cp310-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for hwp_ingest-0.1.0-cp310-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 5cb41d6b94e6b8505be14c69e3ff90cb2f256c8e7abde3affef6b9e56247f970
MD5 1942c5d565ad505a04d68c83f5578861
BLAKE2b-256 8bc44394c880f5b53ec71c3e00b62698765df31615e5fd467b6f25ef6ed04914

See more details on using hashes here.

Provenance

The following attestation bundles were made for hwp_ingest-0.1.0-cp310-abi3-manylinux_2_28_aarch64.whl:

Publisher: publish.yml on iosif2/hwp-ingest

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hwp_ingest-0.1.0-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for hwp_ingest-0.1.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 808acd7adf335063124ba6ddf05d46a10fe3dc2d08388548650b39a8b218247f
MD5 282b03324c71ff8d636afee6a8e3c884
BLAKE2b-256 187e1bea56196fbe32f38ff04694434fda315d02e3fd4c35b5ec04448282a635

See more details on using hashes here.

Provenance

The following attestation bundles were made for hwp_ingest-0.1.0-cp310-abi3-macosx_11_0_arm64.whl:

Publisher: publish.yml on iosif2/hwp-ingest

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hwp_ingest-0.1.0-cp310-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for hwp_ingest-0.1.0-cp310-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 a87df9f6656962600a4ea4bbc3613a3d9b715c51e70bd9af29e5ae33fc816a6e
MD5 495a15df28fb892fde397282a2853311
BLAKE2b-256 6183930cef2ada9e775de611d398b2a5968ddcce93ca385b5d2824691fd53e78

See more details on using hashes here.

Provenance

The following attestation bundles were made for hwp_ingest-0.1.0-cp310-abi3-macosx_10_12_x86_64.whl:

Publisher: publish.yml on iosif2/hwp-ingest

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page