如何用Python的Wand库实现图像中文本字号统一、边框盒子自适应大小
修复方案
问题原因说明
- 盒子重叠/内容丢失:原代码中
y_offset直接赋值为当前盒子高度,没有累加偏移量,导致后续盒子覆盖之前的内容,看起来像空白和丢失盒子 - 边框宽度不一致:Wand的描边是沿路径居中绘制的,原矩形坐标没有考虑描边宽度,导致部分边框被画布边缘裁切
- 文本位置异常:没有基于字体度量的垂直参数调整文本坐标,导致文本偏移挤压内边距
修改后的完整代码
import re from unicodedata import normalize from docx import Document from wand.image import Image from wand.drawing import Drawing from wand.font import Font # 全局配置 FONT_PATH = '/System/Library/Fonts/timesnewroman.ttf' FONT_SIZE = 12 BOX_MAX_WIDTH = 396 BORDER_WIDTH = 2 X_PADDING = 10 Y_PADDING = 10 BOX_SPACING = 10 doc = Document("P.docx") docText = [] for para in doc.paragraphs: docText.append(para.text) fullText = "\n".join(docText) ct = 242 def capitalize(str_list): # 改为返回列表,避免生成器迭代一次失效 return [s[0].upper() + s[1:] if s else s for s in str_list] def find_matches(text): return capitalize( [ m for m in re.findall( r"^[^0-9]\s+([^.;]+\s*)+[.;]+", normalize("NFKD", text), re.MULTILINE ) ] ) def to_chunks(words, size): for idx in range(0, len(words), size): yield words[idx:idx + size] def rebuild_text(words, size, serial_num): # 把编号单独作为最后一行 lines = [" ".join(w) for w in to_chunks(words, size)] lines.append(str(serial_num)) return "\n".join(lines) # 初始化画布,预留足够尺寸 with Image(width=500, height=3000, pseudo='xc:white') as img: current_y = Y_PADDING all_matches = list(find_matches(text=fullText)) for match in all_matches: ct += 1 with Drawing() as ctx: # 配置全局字体样式 ctx.font = FONT_PATH ctx.font_size = FONT_SIZE ctx.text_alignment = 'center' ctx.fill_color = 'black' # 计算文本换行 words = match.split(" ") word_count = len(words) text = "" text_height = 0 max_text_width = BOX_MAX_WIDTH - 2*X_PADDING while word_count > 0: temp_text = rebuild_text(words, word_count, ct) metrics = ctx.get_font_metrics(img, temp_text, multiline=True) if metrics.text_width <= max_text_width: text = temp_text text_height = metrics.text_height break word_count -= 1 # 计算盒子尺寸 box_width = BOX_MAX_WIDTH box_height = text_height + 2*Y_PADDING # 绘制边框和背景 ctx.fill_color = 'white' ctx.stroke_color = 'black' ctx.stroke_width = BORDER_WIDTH ctx.rectangle( left=X_PADDING, top=current_y, width=box_width, height=box_height ) # 绘制文本,垂直居中对齐 text_x = X_PADDING + box_width//2 text_y = current_y + Y_PADDING + int(ctx.get_font_metrics(img, "啊").ascender) ctx.text(text_x, text_y, text) # 渲染当前内容 ctx.draw(img) # 更新下一个盒子的偏移量 current_y += box_height + BOX_SPACING # 裁切空白区域 img.crop(right=X_PADDING + BOX_MAX_WIDTH + X_PADDING, bottom=current_y - BOX_SPACING) img.save(filename='patdrawdemoTest.png')
核心修改点
- 修复了垂直偏移量的累加逻辑,不会再出现盒子重叠
- 调整了边框绘制坐标,所有边框宽度统一
- 基于字体度量调整文本垂直位置,保证文本居中
- 显式设置字号为12号,统一所有文本样式
- 修复了原匹配结果生成器只能迭代一次的问题,不会丢失匹配项
- 单独处理编号行的换行逻辑,不会出现异常断行
内容的提问来源于stack exchange,提问作者Jimmy Wede
相关产品推荐
相关产品推荐

