使用Python+Pillow开发一个图片批量格式转换工具

 更新时间:2026年05月11日 09:17:33   作者:yuanpan  
在日常办公、数据处理、网站开发和图像处理学习中,经常会遇到图片格式转换需求,如果图片数量很少,可以使用图像编辑软件手动转换,但当图片数量达到几十张、几百张甚至更多时,手动操作就非常低效,所以本文介绍了使用Python+Pillow开发一个图片批量格式转换工具

引言

在日常办公、数据处理、网站开发和图像处理学习中,经常会遇到图片格式转换需求,例如:

  • 将 JPG 图片批量转换为 PNG
  • 将 PNG 图片批量转换为 JPG
  • 压缩图片体积,方便上传或传输
  • 批量调整图片尺寸
  • 处理整个目录下的图片文件

如果图片数量很少,可以使用图像编辑软件手动转换。但当图片数量达到几十张、几百张甚至更多时,手动操作就非常低效。Python 的 Pillow 库可以很好地解决这个问题。

本文面向 Python 图像处理入门者,使用 Pillow 实现一个简易的图片批量格式转换工具。

一、Pillow 是什么

Pillow 是 Python 中最常用的图像处理库之一,它是 PIL 的现代维护版本。

PIL 的全称是 Python Imaging Library,但原始 PIL 已经停止维护。现在实际项目中通常安装和使用的是 Pillow,不过导入时仍然使用:

from PIL import Image

Pillow 支持常见图像处理操作,例如:

  • 打开图片
  • 保存图片
  • 图片格式转换
  • 图片压缩
  • 图片缩放
  • 图片裁剪
  • 图片旋转
  • 添加水印
  • 获取图片尺寸和模式

对于 Python 图像处理入门者来说,Pillow 是非常适合练手的库。

二、Pillow 安装

使用 pip 安装:

pip install pillow

如果使用的是国内网络环境,也可以指定镜像源:

pip install pillow -i https://pypi.tuna.tsinghua.edu.cn/simple

验证是否安装成功:

from PIL import Image

print(Image.__version__)

如果可以正常输出版本号,说明 Pillow 安装成功。

三、打开和查看图片信息

在做格式转换之前,先看一下如何读取图片基本信息。

from PIL import Image

image_path = "demo.jpg"

with Image.open(image_path) as img:
    print(f"图片格式:{img.format}")
    print(f"图片尺寸:{img.size}")
    print(f"图片模式:{img.mode}")

常见的图片模式包括:

  • RGB:常见彩色 图片模式
  • RGBA:带透明通道的图片模式
  • L:灰度图模式
  • P:调色板模式

理解图片模式很重要,尤其是在 PNG 转 JPG 时。因为 JPG 不支持透明通道,如果直接保存 RGBA 图片为 JPG,可能会报错。

四、JPG 转 PNG

JPG 转 PNG 的核心逻辑非常简单:打开 JPG 文件,然后保存为 PNG 文件。

from PIL import Image

input_path = "demo.jpg"
output_path = "demo.png"

with Image.open(input_path) as img:
    img.save(output_path, "PNG")

print("JPG 转 PNG 完成")

如果希望统一转换为 RGB 模式,可以写成:

from PIL import Image

with Image.open("demo.jpg") as img:
    img = img.convert("RGB")
    img.save("demo.png", "PNG")

PNG 是无损格式,适合保存截图、图标、透明背景图片等。但 PNG 文件体积通常比 JPG 更大。

五、PNG 转 JPG

PNG 转 JPG 时,需要特别注意透明通道。

JPG 不支持透明背景,如果 PNG 是 RGBA 模式,需要先转换为 RGB

from PIL import Image

input_path = "demo.png"
output_path = "demo.jpg"

with Image.open(input_path) as img:
    img = img.convert("RGB")
    img.save(output_path, "JPEG")

print("PNG 转 JPG 完成")

如果 PNG 图片带透明背景,直接 convert("RGB") 可能会把透明区域变成黑色。更稳妥的方式是先创建一个白色背景,再把 PNG 贴上去。

from PIL import Image

input_path = "logo.png"
output_path = "logo.jpg"

