stroke_width大于1时触发OSError: array allocation size too large求助
PIL绘制带描边文本时
OSError: array allocation size too large问题解析与解决 问题原因
- PIL原生的
stroke_width实现逻辑是通过偏移文本轮廓生成描边,对于Brush King这类轮廓节点极多的手写风格字体,当描边宽度大于1时,会瞬间生成规模远超内存承载能力的像素数组,直接触发内存分配错误。 - 字体尺寸越大,问题越显著——大字体的原始轮廓本身就大,多次偏移后的计算量呈指数级增长,16GB内存也无法支撑这种突发的超大内存申请。
替代方案
方案1:手动分层绘制模拟描边
通过绘制多方向偏移的文本作为描边,再叠加原文本,内存占用可控且实现简单:
draw = ImageDraw.Draw(text_layer) font = ImageFont.truetype(f"{fonts_dir}/{config['round_font']}", config["round_size"]) text = "texttext" fill_color = '#000000' stroke_color = "#000000" stroke_width = 3 # 可按需调整更大值 # 绘制8个方向的偏移文本作为描边 offsets = [(-stroke_width, -stroke_width), (0, -stroke_width), (stroke_width, -stroke_width), (-stroke_width, 0), (stroke_width, 0), (-stroke_width, stroke_width), (0, stroke_width), (stroke_width, stroke_width)] for dx, dy in offsets: draw.text((274 + dx, 584 + dy), text, fill=stroke_color, font=font, anchor="mm") # 叠加中间的原文本 draw.text((274, 584), text, fill=fill_color, font=font, anchor="mm")
- 若需要更平滑的描边,可增加偏移方向(比如16个方向),8个方向已能满足绝大多数场景需求。
方案2:OpenCV辅助生成平滑描边
利用OpenCV的膨胀操作生成描边,适合对描边平滑度要求较高的场景,内存效率远高于PIL原生描边:
import cv2 import numpy as np from PIL import Image, ImageDraw, ImageFont draw = ImageDraw.Draw(text_layer) font = ImageFont.truetype(f"{fonts_dir}/{config['round_font']}", config["round_size"]) text = "texttext" fill_color = '#000000' stroke_color = "#000000" stroke_width = 3 # 1. 创建空白画布绘制原始文本 text_bbox = font.getbbox(text) text_w, text_h = text_bbox[2] - text_bbox[0], text_bbox[3] - text_bbox[1] canvas_size = (text_w + stroke_width*2, text_h + stroke_width*2) text_canvas = Image.new('RGBA', canvas_size, (0,0,0,0)) canvas_draw = ImageDraw.Draw(text_canvas) canvas_draw.text((stroke_width, stroke_width), text, fill=fill_color, font=font) # 2. 转OpenCV格式生成描边 cv_text = cv2.cvtColor(np.array(text_canvas), cv2.COLOR_RGBA2BGRA) # 生成膨胀核,控制描边粗细 kernel = np.ones((stroke_width*2, stroke_width*2), np.uint8) # 膨胀生成描边蒙版 stroke_mask = cv2.dilate(cv_text[:, :, 3], kernel, iterations=1) # 生成描边图层 stroke_layer = Image.new('RGBA', canvas_size, stroke_color) stroke_layer.putalpha(stroke_mask) # 叠加原文本 stroke_layer.paste(text_canvas, (0,0), text_canvas) # 3. 将带描边的文本粘贴到原图层 paste_x = 274 - (text_w // 2) - stroke_width paste_y = 584 - (text_h // 2) - stroke_width text_layer.paste(stroke_layer, (paste_x, paste_y), stroke_layer)
内容的提问来源于stack exchange,提问作者Impasse
相关产品推荐
相关产品推荐

