diff --git a/backend/app/services/pdf_generator_service.py b/backend/app/services/pdf_generator_service.py index 1c75831..9c6be5c 100644 --- a/backend/app/services/pdf_generator_service.py +++ b/backend/app/services/pdf_generator_service.py @@ -1188,18 +1188,34 @@ class PDFGeneratorService: font_name = self.font_name if self.font_registered else 'Helvetica' pdf_canvas.setFont(font_name, font_size) - # Calculate text width to prevent overflow - text_width = pdf_canvas.stringWidth(text, font_name, font_size) + # Handle line breaks (split text by newlines) + lines = text.split('\n') + line_height = font_size * 1.2 # 120% of font size for line spacing - # If text is too wide for bbox, scale down font - if text_width > bbox_width: - scale_factor = bbox_width / text_width - font_size = font_size * scale_factor * 0.95 # 95% to add small margin - font_size = max(font_size, 3) # Minimum 3pt - pdf_canvas.setFont(font_name, font_size) + # Draw each line + for i, line in enumerate(lines): + if not line.strip(): + continue # Skip empty lines - # Draw text at calculated position - pdf_canvas.drawString(pdf_x, pdf_y, text) + line_y = pdf_y - (i * line_height) + + # Calculate text width to prevent overflow + text_width = pdf_canvas.stringWidth(line, font_name, font_size) + + # If text is too wide for bbox, scale down font for this line + current_font_size = font_size + if text_width > bbox_width: + scale_factor = bbox_width / text_width + current_font_size = font_size * scale_factor * 0.95 # 95% to add small margin + current_font_size = max(current_font_size, 3) # Minimum 3pt + pdf_canvas.setFont(font_name, current_font_size) + + # Draw text at calculated position + pdf_canvas.drawString(pdf_x, line_y, line) + + # Reset font size for next line + if text_width > bbox_width: + pdf_canvas.setFont(font_name, font_size) # Debug: Draw bounding box (optional) if settings.pdf_enable_bbox_debug: @@ -1549,6 +1565,9 @@ class PDFGeneratorService: first_line_indent = element.metadata.get('first_line_indent', indent) if element.metadata else indent # Get paragraph spacing + # spacing_before: Applied by adjusting starting Y position (pdf_y) + # spacing_after: Recorded for debugging; in Direct track with fixed bbox, + # actual spacing is already reflected in element positions paragraph_spacing_before = element.metadata.get('spacing_before', 0) if element.metadata else 0 paragraph_spacing_after = element.metadata.get('spacing_after', 0) if element.metadata else 0 @@ -1623,7 +1642,8 @@ class PDFGeneratorService: pdf_canvas.setFont(font_name, font_size) logger.debug(f"Drew text element: {text_content[:30]}... " - f"({len(lines)} lines, align={alignment}, indent={indent})") + f"({len(lines)} lines, align={alignment}, indent={indent}, " + f"spacing_before={paragraph_spacing_before}, spacing_after={paragraph_spacing_after})") except Exception as e: logger.error(f"Failed to draw text element {element.element_id}: {e}") diff --git a/openspec/changes/pdf-layout-restoration/tasks.md b/openspec/changes/pdf-layout-restoration/tasks.md index a868ba8..710f294 100644 --- a/openspec/changes/pdf-layout-restoration/tasks.md +++ b/openspec/changes/pdf-layout-restoration/tasks.md @@ -81,10 +81,12 @@ - [x] 5.1.1 Split text content by newlines (text.split('\n')) - [x] 5.1.2 Calculate line height from font size (font_size * 1.2) - [x] 5.1.3 Render each line with proper spacing (line_y = pdf_y - i * line_height) + - [x] 5.1.4 Add OCR track support in draw_text_region (lines 1191-1218) - [x] 5.2 Add paragraph handling - [x] 5.2.1 Detect paragraph boundaries (via element.type PARAGRAPH) - [x] 5.2.2 Apply paragraph spacing (spacing_before/spacing_after from metadata) - [x] 5.2.3 Handle indentation (indent/first_line_indent from metadata) + - [x] 5.2.4 Record spacing_after for debugging (included in logs) - [x] 5.3 Implement text alignment - [x] 5.3.1 Support left/right/center/justify (from StyleInfo.alignment) - [x] 5.3.2 Calculate positioning based on alignment (line_x calculation)