Initial support for user general remarks

This commit is contained in:
sebastien committed 2026-10-28 13:51:59 +01:00
1 parent a38c1ff4b3
commit 2c9dc65640
16 files changed
+606 -20

No files matched your search

+75
View File
@@ -118,6 +118,81 @@ class LeftMarginTests(unittest.TestCase):
mask[300:960] = False
self.assertIsNone(left_margin.body_edge(mask)['edge_mm'])
def test_bands_starting_beyond_midpoint_are_empty_for_both_windows(self):
mask = np.zeros((1169, 827), bool)
for y in range(370, 1050, 35):
mask[y:y + 5, 450:550] = True
result = left_margin.body_edge(mask)
self.assertIsNone(result['edge_mm'])
self.assertEqual(result['band_starts_mm'], [])
self.assertEqual(result['label_band_starts_mm'], [])
mask[400:410, 100:200] = True
self.assertTrue(left_margin.body_edge(mask)['band_starts_mm'])
def test_label_window_keeps_lower_body_but_excludes_names_and_bottom_eight_percent(self):
mask = np.zeros((1169, 827), bool)
mask[100:300, 5:80] = True # Name/header; exclude from both pools.
mask[1100:1150, 5:80] = True # Footer; below 92%.
for y in range(370, 920, 35):
mask[y:y + 5, 170:270] = True
mask[1000:1010, 40:140] = True # Label at 85.5%; new window only.
result = left_margin.body_edge(mask)
self.assertGreater(min(result['band_starts_mm']), 40)
self.assertAlmostEqual(min(result['label_band_starts_mm']), 10.16)
def test_fifth_percentile_detects_labels_while_page_decile_stays_at_body(self):
images = [Image.new('RGB', (1654, 200)) for _ in range(6)]
bands = [5.] * 7 + [42.] * 93
estimate = {'edge_mm': left_margin.trimmed_left_edge(bands),
'bands': len(bands), 'band_starts_mm': bands,
'label_band_starts_mm': bands}
with patch.object(left_margin, 'estimate_page', return_value=estimate):
result = left_margin.analyse_margins(images, 200, 1654)
group = result['groups'][0]
self.assertEqual(group['edge_mm'], 42)
self.assertEqual(group['body_left_mm'], 22)
self.assertEqual(group['label_edge_mm'], 5)
self.assertTrue(group['labels_in_margin'])
self.assertEqual(result['starts_px'], [0] * 6)
def test_unsampled_coherent_page_can_move_the_whole_group_left(self):
images = [Image.new('RGB', (1654, 200)) for _ in range(6)]
def estimate(image, _dpi):
labels = [5.] * 20 if image is images[2] else []
return {'edge_mm': 42, 'bands': 12, 'band_starts_mm': [42.] * 12,
'label_band_starts_mm': labels + [42.] * 12}
with patch.object(left_margin, 'estimate_page', side_effect=estimate):
result = left_margin.analyse_margins(images, 200, 1654)
group = result['groups'][0]
self.assertNotIn(3, [p['page'] for p in group['samples']])
self.assertIn(3, group['coherent_pages'])
self.assertEqual(result['starts_px'], [0] * 6)
def test_sparse_or_incoherent_pages_do_not_supply_label_evidence(self):
images = [Image.new('RGB', (1654, 200)) for _ in range(6)]
edges = [42, 42, None, 42, 65, 42]
def estimate(image, _dpi):
edge = edges[next(i for i, candidate in enumerate(images) if candidate is image)]
return {'edge_mm': edge, 'bands': 12, 'band_starts_mm': [edge or 42.] * 12,
'label_band_starts_mm': [1.] * 20 if edge in (None, 65) else [42.] * 12}
with patch.object(left_margin, 'estimate_page', side_effect=estimate):
result = left_margin.analyse_margins(images, 200, 1654)
group = result['groups'][0]
self.assertEqual(group['coherent_pages'], [1, 2, 4, 6])
self.assertFalse(group['labels_in_margin'])
self.assertGreater(result['starts_px'][0], 0)
def test_less_than_five_percent_noise_or_small_gap_does_not_trigger_labels(self):
for bands in ([1.] * 4 + [42.] * 96, [35.] * 7 + [42.] * 93):
with self.subTest(bands=bands[:8]):
images = [Image.new('RGB', (1654, 200)) for _ in range(2)]
estimate = {'edge_mm': 42, 'bands': 100, 'band_starts_mm': [42.] * 100,
'label_band_starts_mm': bands}
with patch.object(left_margin, 'estimate_page', return_value=estimate):
result = left_margin.analyse_margins(images, 200, 1654)
self.assertFalse(result['groups'][0]['labels_in_margin'])
self.assertGreater(result['starts_px'][0], 0)
def test_real_mask_rejects_ruling_and_preserves_handwriting(self):
image = Image.new('RGB', (827, 1169), 'white')
draw = ImageDraw.Draw(image)