with Image.open(input_path) as img:
    if img.mode in ("RGBA", "LA"):
        background = Image.new("RGB", img.size, (255, 255, 255))
        background.paste(img, mask=img.getchannel("A"))
        background.save(output_path, "JPEG")
    else:
        img.convert("RGB").save(output_path, "JPEG")

print("PNG 转 JPG 完成")

这种处理方式更适合批量转换,因为它能兼容透明 PNG。

六、图片压缩

图片压缩通常用于减小文件体积。对于 JPG 图片,可以通过 quality 参数控制质量。

from PIL import Image

input_path = "demo.jpg"
output_path = "demo_compressed.jpg"

with Image.open(input_path) as img:
    img = img.convert("RGB")
    img.save(output_path, "JPEG", quality=70, optimize=True)

print("图片压缩完成")

参数说明:

  • quality:图片质量,取值一般为 1 到 95,数值越大质量越高,文件越大
  • optimize=True:让 Pillow 尽量优化保存结果

常用建议:

  • 文章配图可以使用 quality=75
  • 缩略图可以使用 quality=60
  • 高清存档可以使用 quality=90

PNG 也可以压缩:

from PIL import Image

with Image.open("demo.png") as img:
    img.save("demo_compressed.png", "PNG", optimize=True)

需要注意的是,PNG 是无损格式,单纯使用 Pillow 压缩时,体积下降不一定明显。如果对 PNG 压缩要求很高,可以结合专门的压缩工具。

七、图片尺寸调整

调整图片尺寸可以使用 resize()

from PIL import Image

input_path = "demo.jpg"
output_path = "demo_resized.jpg"

with Image.open(input_path) as img:
    resized = img.resize((800, 600))
    resized.save(output_path)

print("图片尺寸调整完成")

不过直接指定固定宽高可能导致图片变形。实际项目中更常见的是按比例缩放。

from PIL import Image

def resize_keep_ratio(img, max_width, max_height):
    img_copy = img.copy()
    img_copy.thumbnail((max_width, max_height))
    return img_copy

with Image.open("demo.jpg") as img:
    resized = resize_keep_ratio(img, 800, 800)
    resized.save("demo_resized.jpg")

thumbnail() 会保持原图比例,并确保图片不会超过指定的最大宽高。

例如,原图是 3000 x 2000,最大尺寸设置为 800 x 800,缩放后会变成 800 x 533,不会被拉伸变形。

八、批量处理整个目录

批量处理目录的核心思路:

  1. 遍历输入目录下的文件
  2. 判断文件后缀是否为图片格式
  3. 使用 Pillow 打开图片
  4. 根据目标格式转换并保存
  5. 遇到异常时跳过并打印错误信息

可以先写一个简单版本:

from pathlib import Path
from PIL import Image

input_dir = Path("input_images")
output_dir = Path("output_images")
output_dir.mkdir(parents=True, exist_ok=True)

for image_path in input_dir.iterdir():
    if image_path.suffix.lower() not in [".jpg", ".jpeg", ".png", ".bmp", ".webp"]:
        continue

    output_path = output_dir / f"{image_path.stem}.png"

    with Image.open(image_path) as img:
        img.save(output_path, "PNG")

    print(f"已转换:{image_path.name} -> {output_path.name}")

这个版本可以完成基本批量转换,但还不够灵活。下面我们会封装成一个完整工具。

九、完整代码案例:图片批量格式转换工具

下面的完整代码支持:

  • JPG、PNG、BMP、WEBP 等常见图片格式输入
  • 输出为 JPG、PNG、WEBP
  • 可选图片压缩质量
  • 可选最大宽高,保持比例缩放
  • 批量处理整个目录
  • 自动创建输出目录
  • 兼容 PNG 透明通道转 JPG 的情况

保存为 batch_image_converter.py

import argparse
from pathlib import Path

from PIL import Image


SUPPORTED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".bmp", ".webp", ".tif", ".tiff"}
SUPPORTED_OUTPUT_FORMATS = {"jpg", "jpeg", "png", "webp"}


