使用PIL二次保存JPEG图像是否需指定quality=100以避免二次压缩?
关于PIL加载JPEG后再次保存的二次压缩问题
这个问题问得特别关键,尤其是在把大量图像存入LMDB的场景下,二次压缩不仅会悄悄损耗图像质量,还可能增加不必要的存储开销。我来给你拆解清楚PIL的行为和最优解决方案:
首先得明确一个核心点:PIL加载JPEG时会完全解码成原始像素数据。也就是说,当你用Image.open()打开那张quality=90的JPEG时,PIL会把压缩后的JPEG数据转换成RGB(或其他模式)的像素矩阵——这一步完成后,原来的quality=90参数就彻底丢失了,PIL此时只知道每个像素的颜色值,完全不知道这张图之前是用什么压缩比保存的。
所以当你再次调用save()方法时,PIL会从头开始重新执行JPEG压缩:
- 如果你不指定
quality参数,PIL会用默认值75进行压缩,这比你原来的90质量更低,肯定会造成二次压缩,图像质量下降、文件大小也会变化; - 哪怕你指定
quality=100,也不是“无压缩”保存——JPEG本身是有损压缩格式,quality=100只是压缩率极低、损失几乎不可见,但文件会比原来的90版本大很多,而且因为已经解码过原始像素,本质还是重新压缩的过程,完全没必要这么做。
最优解决方案(完全避免二次压缩)
如果你不需要对图像做任何像素级修改,只是想把磁盘上的quality=90的JPEG存入LMDB,最稳妥的方式是直接读取原始JPEG字节数据,跳过PIL的解码步骤:
import lmdb # 初始化LMDB环境,map_size根据你的数据量调整 env = lmdb.open('your_lmdb_storage', map_size=1024*1024*1024) with env.begin(write=True) as txn: # 直接读取磁盘上的JPEG文件二进制数据 with open('target_image.jpg', 'rb') as f: raw_jpeg_bytes = f.read() # 存入LMDB,key可以自定义 txn.put(b'image_001', raw_jpeg_bytes)
这种方式100%保留了原来的quality=90的JPEG数据,没有任何解码和重新压缩的过程,是最高效的做法。
必须用PIL处理时的折中方案
如果因为业务需求(比如要裁剪、 resize、调整色彩等)必须用PIL加载图像,那在保存回JPEG时,一定要显式指定quality=90,这样能让重新压缩的质量和原图像一致,把二次压缩的损失降到最低:
from PIL import Image import lmdb import io env = lmdb.open('your_lmdb_storage', map_size=1024*1024*1024) with env.begin(write=True) as txn: img = Image.open('target_image.jpg') # 这里可以做你需要的像素级处理,比如: # img = img.resize((256, 256)) # 用BytesIO缓存图像数据,再存入LMDB buffer = io.BytesIO() img.save(buffer, format='JPEG', quality=90) txn.put(b'image_001', buffer.getvalue())
总结一下
- 只要用PIL加载了JPEG(解码成像素),再次保存就一定会重新压缩,和原图像的quality参数无关;
- 避免二次压缩的最优解是直接存储原始JPEG字节数据;
- 必须用PIL处理时,指定和原图像一致的quality=90即可,不需要用100。
内容的提问来源于stack exchange,提问作者filby
相关产品推荐
相关产品推荐

