Skip to main content

ofdrw-rs for Python

Python 3.10+ bindings to the Rust OFD core through CFFI. Install the matching version from PyPI:

python -m pip install ofdrw-rs==0.4.0

Check the registry and release pages for version availability. The wheel includes the native library; a Rust toolchain is not needed. Wheels for all six supported platforms are also available from GitHub Releases.

from ofdrw_rs import Document

with Document.new() as document:
    document.add_text_page("你好,OFD", 210, 297)
    document.save("hello.ofd")
    print(document.page_text(0))

Use Document.open(path), Document.from_bytes(data) or Document.from_pdf_bytes(data) to read existing content. Use page_svg(0), page_png(0, 96) or to_pdf() to export. Close documents or use a context manager. Coordinates are millimeters and page indexes start at zero.

Set OFDRW_LIB_PATH to an absolute shared-library path for a custom build. Supported behavior and limitations are documented in the repository README.

混合流布局(0.4.0 起)

with Document.new() as document:
    result = document.add_flow_blocks(0, [
        {"type": "paragraph", "text": "第一段"},
        {"type": "spacer", "height": 4},
        {"type": "paragraph", "spans": [{"text": "第二段", "bold": True}]},
    ], block_gap=2)
    document.add_flow_blocks(0, [{"type": "paragraph", "text": "继续"}],
                             start=result["next"])
    document.save("mixed.ofd")

支持图片、跨页表格和 page_break;图片可传 data 字节或 data_base64。 next 包含全局 page_index 和相对页面顶端的 y。整次调用失败时回滚。 详见混合流布局。

盒模型与浮动行(0.4.0 起)

with Document.new() as document:
    result = document.add_box_layout(0, [
        {"type": "box", "size": [40, 10], "padding": [2] * 4,
         "border": [0.2] * 4, "float": "left", "clear": "none"},
        {"type": "box", "size": [40, 10], "float": "right", "clear": "none"},
    ])
    placed = result["placements"][0]
    document.add_text_object(placed["page_index"], "Hello", placed["content_box"])
    document.save("boxes.ofd")

size 是内容宽高;margin、border、padding 均按上、右、下、左排列。 result["next"] 可作为下一次调用的 start。接口布局已测量尺寸的盒子并绘制装饰; 自动测量文本盒与嵌套混合容器见下文的布局接口。详见盒模型说明。

文本自动测量(0.4.0 起)

with Document.new() as document:
    spans = [{"text": "First line\nSecond line"}]
    metrics = document.measure_flowed_spans(0, spans, 40, font_size=5, line_height=6)
    print(metrics["width"], metrics["height"], metrics["lines"])
    boxes = document.add_box_layout(0, [{"type": "box", "size": [40, metrics["height"]],
        "padding": [2] * 4, "border": [0.2] * 4, "integrity": True}])

测量不会增加页面或资源。width 为最大行前进宽度,height 包含内部空行和段间距; 逐行 x、y、baseline 相对段落左上角。页面几何和 start 不参与测量。 将测得高度用于盒模型,再按内容矩形调用文本流式绘制;尺寸属于逻辑行框, 按行拆分的文本盒与一般嵌套容器见下文的布局接口。

Intrinsic image sizes (since 0.4.0)

Flow images, table-cell images and image blocks accept intrinsic_size: true (IntrinsicSize: true in Go). Omit width/height or leave them zero: pixel sizes are converted at 5 pixels/mm, matching Java OFDRW, regardless of embedded DPI metadata. fit_within: [width, height] (FitWithin: &[2]float64{width, height} in Go) optionally shrinks the image to millimeter bounds while preserving aspect ratio. It never enlarges smaller images. Nonzero explicit dimensions cannot be combined with intrinsic sizing. Without intrinsic sizing, both explicit dimensions remain required. These options share the same native validation in C and all bindings, available since 0.4.0.

from pathlib import Path
from ofdrw_rs import Document

with Document.new() as doc:
    doc.add_flow_blocks(0, [{
        "type": "image", "data": Path("picture.png").read_bytes(),
        "format": "PNG", "intrinsic_size": True, "fit_within": [40, 30],
    }])
    Path("picture.ofd").write_bytes(doc.to_bytes())

Automatic text boxes (since 0.4.0)

from pathlib import Path
from ofdrw_rs import Document

with Document.new() as doc:
    result = doc.add_text_boxes(0, [{
        "layout": {"size": [40, 0], "padding": [2, 2, 2, 2],
                   "border": [0.2, 0.2, 0.2, 0.2]},
        "spans": [{"text": "Text wraps and grows this decorated box."}],
        "style": {"font_size": 4, "line_height": 5},
    }])
    Path("text-box.ofd").write_bytes(doc.to_bytes())

Content height replaces layout.size[1] / Layout.Size[1] automatically. Width is clamped before wrapping, and complete lines move to the next page. Typography can enable shaped text or paragraph keep rules; page geometry and continuation come from the shared box options. The result contains all fragment rectangles and next (Next in Go), reusable as start (Start). General nested child containers use the mixed container API below. This API is available since 0.4.0.

Nested mixed containers (since 0.4.0)

from pathlib import Path
from ofdrw_rs import Document

with Document.new() as doc:
    result = doc.add_flow_containers(0, [{
        "layout": {"size": [40, 0], "padding": [1, 1, 1, 1]},
        "gap": 1,
        "children": [
            {"type": "paragraph", "spans": [{"text": "Heading"}],
             "style": {"font_size": 4, "line_height": 5}},
            {"type": "container", "container": {
                "layout": {"size": [30, 0], "border": [0.2, 0.2, 0.2, 0.2]},
                "children": [{"type": "paragraph", "spans": [{"text": "Nested text"}],
                              "style": {"font_size": 2, "line_height": 3}}],
            }},
        ],
    }])
    Path("containers.ofd").write_bytes(doc.to_bytes())

Image children accept data bytes or data_base64; font IDs in nested styles can use the integer returned by add_embedded_font.

Each container has layout, optional gap, and children. Supported child types are paragraph, image, container, spacer, table, line_break and page_area_fill. A table child has a table grid and optional table_style (font_size, line_height, font_id, repeat_header). Images accept explicit dimensions or intrinsic sizing and fit bounds. Spacer height defaults to zero. Returned root fragments and next / Next support continuation with shared start / Start options.

Containers support floating rows at every nesting level. Adjacent nested boxes share rows according to float, clear and width rules, with independent page continuation per column. Paragraphs, images, tables and spacers occupy full rows; gap separates rows. Repeated table headers stay with complete body-row groups, and header/body pairs that cannot fit a full page fail. Fragment heights include repeated headers and the space needed to align continuing floating columns. The whole call rolls back on invalid children. Limits are eight container levels and 10,000 container/child entries. This API is available since 0.4.0.

line_break ends the current nonempty floating row; leading, repeated and trailing empty breaks are ignored. page_area_fill consumes the current page's remaining content area. If that area is already full, it starts and fills the next page, so consecutive fills preserve explicit blank pages. A trailing fill does not append another page. Fills reset row gaps and affect only their own floating column. Both controls accept only type; a complete (integrity) container that would span pages fails atomically.

{"children": [{"type": "line_break"}, {"type": "page_area_fill"}]}

Dashed box borders (since 0.4.0)

border_dash (BorderDash in Go) uses Java Div.setBorderDash arguments: [3] means dash/gap [3, 3]; [3, 2] means dash/gap [3, 2]; [1, 3, 2] sets offset 1 followed by dash/gap [3, 2]. Longer even sequences contain dash/gap pairs, and longer odd sequences start with the offset. Null or an empty sequence selects a solid border. Lengths must be positive and finite, with at most 256 lengths; offsets below 0.000001 are omitted, matching Java. Invalid patterns fail atomically, including placeholders.

This field works in measured boxes, automatic text boxes and nested mixed containers. Equal-width borders use one closed stroked path; different edge widths use separate paths with horizontal edges owning the corners. Page cuts preserve the existing top/bottom border fragmentation rules. Dash phase starts at each emitted path; allocation, text wrapping and continuation are unchanged.