def normalize_format(output_format):
    output_format = output_format.lower().strip(".")
    if output_format not in SUPPORTED_OUTPUT_FORMATS:
        raise ValueError(f"不支持的输出格式:{output_format}")
    return "jpg" if output_format == "jpeg" else output_format


def get_output_suffix(output_format):
    return ".jpg" if output_format in ("jpg", "jpeg") else f".{output_format}"


def prepare_image_for_jpg(img, background_color=(255, 255, 255)):
    if img.mode in ("RGBA", "LA"):
        background = Image.new("RGB", img.size, background_color)
        alpha = img.getchannel("A")
        background.paste(img, mask=alpha)
        return background

    if img.mode == "P":
        img = img.convert("RGBA")
        if "A" in img.getbands():
            background = Image.new("RGB", img.size, background_color)
            background.paste(img, mask=img.getchannel("A"))
            return background

    return img.convert("RGB")


def resize_keep_ratio(img, max_width=None, max_height=None):
    if not max_width and not max_height:
        return img

    width, height = img.size
    target_width = max_width or width
    target_height = max_height or height

    resized = img.copy()
    resized.thumbnail((target_width, target_height))
    return resized


def save_image(img, output_path, output_format, quality):
    if output_format == "jpg":
        img = prepare_image_for_jpg(img)
        img.save(output_path, "JPEG", quality=quality, optimize=True)
        return

    if output_format == "png":
        img.save(output_path, "PNG", optimize=True)
        return

    if output_format == "webp":
        img.save(output_path, "WEBP", quality=quality, method=6)
        return

    raise ValueError(f"不支持的输出格式:{output_format}")


def convert_one_image(image_path, output_dir, output_format, quality, max_width, max_height):
    output_suffix = get_output_suffix(output_format)
    output_path = output_dir / f"{image_path.stem}{output_suffix}"

    with Image.open(image_path) as img:
        img = resize_keep_ratio(img, max_width=max_width, max_height=max_height)
        save_image(img, output_path, output_format, quality)

    return output_path


def batch_convert(input_dir, output_dir, output_format, quality=80, max_width=None, max_height=None):
    input_dir = Path(input_dir)
    output_dir = Path(output_dir)
    output_format = normalize_format(output_format)

    if not input_dir.exists():
        raise FileNotFoundError(f"输入目录不存在:{input_dir}")

    if not input_dir.is_dir():
        raise NotADirectoryError(f"输入路径不是目录:{input_dir}")

    output_dir.mkdir(parents=True, exist_ok=True)

    total = 0
    success = 0
    failed = 0

    for image_path in input_dir.rglob("*"):
        if not image_path.is_file():
            continue

        if image_path.suffix.lower() not in SUPPORTED_EXTENSIONS:
            continue

        total += 1

        try:
            output_path = convert_one_image(
                image_path=image_path,
                output_dir=output_dir,
                output_format=output_format,
                quality=quality,
                max_width=max_width,
                max_height=max_height,
            )
            success += 1
            print(f"[成功] {image_path} -> {output_path}")
        except Exception as exc:
            failed += 1
            print(f"[失败] {image_path},原因:{exc}")

    print("-" * 60)
    print(f"处理完成:总数={total},成功={success},失败={failed}")


def parse_args():
    parser = argparse.ArgumentParser(description="Python Pillow 图片批量格式转换工具")
    parser.add_argument("-i", "--input", required=True, help="输入图片目录")
    parser.add_argument("-o", "--output", required=True, help="输出图片目录")
    parser.add_argument(
        "-f",
        "--format",
        default="jpg",
        choices=["jpg", "jpeg", "png", "webp"],
        help="输出图片格式,默认 jpg",
    )
    parser.add_argument(
        "-q",
        "--quality",
        type=int,
        default=80,
        help="图片质量,主要用于 jpg 和 webp,默认 80",
    )
    parser.add_argument("--max-width", type=int, default=None, help="最大宽度,保持比例缩放")
    parser.add_argument("--max-height", type=int, default=None, help="最大高度,保持比例缩放")
    return parser.parse_args()


def main():
    args = parse_args()

    batch_convert(
        input_dir=args.input,
        output_dir=args.output,
        output_format=args.format,
        quality=args.quality,
        max_width=args.max_width,
        max_height=args.max_height,
    )


