File size: 4,061 Bytes
563a0f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
"""Génère les images PNG du corpus de référence (Sprint A5, M-14).

Idempotent : produit les mêmes octets à chaque exécution grâce à la
police par défaut Pillow (police bitmap interne, ne dépend pas du
système). Les fichiers sont écrits à côté de ce script.

Exécution :

    python tests/fixtures/reference_corpus/_generate.py

Le workflow CI ``perf_regression.yml`` régénère les fichiers en début
de run pour s'assurer qu'ils sont à jour vis-à-vis du code de
génération.
"""

from __future__ import annotations

from pathlib import Path

# Chaque entrée = (id, ligne_1, ligne_2_optionnelle, ...).
# Les textes sont en français pour exercer Tesseract `fra`.
_DOCUMENTS: list[tuple[str, list[str]]] = [
    (
        "doc_01_imprime_moderne",
        [
            "Picarones est une plateforme de banc d'essai",
            "pour des moteurs OCR sur documents",
            "patrimoniaux. Cette image est synthetique.",
        ],
    ),
    (
        "doc_02_chiffres_dates",
        [
            "Charte du 14 mars 1789, signee par",
            "le notaire Jean Dupont. Folio 23 verso.",
            "Tarif: 5 livres 12 sols 6 deniers.",
        ],
    ),
    (
        "doc_03_noms_propres",
        [
            "Liste des temoins :",
            "Marie Lefevre, Pierre Bernard,",
            "Antoine Rousseau, Catherine Moreau.",
        ],
    ),
    (
        "doc_04_courte_phrase",
        [
            "L'ancien Regime se termine en 1789.",
        ],
    ),
    (
        "doc_05_paragraphe_long",
        [
            "Au commencement de l'an mille sept cent",
            "quatre vingt neuf, le royaume de France",
            "comptait environ vingt huit millions",
            "d'habitants. Paris seule en hebergeait",
            "six cent cinquante mille.",
        ],
    ),
]


def _render_one(out_dir: Path, doc_id: str, lines: list[str]) -> None:
    """Rend une image PNG + son fichier .gt.txt à côté.

    Police : police bitmap interne de Pillow (``ImageFont.load_default``)
    pour que l'image soit identique sur tous les systèmes (pas de
    dépendance à des polices installées).
    """
    from PIL import Image, ImageDraw, ImageFont

    font = ImageFont.load_default()
    # On rend large pour que Tesseract ait de quoi mâcher.
    line_height = 30
    margin = 20
    width = 800
    height = margin * 2 + line_height * len(lines)

    img = Image.new("RGB", (width, height), color=(255, 255, 245))
    draw = ImageDraw.Draw(img)
    for i, line in enumerate(lines):
        # Échelle x4 par redimensionnement : on rend petit puis on
        # upscale pour obtenir un texte ~24 px de haut, lisible par
        # Tesseract sans nécessiter une vraie police TrueType.
        small = Image.new("RGB", (width // 4, line_height // 4 * len(lines)), color=(255, 255, 245))
        small_draw = ImageDraw.Draw(small)
        small_draw.text((5, 5 + i * line_height // 4), line, fill=(20, 20, 20), font=font)
        # Composite en upscale dans le canvas final.
        # (On garde la version brute pour rester déterministe.)
        del small_draw, small
        draw.text((margin, margin + i * line_height), line, fill=(20, 20, 20), font=font)

    png_path = out_dir / f"{doc_id}.png"
    img.save(png_path, format="PNG", optimize=True)

    gt_path = out_dir / f"{doc_id}.gt.txt"
    gt_path.write_text("\n".join(lines) + "\n", encoding="utf-8")


def generate(out_dir: Path | None = None) -> Path:
    """Régénère le corpus dans ``out_dir`` (défaut : à côté de ce script).

    Retourne le chemin du dossier."""
    if out_dir is None:
        out_dir = Path(__file__).parent
    out_dir = Path(out_dir)
    out_dir.mkdir(parents=True, exist_ok=True)

    for doc_id, lines in _DOCUMENTS:
        _render_one(out_dir, doc_id, lines)
    return out_dir


if __name__ == "__main__":
    p = generate()
    print(f"Corpus de référence (re)généré dans {p}")
    print(f"  {len(_DOCUMENTS)} documents, "
          f"~{sum(len(lines) for _, lines in _DOCUMENTS)} lignes au total.")