A-A+
python 图片压缩脚本

【注意:此文章为博主原创文章!转载需注意,请带原文链接,至少也要是txt格式!】
上一版的代码虽然会递归查找文件,但它把所有处理后的图片都“拍扁”放在了同一个输出文件夹里。
为了满足你保持原有层级结构(子文件夹)和文件名不变的需求,我们需要引入 os.path.relpath 来计算相对路径,从而在输出目录中重建一模一样的文件夹结构。
这是升级后的代码,完美支持递归查找并保持目录结构。
更新后的功能特点:
- 递归处理:会自动深入所有子文件夹。
- 保持结构:如果原图在
原图文件夹/2023/旅行/,处理后会在输出文件夹/2023/旅行/。 - 智能跳过:如果输出目录里已经存在同名文件,代码会跳过(防止重复劳动),或者你可以选择覆盖。
- 高质量压缩:依然保持
LANCZOS算法和subsampling=0参数,确保 1024px 分辨率下的最顶级画质。
1. 核心算法回顾(LaTeX)
为了保证不变形,我们依然采用以下逻辑: 设原图宽 w,高 h,目标最大边长 Max=1024。 当 max(w,h)>Max 时,缩放因子 k 为:
k=Maxmax(w,h)
新的尺寸为:
wnew=⌊w×k⌋,hnew=⌊h×k⌋
2. 完整代码
请保存为 compress_structure.py:
import os
from PIL import Image, ImageOps
from tqdm import tqdm
def compress_image(file_path, save_path, max_size=1024, quality=88):
"""
读取 file_path,处理后保存到 save_path
"""
try:
# 打开图片
img = Image.open(file_path)
# 1. 修正图片方向 (Exif)
img = ImageOps.exif_transpose(img)
# 获取原始尺寸
width, height = img.size
# 2. 计算调整后的尺寸
# 仅当图片尺寸超过 max_size 时才缩小
if max(width, height) > max_size:
scale_ratio = max_size / max(width, height)
new_width = int(width * scale_ratio)
new_height = int(height * scale_ratio)
# 使用最优质的 LANCZOS 滤镜
img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
# 3. 格式处理 (PNG转JPG以获得更佳压缩率,也可以根据需求保留原格式)
# 如果图片包含透明通道(RGBA),填充白色背景转为RGB
if img.mode in ("RGBA", "P"):
background = Image.new("RGB", img.size, (255, 255, 255))
if img.mode == 'P':
img = img.convert("RGBA")
background.paste(img, mask=img.split()[3]) # 3 is the alpha channel
img = background
elif img.mode != "RGB":
img = img.convert("RGB")
# 4. 保存图片
# optimize=True: 开启优化
# subsampling=0: 4:4:4采样,防止颜色边缘模糊
img.save(save_path, 'JPEG', quality=quality, optimize=True, subsampling=0)
return True
except Exception as e:
print(f"\n[Error] {file_path}: {e}")
return False
def batch_process_preserve_structure(input_root, output_root, max_size=1024):
"""
递归遍历 input_root,保持结构输出到 output_root
"""
valid_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp', '.heic'}
# 收集任务列表 [(原图路径, 目标路径), ...]
tasks = []
print(f"正在扫描目录: {input_root} ...")
for root, dirs, files in os.walk(input_root):
for file in files:
ext = os.path.splitext(file)[1].lower()
if ext in valid_extensions:
# 1. 构建原文件绝对路径
src_path = os.path.join(root, file)
# 2. 计算相对路径 (例如: subfolder/image.jpg)
rel_path = os.path.relpath(root, input_root)
# 3. 构建目标文件夹路径
dest_folder = os.path.join(output_root, rel_path)
# 4. 构建目标文件完整路径 (统一后缀为 .jpg)
file_name_no_ext = os.path.splitext(file)[0]
dest_path = os.path.join(dest_folder, file_name_no_ext + ".jpg")
tasks.append((src_path, dest_folder, dest_path))
total_files = len(tasks)
if total_files == 0:
print("未找到图片文件。")
return
print(f"找到 {total_files} 张图片,开始处理...")
print(f"目标分辨率限制: {max_size}px")
# 使用 tqdm 显示总进度
with tqdm(total=total_files, unit="img") as pbar:
for src_path, dest_folder, dest_path in tasks:
# 如果目标文件夹不存在,创建它 (保持层级结构的关键)
if not os.path.exists(dest_folder):
os.makedirs(dest_folder)
# 执行压缩
compress_image(src_path, dest_path, max_size=max_size)
pbar.update(1)
print("-" * 30)
print(f"全部完成!输出目录: {output_root}")
if __name__ == "__main__":
# ================= 设置区域 =================
# 你的原图根目录
INPUT_DIR = r"C:\Users\YourName\Pictures\Originals"
# 你想输出的根目录 (会自动创建对应的子文件夹)
OUTPUT_DIR = r"C:\Users\YourName\Pictures\Compressed_Structure"
# ===========================================
if not os.path.exists(INPUT_DIR):
print(f"错误: 输入目录不存在 -> {INPUT_DIR}")
else:
batch_process_preserve_structure(INPUT_DIR, OUTPUT_DIR)
布施恩德可便相知重
微信扫一扫打赏
支付宝扫一扫打赏