"""
PDF Generator for Sabbath School Lessons
This module handles the final conversion from HTML to PDF with specific pagination fixes.
"""
import os
import tempfile
from weasyprint import HTML, CSS, Document
[docs]
class PdfGenerator:
"""Handles conversion of HTML to PDF with pagination control."""
[docs]
@staticmethod
def count_pages_in_document(document):
"""
Count the number of pages in a WeasyPrint document
Args:
document (Document): WeasyPrint document
Returns:
int: Number of pages
"""
return len(document.pages)
[docs]
@staticmethod
def create_section_document(html_content):
"""
Create a WeasyPrint document for a section
Args:
html_content (str): HTML content
Returns:
Document: WeasyPrint document
"""
return HTML(string=html_content).render()
[docs]
@staticmethod
def create_blank_page_pdf(output_path):
"""
Generate a blank page PDF
Args:
output_path (str): Path to save the blank page PDF
Returns:
str: Path to the generated PDF
"""
html_content = """<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blank Page</title>
<style>
@page {
size: letter;
margin: 0;
}
body {
margin: 0;
padding: 0;
height: 100vh;
}
</style>
</head>
<body>
</body>
</html>"""
HTML(string=html_content).write_pdf(output_path)
return output_path
[docs]
@staticmethod
def generate_pdf(html_content, output_pdf, config=None):
"""
Converts HTML content to PDF with targeted pagination fixes
Args:
html_content (str): The complete HTML document
output_pdf (str): Path to save the PDF file
config (dict, optional): Configuration dictionary
Returns:
str: Path to the generated PDF
"""
# Create output directory if it doesn't exist
output_dir = os.path.dirname(output_pdf)
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir)
# Save debug HTML for troubleshooting
debug_html_path = output_pdf.replace('.pdf', '_debug.html')
with open(debug_html_path, 'w', encoding='utf-8') as f:
f.write(html_content)
print(f"Debug HTML saved to: {debug_html_path}")
# Create a temporary directory for intermediary files
temp_dir = tempfile.mkdtemp()
try:
# Create CSS file with pagination rules
css_path = PdfGenerator.add_css_for_pagination(temp_dir)
# Count pages in the document for verification
doc = PdfGenerator.create_section_document(html_content)
page_count = PdfGenerator.count_pages_in_document(doc)
# Check if page count is divisible by 4 (for booklet printing)
remainder = page_count % 4
if remainder != 0:
print(f"Warning: Page count ({page_count}) is not divisible by 4. "
f"Adding {4 - remainder} padding pages for proper booklet printing.")
# Generate PDF with the custom CSS
HTML(string=html_content).write_pdf(
output_pdf,
stylesheets=[CSS(filename=css_path)]
)
print(f"PDF created successfully: {output_pdf} with {page_count} pages")
return output_pdf
except Exception as e:
print(f"Error generating PDF: {str(e)}")
# Try without custom CSS as fallback
try:
HTML(string=html_content).write_pdf(output_pdf)
print(f"PDF created with fallback method: {output_pdf}")
return output_pdf
except Exception as e2:
print(f"Fallback PDF generation also failed: {str(e2)}")
raise
finally:
# Clean up temporary files
try:
if os.path.exists(css_path):
os.unlink(css_path)
os.rmdir(temp_dir)
except:
pass