diff --git a/core/renderer.py b/core/renderer.py index 2bbca5c..6709e74 100644 --- a/core/renderer.py +++ b/core/renderer.py @@ -165,8 +165,44 @@ class ExcelRenderer: # Draw background and border # Scale border width: at least 1px, roughly 1px per scale unit but kept thin for aesthetics - border_width = max(1, scale) - draw.rectangle([x1, y1, x2, y2], fill=bg_color, outline=(200, 200, 200), width=border_width) + default_border_width = max(1, scale) + + # Draw background + draw.rectangle([x1, y1, x2, y2], fill=bg_color) + + # Handle borders + # Default thin grey border if no specific border is set (or for gridlines) + # Note: OpenPyXL borders are complex. We'll simplify: check each side. + + border_color = (200, 200, 200) # Default gridline color + + if cell.border: + # Helper to draw a side + def draw_side(side_obj, coords): + if side_obj and side_obj.style: + # Parse color if available, else default black for set borders + b_color = (0, 0, 0) + if side_obj.color: + b_color = self._parse_color(side_obj.color, default=(0, 0, 0)) + + # Determine width based on style + # 'thin', 'medium', 'thick', 'double', 'hair', 'dashed', 'dotted' + width = default_border_width + if side_obj.style in ['medium', 'thick', 'double']: + width = default_border_width * 2 + + draw.line(coords, fill=b_color, width=width) + else: + # Draw default gridline + draw.line(coords, fill=border_color, width=default_border_width) + + draw_side(cell.border.left, [x1, y1, x1, y2]) + draw_side(cell.border.right, [x2, y1, x2, y2]) + draw_side(cell.border.top, [x1, y1, x2, y1]) + draw_side(cell.border.bottom, [x1, y2, x2, y2]) + else: + # Fallback to simple rectangle outline + draw.rectangle([x1, y1, x2, y2], outline=border_color, width=default_border_width) # Content cell_value = cell.value diff --git a/tests/test_border.py b/tests/test_border.py new file mode 100644 index 0000000..305e44d --- /dev/null +++ b/tests/test_border.py @@ -0,0 +1,36 @@ +import pytest +import io +import os +from core.renderer import ExcelRenderer +from PIL import Image + +# Use the file provided by the user for reproduction +TEST_FILE_PATH = "tests/kshj_gt1767081783800.xlsx" + +@pytest.mark.skipif(not os.path.exists(TEST_FILE_PATH), reason="Test file not found") +def test_border_rendering_real_file(): + """ + Test rendering with a real file that has border issues. + This test will generate an output image for visual inspection. + """ + with open(TEST_FILE_PATH, "rb") as f: + content = f.read() + + renderer = ExcelRenderer(content) + + try: + # Render with high DPI scale + img_bytes = renderer.render_to_bytes(scale=3) + + # Save for visual inspection + output_path = "tests/test_output_border.png" + with open(output_path, "wb") as f_out: + f_out.write(img_bytes) + + print(f"Generated test image at: {os.path.abspath(output_path)}") + + assert isinstance(img_bytes, bytes) + assert len(img_bytes) > 0 + + except Exception as e: + pytest.fail(f"Rendering failed: {e}")