diff --git a/core/renderer.py b/core/renderer.py index ab52b82..b9a4846 100644 --- a/core/renderer.py +++ b/core/renderer.py @@ -311,18 +311,23 @@ class ExcelRenderer: return str(value) def _draw_text(self, draw, text, x1, y1, x2, y2, font, color, h_align, v_align, font_size): - # Calculate available width + # Calculate available width and height max_width = x2 - x1 - 10 - text_width = draw.textlength(text, font=font) - # Simple truncation if too long - if text_width > max_width and len(text) > 3: - # Estimate chars that fit + # Use multiline_textbbox for accurate measurement of potentially multiline text + bbox = draw.multiline_textbbox((0, 0), text, font=font) + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + + # Simple truncation if too long (only for single line or very long text) + if text_width > max_width and "\n" not in text and len(text) > 3: char_ratio = max_width / text_width keep_chars = int(len(text) * char_ratio) - 2 if keep_chars > 0: text = text[:keep_chars] + "..." - text_width = draw.textlength(text, font=font) # Re-measure + bbox = draw.multiline_textbbox((0, 0), text, font=font) + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] # Horizontal Position if h_align == 'center': @@ -332,14 +337,13 @@ class ExcelRenderer: else: # left text_x = x1 + 5 - # Vertical Position (Approximate, using fixed height) - # Use font_size as a proxy for height (approximation) - font_height = font_size + # Vertical Position if v_align == 'top': text_y = y1 + 5 elif v_align == 'bottom': - text_y = y2 - font_height - 5 + text_y = y2 - text_height - 5 else: # center - text_y = y1 + (y2 - y1 - font_height) / 2 + text_y = y1 + (y2 - y1 - text_height) / 2 - draw.text((text_x, text_y), text, fill=color, font=font) + # Use multiline_text to support \n + draw.multiline_text((text_x, text_y), text, fill=color, font=font, align=h_align)