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)
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.