You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 15:15:26