【Python】使用PIL库进行多格式批量转换WebP并压缩分辨率

网站将逐步切换到WebP格式图片,今天捣鼓了插件在服务器端替换图片,但WP的媒体库却怎么都搞不定了,媒体库会自动生成很多缩略图用于不同的场景,我不想碰它的缩略图生成效果,因此只写单一的转换代码是没法做出完整的效果的。

退而求其次使用本地对图片进行处理,该脚本使用PIL库,图片分辨率限制为2560最长/宽,可以处理带透明通道的图片,也可以处理GIF,用下来效果还不错。

1月8日更新:

【Python】使用WebP官方库进行WebP转换
【Python】使用cwebp、gif2webp、exiftool实现保留exif信息的WebP转换

import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageSequence
import os

def resize_image(img):
    max_size = 2560
    width, height = img.size

    if width > max_size or height > max_size:
        if width > height:
            new_width = max_size
            new_height = int((new_width / width) * height)
        else:
            new_height = max_size
            new_width = int((new_height / height) * width)
        
        img = img.resize((new_width, new_height), Image.LANCZOS)
    
    return img

def convert_to_webp(input_path):
    try:
        file_extension = os.path.splitext(input_path)[1].lower()
        output_path = os.path.splitext(input_path)[0] + ".webp"

        if not os.path.exists(input_path):
            raise FileNotFoundError(f"文件 {input_path} 不存在,请检查路径。")

        if file_extension == '.webp':
            return f"文件 {input_path} 已是 WebP 格式,无需转换。"

        with Image.open(input_path) as img:
            if file_extension in ['.gif'] and getattr(img, "is_animated", False):
                frames = []
                durations = []
                for frame in ImageSequence.Iterator(img):
                    # 处理透明度
                    if frame.mode == "P":
                        frame = frame.convert("RGBA")
                    
                    # 转换帧为 RGBA 并存储
                    new_frame = frame.copy()
                    frames.append(new_frame)
                    durations.append(frame.info.get('duration', 100))

                # 重复最后一帧
                if len(frames) > 1:
                    durations[-1] = max(durations[-1], 100) 

                # 保存为动态 WebP
                frames[0].save(
                    output_path,
                    format="WEBP",
                    save_all=True,
                    append_images=frames[1:],
                    duration=durations,
                    loop=img.info.get('loop', 0),  # 循环次数
                    transparency=0,  # 确保透明度保留
                    quality=85
                )
            else:
                # 静态图片处理
                if img.mode == "P":
                    if "transparency" in img.info:
                        img = img.convert("RGBA")
                    else:
                        img = img.convert("RGB")

                img = resize_image(img)

                if img.mode != "RGBA":
                    img = img.convert("RGBA")

                img.save(output_path, format="WEBP", quality=85)

        return f"图片已转换并保存为 {output_path}"
    except Exception as e:
        return f"处理文件时发生错误: {e}"


def select_files():
    file_paths = filedialog.askopenfilenames(
        title="选择图片文件",
        filetypes=[("所有图片格式", "*.jpg;*.jpeg;*.png;*.gif;*.webp;*.bmp;*.tiff"), 
                   ("JPEG 图片", "*.jpg;*.jpeg"),
                   ("PNG 图片", "*.png"),
                   ("GIF 图片", "*.gif"),
                   ("WebP 图片", "*.webp"),
                   ("BMP 图片", "*.bmp"),
                   ("TIFF 图片", "*.tiff")]
    )
    if file_paths:
        for path in file_paths:
            file_listbox.insert(tk.END, path)

def convert_and_save_batch():
    files = file_listbox.get(0, tk.END)
    if not files:
        messagebox.showerror("错误", "请选择至少一个图片文件!")
        return

    results = []
    for file_path in files:
        result = convert_to_webp(file_path)
        results.append(result)

    messagebox.showinfo("完成", "\n".join(results))

def clear_list():
    file_listbox.delete(0, tk.END)

root = tk.Tk()
root.title("批量图片转换为 WebP 工具")
root.geometry("600x400")

frame = tk.Frame(root)
frame.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)

scrollbar = tk.Scrollbar(frame, orient=tk.VERTICAL)
file_listbox = tk.Listbox(frame, selectmode=tk.EXTENDED, yscrollcommand=scrollbar.set)
scrollbar.config(command=file_listbox.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
file_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

button_frame = tk.Frame(root)
button_frame.pack(pady=10)

select_button = tk.Button(button_frame, text="选择文件", command=select_files, width=15)
select_button.grid(row=0, column=0, padx=5)

clear_button = tk.Button(button_frame, text="清空列表", command=clear_list, width=15)
clear_button.grid(row=0, column=1, padx=5)

convert_button = tk.Button(button_frame, text="批量转换", command=convert_and_save_batch, width=15)
convert_button.grid(row=0, column=2, padx=5)

root.mainloop()

评论

《“【Python】使用PIL库进行多格式批量转换WebP并压缩分辨率”》 有 1 条评论

  1. […] 此前的代码使用了Pillow库集成的库,这次使用WebP官方库,对GIF、PNG的处理也比较友好。需要添加WebP的库到系统环境变量后使用。 […]

回复 【Python】使用WebP官方库进行WebP转换 – 万雪飞扬 取消回复

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