如何将非显式给定的Python字符串拆分为多行适配Pillow图片?
Hey there! I totally get your frustration—when you're dealing with dynamic strings (like the one returned from your ababou() function), those fixed-string splitting solutions you found just don't cut it. Let's fix this so your text automatically wraps to fit your 300px-wide image.
The Core Idea
We need to calculate how much space each chunk of text takes up with your chosen font, then split the string into lines that don't exceed your image's width. Here's a step-by-step solution tailored to Pillow 5.1:
Create a text-wrapping function
This function will take your dynamic string, font, and max allowed width, then split the text into lines that fit (without breaking words mid-way, which looks messy):def wrap_text(text, font, max_width): lines = [] # Split text into individual words words = text.split() if not words: return lines # Start building the first line with the first word current_line = words[0] for word in words[1:]: # Test if adding the next word keeps us under the max width test_line = f"{current_line} {word}" width, _ = font.getsize(test_line) if width <= max_width: current_line = test_line else: # Push the current line to our list and start a new one lines.append(current_line) current_line = word # Don't forget to add the last line lines.append(current_line) return linesIntegrate the function into your code
Replace your text-drawing line with code that uses this wrapper, then draws each line with a vertical offset so lines don't overlap:import random from PIL import Image, ImageDraw, ImageFont def ababou(): # Your existing ababou function logic here return "Some long dynamic string that needs wrapping, like Ababoubian wisdom for the ages!" def wrap_text(text, font, max_width): lines = [] words = text.split() if not words: return lines current_line = words[0] for word in words[1:]: test_line = f"{current_line} {word}" width, _ = font.getsize(test_line) if width <= max_width: current_line = test_line else: lines.append(current_line) current_line = word lines.append(current_line) return lines print("Ababoubian wisdom!") ababou2 = ababou() # Fixed this to a loop—your original code only checked once! while "Ababou" in ababou2: ababou2 = ababou() font = ImageFont.truetype("Arial.ttf", 14) img_width = 300 img = Image.new('RGB', (img_width, 200), color = (random.randint(0, 255),random.randint(0, 255), random.randint(0, 255))) d = ImageDraw.Draw(img) # Wrap the dynamic text wrapped_lines = wrap_text(ababou2, font, img_width) # Draw each line with vertical spacing (adjust line_height to your liking) y_offset = 0 line_height = 18 # A bit larger than font size for breathing room for line in wrapped_lines: d.text((0, y_offset), line, font=font) y_offset += line_height
Quick Tweaks to Note
- I swapped your
ifstatement for awhileloop—your original code only generated one new string if "Ababou" was present, but the loop will keep going until you get a string without it. - The
line_heightvalue (18px) is slightly bigger than your 14px font to prevent lines from crowding each other—feel free to adjust this number! - Pillow 5.1's
getsize()method returns the width and height of the text, which we use to check if our line fits within the image's width.
Now your dynamic text will automatically split into lines that fit your image perfectly! 🎨
内容的提问来源于stack exchange,提问作者Melcalc

