mirror of
https://git.pumpin.online/funkpower/catena.git
synced 2026-10-23 03:07:13 +00:00
82 lines
2.4 KiB
Python
82 lines
2.4 KiB
Python
"""Decide 2-up scans the way the book pipeline did, for comparison.
|
|||
|
|
|
||
|
|
The four functions below are the originals, copied out of the preprocessing
|
||
|
|
module verbatim — importing it would pull in a PDF renderer and a page tree,
|
||
|
|
and none of that decides anything. What decides is the arithmetic, which is
|
||
|
|
what this compares.
|
||
|
|
|
||
|
|
python3 oracle/pdfgutter.py < cases.ndjson
|
||
|
|
|
||
|
|
One case per line, tagged with what it is asking about. Writes one JSON
|
||
|
|
answer per line.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import json
|
||
|
|
import sys
|
||
|
|
|
||
|
|
import numpy as np
|
||
|
|
|
||
|
|
_MIN_RATIO = 1.15
|
||
|
|
_MIN_GUTTER_FRAC = 0.6
|
||
|
|
_TEXT_COL_INK = 0.02
|
||
|
|
|
||
|
|
|
||
|
|
def _ratio(width: float, height: float) -> float:
|
||
|
|
return width / height if height else 0.0
|
||
|
|
|
||
|
|
|
||
|
|
def _has_gutter(ink: np.ndarray) -> bool:
|
||
|
|
w = len(ink)
|
||
|
|
center = ink[int(0.46 * w):int(0.54 * w)]
|
||
|
|
left = ink[int(0.10 * w):int(0.44 * w)]
|
||
|
|
right = ink[int(0.56 * w):int(0.90 * w)]
|
||
|
|
if center.size == 0 or left.size == 0 or right.size == 0:
|
||
|
|
return False
|
||
|
|
return bool(
|
||
|
|
center.min() < _TEXT_COL_INK
|
||
|
|
and np.median(left) > _TEXT_COL_INK
|
||
|
|
and np.median(right) > _TEXT_COL_INK
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def _sample_indices(n: int, k: int = 8) -> list[int]:
|
||
|
|
if n <= 6:
|
||
|
|
return list(range(n))
|
||
|
|
lo, hi = 2, n - 3
|
||
|
|
step = max(1, (hi - lo) // k)
|
||
|
|
return list(range(lo, hi + 1, step))[:k]
|
||
|
|
|
||
|
|
|
||
|
|
def _verdict(ratios: list[float], gutters: list[bool]) -> dict:
|
||
|
|
median_ratio = float(np.median(ratios)) if ratios else 0.0
|
||
|
|
gutter_frac = (sum(gutters) / len(gutters)) if gutters else 0.0
|
||
|
|
return {
|
||
|
|
"median_ratio": median_ratio,
|
||
|
|
"gutter_fraction": gutter_frac,
|
||
|
|
"two_up": bool(median_ratio > _MIN_RATIO and gutter_frac >= _MIN_GUTTER_FRAC),
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def answer(case: dict) -> dict:
|
||
|
|
kind = case["kind"]
|
||
|
|
if kind == "ratio":
|
||
|
|
return {"ratio": _ratio(case["width"], case["height"])}
|
||
|
|
if kind == "gutter":
|
||
|
|
return {"gutter": _has_gutter(np.asarray(case["ink"], dtype=float))}
|
||
|
|
if kind == "sample":
|
||
|
|
return {"indices": _sample_indices(case["pages"])}
|
||
|
|
if kind == "verdict":
|
||
|
|
return _verdict(case["ratios"], case["gutters"])
|
||
|
|
raise SystemExit(f"no such case: {kind}")
|
||
|
|
|
||
|
|
|
||
|
|
for line in sys.stdin:
|
||
|
|
if not line.strip():
|
||
|
|
continue
|
||
|
|
case = json.loads(line)
|
||
|
|
out = {"name": case["name"], "kind": case["kind"]}
|
||
|
|
out.update(answer(case))
|
||
|
|
sys.stdout.write(json.dumps(out, sort_keys=True) + "\n")
|