Fix review snapshots without handwriting images

This commit is contained in:
sebastien committed 2026-11-03 09:30:50 +01:00
1 parent 5dd0dd2ce9
commit fd943696fb
2 files changed
+33 -3

No files matched your search

+8 -2
View File
@@ -45,8 +45,11 @@ def stage(output, staging, data, notes, *, engine, bnote=None, selected=None, fo
merged_notes.pop(label, None) merged_notes.pop(label, None)
note = notes.get(label) note = notes.get(label)
if note is not None: if note is not None:
filename = '.review-note-' + sha256(label.encode()).hexdigest() + '.png' # Grouped scans retain layout metadata even without handwriting.
note['img'].save(staging / filename) filename = None
if note['img'] is not None:
filename = '.review-note-' + sha256(label.encode()).hexdigest() + '.png'
note['img'].save(staging / filename)
merged_notes[label] = {k: v for k, v in note.items() if k != 'img'} | {'file': filename} merged_notes[label] = {k: v for k, v in note.items() if k != 'img'} | {'file': filename}
payload = {'version': 1, 'engine': engine, 'data': merged_data, 'notes': merged_notes, 'bnote': bnote, 'force_filtered': sorted(retained)} payload = {'version': 1, 'engine': engine, 'data': merged_data, 'notes': merged_notes, 'bnote': bnote, 'force_filtered': sorted(retained)}
# Roundtrip normalizes tuples while rejecting unsupported rendering data. # Roundtrip normalizes tuples while rejecting unsupported rendering data.
@@ -64,6 +67,9 @@ def load(root, output):
notes = {} notes = {}
for label, metadata in saved['notes'].items(): for label, metadata in saved['notes'].items():
filename = metadata['file'] filename = metadata['file']
if filename is None:
notes[label] = {k: v for k, v in metadata.items() if k != 'file'} | {'img': None}
continue
if Path(filename).name != filename: if Path(filename).name != filename:
raise ValueError('Image manuscrite invalide.') raise ValueError('Image manuscrite invalide.')
with Image.open(output / filename) as image: with Image.open(output / filename) as image:
+25 -1
View File
@@ -177,6 +177,29 @@ class WebTests(unittest.TestCase):
class SnapshotTests(unittest.TestCase): class SnapshotTests(unittest.TestCase):
def test_grouped_layout_without_handwriting_replaces_previous_ink(self):
from copienator.review_snapshot import stage, load
from copienator.annotation_layout import legacy_layout
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
seed(root, 'BGnot')
output = root / 'BGnot/Copie01'
data = {label: {'pdf_path': root / f'{label}.pdf', 'result': {'score': 3}}
for label in ('Ex 1', 'Ex 2')}
ink = Image.new('RGBA', (100, 120), 'red')
notes = {label: {'img': ink, 'old_header_h': 20, 'layout': legacy_layout()}
for label in data}
with staged_files(output) as staging:
stage(output, staging, data, notes, engine='grouped')
notes['Ex 1']['img'] = None
for selected in ({'Ex 1'}, None):
with staged_files(output) as staging:
stage(output, staging, data, notes, engine='grouped', selected=selected)
saved, _, restored = load(root, output)
self.assertIsNone(saved['notes']['Ex 1']['file'])
self.assertEqual(restored['Ex 1'], notes['Ex 1'])
self.assertEqual(restored['Ex 2']['img'].getpixel((0, 0)), (255, 0, 0, 255))
def test_selective_redo_merges_raw_inputs_and_preserves_handwriting(self): def test_selective_redo_merges_raw_inputs_and_preserves_handwriting(self):
from copienator.review_snapshot import stage, load from copienator.review_snapshot import stage, load
with tempfile.TemporaryDirectory() as temporary: with tempfile.TemporaryDirectory() as temporary:
@@ -214,8 +237,9 @@ class SnapshotTests(unittest.TestCase):
pdf = root / 'Copies/Copie01/Ex 1.pdf' pdf = root / 'Copies/Copie01/Ex 1.pdf'
pdf.write_bytes(b'placeholder') pdf.write_bytes(b'placeholder')
data = {'Ex 1': {'pdf_path': pdf, 'result': {'score': 3, 'feedback': []}, 'coordinates': [0,0]}} data = {'Ex 1': {'pdf_path': pdf, 'result': {'score': 3, 'feedback': []}, 'coordinates': [0,0]}}
notes = {'Ex 1': {'img': None, 'old_header_h': 20}} if mode == 'BGnot' else {}
with staged_files(output) as staging: with staged_files(output) as staging:
stage(output, staging, data, {}, engine='standard' if mode == 'Bnot' else 'grouped', stage(output, staging, data, notes, engine='standard' if mode == 'Bnot' else 'grouped',
bnote={'images':[{'label':'Ex 1','header_height':20}]}) bnote={'images':[{'label':'Ex 1','header_height':20}]})
set_remark(root, '01', 'Ex 1', 'Une seule remarque') set_remark(root, '01', 'Ex 1', 'Une seule remarque')
with patch.object(annotating, 'make_base_image', return_value=(Image.new('RGB',(100,100),'white'),0,0)), \ with patch.object(annotating, 'make_base_image', return_value=(Image.new('RGB',(100,100),'white'),0,0)), \