【Python】一个适配本网站性能的压缩图片脚本

由于网站的服务器与带宽性能有限,因此上传的图片被严格限制了边长和大小,使用脚本可以有效对想要上传的文件进行批处理,节省时间。

参考代码:

实现对jpg、png、webp等文件的压缩,限制最长边2560,大小2m以下,随机文件名且保留可能含有的EXIF信息。

暂不支持中文路径文件夹。

import os
import random
import string
from PIL import Image
import tkinter as tk
from tkinterdnd2 import TkinterDnD, DND_FILES

# 生成随机文件名
def generate_random_filename(length=10):
    """生成指定长度的随机文件名(字母和数字)"""
    return ''.join(random.choices(string.ascii_letters + string.digits, k=length))

def compress_image(input_path, max_size=2560, max_file_size=2 * 1024 * 1024, quality=85):
    """对图片进行压缩和尺寸调整,保留EXIF信息"""
    img = Image.open(input_path)
    exif_data = img.info.get("exif")  # 获取EXIF数据
    width, height = img.size
    file_size = os.path.getsize(input_path)
    
    # 生成随机文件名前缀
    random_prefix = generate_random_filename(10)  # 10 位随机字符前缀

    # 获取文件扩展名
    file_extension = os.path.splitext(input_path)[1].lower()

    # 如果图片是RGBA格式,将其转换为RGB格式,只对JPEG格式需要转换
    if img.mode == 'RGBA' and file_extension not in ['.jpeg', '.jpg']:
        output_path = os.path.join(os.path.dirname(input_path), f"{random_prefix}_已压缩{file_extension}")
        if exif_data:
            img.save(output_path, quality=quality, optimize=True, exif=exif_data)
        else:
            img.save(output_path, quality=quality, optimize=True)
    else:
        # 如果图片不需要压缩,直接保存为“无需压缩”版本
        if max(width, height) <= max_size and file_size <= max_file_size:
            output_path = os.path.join(os.path.dirname(input_path), f"{random_prefix}_无需压缩{file_extension}")
            if exif_data:
                img.save(output_path, exif=exif_data)
            else:
                img.save(output_path)
        else:
            # 如果需要调整大小
            if max(width, height) > max_size:
                scaling_factor = max_size / float(max(width, height))
                new_size = (int(width * scaling_factor), int(height * scaling_factor))
                img = img.resize(new_size, Image.LANCZOS)
            
            # 保存为JPEG格式,质量为85
            output_path = os.path.join(os.path.dirname(input_path), f"{random_prefix}_已压缩.jpg")
            if exif_data:
                img.save(output_path, quality=quality, optimize=True, exif=exif_data)
            else:
                img.save(output_path, quality=quality, optimize=True)
            
            # 如果文件过大,继续降低质量,直到符合要求
            while os.path.getsize(output_path) > max_file_size and quality > 10:
                quality -= 10
                if exif_data:
                    img.save(output_path, quality=quality, optimize=True, exif=exif_data)
                else:
                    img.save(output_path, quality=quality, optimize=True)
    
    return output_path

# 处理拖动的文件
def on_drop(event):
    file_paths = event.data.split()
    process_images(file_paths)

# 批量处理图片
def process_images(file_paths):
    processed_files = []
    for file_path in file_paths:
        if is_image_file(file_path):
            processed_file = compress_image(file_path)
            processed_files.append(processed_file)
    print(f"处理完成的文件: {processed_files}")

# 判断文件是否为图片
def is_image_file(file_path):
    try:
        img = Image.open(file_path)
        return True
    except IOError:
        return False

# 创建GUI界面
root = TkinterDnD.Tk()
root.title("图片压缩工具")
root.geometry("600x400")

label = tk.Label(root, text="将图片拖到这里", padx=20, pady=20)
label.pack(padx=20, pady=20)

# 绑定拖拽事件
root.drop_target_register(DND_FILES)
root.dnd_bind('<<Drop>>', on_drop)

# 运行主循环
root.mainloop()

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注