{"size": [40, 10], "border": [0.5, 0.5, 0.5, 0.5], "border_dash": [1, 3, 2]}

Box painting layers (since 0.4.0)

Set layout.layer (Layout.Layer in Go) to background, body or foreground. Measured box items accept the same layer field directly. Decoration, ordinary/shaped text, underline paths, images and table children use the selected layer across page fragments. A nested container without a layer inherits its parent; an explicit layer overrides it for that subtree. Roots default to Body. Painting follows OFD Background → Body → Foreground order independently of the order in which boxes were submitted.

Existing direct page layers of the chosen type are reused; another layer is created when needed. Existing empty Body layers on blank pages are retained. Layer selection does not change measured dimensions, pagination or returned placements. Later ordinary drawing calls continue to use Body. Invalid layer values fail atomically. The same rules apply to static and advanced container pagination and to existing pages with nonzero canvas origins.

document.add_box_layout(0, [{"type": "box", "size": [40, 10],
    "background_color": [240, 240, 240], "layer": "background"}])

Fixed page containers (since 0.4.0)

Available since 0.4.0; use bindings with their matching native library. add_fixed_containers draws on an existing global page and returns a placement list:

from pathlib import Path
from ofdrw_rs import Document

with Document.new() as doc:
    doc.add_blank_page(80, 60)
    placements = doc.add_fixed_containers(0, [{
        "position": [10, 20],
        "container": {
            "layout": {"size": [40, 0]},
            "children": [{"type": "paragraph", "spans": [{"text": "Hello"}]}],
        },
    }])
    Path("fixed.ofd").write_bytes(doc.to_bytes())

Positions are absolute OFD millimeters. Zero height measures the content; a positive height controls allocation and decorations while children may overflow. The call never adds pages. It supports the same nested text/image/table content, offsets, layers and placeholders as flow containers. Page-area fillers are ignored. Invalid later content rolls back the entire call. Images accept bytes in data.

Inline placeholders (since 0.4.0)

A span with empty text, placeholder_width in millimeters and font_size as height reserves an indivisible inline rectangle without painting objects or font resources. Width zero is allowed. For example:

with Document.new() as doc:
    metrics = doc.measure_flowed_spans(0, [
        {"text": "Label:"},
        {"text": "", "placeholder_width": 8, "font_size": 4},
        {"text": "value"},
    ], 50)
    assert metrics["lines"][0]["text"] == "Label:value"

The same spans work in styled flow, text boxes, flow blocks and fixed/flow containers. Reserved geometry participates in wrapping and maximum line height; measured/extracted text omits placeholders. Invalid later input rolls back the call. A leading placeholder absorbs a configured first-line indent once. For character-count reservations use count * (font_size + letter_spacing) as the width. Available since 0.4.0; use matching bindings and native library.

Metadata

Release files for ofdrw-rs 0.4.0

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

Built distributions (wheels)

Table of built distributions (wheels) for ofdrw-rs 0.4.0
File Actions
ofdrw_rs-0.4.0-py3-none-win_arm64.whl Python 3 none Windows ARM64 Details for ofdrw_rs-0.4.0-py3-none-win_arm64.whl
ofdrw_rs-0.4.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details for ofdrw_rs-0.4.0-py3-none-win_amd64.whl
ofdrw_rs-0.4.0-py3-none-manylinux_2_35_x86_64.manylinux_2_39_x86_64.whl Python 3 none Linux glibc 2.39+ x86-64, Linux glibc 2.35+ x86-64 Details for ofdrw_rs-0.4.0-py3-none-manylinux_2_35_x86_64.manylinux_2_39_x86_64.whl
ofdrw_rs-0.4.0-py3-none-manylinux_2_35_aarch64.manylinux_2_39_aarch64.whl Python 3 none Linux glibc 2.35+ ARM64, Linux glibc 2.39+ ARM64 Details for ofdrw_rs-0.4.0-py3-none-manylinux_2_35_aarch64.manylinux_2_39_aarch64.whl
ofdrw_rs-0.4.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details for ofdrw_rs-0.4.0-py3-none-macosx_11_0_arm64.whl
ofdrw_rs-0.4.0-py3-none-macosx_10_13_x86_64.whl Python 3 none macOS 10.13+ x86-64 Details for ofdrw_rs-0.4.0-py3-none-macosx_10_13_x86_64.whl

