Spaces:
Runtime error
Runtime error
| from PIL import ImageDraw, ImageFont | |
| # Function for managing longer bodies of text and breaking into a list of lines to be printed based on input arguments | |
| def split_text_into_lines(text, font, max_width, draw): | |
| blocks = text.split('\n') | |
| lines = [] | |
| for block in blocks: | |
| words = block.split() | |
| current_line = '' | |
| for word in words: | |
| # Check width with new word added | |
| test_line = f"{current_line} {word}".strip() | |
| test_width = draw.textlength(text = test_line, font=font) | |
| if test_width <= max_width: | |
| current_line = test_line | |
| else: | |
| #If the line with the new word exceeds the max width, start a new line | |
| lines.append(current_line) | |
| current_line = word | |
| # add the last line | |
| lines.append(current_line) | |
| return lines | |
| # Function for calculating the height of the text at the current font setting | |
| def adjust_font_size_lines_and_spacing(text, font_path, initial_font_size, max_width, area_height, image) : | |
| font_size = initial_font_size | |
| optimal_font_size = font_size | |
| optimal_lines = [] | |
| line_spacing_factor = 1.2 # multiple of font size that will get added between each line | |
| while font_size > 10: # Set minimum font size | |
| font = ImageFont.truetype(font_path, font_size) | |
| draw = ImageDraw.Draw(image) | |
| # Fitting text into box dimensions | |
| lines = split_text_into_lines(text, font, max_width, draw) | |
| # Calculate total height with dynamic line spacing | |
| single_line_height = draw.textbbox((0, 0), "Ay", font=font)[3] - draw.textbbox((0, 0), "Ay", font=font)[1] # Height of 'Ay' | |
| line_spacing = int(single_line_height * line_spacing_factor) - single_line_height | |
| total_text_height = len(lines) * single_line_height + (len(lines) - 1) * line_spacing # Estimate total height of all lines by multiplying number of lines by font height plus number of lines -1 times line spacing | |
| if total_text_height <= area_height : | |
| optimal_font_size = font_size | |
| optimal_lines = lines | |
| break # Exit loop font fits in contraints | |
| else: | |
| font_size -= 1 # Reduce font by 1 to check if it fits | |
| return optimal_font_size, optimal_lines, line_spacing | |
| # Function that takes in an image,text and properties for textfrom card_generator | |
| def render_text_with_dynamic_spacing(image, text, center_position, max_width, area_height,font_path, initial_font_size,description = None, quote = None): | |
| optimal_font_size, optimal_lines, line_spacing = adjust_font_size_lines_and_spacing( | |
| text, font_path, initial_font_size, max_width, area_height, image) | |
| # create an object to draw on | |
| font = ImageFont.truetype(font_path, optimal_font_size) | |
| draw = ImageDraw.Draw(image) | |
| # Shadow settings | |
| shadow_offset = (1, 1) # X and Y offset for shadow | |
| shadow_color = 'grey' # Shadow color | |
| # Unsure about the following line, not sure if I want y_offset to be dynamic | |
| y_offset = center_position[1] | |
| if description or quote : | |
| for line in optimal_lines: | |
| line_width = draw.textlength(text = line, font=font) | |
| x = center_position[0] | |
| # Draw Shadow first | |
| shadow_position = (x + shadow_offset[0], y_offset + shadow_offset[1]) | |
| draw.text(shadow_position, line, font=font, fill=shadow_color) | |
| #Draw text | |
| draw.text((x, y_offset), line, font=font, fill = 'black', align = "left" ) | |
| y_offset += optimal_font_size + line_spacing # Move to next line | |
| return image | |
| for line in optimal_lines: | |
| line_width = draw.textlength(text = line, font=font) | |
| x = center_position[0] - (line_width / 2) | |
| # Draw Shadow first | |
| shadow_position = (x + shadow_offset[0], y_offset + shadow_offset[1]) | |
| draw.text(shadow_position, line, font=font, fill=shadow_color) | |
| #Draw text | |
| draw.text((x, y_offset), line, font=font, fill = 'black', align = "left" ) | |
| y_offset += optimal_font_size + line_spacing # Move to next line | |
| return image | |
| # Function to put the description objects together, this will be the complicated bit, I think iterate through keys excluding title, type and cost | |