当前位置: 代码网 > it编程>前端脚本>Python > 使用Python+Pillow开发一个图片批量格式转换工具

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

2026年05月11日 Python 我要评论
引言在日常办公、数据处理、网站开发和图像处理学习中,经常会遇到图片格式转换需求,例如:将 jpg 图片批量转换为 png将 png 图片批量转换为 jpg压缩图片体积,方便上传或传输批量调整图片尺寸处

引言

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

  • 将 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图片格式转换工具的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com