Skip to content

feat(text): script detection, normalisation, bidi shaping and glyph coverage - #3

Merged
hBouanane merged 5 commits into
chore/dev-toolingfrom
feat/arabic-shaping
Aug 12, 2026
Merged

feat(text): script detection, normalisation, bidi shaping and glyph coverage#3
hBouanane merged 5 commits into
chore/dev-toolingfrom
feat/arabic-shaping

Conversation

@hBouanane

Copy link
Copy Markdown
Collaborator

2 of 9 in the v1.0.0 series. Base: chore/dev-tooling.

Why

Arabic ground truth has two representations that must never be confused: the logical string a model predicts, and the visual string the rasteriser draws. Mixing them up is the single most common way to produce an unusable Arabic OCR dataset, and it is invisible until training plateaus.

What

New ocrsmith.text package.

  • script.py — script classification and first-strong-character base direction.

  • normalization.pyNormalizationPolicy: opt-in, idempotent transforms for diacritics, tatweel, alef/ya/ta-marbuta unification, numeral systems (Western / Arabic-Indic / Eastern), whitespace. Every one of these rewrites the label, so none is applied silently.

  • shaping.py — two interchangeable backends behind one protocol:

    • TransparentShaper when Pillow was built with Raqm (HarfBuzz shapes and reorders);
    • ReshaperBidiShaper otherwise (arabic-reshaper + python-bidi produce presentation forms and visual order).

    Both keep the logical string as the label, so the dataset does not depend on how Pillow was compiled.

  • coverage.py — exact glyph coverage read from the font's cmap via fontTools, cached per file. A font that cannot draw a character becomes rejectable instead of silently rendering tofu that contradicts the label.

Adds fonttools; drops two empty placeholder modules.

Verified

106 tests green. Coverage tests run against the bundled Arabic fonts.

hBouanane and others added 5 commits August 12, 2026 21:43
…ph coverage

Arabic ground truth has two representations that must never be confused: the
logical string the model predicts and the visual string the rasteriser draws.
ocrsmith.text makes that split explicit.

- script.py: script classification and first-strong-character base direction.
- normalization.py: NormalizationPolicy with opt-in, idempotent transforms
  (diacritics, tatweel, alef/ya/ta-marbuta unification, numeral systems,
  whitespace). Every transform changes the label, so none is applied silently.
- shaping.py: two interchangeable backends behind one protocol. Pillow builds
  with Raqm shape and reorder themselves (TransparentShaper); builds without it
  get presentation forms and visual reordering from arabic-reshaper +
  python-bidi (ReshaperBidiShaper). Both keep the logical label identical, so
  the dataset does not depend on how Pillow was compiled.
- coverage.py: exact cmap coverage via fontTools, cached per font file. A font
  that cannot draw a character is now rejectable instead of silently rendering
  tofu that contradicts the label.

Adds fonttools as a dependency and drops two empty placeholder modules.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@hBouanane
hBouanane merged commit 69cdfa0 into chore/dev-tooling Aug 12, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant