logo

Python3实现图片竖排文字的完整指南

作者:谁偷走了我的奶酪2025.09.19 18:44浏览量:0

简介:本文深入探讨Python3中如何在图片上实现竖排文字效果,涵盖Pillow库的使用、文字方向控制、坐标计算及样式优化,为图像处理开发者提供实用解决方案。

Python3图片中竖排文字实现详解

一、竖排文字应用场景与实现难点

在图像处理领域,竖排文字常见于中文书法作品、海报设计、古籍数字化等场景。与横排文字相比,竖排实现存在三大技术挑战:

  1. 文字方向控制:需改变默认从左到右的书写顺序
  2. 坐标系统适配:需重构文字定位逻辑
  3. 字符间距处理:需单独控制每个字符的垂直间距

传统图像处理库(如Pillow)原生支持横排文字,但竖排功能需开发者自行实现。本文将通过系统方法解决这些技术难题。

二、核心实现方案:Pillow库深度应用

2.1 环境准备与基础配置

  1. from PIL import Image, ImageDraw, ImageFont
  2. import numpy as np
  3. # 创建基础画布
  4. img = Image.new('RGB', (800, 600), color=(255, 255, 255))
  5. draw = ImageDraw.Draw(img)
  6. # 加载中文字体(需确保系统存在该字体)
  7. try:
  8. font = ImageFont.truetype("simhei.ttf", 40)
  9. except IOError:
  10. # 备用字体方案
  11. font = ImageFont.load_default()

2.2 基础竖排实现方法

方法一:逐字符绘制法

  1. def vertical_text_simple(draw, text, x, y, spacing=10):
  2. """
  3. 简单竖排实现(从上到下)
  4. :param draw: ImageDraw对象
  5. :param text: 要绘制的文本
  6. :param x: 基准X坐标
  7. :param y: 起始Y坐标
  8. :param spacing: 字符间距
  9. """
  10. for i, char in enumerate(text):
  11. draw.text((x, y + i*spacing), char, font=font, fill=(0,0,0))
  12. # 使用示例
  13. vertical_text_simple(draw, "竖排文字", 100, 50)

方法二:旋转文本法(需注意坐标变换)

  1. def vertical_text_rotate(draw, text, x, y, spacing=10):
  2. """
  3. 通过旋转实现竖排(从右到左)
  4. :param draw: ImageDraw对象
  5. :param text: 要绘制的文本
  6. :param x: 基准X坐标
  7. :param y: 起始Y坐标
  8. :param spacing: 行间距
  9. """
  10. # 计算总高度
  11. text_width = max([font.getbbox(c)[2] for c in text])
  12. total_height = len(text) * (font.getbbox("测")[3] + spacing)
  13. # 创建临时图像
  14. temp_img = Image.new('RGBA', (text_width, total_height), (255,255,255,0))
  15. temp_draw = ImageDraw.Draw(temp_img)
  16. # 逐行绘制(需反转顺序)
  17. for i, char in enumerate(reversed(text)):
  18. temp_draw.text((0, i*(font.getbbox("测")[3] + spacing)),
  19. char, font=font, fill=(0,0,0))
  20. # 旋转90度(顺时针)
  21. rotated = temp_img.rotate(90, expand=1)
  22. img.paste(rotated, (x, y), rotated)

三、进阶实现方案:坐标系统重构

3.1 坐标计算模型

建立竖排坐标系需考虑:

  1. 基准点选择(左上/右上)
  2. 文字增长方向(向上/向下)
  3. 对齐方式(左对齐/居中/右对齐)
  1. class VerticalTextEngine:
  2. def __init__(self, font, spacing=10):
  3. self.font = font
  4. self.spacing = spacing
  5. self.char_height = font.getbbox("测")[3] # 获取单个字符高度
  6. def calculate_positions(self, text, x, y, align='left', direction='down'):
  7. """
  8. 计算竖排文字各字符位置
  9. :param text: 文本内容
  10. :param x: 基准X坐标
  11. :param y: 基准Y坐标
  12. :param align: 对齐方式
  13. :param direction: 增长方向('up'/'down')
  14. :return: 字符位置列表 [(x1,y1), (x2,y2), ...]
  15. """
  16. positions = []
  17. text_length = len(text)
  18. # 计算总高度
  19. total_height = text_length * (self.char_height + self.spacing) - self.spacing
  20. # 根据对齐方式调整基准Y
  21. if align == 'center':
  22. y -= total_height // 2
  23. elif align == 'right':
  24. # 需要计算文本宽度(假设等宽字体)
  25. char_width = self.font.getbbox("测")[2]
  26. x -= char_width # 简单右对齐实现
  27. # 根据方向生成坐标
  28. if direction == 'down':
  29. positions = [(x, y + i*(self.char_height + self.spacing))
  30. for i in range(text_length)]
  31. else: # up
  32. positions = [(x, y - i*(self.char_height + self.spacing))
  33. for i in range(text_length)]
  34. return positions
  35. def render(self, draw, text, x, y, align='left', direction='down', fill=(0,0,0)):
  36. positions = self.calculate_positions(text, x, y, align, direction)
  37. for pos, char in zip(positions, text):
  38. draw.text(pos, char, font=self.font, fill=fill)

3.2 多列竖排布局实现

  1. def multi_column_vertical_text(draw, text, columns, x_start, y_start,
  2. col_spacing=50, row_spacing=10, **kwargs):
  3. """
  4. 多列竖排文本实现
  5. :param text: 完整文本
  6. :param columns: 列数
  7. :param x_start: 起始X坐标
  8. :param y_start: 起始Y坐标
  9. :param col_spacing: 列间距
  10. :param row_spacing: 行间距
  11. """
  12. # 计算每列字符数
  13. total_chars = len(text)
  14. chars_per_col = total_chars // columns
  15. remainder = total_chars % columns
  16. # 分割文本
  17. text_columns = []
  18. start = 0
  19. for i in range(columns):
  20. end = start + chars_per_col + (1 if i < remainder else 0)
  21. text_columns.append(text[start:end])
  22. start = end
  23. # 绘制各列
  24. for i, col_text in enumerate(text_columns):
  25. x = x_start + i * col_spacing
  26. VerticalTextEngine(**kwargs).render(
  27. draw, col_text, x, y_start, **kwargs)

四、性能优化与高级功能

4.1 批量渲染优化

  1. def batch_render_vertical(img_path, text_data):
  2. """
  3. 批量渲染竖排文字到图片
  4. :param img_path: 图片路径
  5. :param text_data: 文本数据列表,每个元素为字典:
  6. {
  7. 'text': '内容',
  8. 'x': 100,
  9. 'y': 200,
  10. 'color': (255,0,0),
  11. 'font_size': 30
  12. }
  13. """
  14. img = Image.open(img_path).convert('RGBA')
  15. draw = ImageDraw.Draw(img)
  16. # 预加载字体(避免重复加载)
  17. fonts = {}
  18. for data in text_data:
  19. size = data.get('font_size', 20)
  20. if size not in fonts:
  21. try:
  22. fonts[size] = ImageFont.truetype("simhei.ttf", size)
  23. except:
  24. fonts[size] = ImageFont.load_default()
  25. # 批量渲染
  26. for data in text_data:
  27. font = fonts[data['font_size']]
  28. engine = VerticalTextEngine(font, spacing=data.get('spacing', 10))
  29. engine.render(
  30. draw,
  31. data['text'],
  32. data['x'],
  33. data['y'],
  34. fill=data.get('color', (0,0,0)),
  35. align=data.get('align', 'left'),
  36. direction=data.get('direction', 'down')
  37. )
  38. return img

4.2 复杂排版示例:古诗竖排

  1. def render_poem_vertical(output_path):
  2. poem = """
  3. 静夜思
  4. 李白
  5. 床前明月光,
  6. 疑是地上霜。
  7. 举头望明月,
  8. 低头思故乡。
  9. """
  10. # 创建画布
  11. img = Image.new('RGB', (600, 800), (240, 240, 220))
  12. draw = ImageDraw.Draw(img)
  13. # 加载字体
  14. try:
  15. title_font = ImageFont.truetype("simhei.ttf", 36)
  16. author_font = ImageFont.truetype("simkai.ttf", 24)
  17. content_font = ImageFont.truetype("simkai.ttf", 28)
  18. except:
  19. title_font = ImageFont.load_default()
  20. author_font = ImageFont.load_default()
  21. content_font = ImageFont.load_default()
  22. # 绘制标题(居中)
  23. title_engine = VerticalTextEngine(title_font, spacing=40)
  24. title_engine.render(draw, "静夜思", 300, 100, align='center')
  25. # 绘制作者(右对齐)
  26. author_engine = VerticalTextEngine(author_font, spacing=30)
  27. author_engine.render(draw, "李白", 550, 180, align='right')
  28. # 绘制诗句(两列)
  29. lines = poem.strip().split("\n")[2:] # 去掉标题和作者
  30. col1 = lines[:2]
  31. col2 = lines[2:]
  32. # 第一列
  33. col1_engine = VerticalTextEngine(content_font, spacing=60)
  34. col1_engine.render(draw, "\n".join(col1), 150, 250)
  35. # 第二列
  36. col2_engine = VerticalTextEngine(content_font, spacing=60)
  37. col2_engine.render(draw, "\n".join(col2), 400, 250)
  38. img.save(output_path)

五、常见问题解决方案

5.1 中文字符显示问题

  1. 字体缺失:确保系统有中文字体,或指定字体路径
  2. 字符宽度不一:使用等宽字体或单独计算每个字符宽度
  3. 换行处理:需预先计算文本宽度进行自动换行

5.2 性能优化建议

  1. 预加载字体对象
  2. 批量处理相似文本
  3. 对大文本使用分块渲染
  4. 考虑使用NumPy进行像素级操作(高级场景)

5.3 跨平台兼容性

  1. def get_system_font(font_name=None):
  2. """获取系统可用中文字体"""
  3. import platform
  4. system = platform.system()
  5. if system == 'Windows':
  6. return font_name or "simhei.ttf" # Windows默认黑体
  7. elif system == 'Darwin': # macOS
  8. return font_name or "PingFang.ttc" # 苹方字体
  9. else: # Linux及其他
  10. return font_name or "wqy-zenhei.ttc" # 文泉驿正黑

六、完整实现示例

  1. from PIL import Image, ImageDraw, ImageFont
  2. import os
  3. class AdvancedVerticalText:
  4. def __init__(self, output_size=(800, 600), bg_color=(255,255,255)):
  5. self.img = Image.new('RGB', output_size, bg_color)
  6. self.draw = ImageDraw.Draw(self.img)
  7. self.fonts = {}
  8. def get_font(self, size):
  9. if size not in self.fonts:
  10. try:
  11. # 尝试加载常见中文字体
  12. font_path = self._find_chinese_font()
  13. self.fonts[size] = ImageFont.truetype(font_path, size)
  14. except:
  15. self.fonts[size] = ImageFont.load_default()
  16. return self.fonts[size]
  17. def _find_chinese_font(self):
  18. """查找系统中的中文字体"""
  19. # 实际实现中可添加更多字体路径检查
  20. common_paths = [
  21. "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc", # Linux
  22. "/Library/Fonts/PingFang.ttc", # macOS
  23. "C:/Windows/Fonts/simhei.ttf" # Windows
  24. ]
  25. for path in common_paths:
  26. if os.path.exists(path):
  27. return path
  28. return "simhei.ttf" # 默认值
  29. def render_vertical(self, text, x, y, font_size=20,
  30. color=(0,0,0), spacing=10,
  31. align='left', direction='down'):
  32. """
  33. 高级竖排渲染
  34. :param text: 要渲染的文本
  35. :param x: 基准X坐标
  36. :param y: 基准Y坐标
  37. :param font_size: 字体大小
  38. :param color: 文字颜色
  39. :param spacing: 字符间距
  40. :param align: 对齐方式(left/center/right)
  41. :param direction: 增长方向(up/down)
  42. """
  43. font = self.get_font(font_size)
  44. engine = VerticalTextEngine(font, spacing)
  45. engine.render(
  46. self.draw, text, x, y,
  47. align=align, direction=direction,
  48. fill=color
  49. )
  50. def save(self, path):
  51. self.img.save(path)
  52. # 使用示例
  53. if __name__ == "__main__":
  54. renderer = AdvancedVerticalText((600, 400))
  55. # 渲染多列竖排文本
  56. poem = "春眠不觉晓处处闻啼鸟夜来风雨声花落知多少"
  57. renderer.render_vertical(
  58. text=poem[:8], # 前8个字
  59. x=100, y=200,
  60. font_size=24,
  61. color=(0, 0, 120),
  62. direction='down'
  63. )
  64. renderer.render_vertical(
  65. text=poem[8:], # 后8个字
  66. x=300, y=200,
  67. font_size=24,
  68. color=(120, 0, 0),
  69. direction='down'
  70. )
  71. # 渲染标题(从下往上)
  72. renderer.render_vertical(
  73. text="春晓",
  74. x=450, y=350,
  75. font_size=30,
  76. color=(0, 120, 0),
  77. direction='up',
  78. align='center'
  79. )
  80. renderer.save("vertical_text_demo.png")

七、总结与扩展建议

本文系统阐述了Python3中实现图片竖排文字的完整方案,涵盖从基础实现到高级排版的各个方面。实际开发中,建议:

  1. 字体管理:建立字体缓存机制,避免重复加载
  2. 性能优化:对大文本使用分块处理和异步渲染
  3. 扩展功能:可结合OpenCV实现更复杂的文字特效
  4. 跨平台:使用字体配置文件管理不同系统的字体路径

通过本文提供的方案,开发者可以灵活实现各种竖排文字效果,满足从简单标注到复杂排版的多样化需求。完整代码示例已在GitHub开源,欢迎开发者贡献改进方案。

相关文章推荐

发表评论