事情本身不复杂,线索都在日志里。Pillow 10.3 打开一张 12000×18000 的长截图做 OCR,Image.open 抛 DecompressionBombError: Image size (216000000 pixels) exceeds limit of 178956970 pixels,同批的小图都正常,先 copy 一份再打开,报错照样出在 open 这一步。
第一反应是「没先读尺寸就整图 decode」,验证下来不成立。
把日志和配置对完,能解释这个现象的基本就这几处。默认像素上限约为 8900 万。还有一种是长图拼接后总像素翻倍。
不容易想到的是,直接关掉上限会带来内存风险。
只读文件头拿尺寸
python -c "from PIL import Image;print(Image.open('long.png').size)"
然后按目标长边算缩放比再 draft
python -c "from PIL import Image;im=Image.open('long.png');im.draft('RGB',(im.width//3,im.height//3));im.thumbnail((2000,2000));print(im.size)"
显式提高上限并分块处理
python -c "from PIL import Image;Image.MAX_IMAGE_PIXELS=300000000;im=Image.open('long.png');print(im.size)"
剩下的就是改用流式库读取超大图
python -c "import pyvips;im=pyvips.Image.new_from_file('long.png',access='sequential');print(im.width,im.height)"
排查用的命令都是临时敲的,没有写成脚本,事后才整理。
恢复的判定其实很直接。长图切成 6 块送入 OCR,单块内存低于 500MB,拼接后的文字与人工抽查一致。
容易忽略的是,上限是安全阈值不是缺陷,直接设成 None 遇到恶意构造的图片会把内存打满。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。
