""" PDF Generator for Edited Comics Generates PDF from comic with user edits preserved """ import os from reportlab.lib.pagesizes import A4 from reportlab.pdfgen import canvas from reportlab.lib.utils import ImageReader from PIL import Image, ImageDraw, ImageFont import json class ComicPDFGenerator: """Generate PDF from edited comic data""" def __init__(self): self.page_width = A4[0] self.page_height = A4[1] self.margin = 20 def generate_pdf(self, pages_data, edited_bubbles, output_path="output/comic_edited.pdf"): """ Generate PDF with edited text and positions Args: pages_data: Original comic pages data edited_bubbles: List of edited bubble data (text, position) output_path: Output PDF path """ # Create PDF c = canvas.Canvas(output_path, pagesize=A4) bubble_index = 0 for page_num, page in enumerate(pages_data): if page_num > 0: c.showPage() # Add page title c.setFont("Helvetica-Bold", 16) c.drawString(self.margin, self.page_height - 30, f"Page {page_num + 1}") # Calculate panel layout panels_per_page = len(page['panels']) if panels_per_page <= 4: cols, rows = 2, 2 else: cols, rows = 3, 2 panel_width = (self.page_width - self.margin * 2 - 10 * (cols - 1)) / cols panel_height = (self.page_height - 100 - 10 * (rows - 1)) / rows # Draw panels for i, panel in enumerate(page['panels']): row = i // cols col = i % cols x = self.margin + col * (panel_width + 10) y = self.page_height - 60 - (row + 1) * (panel_height + 10) # Draw panel image img_path = os.path.join('frames/final', panel['image']) if os.path.exists(img_path): img = Image.open(img_path) img_reader = ImageReader(img) c.drawImage(img_reader, x, y, width=panel_width, height=panel_height, preserveAspectRatio=True) # Draw border c.setStrokeColorRGB(0, 0, 0) c.setLineWidth(2) c.rect(x, y, panel_width, panel_height) # Draw bubbles for this panel for bubble in page.get('bubbles', []): if bubble_index < len(edited_bubbles): edited_bubble = edited_bubbles[bubble_index] # Use edited text and position text = edited_bubble.get('text', bubble['dialog']) # Calculate bubble position if edited_bubble.get('left') and edited_bubble.get('top'): # Convert CSS position to PDF coordinates bubble_x = x + self._parse_position(edited_bubble['left'], panel_width) bubble_y = y + panel_height - self._parse_position(edited_bubble['top'], panel_height) - 30 else: # Use default position bubble_x = x + bubble['bubble_offset_x'] bubble_y = y + panel_height - bubble['bubble_offset_y'] - 30 # Draw speech bubble self._draw_speech_bubble(c, bubble_x, bubble_y, text) bubble_index += 1 # Save PDF c.save() return output_path def _parse_position(self, css_value, max_value): """Convert CSS position (e.g., '50px') to numeric value""" if isinstance(css_value, str) and css_value.endswith('px'): return float(css_value[:-2]) return 0 def _draw_speech_bubble(self, canvas, x, y, text): """Draw a speech bubble with text""" # Measure text canvas.setFont("Helvetica-Bold", 10) text_width = canvas.stringWidth(text, "Helvetica-Bold", 10) # Wrap text if needed words = text.split() lines = [] current_line = [] max_width = 150 for word in words: test_line = ' '.join(current_line + [word]) if canvas.stringWidth(test_line, "Helvetica-Bold", 10) > max_width: if current_line: lines.append(' '.join(current_line)) current_line = [word] else: lines.append(word) else: current_line.append(word) if current_line: lines.append(' '.join(current_line)) # Calculate bubble size bubble_width = min(max_width + 20, 180) bubble_height = len(lines) * 15 + 20 # Draw bubble background canvas.setFillColorRGB(1, 1, 1) canvas.setStrokeColorRGB(0, 0, 0) canvas.setLineWidth(2) # Rounded rectangle for bubble canvas.roundRect(x, y, bubble_width, bubble_height, 10, fill=1, stroke=1) # Draw text canvas.setFillColorRGB(0, 0, 0) text_y = y + bubble_height - 15 for line in lines: canvas.drawString(x + 10, text_y, line) text_y -= 15 def generate_from_html(self, html_path, edited_data, output_path="output/comic_edited.pdf"): """ Alternative: Generate PDF from edited HTML This would require parsing the HTML and extracting positions """ # This is a placeholder for HTML-based PDF generation # In practice, you might use tools like wkhtmltopdf or Playwright pass def generate_edited_pdf(request_data): """ Generate PDF from edit request Args: request_data: Dict with edited bubble data """ generator = ComicPDFGenerator() # Load original pages data with open('output/pages.json', 'r') as f: pages_data = json.load(f) # Get edited bubbles edited_bubbles = request_data.get('bubbles', []) # Generate PDF output_path = generator.generate_pdf(pages_data, edited_bubbles) return output_path