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

如何使用Python-Pillow精准调整JPG文件大小?

用Python-Pillow精准控制JPG文件大小的解决方案

问题根源

你当前仅通过缩放尺寸来控制文件大小,但JPG的文件大小由像素总量+压缩质量共同决定。Pillow保存JPG时默认使用75的质量参数,即便你把尺寸调到对应3MB的量级,高压缩率也会让最终文件远小于预期。

解决思路

要精准控制JPG大小,需结合尺寸预调整和压缩质量循环试探:

  • 先判断原图尺寸是否过大,若远超目标大小对应的像素量,先按比例缩放缩小基础体积
  • 通过二分法循环调整JPG压缩质量参数,每次保存后校验文件大小,直到结果落在目标误差范围内

改进后的代码

import os
from PIL import Image
from pathlib import Path

def get_img_format(suffix):
    lower_suffix = suffix.lower()
    return 'jpeg' if lower_suffix in ('.jpg', '.jpeg') else 'png'

def adjust_jpg_size(image_path, target_size_mb, error_tolerance=0.05):
    target_bytes = target_size_mb * 1024 * 1024  # 转换为字节单位
    img = Image.open(image_path)
    img_format = get_img_format(Path(image_path).suffix)
    
    # 仅处理JPG格式,跳过其他格式文件
    if img_format != 'jpeg':
        print(f"{image_path} 非JPG格式,跳过处理")
        return
    
    # 第一步:预缩放尺寸(若原图远大于目标大小)
    current_size = os.path.getsize(image_path)
    if current_size > target_bytes:
        # 按面积比例估算缩放系数(像素面积与文件大小正相关)
        scale_ratio = (target_bytes / current_size) ** 0.5
        new_width = int(img.width * scale_ratio)
        new_height = int(img.height * scale_ratio)
        # 用LANCZOS插值缩放,保证画质
        img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
    
    # 第二步:二分法查找最优压缩质量
    min_quality = 10
    max_quality = 95
    best_quality = 75
    best_size = float('inf')
    temp_path = Path(image_path).parent / f"temp_{Path(image_path).stem}.jpg"
    
    while min_quality <= max_quality:
        mid_quality = (min_quality + max_quality) // 2
        # 保存临时文件,开启optimize优化压缩
        img.save(temp_path, 'jpeg', quality=mid_quality, optimize=True)
        temp_size = os.path.getsize(temp_path)
        
        # 检查是否在误差容忍范围内
        if abs(temp_size - target_bytes) <= target_bytes * error_tolerance:
            best_quality = mid_quality
            best_size = temp_size
            break
        
        # 调整质量搜索范围
        if temp_size < target_bytes:
            # 文件过小,提高质量(降低压缩率)
            min_quality = mid_quality + 1
        else:
            # 文件过大,降低质量(提高压缩率)
            max_quality = mid_quality - 1
        
        # 记录最接近目标的参数
        if abs(temp_size - target_bytes) < abs(best_size - target_bytes):
            best_quality = mid_quality
            best_size = temp_size
    
    # 保存最终结果并清理临时文件
    final_path = Path(image_path).parent / f"{Path(image_path).stem}_resized.jpg"
    img.save(final_path, 'jpeg', quality=best_quality, optimize=True)
    os.remove(temp_path)
    
    print(f"处理完成:{final_path},实际大小:{best_size/1024/1024:.2f}MB,使用质量参数:{best_quality}")

def batch_process(folder, target_size_mb=3):
    p = Path(folder)
    extensions = ["*.jpg", "*.jpeg", "*.JPG", "*.JPEG"]
    for ext in extensions:
        for file in p.rglob(ext):
            adjust_jpg_size(str(file), target_size_mb)

if __name__ == '__main__':
    batch_process(r'D:\code_prj\Med_OCR\data')

关键说明

  • 压缩质量参数:Pillow的quality取值范围为1-95,数值越高画质越好、文件越大;optimize=True会启用压缩优化,让结果更稳定
  • 二分法查找:相比线性遍历1-95的质量值,二分法能快速缩小范围,提升处理效率
  • 误差容忍:设置error_tolerance=0.05允许最终大小与目标有±5%的误差,避免因JPG压缩的非线性特性导致无限循环
  • 插值缩放:使用Image.Resampling.LANCZOS插值算法,缩放后的图片画质更清晰

注意事项

  • 不同内容的图片(纯色图/复杂风景图)压缩率差异极大,相同质量参数下文件大小可能不同,循环试探是最可靠的控制方式
  • 若原图本身尺寸过小,即使将质量调到95也无法达到目标大小,可在代码中添加提示逻辑
  • 批量处理时建议先测试单张图片,确认参数效果后再推广到全文件夹

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 20:05:35