if __name__ == "__main__":
    main()

十、运行示例

input_images 目录下的图片批量转换为 JPG:

python batch_image_converter.py -i input_images -o output_images -f jpg

转换为 PNG:

python batch_image_converter.py -i input_images -o output_images -f png

转换为 WEBP,并设置压缩质量:

python batch_image_converter.py -i input_images -o output_images -f webp -q 75

批量压缩 JPG:

python batch_image_converter.py -i input_images -o compressed_images -f jpg -q 60

批量调整尺寸,最大宽度和高度不超过 800:

python batch_image_converter.py -i input_images -o resized_images -f jpg --max-width 800 --max-height 800

批量转换并压缩:

python batch_image_converter.py -i input_images -o result_images -f jpg -q 70 --max-width 1200 --max-height 1200

十一、代码设计说明

这个工具把功能拆成了几个函数:

  • normalize_format():统一处理输出格式
  • prepare_image_for_jpg():解决透明 PNG 转 JPG 的问题
  • resize_keep_ratio():保持比例调整尺寸
  • save_image():根据目标格式保存图片
  • convert_one_image():处理单张图片
  • batch_convert():批量处理整个目录
  • parse_args():解析命令行参数

这种拆分方式比把所有逻辑写在一个循环里更容易维护。后续要增加水印、重命名、跳过已存在文件等功能,也可以继续扩展。

十二、GUI 简单扩展思路

当前工具是命令行版本,适合脚本自动化和批处理。如果要做成图形界面,可以使用 Tkinter、PyQt 或 PySide。

一个简单 GUI 可以包含这些控件:

  • 输入目录选择按钮
  • 输出目录选择按钮
  • 输出格式下拉框
  • 图片质量滑块
  • 最大宽度和最大高度输入框
  • 开始转换按钮
  • 转换日志显示区域
  • 进度条

如果使用 Tkinter,基本结构可以这样设计:

import tkinter as tk
from tkinter import filedialog, messagebox


def choose_input_dir():
    path = filedialog.askdirectory()
    input_var.set(path)


def choose_output_dir():
    path = filedialog.askdirectory()
    output_var.set(path)


def start_convert():
    input_dir = input_var.get()
    output_dir = output_var.get()
    output_format = format_var.get()

    if not input_dir or not output_dir:
        messagebox.showwarning("提示", "请选择输入目录和输出目录")
        return

    # 这里可以调用前面的 batch_convert() 函数
    messagebox.showinfo("完成", f"开始转换为 {output_format}")


root = tk.Tk()
root.title("图片批量格式转换工具")
root.geometry("500x260")

input_var = tk.StringVar()
output_var = tk.StringVar()
format_var = tk.StringVar(value="jpg")

tk.Label(root, text="输入目录").pack(anchor="w", padx=20, pady=5)
tk.Entry(root, textvariable=input_var, width=50).pack(anchor="w", padx=20)
tk.Button(root, text="选择输入目录", command=choose_input_dir).pack(anchor="w", padx=20, pady=5)

tk.Label(root, text="输出目录").pack(anchor="w", padx=20, pady=5)
tk.Entry(root, textvariable=output_var, width=50).pack(anchor="w", padx=20)
tk.Button(root, text="选择输出目录", command=choose_output_dir).pack(anchor="w", padx=20, pady=5)

tk.Label(root, text="输出格式").pack(anchor="w", padx=20, pady=5)
tk.OptionMenu(root, format_var, "jpg", "png", "webp").pack(anchor="w", padx=20)

tk.Button(root, text="开始转换", command=start_convert).pack(pady=15)

root.mainloop()

实际开发时,可以直接复用命令行版本中的 batch_convert() 函数。这样核心处理逻辑不用重写,只需要把 GUI 控件中的参数传给函数即可。

如果图片数量很多,GUI 中还需要注意一点:不要在主线程里直接执行批量转换,否则界面可能卡住。可以使用 threading.Thread 把转换任务放到子线程中执行。

十三、常见问题

1. 为什么 PNG 转 JPG 报错

常见原因是 PNG 图片包含透明通道,而 JPG 不支持透明通道。解决方式是先转换为 RGB,或者先合成白色背景。

