Grouping : smaller groups, but be smarter

annotating : fix sorting for good
master
Sébastien Miquel 2026-01-18 15:26:32 +01:00
parent 78d4a61eb2
commit 3c84e33770
2 changed files with 65 additions and 57 deletions

View File

@ -381,6 +381,8 @@ def concat_display_image(subdir):
if not images: if not images:
return return
images.sort(key=lambda f: [int(n) for n in re.findall(r'\d+', str(f))])
# Load images # Load images
opened_imgs = [Image.open(img) for img in images] opened_imgs = [Image.open(img) for img in images]
@ -402,41 +404,6 @@ def concat_display_image(subdir):
print(f"Saved: {save_path}") print(f"Saved: {save_path}")
# subprocess.call(('xdg-open', save_path)) # subprocess.call(('xdg-open', save_path))
def concat_anot_images(directory):
root = Path(directory)
for subdir in root.iterdir():
if subdir.is_dir() and subdir.name.startswith("Anot"):
# Find valid images, excluding previous concatenations
images = sorted([
f for f in subdir.glob("*.jpg")
if f.name != "Concat.jpg"
])
images.sort(key=lambda f: [int(n) for n in re.findall(r'\d+', f)])
if not images:
continue
# Load images
opened_imgs = [Image.open(img) for img in images]
# Calculate dimensions (max width, sum of heights)
max_w = max(i.width for i in opened_imgs)
total_h = sum(i.height for i in opened_imgs)
# Create canvas and paste vertically
canvas = Image.new('RGB', (max_w, total_h))
current_y = 0
for img in opened_imgs:
canvas.paste(img, (0, current_y))
current_y += img.height
# Save
save_path = subdir / "Concat.jpg"
canvas.save(save_path)
print(f"Saved: {save_path}")
subprocess.call(('xdg-open', save_path))
if len(sys.argv) < 2: if len(sys.argv) < 2:

View File

@ -11,7 +11,7 @@ from pdf2image import convert_from_path, pdfinfo_from_path
DPI = 200 # Good balance for readability and size DPI = 200 # Good balance for readability and size
A4_HEIGHT_INCHES = 11.69 A4_HEIGHT_INCHES = 11.69
FULL_PAGE_PX = int(A4_HEIGHT_INCHES * DPI) FULL_PAGE_PX = int(A4_HEIGHT_INCHES * DPI)
MAX_GROUP_HEIGHT = 2.5 * FULL_PAGE_PX MAX_GROUP_HEIGHT = 2. * FULL_PAGE_PX
MAX_GROUP_COUNT = 15 MAX_GROUP_COUNT = 15
SEPARATOR_HEIGHT = 20 SEPARATOR_HEIGHT = 20
LABEL_HEIGHT = 50 LABEL_HEIGHT = 50
@ -79,38 +79,79 @@ def collect_files(root_dir):
return data return data
def group_files(file_list): def group_files(file_list):
"""Groups files based on constraints.""" """
sorted_files = sorted(file_list, key=lambda x: x[0]) Groups files using First Fit Decreasing algorithm to minimize group count.
"""
# 1. Sort by height DESCENDING. Large items are hardest to fit, handle them first.
# (Remove this sort if you must strictly preserve input order logic)
sorted_files = sorted(file_list, key=lambda x: x[2], reverse=True)
# Each group is a dict: {'items': [], 'current_height': 0}
groups = [] groups = []
current_group = []
current_height = 0
for item in sorted_files: for item in sorted_files:
dd, path, height = item dd, path, height = item
placed = False
# Calculate added height (image + separator + approx text space) # 2. Try to fit item into an existing group (First Fit)
# We add separator height only if it's not the first image for group in groups:
added_overhead = SEPARATOR_HEIGHT + 30 if current_group else 0 # Check Count Constraint
if len(group['items']) >= MAX_GROUP_COUNT:
continue
# Check conditions # Calculate Overhead (only if group is not empty)
if (len(current_group) >= MAX_GROUP_COUNT or overhead = (SEPARATOR_HEIGHT + 30) if group['items'] else 0
(current_height + height + added_overhead) > MAX_GROUP_HEIGHT):
# Push current group and start new # Check Height Constraint
if current_group: if (group['current_height'] + height + overhead) <= MAX_GROUP_HEIGHT:
groups.append(current_group) group['items'].append(item)
current_group = [] group['current_height'] += height + overhead
current_height = 0 placed = True
added_overhead = 0 # Reset for first file of new group break
current_group.append(item) # 3. If it doesn't fit anywhere, create a new group
current_height += height + added_overhead if not placed:
groups.append({
'items': [item],
'current_height': height
})
if current_group: # Return list of lists (strip the metadata)
groups.append(current_group) return [g['items'] for g in groups]
return groups # def group_files(file_list):
# """Groups files based on constraints."""
# sorted_files = sorted(file_list, key=lambda x: x[0])
# groups = []
# current_group = []
# current_height = 0
# for item in sorted_files:
# dd, path, height = item
# # Calculate added height (image + separator + approx text space)
# # We add separator height only if it's not the first image
# added_overhead = SEPARATOR_HEIGHT + 30 if current_group else 0
# # Check conditions
# if (len(current_group) >= MAX_GROUP_COUNT or
# (current_height + height + added_overhead) > MAX_GROUP_HEIGHT):
# # Push current group and start new
# if current_group:
# groups.append(current_group)
# current_group = []
# current_height = 0
# added_overhead = 0 # Reset for first file of new group
# current_group.append(item)
# current_height += height + added_overhead
# if current_group:
# groups.append(current_group)
# return groups
def stitch_pdf_pages(images_list): def stitch_pdf_pages(images_list):
"""Vertically concatenates a list of PIL images with no separator.""" """Vertically concatenates a list of PIL images with no separator."""