nima-persianguard 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.
- nima_persianguard-1.0.0/LICENSE +21 -0
- nima_persianguard-1.0.0/PKG-INFO +150 -0
- nima_persianguard-1.0.0/README.md +127 -0
- nima_persianguard-1.0.0/nima_persianguard/__init__.py +41 -0
- nima_persianguard-1.0.0/nima_persianguard/cli.py +60 -0
- nima_persianguard-1.0.0/nima_persianguard/engine.py +381 -0
- nima_persianguard-1.0.0/nima_persianguard/scene.py +112 -0
- nima_persianguard-1.0.0/nima_persianguard/textops.py +286 -0
- nima_persianguard-1.0.0/nima_persianguard/validator.py +129 -0
- nima_persianguard-1.0.0/nima_persianguard.egg-info/PKG-INFO +150 -0
- nima_persianguard-1.0.0/nima_persianguard.egg-info/SOURCES.txt +15 -0
- nima_persianguard-1.0.0/nima_persianguard.egg-info/dependency_links.txt +1 -0
- nima_persianguard-1.0.0/nima_persianguard.egg-info/entry_points.txt +2 -0
- nima_persianguard-1.0.0/nima_persianguard.egg-info/requires.txt +10 -0
- nima_persianguard-1.0.0/nima_persianguard.egg-info/top_level.txt +1 -0
- nima_persianguard-1.0.0/pyproject.toml +35 -0
- nima_persianguard-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nima Esmaili
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nima-persianguard
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: PersianGuard: modular Persian shaping/layout validation and infographic renderer with a single-pass RTL contract.
|
|
5
|
+
Author: Nima Esmaili
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: persian,rtl,bidi,arabic-reshaper,infographic,pillow
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: Pillow>=9.0
|
|
15
|
+
Provides-Extra: rtl
|
|
16
|
+
Requires-Dist: arabic-reshaper>=3.0; extra == "rtl"
|
|
17
|
+
Requires-Dist: python-bidi>=0.4; extra == "rtl"
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
20
|
+
Requires-Dist: arabic-reshaper>=3.0; extra == "dev"
|
|
21
|
+
Requires-Dist: python-bidi>=0.4; extra == "dev"
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# nima_persianguard
|
|
25
|
+
|
|
26
|
+
A clean, modular Python package extracted from the original PersianGuard
|
|
27
|
+
infographic scripts (`nima_persianguard.py`,
|
|
28
|
+
`Persian_Infographic-Nima_PersianGuard.py`). It preserves the exact text
|
|
29
|
+
content, layout constants and rendering behavior while separating concerns
|
|
30
|
+
into validation, layout, shaping and rendering modules with a stable public
|
|
31
|
+
API and CLI.
|
|
32
|
+
|
|
33
|
+
## Single-pass RTL contract
|
|
34
|
+
|
|
35
|
+
The package enforces the audited contract from
|
|
36
|
+
`shaping_bidi_review_report.txt`:
|
|
37
|
+
|
|
38
|
+
1. **Logical source only** — every text entering the engine is validated by
|
|
39
|
+
`validate_source`: Arabic presentation forms (`U+FB50..U+FDFF`,
|
|
40
|
+
`U+FE70..U+FEFF`) and bidi control characters (`LRE/RLE/LRO/RLO/PDF/
|
|
41
|
+
LRI/RLI/FSI/PDI`) are rejected, so pre-shaped or visual-order text can
|
|
42
|
+
never enter the pipeline.
|
|
43
|
+
2. **Shaping exactly once** — `arabic_reshaper.reshape` and
|
|
44
|
+
`bidi.algorithm.get_display` are combined only inside `shape()`. The final
|
|
45
|
+
display strings are produced once per line in the layout pass and cached
|
|
46
|
+
on the block (`display_lines`); the render pass draws the cached strings
|
|
47
|
+
verbatim and never reshapes. Intermediate measurement/wrapping passes are
|
|
48
|
+
direction-agnostic (they shape candidates only transiently to obtain
|
|
49
|
+
metrics and never store them).
|
|
50
|
+
3. **No mirroring** — no canvas/coordinate flip or `ImageOps.mirror` exists;
|
|
51
|
+
directional work happens solely through Pillow text anchors
|
|
52
|
+
(`"ra"`, `"ma"`, `"la"`).
|
|
53
|
+
|
|
54
|
+
The pytest suite (`tests/`) asserts these properties directly, e.g. that the
|
|
55
|
+
render pass never re-applies `get_display` to already-final display lines and
|
|
56
|
+
that a double-shaped source is rejected by `validate_source`.
|
|
57
|
+
|
|
58
|
+
## Public API
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from nima_persianguard import NimaPersianGuard, build_scene
|
|
62
|
+
|
|
63
|
+
guard = build_scene(3000, 2000) # full default infographic
|
|
64
|
+
image = guard.render() # validates + renders (single pass)
|
|
65
|
+
guard.update_text("title", "...") # any change marks the scene dirty
|
|
66
|
+
image = guard.render() # full re-validation + re-render
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Other entry points:
|
|
70
|
+
|
|
71
|
+
- `NimaPersianGuard(width, height, font_path)` — empty canvas engine;
|
|
72
|
+
`add_text`, `update_text`, `set_font_size`, `resize_canvas`, `validate`,
|
|
73
|
+
`render`, `save`.
|
|
74
|
+
- `nima_persianguard.validation.validate_source(text)` — logical-Unicode gate.
|
|
75
|
+
- `nima_persianguard.textops.shape(text)` — the single shaping point
|
|
76
|
+
(`get_display(reshape(text))`).
|
|
77
|
+
|
|
78
|
+
## CLI
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
python -m nima_persianguard --width 3000 --height 2000 -o out.png
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Running the module rebuilds the default infographic, performs the mandatory
|
|
85
|
+
resize/re-render invalidation check (2700×1800 → 3000×2000), exercises the
|
|
86
|
+
font-size / text-update hooks and writes an optimized PNG.
|
|
87
|
+
|
|
88
|
+
## Dependencies
|
|
89
|
+
|
|
90
|
+
- Required: `Pillow`
|
|
91
|
+
- Optional extras (recommended, used by the original renderer when
|
|
92
|
+
available): `arabic-reshaper`, `python-bidi`
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
pip install Pillow
|
|
96
|
+
pip install arabic-reshaper python-bidi # optional
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Font: the original scripts use `/usr/share/fonts/truetype/Vazir.ttf`
|
|
100
|
+
(`Vazir.ttf`); pass an alternative path via `NimaPersianGuard(font_path=...)`
|
|
101
|
+
or `--font`.
|
|
102
|
+
|
|
103
|
+
## Example
|
|
104
|
+
|
|
105
|
+
`examples/recreate_infographic.py` recreates the original infographic with
|
|
106
|
+
the packaged API:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
python examples/recreate_infographic.py -o persian_infographic.png
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Tests
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
pytest tests/
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Tests focus on the single-pass RTL contract: `shape` is the only shaping
|
|
119
|
+
point, final display lines are cached and never reshaped again, and the
|
|
120
|
+
render pass consumes cached strings.
|
|
121
|
+
|
|
122
|
+
## Zeno v2 submission note
|
|
123
|
+
|
|
124
|
+
For the Zeno v2 submission of *Nima Persiangard*:
|
|
125
|
+
|
|
126
|
+
1. **What to submit**
|
|
127
|
+
- the full source archive `nima_persianguard_package.zip` (this package:
|
|
128
|
+
`nima_persianguard/`, `examples/`, `tests/`, `pyproject.toml`,
|
|
129
|
+
`README.md`, `LICENSE`), and
|
|
130
|
+
- the final rendered PNG produced by the example/CLI
|
|
131
|
+
(`persian_infographic_persianguard_v2.png`, 3000×2000, optimized).
|
|
132
|
+
2. **How to describe the single-pass RTL guarantee** (use this wording or a
|
|
133
|
+
close paraphrase):
|
|
134
|
+
> "Every Persian string is supplied as logical Unicode and is validated at
|
|
135
|
+
> the boundary (`validate_source` rejects presentation forms and bidi
|
|
136
|
+
> control characters). Shaping (`arabic_reshaper.reshape`) followed by bidi
|
|
137
|
+
> reordering (`bidi.algorithm.get_display`) is applied exactly once, only
|
|
138
|
+
> in the final render pass, on cached per-line display strings. All
|
|
139
|
+
> intermediate measurement and layout passes are direction-agnostic and
|
|
140
|
+
> never produce or mutate display strings. There is no canvas flip, no
|
|
141
|
+
> mirror and no second shaping, so text cannot be reversed or
|
|
142
|
+
> double-shaped; this is enforced by automated contract tests in
|
|
143
|
+
> `tests/test_contract.py`."
|
|
144
|
+
3. Reference `docs/shaping_bidi_review_report.txt` (verbatim audit report)
|
|
145
|
+
and `docs/current_texts.txt` (verbatim user Persian text) as supporting
|
|
146
|
+
evidence.
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
MIT — see `LICENSE`.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# nima_persianguard
|
|
2
|
+
|
|
3
|
+
A clean, modular Python package extracted from the original PersianGuard
|
|
4
|
+
infographic scripts (`nima_persianguard.py`,
|
|
5
|
+
`Persian_Infographic-Nima_PersianGuard.py`). It preserves the exact text
|
|
6
|
+
content, layout constants and rendering behavior while separating concerns
|
|
7
|
+
into validation, layout, shaping and rendering modules with a stable public
|
|
8
|
+
API and CLI.
|
|
9
|
+
|
|
10
|
+
## Single-pass RTL contract
|
|
11
|
+
|
|
12
|
+
The package enforces the audited contract from
|
|
13
|
+
`shaping_bidi_review_report.txt`:
|
|
14
|
+
|
|
15
|
+
1. **Logical source only** — every text entering the engine is validated by
|
|
16
|
+
`validate_source`: Arabic presentation forms (`U+FB50..U+FDFF`,
|
|
17
|
+
`U+FE70..U+FEFF`) and bidi control characters (`LRE/RLE/LRO/RLO/PDF/
|
|
18
|
+
LRI/RLI/FSI/PDI`) are rejected, so pre-shaped or visual-order text can
|
|
19
|
+
never enter the pipeline.
|
|
20
|
+
2. **Shaping exactly once** — `arabic_reshaper.reshape` and
|
|
21
|
+
`bidi.algorithm.get_display` are combined only inside `shape()`. The final
|
|
22
|
+
display strings are produced once per line in the layout pass and cached
|
|
23
|
+
on the block (`display_lines`); the render pass draws the cached strings
|
|
24
|
+
verbatim and never reshapes. Intermediate measurement/wrapping passes are
|
|
25
|
+
direction-agnostic (they shape candidates only transiently to obtain
|
|
26
|
+
metrics and never store them).
|
|
27
|
+
3. **No mirroring** — no canvas/coordinate flip or `ImageOps.mirror` exists;
|
|
28
|
+
directional work happens solely through Pillow text anchors
|
|
29
|
+
(`"ra"`, `"ma"`, `"la"`).
|
|
30
|
+
|
|
31
|
+
The pytest suite (`tests/`) asserts these properties directly, e.g. that the
|
|
32
|
+
render pass never re-applies `get_display` to already-final display lines and
|
|
33
|
+
that a double-shaped source is rejected by `validate_source`.
|
|
34
|
+
|
|
35
|
+
## Public API
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from nima_persianguard import NimaPersianGuard, build_scene
|
|
39
|
+
|
|
40
|
+
guard = build_scene(3000, 2000) # full default infographic
|
|
41
|
+
image = guard.render() # validates + renders (single pass)
|
|
42
|
+
guard.update_text("title", "...") # any change marks the scene dirty
|
|
43
|
+
image = guard.render() # full re-validation + re-render
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Other entry points:
|
|
47
|
+
|
|
48
|
+
- `NimaPersianGuard(width, height, font_path)` — empty canvas engine;
|
|
49
|
+
`add_text`, `update_text`, `set_font_size`, `resize_canvas`, `validate`,
|
|
50
|
+
`render`, `save`.
|
|
51
|
+
- `nima_persianguard.validation.validate_source(text)` — logical-Unicode gate.
|
|
52
|
+
- `nima_persianguard.textops.shape(text)` — the single shaping point
|
|
53
|
+
(`get_display(reshape(text))`).
|
|
54
|
+
|
|
55
|
+
## CLI
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
python -m nima_persianguard --width 3000 --height 2000 -o out.png
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Running the module rebuilds the default infographic, performs the mandatory
|
|
62
|
+
resize/re-render invalidation check (2700×1800 → 3000×2000), exercises the
|
|
63
|
+
font-size / text-update hooks and writes an optimized PNG.
|
|
64
|
+
|
|
65
|
+
## Dependencies
|
|
66
|
+
|
|
67
|
+
- Required: `Pillow`
|
|
68
|
+
- Optional extras (recommended, used by the original renderer when
|
|
69
|
+
available): `arabic-reshaper`, `python-bidi`
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
pip install Pillow
|
|
73
|
+
pip install arabic-reshaper python-bidi # optional
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Font: the original scripts use `/usr/share/fonts/truetype/Vazir.ttf`
|
|
77
|
+
(`Vazir.ttf`); pass an alternative path via `NimaPersianGuard(font_path=...)`
|
|
78
|
+
or `--font`.
|
|
79
|
+
|
|
80
|
+
## Example
|
|
81
|
+
|
|
82
|
+
`examples/recreate_infographic.py` recreates the original infographic with
|
|
83
|
+
the packaged API:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
python examples/recreate_infographic.py -o persian_infographic.png
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Tests
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
pytest tests/
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Tests focus on the single-pass RTL contract: `shape` is the only shaping
|
|
96
|
+
point, final display lines are cached and never reshaped again, and the
|
|
97
|
+
render pass consumes cached strings.
|
|
98
|
+
|
|
99
|
+
## Zeno v2 submission note
|
|
100
|
+
|
|
101
|
+
For the Zeno v2 submission of *Nima Persiangard*:
|
|
102
|
+
|
|
103
|
+
1. **What to submit**
|
|
104
|
+
- the full source archive `nima_persianguard_package.zip` (this package:
|
|
105
|
+
`nima_persianguard/`, `examples/`, `tests/`, `pyproject.toml`,
|
|
106
|
+
`README.md`, `LICENSE`), and
|
|
107
|
+
- the final rendered PNG produced by the example/CLI
|
|
108
|
+
(`persian_infographic_persianguard_v2.png`, 3000×2000, optimized).
|
|
109
|
+
2. **How to describe the single-pass RTL guarantee** (use this wording or a
|
|
110
|
+
close paraphrase):
|
|
111
|
+
> "Every Persian string is supplied as logical Unicode and is validated at
|
|
112
|
+
> the boundary (`validate_source` rejects presentation forms and bidi
|
|
113
|
+
> control characters). Shaping (`arabic_reshaper.reshape`) followed by bidi
|
|
114
|
+
> reordering (`bidi.algorithm.get_display`) is applied exactly once, only
|
|
115
|
+
> in the final render pass, on cached per-line display strings. All
|
|
116
|
+
> intermediate measurement and layout passes are direction-agnostic and
|
|
117
|
+
> never produce or mutate display strings. There is no canvas flip, no
|
|
118
|
+
> mirror and no second shaping, so text cannot be reversed or
|
|
119
|
+
> double-shaped; this is enforced by automated contract tests in
|
|
120
|
+
> `tests/test_contract.py`."
|
|
121
|
+
3. Reference `docs/shaping_bidi_review_report.txt` (verbatim audit report)
|
|
122
|
+
and `docs/current_texts.txt` (verbatim user Persian text) as supporting
|
|
123
|
+
evidence.
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
MIT — see `LICENSE`.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""nima_persianguard - modular Persian shaping/layout validation + infographic renderer.
|
|
2
|
+
|
|
3
|
+
Public API::
|
|
4
|
+
|
|
5
|
+
from nima_persianguard import NimaPersianGuard, build_scene, render_infographic
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .engine import NimaPersianGuard, TextItem
|
|
9
|
+
from .scene import build_scene, SCENE_WIDTH, SCENE_HEIGHT
|
|
10
|
+
from .textops import (TextSourceError, ReorderingSkipped, validate_source,
|
|
11
|
+
shape, TextBlock, stats as text_stats)
|
|
12
|
+
from .validator import ValidationReport, ValidationError, validate_layout
|
|
13
|
+
|
|
14
|
+
__version__ = "1.0.0"
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"NimaPersianGuard",
|
|
18
|
+
"TextItem",
|
|
19
|
+
"build_scene",
|
|
20
|
+
"render_infographic",
|
|
21
|
+
"SCENE_WIDTH",
|
|
22
|
+
"SCENE_HEIGHT",
|
|
23
|
+
"validate_source",
|
|
24
|
+
"shape",
|
|
25
|
+
"TextBlock",
|
|
26
|
+
"TextSourceError",
|
|
27
|
+
"ReorderingSkipped",
|
|
28
|
+
"ValidationReport",
|
|
29
|
+
"ValidationError",
|
|
30
|
+
"validate_layout",
|
|
31
|
+
"text_stats",
|
|
32
|
+
"__version__",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def render_infographic(path: str, width: int = SCENE_WIDTH,
|
|
37
|
+
height: int = SCENE_HEIGHT,
|
|
38
|
+
font_path: str = None) -> str:
|
|
39
|
+
"""Build the default 3000x2000 infographic and save it as PNG."""
|
|
40
|
+
guard = build_scene(width, height, font_path=font_path)
|
|
41
|
+
return guard.save(path)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Command-line entrypoint: ``nima-persianguard render`` / ``validate``."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
from typing import List, Optional
|
|
8
|
+
|
|
9
|
+
from .engine import NimaPersianGuard, DEFAULT_FONT_CANDIDATES
|
|
10
|
+
from .scene import build_scene, SCENE_WIDTH, SCENE_HEIGHT
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _common_args(parser: argparse.ArgumentParser) -> None:
|
|
14
|
+
parser.add_argument("--width", type=int, default=SCENE_WIDTH)
|
|
15
|
+
parser.add_argument("--height", type=int, default=SCENE_HEIGHT)
|
|
16
|
+
parser.add_argument("--font", default=None,
|
|
17
|
+
help="path to a Persian-capable TTF (default: auto)")
|
|
18
|
+
parser.add_argument("--lenient", action="store_true",
|
|
19
|
+
help="do not raise on validation issues; report only")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def main(argv: Optional[List[str]] = None) -> int:
|
|
23
|
+
parser = argparse.ArgumentParser(
|
|
24
|
+
prog="nima-persianguard",
|
|
25
|
+
description="PersianGuard: single-pass Persian shaping, validation "
|
|
26
|
+
"and infographic rendering.")
|
|
27
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
28
|
+
|
|
29
|
+
p_render = sub.add_parser("render", help="render the default infographic")
|
|
30
|
+
_common_args(p_render)
|
|
31
|
+
p_render.add_argument("-o", "--output", default="persian_infographic.png")
|
|
32
|
+
|
|
33
|
+
p_validate = sub.add_parser("validate", help="validate and print a report")
|
|
34
|
+
_common_args(p_validate)
|
|
35
|
+
|
|
36
|
+
args = parser.parse_args(argv)
|
|
37
|
+
guard = build_scene(args.width, args.height, font_path=args.font)
|
|
38
|
+
guard.strict = not args.lenient
|
|
39
|
+
|
|
40
|
+
if args.command == "validate":
|
|
41
|
+
report = guard.validate()
|
|
42
|
+
print(report.summary())
|
|
43
|
+
return 0 if report.ok else 1
|
|
44
|
+
|
|
45
|
+
# mandatory resize/re-render invalidation check
|
|
46
|
+
w0, h0 = guard.width, guard.height
|
|
47
|
+
guard.resize_canvas(int(w0 * 0.9), int(h0 * 0.9))
|
|
48
|
+
guard.resize_canvas(w0, h0)
|
|
49
|
+
report = guard.validate()
|
|
50
|
+
if not report.ok:
|
|
51
|
+
print(report.summary(), file=sys.stderr)
|
|
52
|
+
return 1
|
|
53
|
+
path = guard.save(args.output)
|
|
54
|
+
print("rendered %s (%dx%d, %d text blocks, state=%s)"
|
|
55
|
+
% (path, guard.width, guard.height, len(guard), guard.state))
|
|
56
|
+
return 0
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if __name__ == "__main__": # pragma: no cover
|
|
60
|
+
raise SystemExit(main())
|