Skip to content

Commit 86f8670

Browse files
authored
Merge dev-talesam into main
Merge performed by GitRepo.
2 parents b5f6677 + 9ffc2f9 commit 86f8670

372 files changed

Lines changed: 140629 additions & 115946 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,19 @@ cython_debug/
164164
.pypirc
165165

166166
# Project-specific
167+
.bigocrpdf-cpython-3.14/
168+
.bigocrpdf-debian-runtime/
169+
.bigocrpdf-venv/
170+
*.mo
171+
.bigocr_processing_*.pdf
172+
.bigocr_textlayer_*.pdf
173+
benchmark_results/**/export_complex_top3/
174+
benchmark_results/**/export_smoke/
175+
benchmark_results/**/exports/
167176
.pyscn/
168177
.vscode/
178+
pkgbuild/pkg/
179+
pkgbuild/src/
169180
feedback.md
170181
log.txt
171182
models-language.txt

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Changelog
2+
3+
All notable user-visible and release-engineering changes are documented here.
4+
5+
## 3.0.0 - 2026-08-02
6+
7+
- Use the current libadwaita shortcuts dialog instead of the deprecated GTK widget.
8+
- Validate GTK 4.22 and libadwaita 1.8 before importing the graphical applications.
9+
- Use OpenVINO's public Python API for backend availability checks.
10+
- Fix AVIF pages being accepted by the editor but treated as PDF input during save.
11+
- Align desktop, KIO, Nemo, and Nautilus MIME types with the formats each workflow accepts.
12+
- Make the Arch package version deterministic and pin the fallback Git source to the release tag.
13+
- Correct Arch and Nix Poppler dependencies, Nix data paths, runtime command lookup, and ICC profile discovery.
14+
- Enable PDF/A metadata preparation by default, with an explicit regular-PDF opt-out, and document that formal conformance requires external validation.
15+
- Require a Pillow version that can decode AVIF when built with libavif support.
16+
- Normalize gettext revision headers and validate all catalogs against the template.
17+
- Add release hygiene checks for bytecode, compiled translations, and generated package metadata.
18+
- Remove generated Python metadata, bytecode, and unused npm placeholder files from the source release.
19+
- Replace the refactoring plan with current architecture and maintenance documentation.

