📚 前言
编程基础第一期《11-30》-- 在图像处理工作中,我们经常需要将大量图片从一种格式转换为另一种格式。本教程将介绍如何使用Python的Pillow库开发一个简单但功能强大的图片格式批量转换器,帮助你高效处理图片格式转换任务。
目录
-
- [📚 前言](#📚 前言)
- [🛠️ 开发环境准备](#🛠️ 开发环境准备)
- [💡 核心功能](#💡 核心功能)
- [🧩 技术要点](#🧩 技术要点)
-
- [1. Pillow库基础](#1. Pillow库基础)
- [2. 文件系统操作](#2. 文件系统操作)
- [3. 用户界面](#3. 用户界面)
- [📝 代码实现与解析](#📝 代码实现与解析)
-
- [1. 导入必要的库](#1. 导入必要的库)
- [2. 图片格式转换核心函数](#2. 图片格式转换核心函数)
- [3. 批量转换功能](#3. 批量转换功能)
- [4. 命令行界面](#4. 命令行界面)
- [5. 图形用户界面](#5. 图形用户界面)
- [6. 主函数](#6. 主函数)
- [🎮 使用方法](#🎮 使用方法)
- [🔍 进阶知识点](#🔍 进阶知识点)
-
- [1. 图像处理基础](#1. 图像处理基础)
- [2. Pillow高级特性](#2. Pillow高级特性)
- [3. 性能优化](#3. 性能优化)
- [🚀 可扩展功能](#🚀 可扩展功能)
- [📝 总结](#📝 总结)
🛠️ 开发环境准备
- Python 3.6+
- Pillow库 (PIL的fork版本)
安装Pillow库:
bash
pip install pillow
💡 核心功能
- 支持多种常见图片格式之间的转换(JPG, PNG, BMP, GIF, TIFF等)
- 批量处理指定文件夹中的所有图片
- 可选择保留原始图片或仅保留转换后的图片
- 支持调整图片质量和大小
- 简单的命令行界面和图形用户界面(GUI)两种使用方式
🧩 技术要点
1. Pillow库基础
Pillow是Python图像处理库(PIL)的一个分支,提供了丰富的图像处理功能。主要用到的模块:
Image
: 图像对象的创建、读取和保存ImageOps
: 图像操作,如调整大小、翻转等ImageEnhance
: 图像增强,如亮度、对比度调整
2. 文件系统操作
- 使用
os
和pathlib
模块处理文件路径 - 递归遍历目录
- 文件类型判断
3. 用户界面
- 命令行参数解析
- 简单GUI界面构建(使用tkinter)
📝 代码实现与解析
1. 导入必要的库
python
from PIL import Image
import os
import sys
import argparse
from pathlib import Path
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
知识点:
PIL.Image
: Pillow的核心模块,用于图像处理os
和pathlib
: 文件系统操作argparse
: 命令行参数解析tkinter
: Python标准GUI库
2. 图片格式转换核心函数
python
def convert_image(input_path, output_path, format, quality=95, resize=None):
"""
转换单个图片的格式
参数:
input_path - 输入图片路径
output_path - 输出图片路径
format - 目标格式 (如 'JPEG', 'PNG')
quality - 图片质量 (1-100, 仅对JPEG格式有效)
resize - 调整大小的元组 (width, height) 或 None
返回:
bool - 转换是否成功
"""
try:
# 打开图片
img = Image.open(input_path)
# 如果是RGBA模式且转换为JPEG,需要转换为RGB模式
if img.mode == 'RGBA' and format.upper() == 'JPEG':
img = img.convert('RGB')
# 调整大小
if resize:
img = img.resize(resize, Image.LANCZOS)
# 保存转换后的图片
if format.upper() == 'JPEG':
img.save(output_path, format=format, quality=quality)
else:
img.save(output_path, format=format)
return True
except Exception as e:
print(f"转换图片 {input_path} 时出错: {e}")
return False
知识点:
Image.open()
: 打开图片文件- 图像模式转换: RGBA转RGB(JPEG不支持透明通道)
Image.LANCZOS
: 高质量的图像缩放算法- 异常处理: 捕获并处理可能的错误
3. 批量转换功能
python
def batch_convert(input_dir, output_dir, target_format, quality=95,
resize=None, recursive=False, keep_original=True):
"""
批量转换指定目录中的图片
参数:
input_dir - 输入目录
output_dir - 输出目录
target_format - 目标格式
quality - 图片质量
resize - 调整大小的元组
recursive - 是否递归处理子目录
keep_original - 是否保留原始图片
返回:
tuple - (成功数量, 失败数量)
"""
# 支持的图片格式
supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff']
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
success_count = 0
failed_count = 0
# 遍历目录
for root, dirs, files in os.walk(input_dir):
# 如果不递归处理子目录且不是根目录,则跳过
if not recursive and root != input_dir:
continue
# 创建对应的输出子目录
rel_path = os.path.relpath(root, input_dir)
if rel_path != '.':
current_output_dir = os.path.join(output_dir, rel_path)
os.makedirs(current_output_dir, exist_ok=True)
else:
current_output_dir = output_dir
# 处理文件
for file in files:
# 检查文件扩展名
ext = os.path.splitext(file)[1].lower()
if ext not in supported_formats:
continue
# 构建输入和输出路径
input_path = os.path.join(root, file)
output_filename = os.path.splitext(file)[0] + '.' + target_format.lower()
output_path = os.path.join(current_output_dir, output_filename)
# 转换图片
if convert_image(input_path, output_path, target_format, quality, resize):
success_count += 1
# 如果不保留原始图片且不是在原目录操作,则删除原始图片
if not keep_original and input_dir != output_dir:
try:
os.remove(input_path)
except:
pass
else:
failed_count += 1
return (success_count, failed_count)
知识点:
os.walk()
: 递归遍历目录os.path.relpath()
: 获取相对路径os.makedirs()
: 创建多级目录- 文件扩展名处理: 使用
os.path.splitext()
分离文件名和扩展名
4. 命令行界面
python
def setup_cli():
"""设置命令行参数解析器"""
parser = argparse.ArgumentParser(description='批量转换图片格式')
parser.add_argument('input', help='输入目录或文件')
parser.add_argument('output', help='输出目录')
parser.add_argument('format', help='目标格式 (如: jpg, png, bmp)')
parser.add_argument('-q', '--quality', type=int, default=95,
help='图片质量 (1-100, 默认: 95)')
parser.add_argument('-r', '--recursive', action='store_true',
help='递归处理子目录')
parser.add_argument('-k', '--keep', action='store_true',
help='保留原始图片')
parser.add_argument('--resize', nargs=2, type=int, metavar=('WIDTH', 'HEIGHT'),
help='调整图片大小')
return parser.parse_args()
知识点:
argparse
: 命令行参数解析- 参数类型: 位置参数、可选参数、标志参数
- 参数类型转换: 使用
type=int
将字符串转换为整数
5. 图形用户界面
python
class ImageConverterGUI:
def __init__(self, root):
self.root = root
self.root.title("图片格式批量转换器")
self.root.geometry("600x450")
self.root.resizable(True, True)
# 创建主框架
main_frame = ttk.Frame(root, padding="10")
main_frame.pack(fill=tk.BOTH, expand=True)
# 输入目录
ttk.Label(main_frame, text="输入目录:").grid(column=0, row=0, sticky=tk.W, pady=5)
self.input_dir = tk.StringVar()
ttk.Entry(main_frame, width=50, textvariable=self.input_dir).grid(column=1, row=0, pady=5)
ttk.Button(main_frame, text="浏览...", command=self.browse_input).grid(column=2, row=0, padx=5, pady=5)
# 输出目录
ttk.Label(main_frame, text="输出目录:").grid(column=0, row=1, sticky=tk.W, pady=5)
self.output_dir = tk.StringVar()
ttk.Entry(main_frame, width=50, textvariable=self.output_dir).grid(column=1, row=1, pady=5)
ttk.Button(main_frame, text="浏览...", command=self.browse_output).grid(column=2, row=1, padx=5, pady=5)
# 目标格式
ttk.Label(main_frame, text="目标格式:").grid(column=0, row=2, sticky=tk.W, pady=5)
self.format_var = tk.StringVar(value="JPEG")
formats = ["JPEG", "PNG", "BMP", "GIF", "TIFF"]
ttk.Combobox(main_frame, textvariable=self.format_var, values=formats, width=10).grid(column=1, row=2, sticky=tk.W, pady=5)
# 图片质量
ttk.Label(main_frame, text="图片质量:").grid(column=0, row=3, sticky=tk.W, pady=5)
self.quality_var = tk.IntVar(value=95)
quality_frame = ttk.Frame(main_frame)
quality_frame.grid(column=1, row=3, sticky=tk.W, pady=5)
ttk.Scale(quality_frame, from_=1, to=100, variable=self.quality_var, orient=tk.HORIZONTAL, length=200).pack(side=tk.LEFT)
ttk.Label(quality_frame, textvariable=self.quality_var).pack(side=tk.LEFT, padx=5)
# 调整大小
ttk.Label(main_frame, text="调整大小:").grid(column=0, row=4, sticky=tk.W, pady=5)
resize_frame = ttk.Frame(main_frame)
resize_frame.grid(column=1, row=4, sticky=tk.W, pady=5)
self.resize_enabled = tk.BooleanVar(value=False)
ttk.Checkbutton(resize_frame, text="启用", variable=self.resize_enabled).pack(side=tk.LEFT)
ttk.Label(resize_frame, text="宽:").pack(side=tk.LEFT, padx=(10, 0))
self.width_var = tk.IntVar(value=800)
ttk.Entry(resize_frame, width=5, textvariable=self.width_var).pack(side=tk.LEFT, padx=(0, 5))
ttk.Label(resize_frame, text="高:").pack(side=tk.LEFT)
self.height_var = tk.IntVar(value=600)
ttk.Entry(resize_frame, width=5, textvariable=self.height_var).pack(side=tk.LEFT)
# 递归处理
self.recursive_var = tk.BooleanVar(value=False)
ttk.Checkbutton(main_frame, text="递归处理子目录", variable=self.recursive_var).grid(column=1, row=5, sticky=tk.W, pady=5)
# 保留原始图片
self.keep_original_var = tk.BooleanVar(value=True)
ttk.Checkbutton(main_frame, text="保留原始图片", variable=self.keep_original_var).grid(column=1, row=6, sticky=tk.W, pady=5)
# 转换按钮
ttk.Button(main_frame, text="开始转换", command=self.start_conversion).grid(column=1, row=7, pady=10)
# 进度条
self.progress_var = tk.DoubleVar()
ttk.Progressbar(main_frame, variable=self.progress_var, maximum=100).grid(column=0, row=8, columnspan=3, sticky=(tk.W, tk.E), pady=5)
# 状态标签
self.status_var = tk.StringVar(value="就绪")
ttk.Label(main_frame, textvariable=self.status_var).grid(column=0, row=9, columnspan=3, sticky=tk.W, pady=5)
def browse_input(self):
directory = filedialog.askdirectory()
if directory:
self.input_dir.set(directory)
def browse_output(self):
directory = filedialog.askdirectory()
if directory:
self.output_dir.set(directory)
def start_conversion(self):
input_dir = self.input_dir.get()
output_dir = self.output_dir.get()
target_format = self.format_var.get()
quality = self.quality_var.get()
recursive = self.recursive_var.get()
keep_original = self.keep_original_var.get()
# 检查输入
if not input_dir or not output_dir:
messagebox.showerror("错误", "请指定输入和输出目录")
return
# 检查调整大小参数
resize = None
if self.resize_enabled.get():
try:
width = self.width_var.get()
height = self.height_var.get()
if width <= 0 or height <= 0:
raise ValueError("宽度和高度必须大于0")
resize = (width, height)
except:
messagebox.showerror("错误", "调整大小参数无效")
return
# 开始转换
self.status_var.set("转换中...")
self.root.update()
try:
success, failed = batch_convert(
input_dir, output_dir, target_format, quality,
resize, recursive, keep_original
)
self.status_var.set(f"转换完成。成功: {success}, 失败: {failed}")
messagebox.showinfo("完成", f"转换完成\n成功: {success}\n失败: {failed}")
except Exception as e:
self.status_var.set(f"转换出错: {str(e)}")
messagebox.showerror("错误", f"转换过程中出错:\n{str(e)}")
知识点:
tkinter
: Python标准GUI库- 布局管理: 使用
grid
布局 - 控件使用: 标签、输入框、按钮、复选框、组合框、进度条等
- 事件处理: 按钮点击事件
- 文件对话框: 使用
filedialog
选择目录
6. 主函数
python
def main():
# 检查是否有命令行参数
if len(sys.argv) > 1:
# 命令行模式
args = setup_cli()
# 检查输入和输出目录
if not os.path.exists(args.input):
print(f"错误: 输入路径 '{args.input}' 不存在")
return
# 调整大小参数
resize = tuple(args.resize) if args.resize else None
# 开始转换
print(f"开始转换图片从 {args.input} 到 {args.output},格式: {args.format}")
success, failed = batch_convert(
args.input, args.output, args.format.upper(),
args.quality, resize, args.recursive, args.keep
)
print(f"转换完成。成功: {success}, 失败: {failed}")
else:
# GUI模式
root = tk.Tk()
app = ImageConverterGUI(root)
root.mainloop()
if __name__ == "__main__":
main()
总代码
py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
图片格式批量转换器
功能: 批量将图片从一种格式转换为另一种格式,支持调整大小和质量
作者: Python开发者
"""
from PIL import Image
import os
import sys
import argparse
from pathlib import Path
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
def convert_image(input_path, output_path, format, quality=95, resize=None):
"""
转换单个图片的格式
参数:
input_path - 输入图片路径
output_path - 输出图片路径
format - 目标格式 (如 'JPEG', 'PNG')
quality - 图片质量 (1-100, 仅对JPEG格式有效)
resize - 调整大小的元组 (width, height) 或 None
返回:
bool - 转换是否成功
"""
try:
# 打开图片
img = Image.open(input_path)
# 如果是RGBA模式且转换为JPEG,需要转换为RGB模式
if img.mode == 'RGBA' and format.upper() == 'JPEG':
img = img.convert('RGB')
# 调整大小
if resize:
img = img.resize(resize, Image.LANCZOS)
# 保存转换后的图片
if format.upper() == 'JPEG':
img.save(output_path, format=format, quality=quality)
else:
img.save(output_path, format=format)
return True
except Exception as e:
print(f"转换图片 {input_path} 时出错: {e}")
return False
def batch_convert(input_dir, output_dir, target_format, quality=95,
resize=None, recursive=False, keep_original=True):
"""
批量转换指定目录中的图片
参数:
input_dir - 输入目录
output_dir - 输出目录
target_format - 目标格式
quality - 图片质量
resize - 调整大小的元组
recursive - 是否递归处理子目录
keep_original - 是否保留原始图片
返回:
tuple - (成功数量, 失败数量)
"""
# 支持的图片格式
supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff']
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
success_count = 0
failed_count = 0
# 遍历目录
for root, dirs, files in os.walk(input_dir):
# 如果不递归处理子目录且不是根目录,则跳过
if not recursive and root != input_dir:
continue
# 创建对应的输出子目录
rel_path = os.path.relpath(root, input_dir)
if rel_path != '.':
current_output_dir = os.path.join(output_dir, rel_path)
os.makedirs(current_output_dir, exist_ok=True)
else:
current_output_dir = output_dir
# 处理文件
for file in files:
# 检查文件扩展名
ext = os.path.splitext(file)[1].lower()
if ext not in supported_formats:
continue
# 构建输入和输出路径
input_path = os.path.join(root, file)
output_filename = os.path.splitext(file)[0] + '.' + target_format.lower()
output_path = os.path.join(current_output_dir, output_filename)
# 转换图片
if convert_image(input_path, output_path, target_format, quality, resize):
success_count += 1
# 如果不保留原始图片且不是在原目录操作,则删除原始图片
if not keep_original and input_dir != output_dir:
try:
os.remove(input_path)
except:
pass
else:
failed_count += 1
return (success_count, failed_count)
def setup_cli():
"""设置命令行参数解析器"""
parser = argparse.ArgumentParser(description='批量转换图片格式')
parser.add_argument('input', help='输入目录或文件')
parser.add_argument('output', help='输出目录')
parser.add_argument('format', help='目标格式 (如: jpg, png, bmp)')
parser.add_argument('-q', '--quality', type=int, default=95,
help='图片质量 (1-100, 默认: 95)')
parser.add_argument('-r', '--recursive', action='store_true',
help='递归处理子目录')
parser.add_argument('-k', '--keep', action='store_true',
help='保留原始图片')
parser.add_argument('--resize', nargs=2, type=int, metavar=('WIDTH', 'HEIGHT'),
help='调整图片大小')
return parser.parse_args()
class ImageConverterGUI:
def __init__(self, root):
self.root = root
self.root.title("图片格式批量转换器")
self.root.geometry("600x450")
self.root.resizable(True, True)
# 创建主框架
main_frame = ttk.Frame(root, padding="10")
main_frame.pack(fill=tk.BOTH, expand=True)
# 输入目录
ttk.Label(main_frame, text="输入目录:").grid(column=0, row=0, sticky=tk.W, pady=5)
self.input_dir = tk.StringVar()
ttk.Entry(main_frame, width=50, textvariable=self.input_dir).grid(column=1, row=0, pady=5)
ttk.Button(main_frame, text="浏览...", command=self.browse_input).grid(column=2, row=0, padx=5, pady=5)
# 输出目录
ttk.Label(main_frame, text="输出目录:").grid(column=0, row=1, sticky=tk.W, pady=5)
self.output_dir = tk.StringVar()
ttk.Entry(main_frame, width=50, textvariable=self.output_dir).grid(column=1, row=1, pady=5)
ttk.Button(main_frame, text="浏览...", command=self.browse_output).grid(column=2, row=1, padx=5, pady=5)
# 目标格式
ttk.Label(main_frame, text="目标格式:").grid(column=0, row=2, sticky=tk.W, pady=5)
self.format_var = tk.StringVar(value="JPEG")
formats = ["JPEG", "PNG", "BMP", "GIF", "TIFF"]
ttk.Combobox(main_frame, textvariable=self.format_var, values=formats, width=10).grid(column=1, row=2,
sticky=tk.W, pady=5)
# 图片质量
ttk.Label(main_frame, text="图片质量:").grid(column=0, row=3, sticky=tk.W, pady=5)
self.quality_var = tk.IntVar(value=95)
quality_frame = ttk.Frame(main_frame)
quality_frame.grid(column=1, row=3, sticky=tk.W, pady=5)
ttk.Scale(quality_frame, from_=1, to=100, variable=self.quality_var, orient=tk.HORIZONTAL, length=200).pack(
side=tk.LEFT)
ttk.Label(quality_frame, textvariable=self.quality_var).pack(side=tk.LEFT, padx=5)
# 调整大小
ttk.Label(main_frame, text="调整大小:").grid(column=0, row=4, sticky=tk.W, pady=5)
resize_frame = ttk.Frame(main_frame)
resize_frame.grid(column=1, row=4, sticky=tk.W, pady=5)
self.resize_enabled = tk.BooleanVar(value=False)
ttk.Checkbutton(resize_frame, text="启用", variable=self.resize_enabled).pack(side=tk.LEFT)
ttk.Label(resize_frame, text="宽:").pack(side=tk.LEFT, padx=(10, 0))
self.width_var = tk.IntVar(value=800)
ttk.Entry(resize_frame, width=5, textvariable=self.width_var).pack(side=tk.LEFT, padx=(0, 5))
ttk.Label(resize_frame, text="高:").pack(side=tk.LEFT)
self.height_var = tk.IntVar(value=600)
ttk.Entry(resize_frame, width=5, textvariable=self.height_var).pack(side=tk.LEFT)
# 递归处理
self.recursive_var = tk.BooleanVar(value=False)
ttk.Checkbutton(main_frame, text="递归处理子目录", variable=self.recursive_var).grid(column=1, row=5,
sticky=tk.W, pady=5)
# 保留原始图片
self.keep_original_var = tk.BooleanVar(value=True)
ttk.Checkbutton(main_frame, text="保留原始图片", variable=self.keep_original_var).grid(column=1, row=6,
sticky=tk.W, pady=5)
# 转换按钮
ttk.Button(main_frame, text="开始转换", command=self.start_conversion).grid(column=1, row=7, pady=10)
# 进度条
self.progress_var = tk.DoubleVar()
ttk.Progressbar(main_frame, variable=self.progress_var, maximum=100).grid(column=0, row=8, columnspan=3,
sticky=(tk.W, tk.E), pady=5)
# 状态标签
self.status_var = tk.StringVar(value="就绪")
ttk.Label(main_frame, textvariable=self.status_var).grid(column=0, row=9, columnspan=3, sticky=tk.W, pady=5)
def browse_input(self):
directory = filedialog.askdirectory()
if directory:
self.input_dir.set(directory)
def browse_output(self):
directory = filedialog.askdirectory()
if directory:
self.output_dir.set(directory)
def start_conversion(self):
input_dir = self.input_dir.get()
output_dir = self.output_dir.get()
target_format = self.format_var.get()
quality = self.quality_var.get()
recursive = self.recursive_var.get()
keep_original = self.keep_original_var.get()
# 检查输入
if not input_dir or not output_dir:
messagebox.showerror("错误", "请指定输入和输出目录")
return
# 检查调整大小参数
resize = None
if self.resize_enabled.get():
try:
width = self.width_var.get()
height = self.height_var.get()
if width <= 0 or height <= 0:
raise ValueError("宽度和高度必须大于0")
resize = (width, height)
except:
messagebox.showerror("错误", "调整大小参数无效")
return
# 开始转换
self.status_var.set("转换中...")
self.root.update()
try:
success, failed = batch_convert(
input_dir, output_dir, target_format, quality,
resize, recursive, keep_original
)
self.status_var.set(f"转换完成。成功: {success}, 失败: {failed}")
messagebox.showinfo("完成", f"转换完成\n成功: {success}\n失败: {failed}")
except Exception as e:
self.status_var.set(f"转换出错: {str(e)}")
messagebox.showerror("错误", f"转换过程中出错:\n{str(e)}")
def main():
# 检查是否有命令行参数
if len(sys.argv) > 1:
# 命令行模式
args = setup_cli()
# 检查输入和输出目录
if not os.path.exists(args.input):
print(f"错误: 输入路径 '{args.input}' 不存在")
return
# 调整大小参数
resize = tuple(args.resize) if args.resize else None
# 开始转换
print(f"开始转换图片从 {args.input} 到 {args.output},格式: {args.format}")
success, failed = batch_convert(
args.input, args.output, args.format.upper(),
args.quality, resize, args.recursive, args.keep
)
print(f"转换完成。成功: {success}, 失败: {failed}")
else:
# GUI模式
root = tk.Tk()
app = ImageConverterGUI(root)
root.mainloop()
if __name__ == "__main__":
main()
知识点:
- 命令行模式和GUI模式的切换
sys.argv
: 获取命令行参数tkinter
主循环:root.mainloop()
🎮 使用方法
命令行方式
bash
# 基本用法
python image_converter.py 输入目录 输出目录 目标格式
# 示例: 将input_folder中的图片转换为PNG格式并保存到output_folder
python image_converter.py input_folder output_folder png
# 高级用法
python image_converter.py input_folder output_folder jpg -q 85 -r --resize 800 600
GUI方式
直接运行程序,不带任何参数:
bash
python image_converter.py
然后在图形界面中:
- 选择输入目录
- 选择输出目录
- 设置目标格式和其他选项
- 点击"开始转换"按钮
🔍 进阶知识点
1. 图像处理基础
- 像素: 图像的基本单位
- 颜色模式: RGB, RGBA, CMYK, 灰度等
- 图像格式特点:
- JPEG: 有损压缩,不支持透明度,适合照片
- PNG: 无损压缩,支持透明度,适合图标和截图
- GIF: 支持动画,有限的颜色数量
- BMP: 无压缩,文件较大
- TIFF: 高质量,支持多页,常用于专业印刷
2. Pillow高级特性
- 图像增强: 亮度、对比度、锐化等调整
- 滤镜效果: 模糊、锐化、边缘检测等
- 图像合成: 图层混合、水印等
- 批处理: 多进程处理提高效率
3. 性能优化
- 使用生成器减少内存占用
- 多线程/多进程处理提高转换速度
- 缩略图生成优化
🚀 可扩展功能
-
批量水印添加:为图片添加文字或图片水印
-
图片批量裁剪:自动裁剪图片到指定比例或尺寸
-
批量图片优化:自动调整亮度、对比度和图片锐化
-
批量重命名:根据规则批量重命名图片文件
-
元数据处理:保留或清除EXIF信息
📝 总结
通过这个图片格式批量转换器项目,我们学习了以下Python编程知识:
- Pillow库的基本使用
- 文件系统操作
- 命令行参数解析
- GUI界面开发
- 批处理和异常处理
- 图像处理基础知识
物物而不物于物,念念而不念于念