lsatone / backend /fixed_12_pages_2x2.py
3v324v23's picture
Update Comic123 with local comic folder files
83e35a7
"""
Generate 12 pages of 2x2 grid comics (48 panels total)
Only selecting meaningful story moments
"""
from backend.class_def import panel, Page
def generate_12_pages_2x2_grid(frame_files, bubbles):
"""Generate 12 pages, each with 2x2 grid (4 panels per page)"""
pages = []
panels_per_page = 4 # 2x2 grid
total_pages = 12
target_panels = total_pages * panels_per_page # 48 panels
# Select meaningful frames (up to 48)
selected_frames = select_meaningful_frames(frame_files, target_panels)
num_frames = len(selected_frames)
print(f"πŸ“„ Generating {total_pages} pages with 2x2 grid")
print(f"🎯 Selected {num_frames} meaningful frames from {len(frame_files)} total")
frame_idx = 0
bubble_idx = 0
# Create 12 pages
for page_num in range(total_pages):
page_panels = []
page_bubbles = []
# Create 4 panels for this page (2x2 grid)
for i in range(panels_per_page):
if frame_idx < num_frames:
# Each panel takes 1/4 of the page
panel_obj = panel(
image=selected_frames[frame_idx],
row_span=6, # Half the height (12/2 = 6)
col_span=6 # Half the width (12/2 = 6)
)
page_panels.append(panel_obj)
# Add corresponding bubble if available
if bubble_idx < len(bubbles):
page_bubbles.append(bubbles[bubble_idx])
bubble_idx += 1
frame_idx += 1
else:
# Create empty panel if we run out of frames
panel_obj = panel(
image=selected_frames[0] if selected_frames else 'blank.png',
row_span=6,
col_span=6
)
page_panels.append(panel_obj)
# Create 2x2 arrangement
# Panel layout:
# [0][1]
# [2][3]
arrangement = [
'0011', # Row 1: Panel 0, Panel 1
'0011', # Row 2: Panel 0, Panel 1
'0011', # Row 3: Panel 0, Panel 1
'2233', # Row 4: Panel 2, Panel 3
'2233', # Row 5: Panel 2, Panel 3
'2233' # Row 6: Panel 2, Panel 3
]
# Create page (Page class doesn't take panel_arrangement parameter)
page = Page(
panels=page_panels,
bubbles=page_bubbles
)
pages.append(page)
# Show progress
panels_on_page = min(4, num_frames - (page_num * 4))
if panels_on_page > 0:
print(f" βœ“ Page {page_num + 1}: {panels_on_page} panels")
print(f"βœ… Generated {len(pages)} pages with {min(num_frames, target_panels)} total panels")
return pages
def select_meaningful_frames(all_frames, target_count):
"""Select frames to tell complete story"""
if len(all_frames) <= target_count:
print(f"πŸ“š Using all {len(all_frames)} frames (complete story)")
return all_frames
print(f"πŸ“š Selecting {target_count} frames from {len(all_frames)} to tell complete story")
# Smart selection based on story phases
# Allocate frames to different story parts:
# - Introduction: 8 panels (2 pages)
# - Development: 16 panels (4 pages)
# - Climax: 16 panels (4 pages)
# - Resolution: 8 panels (2 pages)
selected = []
total = len(all_frames)
# Introduction (first 15% of frames)
intro_end = int(total * 0.15)
intro_frames = all_frames[:intro_end]
intro_step = max(1, len(intro_frames) // 8)
selected.extend(intro_frames[::intro_step][:8])
# Development (15% to 50%)
dev_start = intro_end
dev_end = int(total * 0.5)
dev_frames = all_frames[dev_start:dev_end]
dev_step = max(1, len(dev_frames) // 16)
selected.extend(dev_frames[::dev_step][:16])
# Climax (50% to 85%)
climax_start = dev_end
climax_end = int(total * 0.85)
climax_frames = all_frames[climax_start:climax_end]
climax_step = max(1, len(climax_frames) // 16)
selected.extend(climax_frames[::climax_step][:16])
# Resolution (last 15%)
resolution_frames = all_frames[climax_end:]
resolution_step = max(1, len(resolution_frames) // 8)
selected.extend(resolution_frames[::resolution_step][:8])
# Ensure we have exactly the target count
if len(selected) > target_count:
selected = selected[:target_count]
elif len(selected) < target_count:
# Fill with evenly distributed frames
remaining = target_count - len(selected)
step = total // remaining
for i in range(remaining):
idx = i * step
if all_frames[idx] not in selected:
selected.append(all_frames[idx])
return selected[:target_count]