DEBUG.WIKI
丽萨主机;为跨境业务选好 IP;原生 / 住宅 IP · 按套餐选择;查看 IP →
晚安云;香港 CN2 ¥15/月
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS

灰度 AVIF 保存报 rgb data has incorrect size,检查 libavif

源码构建的 Pillow 配合旧系统 libavif,灰度 AVIF 可能按 RGB 尺寸校验失败。限定 8 位 L 图的 RGB 副本绕行,并核对位深和实际链接库。

灰度图保存 AVIF 失败,报 rgb data has incorrect size,而同一张图先转 RGB 就能保存。若 Pillow 是从源码构建、链接系统里的旧 libavif,应核对灰度数据格式与 C 扩展选用的通道数。

明确触发环境为 Ubuntu 24.04、libavif 1.0.4 与开发构建 Pillow 13.1.0.dev0。正式 Pillow 13.0.0 也保留相关条件:Python 编码端可传 L 灰度数据,C 端只有编译时 libavif 至少为 1.3.0 才选择 AVIF_RGB_FORMAT_GRAY;更旧的库会按 RGB 处理,字节尺寸便可能对不上。不能据此说所有 Pillow 安装包的 AVIF 都不可用,官方 wheel 可能捆绑更新的库。

先核对实际库版本

在真正执行保存的解释器中读取版本:

import PIL
from PIL import features

print(PIL.__version__)
print(features.version("avif"))

这不同于系统包管理器显示的某个安装版本。构建时使用哪个库、运行时加载哪个库,以及 wheel 自带的库,需要按当前环境判断;不要为了一个 Python 编码异常就替换全系统图像库。

如果完全没有 AVIF 支持,或者错误在加载源图时发生,则不属于这条灰度字节尺寸路径,应保留实际异常继续核对。

普通 8 位 L 图可显式转 RGB 副本

当业务允许以 RGB 表达这份 8 位灰度图时,可在输出边界转换:

from PIL import Image

with Image.open("input.png") as image:
    if image.mode != "L":
        raise ValueError("this path expects an 8-bit L image")
    rgb = image.convert("RGB")
    rgb.save("output.avif", format="AVIF")

输入与输出是不同路径,原图仍保留。这个转换将灰度值表达为三个颜色通道,会改变图像模式和可能的文件大小;AVIF 压缩本身还可能改变解码像素,验收应按应用的质量参数判断。

不要把这个片段扩展到所有 I、I;16 或 F 图像。整数高位深与浮点图转到普通 RGB 可能丢失动态范围或精度,医学、科学或测量数据应先决定可接受的位深与输出格式。含透明度或多帧数据也需要自己的保存流程,不能按单张 L 图处理。

构建修正后仍需往返读取

需要原生灰度 AVIF 时,选择与当前 Pillow 源码兼容、支持该灰度格式的 libavif 构建,并重建对应扩展或采用符合项目约束的发行包。仅把某个库文件换掉,不保证现有扩展当初的编译分支改变;应让锁定和构建记录能够重现环境。

保存后关闭写入,再重新打开输出,核对宽高、模式、关键像素范围、颜色表现及需要保留的 ICC、EXIF 等元数据。上面的最小片段没有自动承诺完整元数据传递。

已失败的输出可能是部分文件,不应当成可用产物交给下游。保留原件,重新输出到独立位置;确认新文件可读取且质量符合要求后,再按原流程替换。问题关闭不证明某个正式版已经修好旧库组合,升级仍需核对实际 Pillow 与 libavif 的配对。