waffensachkunde

Waffensachkunde – Lernsoftware für die Sachkundeprüfung nach § 7 WaffG. Barrierefrei, offline, EUPL-1.2.

/ data-pipeline explore_layout.py

2,4 KB Rohdatei
data-pipeline/explore_layout.py — 69 Zeilen
1 # -*- coding: utf-8 -*-
2 """Vermisst das Tabellenlayout des BVA-Fragenkatalogs.
3
4 Erkundungsskript (kein Teil der Produktivpipeline): ermittelt Spaltengrenzen,
5 Zeilentrenner, Checkbox-Geometrie und Kapitelkopfzeilen, damit der eigentliche
6 Parser auf verifizierten Koordinaten aufsetzen kann.
7 """
8 import io
9 import sys
10 from collections import Counter
11
12 import fitz
13
14 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
15
16 PDF = r"C:\Antigravity\Waffensachkundeprüfung\Fragenkatalog_sachkunde_mitAntworten.pdf"
17
18 doc = fitz.open(PDF)
19 print(f"Seiten: {doc.page_count} Metadaten: {doc.metadata.get('title')!r} / {doc.metadata.get('author')!r}")
20
21 page = doc[5] # erste Fragenseite
22 print(f"\nSeitengröße: {page.rect}")
23
24 drawings = page.get_drawings()
25 print(f"Vektorobjekte auf Seite 6: {len(drawings)}")
26
27 vert_lines = Counter()
28 horiz_lines = Counter()
29 rects = []
30 for d in drawings:
31 for item in d["items"]:
32 if item[0] == "l": # Linie
33 p1, p2 = item[1], item[2]
34 if abs(p1.x - p2.x) < 0.6:
35 vert_lines[round(p1.x)] += 1
36 elif abs(p1.y - p2.y) < 0.6:
37 horiz_lines[round(p1.y)] += 1
38 elif item[0] == "re": # Rechteck
39 r = item[1]
40 rects.append(r)
41 if r.width < 1.5 and r.height > 3:
42 vert_lines[round(r.x0)] += 1
43 elif r.height < 1.5 and r.width > 3:
44 horiz_lines[round(r.y0)] += 1
45
46 print(f"\nVertikale Trenner (x -> Anzahl): {sorted(vert_lines.items())}")
47 print(f"Horizontale Trenner (y): {sorted(horiz_lines.items())[:40]}")
48
49 # Checkbox-Kandidaten: annähernd quadratische Rechtecke
50 boxes = [r for r in rects if 6 < r.width < 20 and 6 < r.height < 20 and abs(r.width - r.height) < 4]
51 print(f"\nCheckbox-Kandidaten: {len(boxes)}")
52 for b in boxes[:6]:
53 print(f" x0={b.x0:.1f} y0={b.y0:.1f} w={b.width:.1f} h={b.height:.1f}")
54
55 # Textblöcke mit Spaltenzuordnung
56 print("\n--- Textzeilen Seite 6 mit x-Positionen ---")
57 d = page.get_text("dict")
58 for block in d["blocks"]:
59 if block["type"] != 0:
60 continue
61 for line in block["lines"]:
62 txt = "".join(s["text"] for s in line["spans"]).strip()
63 if not txt:
64 continue
65 x0 = line["bbox"][0]
66 y0 = line["bbox"][1]
67 flags = {s["flags"] for s in line["spans"]}
68 fonts = {s["font"] for s in line["spans"]}
69 print(f" x={x0:6.1f} y={y0:6.1f} {txt[:62]!r} fonts={fonts} flags={flags}")