Use per-page annotation spacing with inferred margin fallback

This commit is contained in:
sebastien committed 2026-11-03 12:02:06 +01:00
1 parent b069805988
commit 0bb6f7d97c
10 files changed
+170 -39

No files matched your search

+21 -3
View File
@@ -27,6 +27,15 @@ STANDARD_LINE_HEIGHT_MM = 8
MAX_EXCEPTION_LINES = 4
def margins_with_fallback(pages: list[dict]) -> list[dict]:
"""Keep measurements intact; unknown pages borrow the copy's measured mean."""
known = [page['edge_mm'] for page in pages if page.get('edge_mm') is not None]
average = sum(known) / len(known) if known else None
return [{**page, 'effective_edge_mm': (
page['edge_mm'] if page.get('edge_mm') is not None else average
)} for page in pages]
def trimmed_left_edge(starts: list[float]) -> float | None:
"""Discard the leftmost 10% of occupied bands; retain the next minimum."""
if not starts:
@@ -142,9 +151,13 @@ def analyse_margins(images: list[Image.Image], render_dpi: int, reference_width:
if name_localized else estimate_page(images[index], render_dpi))
return page_estimates[index]
page_estimates = dict(enumerate(margins_with_fallback(
[page_estimate(index) for index in range(len(images))])))
for indices in format_groups(images, reference_width):
estimates = {index: page_estimate(index) for index in indices}
values = [item['edge_mm'] for item in estimates.values() if item['edge_mm'] is not None]
values = [item['effective_edge_mm'] for item in estimates.values()
if item['effective_edge_mm'] is not None]
band_starts = [start for item in estimates.values() for start in item['band_starts_mm']]
status = 'insufficient-ink'
edge = round(float(np.median(values)), 1) if values else None
@@ -178,10 +191,15 @@ def analyse_margins(images: list[Image.Image], render_dpi: int, reference_width:
previous_coherent = 0
for index in indices:
estimate = page_estimate(index)
low = estimate['edge_mm'] is not None and estimate['edge_mm'] < MIN_MARGIN_MM
effective_edge = estimate['effective_edge_mm']
low = effective_edge is not None and effective_edge < MIN_MARGIN_MM
tolerated = (status == 'margin' and low and previous_coherent >= 2
and short_margin_exception(estimate, edge))
starts[index] = 0 if low and not tolerated else start
if estimate['edge_mm'] is None and status not in {'narrow-page', 'labels-in-margin'}:
fallback_left = (max(effective_edge / 2, effective_edge - MARGIN_CLEARANCE_MM)
if effective_edge is not None and effective_edge >= MIN_MARGIN_MM else 0)
starts[index] = round(fallback_left * render_dpi / 25.4)
estimate['short_margin_exception'] = tolerated
estimate['decision'] = ('short-exception' if tolerated else
'page-near-edge' if low else status)
@@ -209,7 +227,7 @@ def analyse_margins(images: list[Image.Image], render_dpi: int, reference_width:
'status': 'unknown' if edge is None else
('low' if edge < MIN_MARGIN_MM else 'normal')})
return {'version': 13, 'pages': pages, 'starts_px': starts, 'groups': groups,
return {'version': 14, 'pages': pages, 'starts_px': starts, 'groups': groups,
'no_margin_from_page': None,
'discard_left_fraction': DISCARD_LEFT_FRACTION, 'margin_clearance_mm': MARGIN_CLEARANCE_MM,
'cut_fraction_of_margin': .5, 'cut_rule': 'maximum',