2. 为什么压缩后图片还是很大

可能原因包括:

  • 原图尺寸太大
  • quality 设置过高
  • PNG 本身不适合用 Pillow 大幅压缩
  • 图片内容复杂,压缩空间有限

可以同时使用降低质量和调整尺寸两种方式。

3. 为什么批量处理时有些图片失败

可能原因包括:

  • 文件扩展名是图片,但文件内容已经损坏
  • 文件权限不足
  • 路径中存在特殊权限问题
  • 输出目录不可写

所以批量脚本中要使用 try except,避免一张图片失败导致整个任务中断。

十四、总结

本文使用 Python + Pillow 实现了一个图片批量格式转换工具,覆盖了图像处理入门中非常常见的几个需求:

  • 安装 Pillow
  • JPG 转 PNG
  • PNG 转 JPG
  • 图片压缩
  • 图片尺寸调整
  • 批量处理整个目录
  • 命令行完整代码案例
  • GUI 图形界面扩展思路

这个案例非常适合作为 Python 图像处理入门练习。掌握这些基础之后,可以继续扩展水印添加、图片裁剪、缩略图生成、图片重命名、EXIF 信息读取等功能,逐步做成一个更完整的图片处理工具箱。

以上就是使用Python+Pillow开发一个图片批量格式转换工具的详细内容,更多关于Python Pillow图片格式转换工具的资料请关注脚本之家其它相关文章!

相关文章

  • Python函数进阶与文件操作详情

    Python函数进阶与文件操作详情

    这篇文章主要介绍了Python函数进阶与文件操作详情,文章为荣啊主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-08-08
  • Python SMTP发送电子邮件的示例

    Python SMTP发送电子邮件的示例

    这篇文章主要介绍了Python SMTP发送电子邮件的示例,帮助大家更好的理解和使用python,感兴趣的朋友可以了解下
    2020-09-09
  • Python实现GUI计算器(附源码)

    Python实现GUI计算器(附源码)

    这篇文章主要为大家详细介绍了如何利用Python语言实现GUI计算器,可执行复杂运算,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下
    2022-11-11
  • 使用python-magic和wxPython实现识别文档类型

    使用python-magic和wxPython实现识别文档类型

    这篇文章主要介绍了如何使用python-magic模块和wxPython库创建一个简单的文件列表应用程序,该应用程序可以显示所选文件夹中文件的类型,需要的可以参考下
    2023-08-08
  • python将Dataframe格式的数据写入opengauss数据库并查询

    python将Dataframe格式的数据写入opengauss数据库并查询

    这篇文章主要介绍了python将Dataframe格式的数据写入opengauss数据库并查询,文章介绍详细具有一定的参考价值,希望对你的学习有所帮助
    2022-04-04
  • Python如何telnet到网络设备

    Python如何telnet到网络设备

    这篇文章主要介绍了Python如何telnet到网络设备,帮助大家更好的理解和使用python,感兴趣的朋友可以了解下
    2021-02-02
  • Python使用Flask-SQLAlchemy连接数据库操作示例

    Python使用Flask-SQLAlchemy连接数据库操作示例

    这篇文章主要介绍了Python使用Flask-SQLAlchemy连接数据库操作,简单介绍了flask、Mysql-Python以及Flask-SQLAlchemy的安装方法,并结合实例形式分析了基于Flask-SQLAlchemy的数据库连接相关操作技巧,需要的朋友可以参考下
    2018-08-08
  • Django用户认证系统 组与权限解析

    Django用户认证系统 组与权限解析

    这篇文章主要介绍了Django用户认证系统 组与权限解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • 使用Python计算TRC20地址

    使用Python计算TRC20地址

    这篇文章主要为大家详细介绍了如何使用Python实现计算TRC20地址,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-02-02
  • M1 mac安装PyTorch的实现步骤

    M1 mac安装PyTorch的实现步骤

    本文将介绍如何在M1机器上本地安装和运行PyTorch。你使用的M1机型(Air、Pro、Mini或iMac)没有区别。感兴趣的可以了解一下
    2021-08-08

最新评论