@@ -4,10 +4,104 @@ All notable changes to this project are documented here. The format follows
44[ Keep a Changelog] ( https://keepachangelog.com/en/1.1.0/ ) and the project adheres to
55[ Semantic Versioning] ( https://semver.org/spec/v2.0.0.html ) .
66
7- ## [ Unreleased]
7+ ## [ 1.0.0] - 2026-08-12
8+
9+ The first release of OCRSmith as a document forge rather than a line-image generator.
10+ The v0 engine produced one image with one string; v1 produces whole pages with word-level
11+ boxes, typed layout regions, table structure and markup ground truth, and validates every
12+ page before it reaches the dataset.
813
914### Added
1015
16+ - ` ocrsmith.quality ` : validation and statistics.
17+ - Six validators for the failures that do not raise — blank pages, washed-out text,
18+ boxes off the canvas, overlapping blocks, illegibly small lines, empty labels. Each
19+ explains itself, so a rejection rate is diagnosable rather than merely alarming.
20+ - The generation pipeline runs them as a gate; a shard that rejects more than
21+ ` quality.max_rejection_rate ` aborts, because that is a configuration problem and a
22+ shard full of holes would hide it behind a plausible-looking dataset.
23+ - ` DatasetStats ` accumulates the distributions that define a corpus — templates, capture
24+ conditions, direction, region types, alphabet, line-height percentiles — in constant
25+ memory, and renders a dataset-card fragment.
26+ - ` ocrsmith.evaluation ` : CER, WER, normalised edit similarity, TEDS-style table similarity
27+ and IoU-thresholded detection P/R/F1, plus a harness that scores a model's predictions
28+ against a generated benchmark. Diacritic sensitivity is an explicit argument rather than
29+ a silent convention.
30+ - ` ocrsmith.domain.page_from_dict ` and friends: annotations round-trip, so validation,
31+ statistics and evaluation all read the same records the writers produce.
32+ - CLI: ` validate ` , ` stats ` and ` evaluate ` .
33+ - ` ocrsmith.pipeline ` : streaming generation.
34+ - ` SampleFactory.create(index) ` derives a per-sample seed from ` (config.seed, index) `
35+ and yields one annotated ` Sample ` per page. Any sample can be regenerated on its own,
36+ without replaying the run that produced it.
37+ - ` iter_samples ` is a generator end to end, so a ten-million-page run holds one page in
38+ memory at a time.
39+ - Work is sharded, and each worker * writes* its own shard rather than shipping images
40+ back through a pickle queue. Completed shards are marked, so an interrupted job
41+ resumes instead of restarting.
42+ - ` ocrsmith.datasets.writers ` : six output formats behind one ` SampleSink ` protocol —
43+ ` jsonl ` , ` parquet ` , ` webdataset ` , ` coco ` (word/line/region instances), ` paddleocr `
44+ (detection labels plus line crops) and ` chat ` (image + instruction + Markdown answer for
45+ vision-language fine-tuning). Sinks write incrementally, so a killed run leaves valid
46+ shards rather than one truncated file.
47+ - ` ocrsmith.config ` : a single validated ` GenerationConfig ` describing a whole corpus, with
48+ every per-sample choice expressed as a distribution. Dotted-key CLI overrides
49+ (` --set run.workers=8 ` ) and a JSON-serialisable payload that crosses the process
50+ boundary intact.
51+ - New ` ocrsmith ` CLI (typer + rich): ` generate ` , ` preview ` , ` fonts ` , ` doctor ` ,
52+ ` show-config ` . ` doctor ` reports whether this machine can produce correct Arabic; the CLI
53+ forces UTF-8 output so a cp1252 Windows console cannot crash a tool whose entire purpose
54+ is Arabic text.
55+ - ` ocrsmith.core.degradations ` : capture-condition modelling, where every degradation takes
56+ the annotation as well as the image and returns both.
57+ - Geometric: ` Rotation ` and ` PerspectiveWarp ` derive an explicit forward point mapping
58+ and push the whole annotation through it, so boxes track the ink instead of drifting
59+ silently. Rotated words gain polygons.
60+ - Photometric: gaussian noise, paper grain, defocus and motion blur, brightness,
61+ contrast, JPEG artefacts, downscaling, ink spread/erosion, bleed-through, shadow,
62+ vignette, glare, stains and folds.
63+ - Five presets — ` clean ` , ` scan ` , ` photo ` , ` fax ` , ` archive ` — ordered along the physical
64+ capture chain, so a corpus can be composed by capture condition rather than by
65+ undifferentiated noise.
66+ - ` ocrsmith.core.documents ` : a document engine that produces full pages, not single lines.
67+ - ` DocumentBuilder ` / ` DocumentContent ` separate * what a document says* from * how it
68+ looks* , so the same content laid out in one column or two yields identical markup
69+ ground truth.
70+ - ` PageSpec.from_paper ` derives the canvas from paper size and DPI, with margins,
71+ multi-column layout (right-first for RTL) and reserved header/footer bands.
72+ - ` DocumentRenderer ` pours blocks down columns and onto further pages, splitting prose
73+ and moving structure whole. Nothing is clipped, nothing overlaps, and pages can be
74+ streamed one at a time.
75+ - ` TableRenderer ` emits per-cell boxes, content-derived column widths, in-cell wrapping,
76+ RTL column mirroring, and five border styles.
77+ - ` TypographySampler ` samples one coherent font family per document with per-role sizes
78+ and spacing, rather than a random face per block.
79+ - Six document genres (article, report, newspaper, letter, form, invoice) behind a
80+ weighted ` TemplateRegistry ` .
81+ - ` ocrsmith.core.rendering ` : a text renderer that emits pixels and their annotation in
82+ the same pass, so the two cannot disagree.
83+ - Words are drawn individually, which yields exact per-word boxes and is typographically
84+ safe for Arabic (letters never join across a space).
85+ - ` visual_word_order ` implements word-level bidi run reordering, so mixed
86+ Arabic/Latin/digit lines are drawn in the right place while the label stays logical.
87+ - Wrapping is lossless: no word is silently dropped, oversized words are broken rather
88+ than overflowed, and lines that do not fit the height budget are * reported* so the
89+ label can be trimmed to exactly what was drawn.
90+ - ` TextStyle ` covers alignment (including natural RTL), line/word spacing, stroke,
91+ underline, strikethrough, synthetic bold/italic, and baseline/word-gap jitter, with an
92+ injectable ` random.Random ` so any sample is reproducible.
93+ - ` ocrsmith.text ` : a text subsystem that owns everything happening to a string before it
94+ becomes pixels.
95+ - Script and base-direction detection (` detect_script ` , ` detect_direction ` ).
96+ - ` NormalizationPolicy ` — opt-in, idempotent transforms for diacritics, tatweel,
97+ alef/ya/ta-marbuta unification, numeral systems and whitespace. Each one changes the
98+ label, so each one is explicit and recorded.
99+ - Bidi/shaping with two interchangeable backends: ` TransparentShaper ` when Pillow has
100+ Raqm, ` ReshaperBidiShaper ` (arabic-reshaper + python-bidi) otherwise. Both keep the
101+ logical string as the label so datasets are identical across machines.
102+ - Font glyph coverage via fontTools ` cmap ` (` supports_text ` , ` fonts_supporting ` ), so a
103+ font that cannot draw a character is rejected instead of silently emitting tofu.
104+
11105- Development tooling: ruff lint/format configuration, pytest configuration with
12106 ` pythonpath = ["src"] ` (so a clean clone is testable without installing), coverage
13107 settings, and a GitHub Actions CI matrix over Linux/Windows and Python 3.10/3.12.
@@ -22,8 +116,19 @@ All notable changes to this project are documented here. The format follows
22116- ` HuggingFaceTextLoader ` accepts any iterable of mappings, streams records via
23117 ` iter_texts ` , and defers the ` datasets ` import to call time.
24118
119+ ### Removed
120+
121+ - The v0 engine and everything coupled to it: ` OCRSmithEngine ` , ` core/app.py ` , the four
122+ ` *Manager ` classes, and the ` augmentation ` , ` text_renderers ` , ` text_placement ` ,
123+ ` backgrounds ` and ` fonts ` strategy packages. Their responsibilities now live in
124+ ` core/rendering ` , ` core/documents ` , ` core/degradations ` , ` core/fonts.py ` ,
125+ ` core/backgrounds.py ` and ` pipeline/ ` , with word-level ground truth throughout.
126+ - ` ocrsmith.utils ` , whose remaining helpers had no callers.
127+
25128### Fixed
26129
27130- ` wrap_text_by_pixels ` raised ` TypeError ` when ` layout.max_width ` / ` layout.max_height `
28131 were unset, which made every sample fail for configs that omit them.
29132- Whitespace-only input no longer produces a zero-sized canvas.
133+
134+ [ 1.0.0 ] : https://github.com/atlasia-ma/OCRSmith/releases/tag/v1.0.0
0 commit comments