Total release size: 70.2 MB

Release files / ofdrw_rs-0.4.0-py3-none-win_arm64.whl

Download URL ofdrw_rs-0.4.0-py3-none-win_arm64.whl
Size 10.8 MB
Tags Python 3 Windows ARM64
SHA-256 checksum
How to use checksums
97e25051fc80e7f2ef341e60e7d2202c14140537ac73aeb92fc9475502baa01c
BLAKE2b-256 checksum
How to use checksums
842cc2c8d5f17f4f820e8ddd50f5d9693e16d43720b47630bd386c8bfdb308ed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Release files / ofdrw_rs-0.4.0-py3-none-win_amd64.whl

Download URL ofdrw_rs-0.4.0-py3-none-win_amd64.whl
Size 11.5 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
bb60c85df3aa08252706432da7be1faecb241c582bbff4b598c16062432cca31
BLAKE2b-256 checksum
How to use checksums
fe48f0cf102bd5a1684039fc150dea71e3e8828c80ef0a67c1d219667ef9a7d8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Release files / ofdrw_rs-0.4.0-py3-none-manylinux_2_35_x86_64.manylinux_2_39_x86_64.whl

Download URL ofdrw_rs-0.4.0-py3-none-manylinux_2_35_x86_64.manylinux_2_39_x86_64.whl
Size 12.5 MB
Tags Linux glibc 2.35+ x86-64 Linux glibc 2.39+ x86-64 Python 3
SHA-256 checksum
How to use checksums
3696c7be81eea87bf91410d92862009fc4125d406a478f07a90e40edd2350123
BLAKE2b-256 checksum
How to use checksums
4e97ddc443545f1ae50dd17c987d07928c6d6ff8616226f1bca1d67a4762c0ea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Release files / ofdrw_rs-0.4.0-py3-none-manylinux_2_35_aarch64.manylinux_2_39_aarch64.whl

Download URL ofdrw_rs-0.4.0-py3-none-manylinux_2_35_aarch64.manylinux_2_39_aarch64.whl
Size 12.0 MB
Tags Linux glibc 2.35+ ARM64 Linux glibc 2.39+ ARM64 Python 3
SHA-256 checksum
How to use checksums
ce774c58e0ff223a3bf9f8362edc55285868fc739c453421c0e09bdef797ed36
BLAKE2b-256 checksum
How to use checksums
67d0fc88aec7681b1733da764e330d39f0994633994e080179633c04ffb36087
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Release files / ofdrw_rs-0.4.0-py3-none-macosx_11_0_arm64.whl

Download URL ofdrw_rs-0.4.0-py3-none-macosx_11_0_arm64.whl
Size 11.4 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
852fc98b983764a13e4e6c7689a23c6a72d859ab3c0d2e81bca9d1f954fff3dc
BLAKE2b-256 checksum
How to use checksums
dae1c70b9024914144f64a875d385d8f1ab77767ab0fcf0bd4276014dbf4f153
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Release files / ofdrw_rs-0.4.0-py3-none-macosx_10_13_x86_64.whl

Download URL ofdrw_rs-0.4.0-py3-none-macosx_10_13_x86_64.whl
Size 12.0 MB
Tags Python 3 macOS 10.13+ x86-64
SHA-256 checksum
How to use checksums
624939c8ffda1dcc4ea541106690a3167bf8d665ec0b16ddba1fe9e22877bcf6
BLAKE2b-256 checksum
How to use checksums
79a6f1129d04b259bccdb0e0fb7e3565df7515a8b84b37caeb82559584261b52
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Security for ofdrw-rs 0.4.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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