如何从返回AVIF二进制数据的URL中获取并打开图片?
处理返回AVIF格式二进制数据的URL,实现图片创建、获取与打开
当请求URL返回AVIF格式的二进制数据(示例开头为\x00\x00\x00 ftypavif\x00\x00\x00\ ... \x87"y~\x13 $%\\\xad ... xb5\xa07tR\x80,实际数据更长)时,使用Python 2.7及PIL(Pillow)库直接处理会遇到问题,以下是问题分析和解决方法:
问题根源
你当前使用的Python 2.7环境下的PIL/Pillow版本不支持AVIF格式解码,因此直接调用Image.open()会抛出IOError: cannot identify image file错误。你尝试的bytes.fromhex()、binascii.a2b_hex()等方法属于错误操作——r.content已经是二进制数据,这些方法会将其当作十六进制字符串解析,导致数据损坏,自然无法识别。
解决方案(Python 2.7兼容)
由于旧版PIL/Pillow不支持AVIF,需要先将AVIF数据转换为PIL支持的格式(如PNG、JPG),再进行处理。推荐通过命令行工具结合subprocess实现转换:
步骤1:安装AVIF转换工具
首先在系统中安装支持AVIF解码的工具,比如:
- Linux:通过包管理器安装
libavif-tools(如apt install libavif-tools) - Windows:从libavif官方渠道下载预编译的
avifdec二进制文件
步骤2:代码实现
import requests import subprocess import cStringIO from PIL import Image # 目标AVIF图片URL imgurl = "https://media-cldnry.s-nbcnews.com/image/upload/t_focal-860x484,f_avif,q_auto:eco,dpr_2/MSNBC/Components/Video/201610/tdy_food_brisket_161021__142565.jpg" # 下载AVIF二进制数据 r = requests.get(imgurl, verify=False, timeout=3) avif_data = r.content # 通过avifdec将AVIF转换为PNG(使用管道避免临时文件) proc = subprocess.Popen( ["avifdec", "-", "-"], # 从stdin读入AVIF,stdout输出PNG stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) png_data, err_msg = proc.communicate(input=avif_data) # 检查转换是否成功 if proc.returncode != 0: raise IOError("AVIF转换失败: {}".format(err_msg)) # 用PIL打开转换后的PNG图片 image = Image.open(cStringIO.StringIO(png_data)) # 展示图片 image.show()
替代方案(使用FFmpeg)
如果无法安装avifdec,也可以用FFmpeg实现转换,将subprocess.Popen的参数替换为:
proc = subprocess.Popen( ["ffmpeg", "-i", "-", "-f", "png", "-"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
可选升级方案(若允许)
如果可以脱离Python 2.7环境,升级到Python 3.8+并安装Pillow 9.1.0及以上版本,新版Pillow原生支持AVIF格式,此时可以直接用Image.open(io.BytesIO(r.content))处理,无需额外转换。
内容的提问来源于stack exchange,提问作者user984003
相关产品推荐
相关产品推荐

