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

Django ImageField保存ICO转PNG时触发Pillow的ValueError异常

问题解决:Django保存ICO转PNG后无法获取宽高报错

问题场景

现有Django模型:

class Website(models.Model):
    favicon = models.ImageField(
        null=False,
        blank=True,
        default="",
        width_field="favicon_width",
        height_field="favicon_height",
    )
    favicon_width = models.PositiveSmallIntegerField(null=True, blank=True)
    favicon_height = models.PositiveSmallIntegerField(null=True, blank=True)

通过以下代码获取ICO文件并转PNG保存到favicon字段:

import io
import requests
from django.core import files
from .models import Website

website = Website.objects.get(pk=1)
response = requests.get("https://www.blogger.com/favicon.ico", stream=True)
image_data = io.BytesIO(response.content)
website.favicon.save("favicon.png", files.File(image_data))

执行后PNG文件能成功保存,但触发ValueError: not enough image data错误,回溯指向Django尝试获取图片宽高时Pillow解析失败,仅部分ICO文件可正常工作。

问题原因

部分ICO文件包含多尺寸图标,直接将原始ICO二进制数据存入BytesIO后,Django调用file.width时,Pillow可能因数据流指针位置错误(如停在末尾)或无法解析ICO多帧结构,导致读取数据不完整。

解决方案

用Pillow先打开ICO文件,提取图像并转换为PNG格式,重新写入BytesIO后再保存,同时重置数据流指针到起始位置:

import io
import requests
from PIL import Image
from django.core import files
from .models import Website

website = Website.objects.get(pk=1)
response = requests.get("https://www.blogger.com/favicon.ico", stream=True)

# 用Pillow解析ICO文件
with Image.open(io.BytesIO(response.content)) as img:
    # 转换为RGBA模式保留透明通道
    img = img.convert("RGBA")
    # 创建新BytesIO存储转换后的PNG数据
    png_data = io.BytesIO()
    img.save(png_data, format="PNG")
    # 重置指针到起始位置,确保Django能读取完整数据
    png_data.seek(0)
    
    # 保存到模型字段
    website.favicon.save("favicon.png", files.File(png_data))

额外说明

  • 转换为RGBA模式可避免ICO转PNG时出现黑底问题,保留透明通道
  • 必须调用seek(0)重置数据流指针,否则Django读取时会从末尾开始,导致数据为空

内容的提问来源于stack exchange,提问作者Phil Gyford

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 19:09:52