MAINTENANCE.md

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
# BigOCRPDF maintenance guide
2+
3+
This document records durable implementation contracts. Temporary plans, audit
4+
checklists, command logs, screenshots, and generated benchmark exports do not
5+
belong in the source tree.
6+
7+
## Ownership map
8+
9+
- `src/bigocrpdf/application.py`, `window.py`, and `image_application.py` own
10+
application lifecycle and top-level GTK state.
11+
- `src/bigocrpdf/ui/` owns presentation, focus, actions, and main-loop delivery.
12+
- `src/bigocrpdf/services/settings.py` owns the flat settings API consumed by the UI.
13+
- `src/bigocrpdf/services/processor.py` owns queue and OCR orchestration.
14+
- `src/bigocrpdf/services/rapidocr_service/` owns OCR, PDF inspection, geometry,
15+
text-layer generation, compression, and worker protocols.
16+
- `src/bigocrpdf/services/export_service.py` and the ODF/Markdown owners implement
17+
document exports.
18+
- `src/bigocrpdf/utils/config_manager.py`, `durable_writes.py`, history, and
19+
checkpoint modules own durable application state.
20+
- `usr/share/`, `tools/stage-data.sh`, `pkgbuild/PKGBUILD`, and `default.nix` own
21+
installed desktop integration.
22+
23+
Keep ownership names domain-specific. Do not add generic `manager`, `helper`, or
24+
`util` modules to avoid choosing an owner.
25+
26+
## Runtime contract
27+
28+
BigOCRPDF is a Linux GTK 4.22+/libadwaita application on Python 3.12+. Python remains responsible for
29+
GTK state, asynchronous delivery, OCR orchestration, and PDF/document models.
30+
Shell is limited to validation, staging, and packaging.
31+
32+
The base runtime includes GTK4, libadwaita, RapidOCR with the PP-OCRv6 small
33+
model, OpenVINO, Poppler tools, pikepdf, Pillow, OpenCV, NumPy, SciPy, ReportLab,
34+
and odfpy. ONNX Runtime is an optional inference backend. `jbig2enc` is optional;
35+
when it is absent, bilevel output must continue through CCITT Group 4.
36+
37+
Subprocess calls use direct argv. A zero exit status is authoritative success;
38+
nonzero status, timeout, or signal is an explicit error/cancellation result.
39+
40+
## OCR and PDF invariants
41+
42+
- CPU OCR remains fully functional.
43+
- The supported recognition model is PP-OCRv6 small with its unified language
44+
coverage. Do not reconstruct legacy language-model selection.
45+
- OCR configuration, including engine, DPI, thresholds, batch size, and render
46+
limits, travels through `OCRConfig`; do not rebuild a partial settings object.
47+
- Unicode searchable PDFs use real extractable text. Validation must include
48+
`pdftotext`, not only inspection of internal strings.
49+
- The text layer preserves page geometry and keeps OCR/native-text detection
50+
working after crop, deskew, dewarp, rotation, and mixed-content processing.
51+
- PDF resource limits and hostile-input checks remain enforced.
52+
- Structured `*.bigocr.json` sidecars are the preferred source for TXT,
53+
Markdown, and ODT export. Version 2 binds the payload to the PDF byte size and
54+
SHA-256 and records either `document` or `unavailable`; a stale fingerprint or
55+
explicit unavailable marker requires PDF fallback. Version 1 can be decoded
56+
only through the explicit `allow_unverified_legacy` compatibility opt-in; it
57+
is never authoritative by default. Fallback behavior must remain explicit.
58+
- Positioned ODT keeps editable text at page coordinates; reflowable ODT keeps
59+
paragraphs, tables, and columns; empty pages remain present.
60+
61+
OCR or geometry changes require a focused regression plus a representative
62+
benchmark. File-size or line-count pressure alone is not a reason to rewrite an
63+
algorithm.
64+
65+
## Durable state
66+
67+
Configuration, history, checkpoints, and published output are user data.
68+
69+
- Writes use a temporary file on the destination filesystem, flush and fsync the
70+
file, replace atomically, fsync the directory, and clean up on failure.
71+
- Published files use private reflink/copy snapshots, so a staged path that cannot
72+
be removed can never remain a mutable hardlink to user-visible output.
73+
- Multi-file publication is restricted to one canonical destination directory.
74+
Its private `PREPARING` -> `PREPARED` -> `COMMITTED`/`ROLLED_BACK` journal makes
75+
interrupted batches converge to the complete old or new set. Recovery runs
76+
before the next publication in that directory and is also available through
77+
`recover_pending_publications()`.
78+
- Every OCR PDF is published in the same transaction as its versioned sidecar.
79+
A split output publishes all PDF/sidecar pairs as one set. Sidecar generation
80+
failure fails the input rather than exposing a PDF with stale metadata.
81+
- Non-overwriting multi-file publication applies one collision counter to the
82+
complete batch. Domain callers that derive companion names provide their
83+
candidate family under the destination-directory lock.
84+
- POSIX cannot make several destination names visible as one atomic operation.
85+
Readers may observe a mixed set during the interruption window, but journal
86+
recovery never accepts that mixed set as the final state.
87+
- Rollback currently restores destination names, bytes, and regular access mode.
88+
Extended attributes, ACLs, and timestamps are not part of that recovery
89+
contract; callers must not use publication to preserve those metadata.
90+
- Existing configuration keys and migrations remain readable unless a documented
91+
migration with rollback replaces them.
92+
- Corrupt or partial input must not destroy the last readable state.
93+
- Destructive operations are idempotent and scoped to product-owned temporary
94+
paths or an explicitly confirmed user target.
95+
96+
## UI contract
97+
98+
The main journey is queue -> settings -> processing -> results. The image journey
99+
is source selection/capture -> processing -> copyable result. Visible state comes
100+
from the queue, dependency probe, worker outcome, and editor model; the UI must not
101+
announce readiness or success before those sources resolve.
102+
103+
Render information already held by the caller immediately. File page counts,
104+
Poppler metadata, thumbnails, and other I/O must not block the GTK main loop.
105+
Worker results may update only a still-live row/document.
106+
107+
Required controls are keyboard reachable and have stable AT-SPI names. Icon-only
108+
actions have a matching accessible name and native tooltip. Status changes need a
109+
real accessible event; an invisible label is not proof of an announcement.
110+
111+
Use native GTK/libadwaita components and theme tokens. Do not add visual decoration
112+
or custom transient widgets when the toolkit already owns the interaction.
113+
114+
The supported floor is GTK 4.14 with libadwaita 1.5, which is what an AppImage
115+
built on Ubuntu 24.04 carries; it is not the version we develop against. Widgets
116+
introduced after that floor go through `utils/adw_compat.py`, which probes with
117+
`hasattr` -- a symbol can be missing because the library is old or because its
118+
typelib was bundled incompletely -- and falls back to an equivalent that renders
119+
the same. `tests/test_adw_compat.py` exercises both branches and fails if such a
120+
widget is used directly anywhere else.
121+
122+
Every symbolic icon the interface references is bundled under
123+
`src/bigocrpdf/resources/icontheme/` and registered as a private icon theme by
124+
`utils/icons.py` during application startup, so the interface renders identically
125+
on any host and inside an AppImage. Adding an `icon-name` means adding the
126+
matching SVG; `tests/test_icons.py` enforces this in both directions. The theme
127+
inherits Adwaita and hicolor, so unbundled names still resolve.
128+
129+
Changed user-visible journeys require all three forms of evidence:
130+
131+
1. a rendered 1280x720 screenshot review;
132+
2. AT-SPI roles, names, states, and actions;
133+
3. the real action's observable side effect.
134+
135+
Measure 25, 100, and 500 queue/editor objects before considering list
136+
virtualization. Keep the current structure when it meets the measured budget.
137+
138+
## Internationalization and desktop metadata
139+
140+
`locale/bigocrpdf.pot` and `locale/*.po` are the gettext text sources. Compiled
141+
MO files are build artifacts produced by `tools/stage-data.sh` and are not
142+
versioned.
143+
144+
Translations embedded in `.desktop`, `.desktop.in`, and Nemo metadata remain in
145+
those files. They are not extracted to or generated from PO catalogs. Staging
146+
copies this content unchanged, then renames KIO `.desktop.in` files in the
147+
destination only.
148+
149+
Every PO must validate without fuzzy, obsolete, or untranslated entries. Preserve
150+
placeholders, plural forms, Pango/XML markup, and accelerators.
151+
152+
`utils/i18n.py` resolves the catalog directory at runtime, in this order:
153+
`BIGOCRPDF_LOCALE_DIR`, `$APPDIR/usr/share/locale`, `$TEXTDOMAINDIR` (exported by
154+
the AppRun that appimage-creator generates), directories walked up from the
155+
installed package, then `sys.prefix` and `/usr/share/locale`. A candidate only
156+
counts when it actually holds `*/LC_MESSAGES/bigocrpdf.mo`, so a relocatable
157+
build never silently falls through to a stale host catalog. The domain is bound
158+
on both `gettext` and the C library, the latter covering strings GLib translates
159+
on our behalf.
160+
161+
## Benchmarks
162+
163+
Benchmark sources and commands live in `benchmarks/prepare_benchmark_datasets.py`,
164+
`benchmarks/ocr_benchmark.py`, `benchmarks/validate_text_layer.py`, and
165+
`benchmarks/compare_benchmarks.py`. Raw datasets and generated PDF/ODT/TXT/Markdown
166+
exports stay outside the repository. Keep only compact READMEs, manifests, JSONL,
167+
CSV, and JSON summaries needed to interpret or reproduce a run.
168+
169+
The retained July 2026 baselines establish the following reference points:
170+
171+
- all 36 RapidOCR v6 CPU matrix runs completed and produced text layers;
172+
- ONNX Runtime small was fastest in that six-page run, but startup/model loading
173+
was included and the sample is not a universal engine ranking;
174+
- complex FUNSD pages exposed recognition and layout limits;
175+
- structured sidecars improved export token recall and restored table structures
176+
in two of three dense forms;
177+
- the form separator refinement preserved recall and table counts.
178+
179+
Do not report a roadmap, read document, or generated artifact as implemented
180+
behavior. A new performance claim includes command, dataset manifest, environment,
181+
before/after metrics, and failure count.
182+
183+
## Validation and release
184+
185+
Run the canonical local gate:
186+
187+
```bash
188+
bash tools/validate.sh
189+
```
190+
191+
The gate covers Python compilation, Ruff, formatting, Pyright, gettext freshness
192+
and completeness, staged desktop/AppStream data, ShellCheck, shfmt, pytest, and the
193+
frozen CLI/settings compatibility snapshot in `tools/compatibility-baseline.json`.
194+
CI runs that gate in Arch Linux so its Python and GTK versions satisfy the declared
195+
Python 3.12 and GTK 4.22 runtime floors.
196+
197+
Before release, also build and inspect the Arch package, run `nix flake check` and
198+
`nix build` in a working Nix environment, inspect installed file ownership and
199+
permissions, and exercise the installed package in a disposable VM. Verify KIO,
200+
Nemo, Nautilus, desktop launchers, OCR without `jbig2enc`, and a real Unicode
201+
`pdftotext` round trip.
202+
203+
## Reduction policy
204+
205+
Prefer deletion, direct imports, and existing owners. A new file or abstraction is
206+
acceptable only when it removes more duplicated behavior and shortens callers.
207+
Tests cover distinct observable regressions, not getters, constants, wrappers,
208+
private call order, or toolkit behavior. A compiler, type checker, authoritative
209+
metadata validator, or existing public-flow test is sufficient for mechanical
210+
changes it completely covers.

0 commit comments

Comments
 (0)