Testcomic / backend /pdf_generator.py
3v324v23's picture
Update Comic123 with local comic folder files
83e35a7
"""
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