Spaces:
Sleeping
Sleeping
| import os | |
| import re | |
| from PIL import Image, ImageDraw, ImageFont | |
| import textwrap | |
| import io | |
| def find_text_in_answer(text): | |
| print("Full caption:", text) | |
| text = text.split("Caption:")[1] | |
| text = text.replace("\n", "") | |
| text = text.replace("model", "") | |
| # Remove everything that lookslike <> | |
| text = re.sub(r'<[^>]*>', '', text) | |
| # Remove non-alphanumeric characters (keeping spaces) | |
| text = re.sub(r'[^a-zA-Z0-9\?\!\s]', '', text) | |
| print("Filtered caption:", text) | |
| if text: | |
| return text | |
| else: | |
| return "Me when I couldn't parse the model's answer but I still want you to smile :)" | |
| def draw_text(draw, text, position, font, max_width, outline_color="black", text_color="white", outline_width=2): | |
| """ | |
| Draw text on the image with an outline, splitting it into lines if necessary and returning the total height used by the text. | |
| The text is horizontally centered in the specified max_width. | |
| """ | |
| print("Adding the caption on the image...") | |
| # Split the text into multiple lines based on the max width | |
| lines = [] | |
| words = text.split() | |
| line = '' | |
| for word in words: | |
| test_line = f'{line} {word}'.strip() | |
| bbox = draw.textbbox((0, 0), test_line, font=font) | |
| width = bbox[2] - bbox[0] # Width of the text | |
| if width <= max_width: | |
| line = test_line | |
| else: | |
| if line: # Avoid appending empty lines | |
| lines.append(line) | |
| line = word | |
| if line: | |
| lines.append(line) | |
| y = position[1] | |
| # Draw the text with an outline (black) first, centered horizontally | |
| for line in lines: | |
| # Calculate the width of the line and adjust the x position to center it | |
| bbox = draw.textbbox((0, 0), line, font=font) | |
| line_width = bbox[2] - bbox[0] | |
| x = (max_width - line_width) // 2 + position[0] | |
| # Draw the outline by drawing the text multiple times around the original position | |
| for offset_x in [-outline_width, 0, outline_width]: | |
| for offset_y in [-outline_width, 0, outline_width]: | |
| if offset_x != 0 or offset_y != 0: | |
| draw.text((x + offset_x, y + offset_y), line, font=font, fill=outline_color) | |
| # Draw the main text (white) on top of the outline | |
| draw.text((x, y), line, font=font, fill=text_color) | |
| y += bbox[3] - bbox[1] # Update y position based on line height | |
| return y - position[1] # Return the total height used by the text | |
| def calculate_text_height(caption, font, max_width): | |
| """ | |
| Calculate the height of the text when drawn, given the caption, font, and maximum width. | |
| """ | |
| image = Image.new('RGB', (max_width, 1)) | |
| draw = ImageDraw.Draw(image) | |
| return draw_text(draw, caption, (0, 0), font, max_width) | |
| def add_caption(image_path, caption, top_margin=10, bottom_margin=10, max_caption_length=10, min_distance_from_bottom_mm=10): | |
| image = image_path | |
| draw = ImageDraw.Draw(image) | |
| width, height = image.size | |
| # Convert mm to pixels (assuming 96 DPI) | |
| dpi = 96 | |
| min_distance_from_bottom_px = min_distance_from_bottom_mm * dpi / 25.4 | |
| # Split the caption into two parts if it is too long | |
| if len(caption.split()) > max_caption_length: | |
| font_size=20 | |
| total_len = len(caption.split()) | |
| mid = int(total_len / 2) | |
| top_caption = caption.split()[:mid] | |
| bottom_caption = caption.split()[mid:] | |
| top_caption = " ".join(top_caption) | |
| bottom_caption = " ".join(bottom_caption) | |
| else: | |
| top_caption = "" | |
| bottom_caption = caption | |
| font_size=30 | |
| # Load a font | |
| font = ImageFont.truetype(r"fonts/Anton/Anton-Regular.ttf", font_size) | |
| # Top caption | |
| top_caption_position = (width // 10, top_margin) | |
| draw_text(draw, top_caption, top_caption_position, font, width - 2 * (width // 10)) | |
| # Bottom caption | |
| if bottom_caption: # Draw bottom caption only if it's not empty | |
| # Calculate the height of the bottom caption | |
| bottom_caption_height = calculate_text_height(bottom_caption, font, width - 2 * (width // 10)) | |
| bottom_caption_position = (width // 10, height - min_distance_from_bottom_px - bottom_caption_height) | |
| draw_text(draw, bottom_caption, bottom_caption_position, font, width - 2 * (width // 10)) | |
| buffered = io.BytesIO() | |
| image.save(buffered, format="JPEG") | |
| return buffered.getvalue() | |
| return image | |
| def overlay_caption(text, img_path): | |
| text = find_text_in_answer(text) | |
| text = text.strip(".") | |
| image = add_caption(img_path, text) | |
| return image | |