from PIL import Image, ImageDraw, ImageFont import io def create_text_image(text: str, width: int = 1000, font_size: int = 25) -> bytes: """将文本转换为图片,智能处理各种字符""" def load_fonts(): """加载文本和 Emoji 字体""" # 尝试加载 Emoji 字体 emoji_font = None try: emoji_font = ImageFont.truetype("/usr/share/fonts/truetype/noto/NotoColorEmoji.ttf", font_size) print("成功加载 Emoji 字体") except Exception as e: print(f"加载 Emoji 字体失败: {e}") # 尝试加载文本字体 text_font = None font_paths = [ "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", "/usr/share/fonts/wqy-microhei/wqy-microhei.ttc", "/usr/share/fonts/wqy-zenhei/wqy-zenhei.ttc", "C:/Windows/Fonts/msyh.ttc", "C:/Windows/Fonts/simhei.ttf", ] for path in font_paths: try: text_font = ImageFont.truetype(path, font_size) print(f"成功加载文本字体: {path}") break except Exception: continue if text_font is None: text_font = ImageFont.load_default() print("使用默认字体") return text_font, emoji_font def is_emoji(char): """判断字符是否为 Emoji""" return len(char.encode('utf-8')) >= 4 def draw_text_with_fonts(draw, text, x, y, text_font, emoji_font): """使用不同的字体绘制文本和 Emoji""" current_x = x for char in text: # 选择合适的字体 font = emoji_font if (is_emoji(char) and emoji_font) else text_font # 绘制字符 draw.text((current_x, y), char, font=font, fill=(0, 0, 0)) # 计算字符宽度 bbox = draw.textbbox((current_x, y), char, font=font) char_width = bbox[2] - bbox[0] current_x += char_width return current_x - x def calculate_text_dimensions(text, text_font, emoji_font): """计算文本尺寸""" test_img = Image.new('RGB', (1, 1), color=(255, 255, 255)) test_draw = ImageDraw.Draw(test_img) total_width = 0 max_height = 0 for char in text: font = emoji_font if (is_emoji(char) and emoji_font) else text_font bbox = test_draw.textbbox((0, 0), char, font=font) char_width = bbox[2] - bbox[0] char_height = bbox[3] - bbox[1] total_width += char_width max_height = max(max_height, char_height) return total_width, max_height # 加载字体 text_font, emoji_font = load_fonts() # 基础配置 padding = 40 effective_width = width - (2 * padding) def smart_text_wrap(text): """智能文本换行""" lines = [] current_line = "" current_width = 0 for paragraph in text.split('\n'): if not paragraph: lines.append("") continue for char in paragraph: char_width, _ = calculate_text_dimensions(char, text_font, emoji_font) if current_width + char_width <= effective_width: current_line += char current_width += char_width else: if current_line: lines.append(current_line) current_line = char current_width = char_width if current_line: lines.append(current_line) current_line = "" current_width = 0 return lines # 智能换行处理 lines = smart_text_wrap(text) # 计算行高 _, line_height = calculate_text_dimensions("测试", text_font, emoji_font) line_spacing = int(line_height * 0.5) # 行间距为行高的50% total_line_height = line_height + line_spacing # 计算总高度 total_height = (len(lines) * total_line_height) + (2 * padding) height = max(total_height, 200) # 最小高度200像素 # 创建图片 image = Image.new('RGB', (width, int(height)), color=(252, 252, 252)) draw = ImageDraw.Draw(image) # 绘制文本 y = padding for line in lines: if line: # 跳过空行 draw_text_with_fonts(draw, line, padding, y, text_font, emoji_font) y += total_line_height # 转换为字节流 img_byte_arr = io.BytesIO() image.save(img_byte_arr, format='PNG', quality=95) img_byte_arr.seek(0) return img_byte_arr.getvalue()