From 34fd17ba55e51a98aebf68d4af7b0b330b3d83a6 Mon Sep 17 00:00:00 2001 From: Chris Coutinho Date: Sat, 22 Nov 2025 17:04:11 +0100 Subject: [PATCH] fix: Use alpha_composite for proper RGBA highlight blending MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drawing directly with ImageDraw on RGBA mode doesn't blend alpha properly. Use Image.alpha_composite() with a transparent overlay to achieve correct semi-transparent highlight fills. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Dockerfile | 1 + nextcloud_mcp_server/search/pdf_highlighter.py | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9c78966..80bc27a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,6 +18,7 @@ RUN uv sync --locked --no-dev --no-editable --no-cache ENV PYTHONUNBUFFERED=1 ENV VIRTUAL_ENV=/app/.venv +ENV PATH=/app/.vnev/bin:$PATH ENV TESSDATA_PREFIX=/usr/share/tesseract-ocr/5/tessdata ENTRYPOINT ["/app/.venv/bin/nextcloud-mcp-server", "--host", "0.0.0.0"] diff --git a/nextcloud_mcp_server/search/pdf_highlighter.py b/nextcloud_mcp_server/search/pdf_highlighter.py index 655503d..7e20007 100644 --- a/nextcloud_mcp_server/search/pdf_highlighter.py +++ b/nextcloud_mcp_server/search/pdf_highlighter.py @@ -845,9 +845,8 @@ class PDFHighlighter: logger.warning(f"Chunk {chunk_index}: could not find bbox") continue - # Copy base image and draw highlight using PIL (fast!) + # Copy base image for this chunk chunk_image = base_image.copy() - draw = ImageDraw.Draw(chunk_image, "RGBA") # Scale bbox coordinates to pixmap coordinates scale_x = base_pix.width / page_rect.width @@ -859,10 +858,17 @@ class PDFHighlighter: int(bbox[3] * scale_y), ) - # Draw semi-transparent fill - draw.rectangle(pil_bbox, fill=fill_color) - # Draw dashed border (PIL doesn't support dashes, use solid) - draw.rectangle(pil_bbox, outline=pil_color, width=3) + # Create transparent overlay for fill (proper alpha blending) + overlay = Image.new("RGBA", chunk_image.size, (0, 0, 0, 0)) + overlay_draw = ImageDraw.Draw(overlay) + overlay_draw.rectangle(pil_bbox, fill=fill_color) + + # Alpha composite the overlay onto the chunk image + chunk_image = Image.alpha_composite(chunk_image, overlay) + + # Draw border on top (solid, not transparent) + border_draw = ImageDraw.Draw(chunk_image) + border_draw.rectangle(pil_bbox, outline=pil_color, width=3) # Convert back to PNG bytes output = BytesIO()