pd4ml 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pd4ml-1.0.0/MANIFEST.in +7 -0
- pd4ml-1.0.0/PKG-INFO +217 -0
- pd4ml-1.0.0/README.md +185 -0
- pd4ml-1.0.0/docs/guide.md +751 -0
- pd4ml-1.0.0/docs/releasing.md +51 -0
- pd4ml-1.0.0/examples/convert.py +44 -0
- pd4ml-1.0.0/pyproject.toml +59 -0
- pd4ml-1.0.0/setup.cfg +4 -0
- pd4ml-1.0.0/src/pd4ml/__init__.py +109 -0
- pd4ml-1.0.0/src/pd4ml/__init__.pyi +779 -0
- pd4ml-1.0.0/src/pd4ml/__main__.py +30 -0
- pd4ml-1.0.0/src/pd4ml/_api.py +366 -0
- pd4ml-1.0.0/src/pd4ml/_install.py +265 -0
- pd4ml-1.0.0/src/pd4ml/_jvm.py +152 -0
- pd4ml-1.0.0/src/pd4ml/py.typed +0 -0
- pd4ml-1.0.0/src/pd4ml.egg-info/PKG-INFO +217 -0
- pd4ml-1.0.0/src/pd4ml.egg-info/SOURCES.txt +25 -0
- pd4ml-1.0.0/src/pd4ml.egg-info/dependency_links.txt +1 -0
- pd4ml-1.0.0/src/pd4ml.egg-info/entry_points.txt +3 -0
- pd4ml-1.0.0/src/pd4ml.egg-info/requires.txt +4 -0
- pd4ml-1.0.0/src/pd4ml.egg-info/top_level.txt +1 -0
- pd4ml-1.0.0/tests/conftest.py +34 -0
- pd4ml-1.0.0/tests/test_docs.py +37 -0
- pd4ml-1.0.0/tests/test_install.py +105 -0
- pd4ml-1.0.0/tests/test_pd4ml.py +140 -0
- pd4ml-1.0.0/tools/gen_stubs.py +253 -0
- pd4ml-1.0.0/tools/pd4ml_classpath.py +63 -0
pd4ml-1.0.0/MANIFEST.in
ADDED
pd4ml-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pd4ml
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: PD4ML for Python: HTML and CSS to PDF, PDF/A, PDF/UA, ZUGFeRD, DOCX, RTF and images
|
|
5
|
+
Author-email: PD4ML <support@pd4ml.com>
|
|
6
|
+
License-Expression: LicenseRef-Proprietary
|
|
7
|
+
Project-URL: Homepage, https://pd4ml.com
|
|
8
|
+
Project-URL: Documentation, https://pd4ml.com/docs/
|
|
9
|
+
Project-URL: Usage examples, https://pd4ml.com/docs/usage-examples.html
|
|
10
|
+
Keywords: pdf,html,html-to-pdf,pdf/a,pdf/ua,zugferd,factur-x,docx,rtf,pd4ml
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Programming Language :: Java
|
|
23
|
+
Classifier: Topic :: Printing
|
|
24
|
+
Classifier: Topic :: Office/Business
|
|
25
|
+
Classifier: Topic :: Text Processing :: Markup :: HTML
|
|
26
|
+
Classifier: Typing :: Typed
|
|
27
|
+
Requires-Python: >=3.9
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
Requires-Dist: JPype1>=1.5
|
|
30
|
+
Provides-Extra: test
|
|
31
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
32
|
+
|
|
33
|
+
# pd4ml — PD4ML for Python
|
|
34
|
+
|
|
35
|
+
HTML and CSS to **PDF**, **PDF/A**, **PDF/UA**, **ZUGFeRD/Factur-X**, **DOCX**, **RTF** and page
|
|
36
|
+
**images**, with the full public [PD4ML](https://pd4ml.com) API (Java package `com.pd4ml`)
|
|
37
|
+
available to Python applications.
|
|
38
|
+
|
|
39
|
+
PD4ML runs in a Java virtual machine inside the Python process, through
|
|
40
|
+
[JPype](https://jpype.readthedocs.io). Every public Java class, method, constant and enum can be
|
|
41
|
+
used directly, and the module adds Python I/O (paths, bytes, file objects) on top. New converters
|
|
42
|
+
use PD4ML's **v42 layout engine** by default.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
pip install pd4ml
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
import pd4ml
|
|
50
|
+
|
|
51
|
+
pd = pd4ml.PD4ML() # v42 layout engine
|
|
52
|
+
pd.setPageSize(pd4ml.PageSize.A4)
|
|
53
|
+
pd.setPageMargins(pd4ml.PageMargins(15, 15, 15, 15, pd4ml.Units.MM))
|
|
54
|
+
pd.readHTML("invoice.html") # a path, URL, bytes or file object
|
|
55
|
+
pd.writePDF("invoice.pdf", pd4ml.PdfSpec.PDFA_3B) # a path or file object; no target: bytes
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The first use downloads the most recent PD4ML build (see *Installation* below).
|
|
59
|
+
|
|
60
|
+
## Requirements
|
|
61
|
+
|
|
62
|
+
- Python 3.9 or later.
|
|
63
|
+
- Java 8 or later: a JDK or JRE of the same bitness as Python; 17 or 21 is recommended. JPype
|
|
64
|
+
finds it through `JAVA_HOME` or the system's default Java. To use a specific JVM library
|
|
65
|
+
(`jvm.dll`, `libjvm.so`), set `PD4ML_JVM`.
|
|
66
|
+
|
|
67
|
+
## Installation
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
pip install pd4ml
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The package contains the Python module only. The PD4ML library itself comes from the PD4ML
|
|
74
|
+
Maven repository (<https://pd4ml.com/maven2>):
|
|
75
|
+
|
|
76
|
+
- **Automatically.** If no PD4ML build is installed or configured, the first use of PD4ML
|
|
77
|
+
downloads the most recent 4.x release. Bouncy Castle (for encryption and signing) comes along
|
|
78
|
+
from Maven Central. Every file is verified against its published SHA-1 checksum and stored in
|
|
79
|
+
a per-user cache directory: `%LOCALAPPDATA%\pd4ml-python` on Windows, `~/.cache/pd4ml-python`
|
|
80
|
+
elsewhere, or `PD4ML_HOME`. A notice on standard error reports the download.
|
|
81
|
+
- **Ahead of time**, which is better for servers and container images:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
pd4ml install # the most recent 4.x release (also: python -m pd4ml install)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Run it again to update to a newer release. From Python, call `pd4ml.install()`.
|
|
88
|
+
|
|
89
|
+
`PD4ML_AUTO_INSTALL=0` turns the automatic download off; the module then raises
|
|
90
|
+
`pd4ml.ClasspathError` until a build is installed or configured.
|
|
91
|
+
|
|
92
|
+
| Command | |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `pd4ml install` | download the most recent 4.x release, or update to it |
|
|
95
|
+
| `pd4ml install --version 4.0.23fx2` | an exact version |
|
|
96
|
+
| `pd4ml install --snapshots` | the most recent build, including development snapshots |
|
|
97
|
+
| `pd4ml install --jakarta` | the `-jakarta` variant |
|
|
98
|
+
| `pd4ml install --list` | the available versions |
|
|
99
|
+
| `pd4ml install --home DIR` | install into `DIR` (then set `PD4ML_HOME=DIR` for the application) |
|
|
100
|
+
| `pd4ml version` | the PD4ML version the module runs |
|
|
101
|
+
|
|
102
|
+
**Other PD4ML builds.** The module takes PD4ML from the first of these that is set:
|
|
103
|
+
|
|
104
|
+
1. `pd4ml.start(classpath=[...])`, called before first use;
|
|
105
|
+
2. `PD4ML_CLASSPATH`: jars and class directories separated by `;` on Windows and `:` elsewhere,
|
|
106
|
+
with `dir/*` for all jars of a directory;
|
|
107
|
+
3. `PD4ML_CLASSPATH_FILE`: a file with one entry per line;
|
|
108
|
+
4. the build `pd4ml install` downloaded.
|
|
109
|
+
|
|
110
|
+
The v42 layout engine is new in PD4ML 4.2. With an earlier build, such as the published 4.1.x,
|
|
111
|
+
a converter uses that build's own engine and warns once. `pd4ml.has_layout_engines()` tells
|
|
112
|
+
which kind of build is loaded.
|
|
113
|
+
|
|
114
|
+
## API
|
|
115
|
+
|
|
116
|
+
### The Java API
|
|
117
|
+
|
|
118
|
+
All public classes of `com.pd4ml` are module attributes under their own names:
|
|
119
|
+
|
|
120
|
+
| Python | Java |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `pd4ml.PD4ML` | `com.pd4ml.PD4ML` (wrapped, see below; the bare class is `pd4ml.JPD4ML`) |
|
|
123
|
+
| `pd4ml.Constants`, `pd4ml.LayoutEngine`, `pd4ml.ErrorPolicy` | `Constants`, `Constants.LayoutEngine`, `Constants.ErrorPolicy` |
|
|
124
|
+
| `pd4ml.PageSize`, `pd4ml.PageMargins`, `pd4ml.Dimensions`, `pd4ml.Units` | `PageSize`, `PageMargins`, `Dimensions`, `Dimensions.Units` |
|
|
125
|
+
| `pd4ml.PdfSpec`, `pd4ml.PdfDocument` | `PdfSpec`, `PdfDocument` |
|
|
126
|
+
| `pd4ml.ProgressListener`, `pd4ml.ResourceProvider`, `pd4ml.CustomTag`, `pd4ml.StatusMessage` | the same |
|
|
127
|
+
| `pd4ml.InvokeException`, `pd4ml.InvalidPasswordException`, `pd4ml.ForcedTerminationException`, `pd4ml.ConflictingParametersException`, `pd4ml.PdfSpecViolationException`, `pd4ml.PdfSpecUnsupportedException` | the exceptions |
|
|
128
|
+
|
|
129
|
+
Methods keep their Java names and take Python values:
|
|
130
|
+
|
|
131
|
+
- `str`, `int`, `float`, `bool`;
|
|
132
|
+
- `bytes` for `byte[]`;
|
|
133
|
+
- `None` for `null`.
|
|
134
|
+
|
|
135
|
+
Java `null` results become `None`, and Java strings become `str`. Any other Java class is
|
|
136
|
+
available through `pd4ml.java_class("java.util.HashMap")`.
|
|
137
|
+
|
|
138
|
+
Java exceptions are Python exceptions; catch them by their class:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
try:
|
|
142
|
+
pd.readHTML("missing.html")
|
|
143
|
+
pd.writePDF("out.pdf")
|
|
144
|
+
except pd4ml.java_class("java.io.IOException") as e:
|
|
145
|
+
print("conversion failed:", e)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### `pd4ml.PD4ML`
|
|
149
|
+
|
|
150
|
+
`PD4ML(*args, engine="v42", html_width=None)` creates a `com.pd4ml.PD4ML`, passing `*args` to
|
|
151
|
+
the Java constructor: nothing, a license key, or an HTML width. It then selects the layout
|
|
152
|
+
engine: `engine="v40"` for the previous engine, `engine=None` for the Java default.
|
|
153
|
+
|
|
154
|
+
Every Java method is available. These also accept Python I/O:
|
|
155
|
+
|
|
156
|
+
| Method | Python additions |
|
|
157
|
+
|---|---|
|
|
158
|
+
| `readHTML(source, base_url=None, encoding=None)` | `source`: a path, `pathlib.Path`, URL string, bytes, binary file object, or Java `InputStream`/`URL` |
|
|
159
|
+
| `read_html_string(html, base_url=None)` | the document as a string |
|
|
160
|
+
| `writePDF(target=None, spec=None)` | `target`: a path, file object or Java `OutputStream`; with no target, returns bytes. `spec`: a `PdfSpec`, a keyword (`"pdf/a-2b"`, see `PdfSpec.listKeywords()`) or `"PDF"`/`"PDFA"`/`"PDFUA"` |
|
|
161
|
+
| `writeDOCX(target=None)`, `writeRTF(target=None, rtf_wmf=False)` | as `writePDF` |
|
|
162
|
+
| `renderAsImages(format)` | the pages as a list of bytes; `render_png()` for PNG |
|
|
163
|
+
| `monitorProgressWith(listener)` | a Python callable `(message_id, progress, note, msec)` |
|
|
164
|
+
| `useHtmlRenderer(engine, html_width=None, params=None)` | the engine as `"v42"`/`"v40"`; params as a dict |
|
|
165
|
+
|
|
166
|
+
Static members of the Java class are on the wrapper class: `pd4ml.PD4ML.getVersion()`,
|
|
167
|
+
`pd4ml.PD4ML.disableBatik = True`. The underlying Java object is `pd.java`.
|
|
168
|
+
|
|
169
|
+
### Helpers
|
|
170
|
+
|
|
171
|
+
- `pd4ml.html_to_pdf(source, target=None, *, base_url, page_size, page_margins, spec, engine, html_width)`
|
|
172
|
+
- `pd4ml.open_pdf(source, password=None)`: a `PdfDocument` from a path, URL, bytes or file
|
|
173
|
+
- `pd4ml.write_pdf(document, target=None, password=None, permissions=None)`
|
|
174
|
+
- `pd4ml.merge_pdfs(first, second, target=None)`
|
|
175
|
+
- `pd4ml.pdf_spec(keyword)`: the `PdfSpec` for a keyword; unknown keywords raise `ValueError`
|
|
176
|
+
- `pd4ml.progress_listener(callback)`: a Java `ProgressListener` for a callable
|
|
177
|
+
- `pd4ml.version()`, `pd4ml.start(...)`, `pd4ml.is_started()`, `pd4ml.java_class(name)`
|
|
178
|
+
- `pd4ml.install(...)`, `pd4ml.installed_jar()`, `pd4ml.installed_version()`, `pd4ml.has_layout_engines()`
|
|
179
|
+
|
|
180
|
+
The JVM starts on the first use of PD4ML. To pass JVM options, call
|
|
181
|
+
`pd4ml.start(jvm_options=["-Xmx2g"])` first, or set `PD4ML_JVM_OPTIONS`. The JVM runs headless,
|
|
182
|
+
and it can be started only once per process.
|
|
183
|
+
|
|
184
|
+
### Limitations
|
|
185
|
+
|
|
186
|
+
- `ResourceProvider` and `CustomTag` are Java classes to extend. Write those in Java and register
|
|
187
|
+
them by class name (`addCustomResourceProvider`) or instance. Python can implement only Java
|
|
188
|
+
*interfaces*, such as `ProgressListener`.
|
|
189
|
+
- As of PD4ML 4.2.0, the v42 layout engine reports only `DOC_WRITE_BEGIN` to a
|
|
190
|
+
`ProgressListener`; v40 reports every stage.
|
|
191
|
+
|
|
192
|
+
## Documentation
|
|
193
|
+
|
|
194
|
+
- **User guide**: `docs/guide.md` in the source distribution (`pip download --no-binary :all: pd4ml`).
|
|
195
|
+
It covers prerequisites, installation, use cases with code, tips and troubleshooting.
|
|
196
|
+
- The PD4ML manual: <https://pd4ml.com/docs/>.
|
|
197
|
+
- Usage examples: <https://pd4ml.com/docs/usage-examples.html>.
|
|
198
|
+
- Licensing: without a license, PD4ML runs in evaluation mode and watermarks its output. See
|
|
199
|
+
<https://pd4ml.com/docs/#3.-licensing>.
|
|
200
|
+
|
|
201
|
+
## Development
|
|
202
|
+
|
|
203
|
+
These steps need the source distribution or repository.
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
pip install -e ".[test]"
|
|
207
|
+
python tools/pd4ml_classpath.py <pd4ml maven project> # writes ./pd4ml.classpath (optional)
|
|
208
|
+
python -m pytest
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
- **Tests** use `./pd4ml.classpath` (or `PD4ML_CLASSPATH`/`PD4ML_CLASSPATH_FILE`), and are
|
|
212
|
+
skipped without one. `PD4ML_NETWORK_TESTS=1` adds tests that download the latest release, both
|
|
213
|
+
explicitly and through the automatic first-use download.
|
|
214
|
+
- **Type stubs**: `src/pd4ml/__init__.pyi` declares the whole API for IDEs and type checkers.
|
|
215
|
+
After an API change, regenerate it with `python tools/gen_stubs.py`.
|
|
216
|
+
- **Releases** to PyPI are described in `docs/releasing.md`.
|
|
217
|
+
- **Example**: `python examples/convert.py page.html page.pdf --pdfa pdf/a-2b`.
|
pd4ml-1.0.0/README.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# pd4ml — PD4ML for Python
|
|
2
|
+
|
|
3
|
+
HTML and CSS to **PDF**, **PDF/A**, **PDF/UA**, **ZUGFeRD/Factur-X**, **DOCX**, **RTF** and page
|
|
4
|
+
**images**, with the full public [PD4ML](https://pd4ml.com) API (Java package `com.pd4ml`)
|
|
5
|
+
available to Python applications.
|
|
6
|
+
|
|
7
|
+
PD4ML runs in a Java virtual machine inside the Python process, through
|
|
8
|
+
[JPype](https://jpype.readthedocs.io). Every public Java class, method, constant and enum can be
|
|
9
|
+
used directly, and the module adds Python I/O (paths, bytes, file objects) on top. New converters
|
|
10
|
+
use PD4ML's **v42 layout engine** by default.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
pip install pd4ml
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
import pd4ml
|
|
18
|
+
|
|
19
|
+
pd = pd4ml.PD4ML() # v42 layout engine
|
|
20
|
+
pd.setPageSize(pd4ml.PageSize.A4)
|
|
21
|
+
pd.setPageMargins(pd4ml.PageMargins(15, 15, 15, 15, pd4ml.Units.MM))
|
|
22
|
+
pd.readHTML("invoice.html") # a path, URL, bytes or file object
|
|
23
|
+
pd.writePDF("invoice.pdf", pd4ml.PdfSpec.PDFA_3B) # a path or file object; no target: bytes
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The first use downloads the most recent PD4ML build (see *Installation* below).
|
|
27
|
+
|
|
28
|
+
## Requirements
|
|
29
|
+
|
|
30
|
+
- Python 3.9 or later.
|
|
31
|
+
- Java 8 or later: a JDK or JRE of the same bitness as Python; 17 or 21 is recommended. JPype
|
|
32
|
+
finds it through `JAVA_HOME` or the system's default Java. To use a specific JVM library
|
|
33
|
+
(`jvm.dll`, `libjvm.so`), set `PD4ML_JVM`.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
pip install pd4ml
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The package contains the Python module only. The PD4ML library itself comes from the PD4ML
|
|
42
|
+
Maven repository (<https://pd4ml.com/maven2>):
|
|
43
|
+
|
|
44
|
+
- **Automatically.** If no PD4ML build is installed or configured, the first use of PD4ML
|
|
45
|
+
downloads the most recent 4.x release. Bouncy Castle (for encryption and signing) comes along
|
|
46
|
+
from Maven Central. Every file is verified against its published SHA-1 checksum and stored in
|
|
47
|
+
a per-user cache directory: `%LOCALAPPDATA%\pd4ml-python` on Windows, `~/.cache/pd4ml-python`
|
|
48
|
+
elsewhere, or `PD4ML_HOME`. A notice on standard error reports the download.
|
|
49
|
+
- **Ahead of time**, which is better for servers and container images:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
pd4ml install # the most recent 4.x release (also: python -m pd4ml install)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Run it again to update to a newer release. From Python, call `pd4ml.install()`.
|
|
56
|
+
|
|
57
|
+
`PD4ML_AUTO_INSTALL=0` turns the automatic download off; the module then raises
|
|
58
|
+
`pd4ml.ClasspathError` until a build is installed or configured.
|
|
59
|
+
|
|
60
|
+
| Command | |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `pd4ml install` | download the most recent 4.x release, or update to it |
|
|
63
|
+
| `pd4ml install --version 4.0.23fx2` | an exact version |
|
|
64
|
+
| `pd4ml install --snapshots` | the most recent build, including development snapshots |
|
|
65
|
+
| `pd4ml install --jakarta` | the `-jakarta` variant |
|
|
66
|
+
| `pd4ml install --list` | the available versions |
|
|
67
|
+
| `pd4ml install --home DIR` | install into `DIR` (then set `PD4ML_HOME=DIR` for the application) |
|
|
68
|
+
| `pd4ml version` | the PD4ML version the module runs |
|
|
69
|
+
|
|
70
|
+
**Other PD4ML builds.** The module takes PD4ML from the first of these that is set:
|
|
71
|
+
|
|
72
|
+
1. `pd4ml.start(classpath=[...])`, called before first use;
|
|
73
|
+
2. `PD4ML_CLASSPATH`: jars and class directories separated by `;` on Windows and `:` elsewhere,
|
|
74
|
+
with `dir/*` for all jars of a directory;
|
|
75
|
+
3. `PD4ML_CLASSPATH_FILE`: a file with one entry per line;
|
|
76
|
+
4. the build `pd4ml install` downloaded.
|
|
77
|
+
|
|
78
|
+
The v42 layout engine is new in PD4ML 4.2. With an earlier build, such as the published 4.1.x,
|
|
79
|
+
a converter uses that build's own engine and warns once. `pd4ml.has_layout_engines()` tells
|
|
80
|
+
which kind of build is loaded.
|
|
81
|
+
|
|
82
|
+
## API
|
|
83
|
+
|
|
84
|
+
### The Java API
|
|
85
|
+
|
|
86
|
+
All public classes of `com.pd4ml` are module attributes under their own names:
|
|
87
|
+
|
|
88
|
+
| Python | Java |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `pd4ml.PD4ML` | `com.pd4ml.PD4ML` (wrapped, see below; the bare class is `pd4ml.JPD4ML`) |
|
|
91
|
+
| `pd4ml.Constants`, `pd4ml.LayoutEngine`, `pd4ml.ErrorPolicy` | `Constants`, `Constants.LayoutEngine`, `Constants.ErrorPolicy` |
|
|
92
|
+
| `pd4ml.PageSize`, `pd4ml.PageMargins`, `pd4ml.Dimensions`, `pd4ml.Units` | `PageSize`, `PageMargins`, `Dimensions`, `Dimensions.Units` |
|
|
93
|
+
| `pd4ml.PdfSpec`, `pd4ml.PdfDocument` | `PdfSpec`, `PdfDocument` |
|
|
94
|
+
| `pd4ml.ProgressListener`, `pd4ml.ResourceProvider`, `pd4ml.CustomTag`, `pd4ml.StatusMessage` | the same |
|
|
95
|
+
| `pd4ml.InvokeException`, `pd4ml.InvalidPasswordException`, `pd4ml.ForcedTerminationException`, `pd4ml.ConflictingParametersException`, `pd4ml.PdfSpecViolationException`, `pd4ml.PdfSpecUnsupportedException` | the exceptions |
|
|
96
|
+
|
|
97
|
+
Methods keep their Java names and take Python values:
|
|
98
|
+
|
|
99
|
+
- `str`, `int`, `float`, `bool`;
|
|
100
|
+
- `bytes` for `byte[]`;
|
|
101
|
+
- `None` for `null`.
|
|
102
|
+
|
|
103
|
+
Java `null` results become `None`, and Java strings become `str`. Any other Java class is
|
|
104
|
+
available through `pd4ml.java_class("java.util.HashMap")`.
|
|
105
|
+
|
|
106
|
+
Java exceptions are Python exceptions; catch them by their class:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
try:
|
|
110
|
+
pd.readHTML("missing.html")
|
|
111
|
+
pd.writePDF("out.pdf")
|
|
112
|
+
except pd4ml.java_class("java.io.IOException") as e:
|
|
113
|
+
print("conversion failed:", e)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### `pd4ml.PD4ML`
|
|
117
|
+
|
|
118
|
+
`PD4ML(*args, engine="v42", html_width=None)` creates a `com.pd4ml.PD4ML`, passing `*args` to
|
|
119
|
+
the Java constructor: nothing, a license key, or an HTML width. It then selects the layout
|
|
120
|
+
engine: `engine="v40"` for the previous engine, `engine=None` for the Java default.
|
|
121
|
+
|
|
122
|
+
Every Java method is available. These also accept Python I/O:
|
|
123
|
+
|
|
124
|
+
| Method | Python additions |
|
|
125
|
+
|---|---|
|
|
126
|
+
| `readHTML(source, base_url=None, encoding=None)` | `source`: a path, `pathlib.Path`, URL string, bytes, binary file object, or Java `InputStream`/`URL` |
|
|
127
|
+
| `read_html_string(html, base_url=None)` | the document as a string |
|
|
128
|
+
| `writePDF(target=None, spec=None)` | `target`: a path, file object or Java `OutputStream`; with no target, returns bytes. `spec`: a `PdfSpec`, a keyword (`"pdf/a-2b"`, see `PdfSpec.listKeywords()`) or `"PDF"`/`"PDFA"`/`"PDFUA"` |
|
|
129
|
+
| `writeDOCX(target=None)`, `writeRTF(target=None, rtf_wmf=False)` | as `writePDF` |
|
|
130
|
+
| `renderAsImages(format)` | the pages as a list of bytes; `render_png()` for PNG |
|
|
131
|
+
| `monitorProgressWith(listener)` | a Python callable `(message_id, progress, note, msec)` |
|
|
132
|
+
| `useHtmlRenderer(engine, html_width=None, params=None)` | the engine as `"v42"`/`"v40"`; params as a dict |
|
|
133
|
+
|
|
134
|
+
Static members of the Java class are on the wrapper class: `pd4ml.PD4ML.getVersion()`,
|
|
135
|
+
`pd4ml.PD4ML.disableBatik = True`. The underlying Java object is `pd.java`.
|
|
136
|
+
|
|
137
|
+
### Helpers
|
|
138
|
+
|
|
139
|
+
- `pd4ml.html_to_pdf(source, target=None, *, base_url, page_size, page_margins, spec, engine, html_width)`
|
|
140
|
+
- `pd4ml.open_pdf(source, password=None)`: a `PdfDocument` from a path, URL, bytes or file
|
|
141
|
+
- `pd4ml.write_pdf(document, target=None, password=None, permissions=None)`
|
|
142
|
+
- `pd4ml.merge_pdfs(first, second, target=None)`
|
|
143
|
+
- `pd4ml.pdf_spec(keyword)`: the `PdfSpec` for a keyword; unknown keywords raise `ValueError`
|
|
144
|
+
- `pd4ml.progress_listener(callback)`: a Java `ProgressListener` for a callable
|
|
145
|
+
- `pd4ml.version()`, `pd4ml.start(...)`, `pd4ml.is_started()`, `pd4ml.java_class(name)`
|
|
146
|
+
- `pd4ml.install(...)`, `pd4ml.installed_jar()`, `pd4ml.installed_version()`, `pd4ml.has_layout_engines()`
|
|
147
|
+
|
|
148
|
+
The JVM starts on the first use of PD4ML. To pass JVM options, call
|
|
149
|
+
`pd4ml.start(jvm_options=["-Xmx2g"])` first, or set `PD4ML_JVM_OPTIONS`. The JVM runs headless,
|
|
150
|
+
and it can be started only once per process.
|
|
151
|
+
|
|
152
|
+
### Limitations
|
|
153
|
+
|
|
154
|
+
- `ResourceProvider` and `CustomTag` are Java classes to extend. Write those in Java and register
|
|
155
|
+
them by class name (`addCustomResourceProvider`) or instance. Python can implement only Java
|
|
156
|
+
*interfaces*, such as `ProgressListener`.
|
|
157
|
+
- As of PD4ML 4.2.0, the v42 layout engine reports only `DOC_WRITE_BEGIN` to a
|
|
158
|
+
`ProgressListener`; v40 reports every stage.
|
|
159
|
+
|
|
160
|
+
## Documentation
|
|
161
|
+
|
|
162
|
+
- **User guide**: `docs/guide.md` in the source distribution (`pip download --no-binary :all: pd4ml`).
|
|
163
|
+
It covers prerequisites, installation, use cases with code, tips and troubleshooting.
|
|
164
|
+
- The PD4ML manual: <https://pd4ml.com/docs/>.
|
|
165
|
+
- Usage examples: <https://pd4ml.com/docs/usage-examples.html>.
|
|
166
|
+
- Licensing: without a license, PD4ML runs in evaluation mode and watermarks its output. See
|
|
167
|
+
<https://pd4ml.com/docs/#3.-licensing>.
|
|
168
|
+
|
|
169
|
+
## Development
|
|
170
|
+
|
|
171
|
+
These steps need the source distribution or repository.
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
pip install -e ".[test]"
|
|
175
|
+
python tools/pd4ml_classpath.py <pd4ml maven project> # writes ./pd4ml.classpath (optional)
|
|
176
|
+
python -m pytest
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
- **Tests** use `./pd4ml.classpath` (or `PD4ML_CLASSPATH`/`PD4ML_CLASSPATH_FILE`), and are
|
|
180
|
+
skipped without one. `PD4ML_NETWORK_TESTS=1` adds tests that download the latest release, both
|
|
181
|
+
explicitly and through the automatic first-use download.
|
|
182
|
+
- **Type stubs**: `src/pd4ml/__init__.pyi` declares the whole API for IDEs and type checkers.
|
|
183
|
+
After an API change, regenerate it with `python tools/gen_stubs.py`.
|
|
184
|
+
- **Releases** to PyPI are described in `docs/releasing.md`.
|
|
185
|
+
- **Example**: `python examples/convert.py page.html page.pdf --pdfa pdf/a-2b`.
|