功能特点
- 两种尺寸输出:自动生成28×28和108×108像素的PNG图片
- 保持透明度:自动转换为RGBA模式支持透明背景
- 高质量重采样:使用LANCZOS算法保持图片质量
- 批量处理:支持处理整个目录的图片
- 错误处理:完善的异常处理机制
- 运行程序后,选择你的logo图片,程序会在同目录下的resized_logos文件夹中生成两个尺寸的新图片。
源码运行
方法1:处理单个文件
运行程序后,输入单个图片文件的路径,程序会生成两个尺寸的PNG文件。
方法2:批量处理
输入包含多个图片的目录路径,程序会处理目录中的所有图片文件。
from PIL import Image
import os
def resize_logo(input_path, output_dir="resized_logos"):
"""
将logo图片转换为28x28像素和108x108像素的PNG格式图片
参数:
input_path: 输入图片路径
output_dir: 输出目录
"""
try:
# 创建输出目录
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# 打开原始图片
with Image.open(input_path) as img:
# 确保图片是RGBA模式(支持透明度)
if img.mode != 'RGBA':
img = img.convert('RGBA')
# 获取文件名(不含扩展名)
filename = os.path.splitext(os.path.basename(input_path))[0]
# 尺寸列表
sizes = [(28, 28), (108, 108)]
# 转换并保存不同尺寸的图片
for width, height in sizes:
# 调整尺寸,使用LANCZOS重采样算法保持质量
resized_img = img.resize((width, height), Image.Resampling.LANCZOS)
# 生成输出文件名
output_filename = f"{filename}_{width}x{height}.png"
output_path = os.path.join(output_dir, output_filename)
# 保存为PNG格式
resized_img.save(output_path, 'PNG')
print(f"已生成: {output_path}")
print("所有尺寸转换完成!")
except FileNotFoundError:
print(f"错误:找不到文件 '{input_path}'")
except Exception as e:
print(f"处理图片时出错: {e}")
def batch_resize_logos(input_dir, output_dir="resized_logos"):
"""
批量处理目录中的所有图片
参数:
input_dir: 输入图片目录
output_dir: 输出目录
"""
# 支持的图片格式
supported_formats = {'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff', '.webp'}
try:
# 获取目录中的所有文件
for filename in os.listdir(input_dir):
file_path = os.path.join(input_dir, filename)
# 检查是否是文件且为支持的图片格式
if (os.path.isfile(file_path) and
os.path.splitext(filename)[1].lower() in supported_formats):
print(f"\n处理文件: {filename}")
resize_logo(file_path, output_dir)
except FileNotFoundError:
print(f"错误:找不到目录 '{input_dir}'")
if __name__ == "__main__":
# 使用方法1:处理单个文件
logo_path = input("请输入logo图片路径(直接回车跳过): ").strip()
if logo_path:
if os.path.exists(logo_path):
resize_logo(logo_path)
else:
print("文件不存在,请检查路径")
# 使用方法2:批量处理目录中的图片
else:
dir_path = input("请输入包含logo图片的目录路径: ").strip()
if dir_path and os.path.exists(dir_path):
batch_resize_logos(dir_path)
else:
print("目录不存在,程序结束")
tkinter
from PIL import Image
import os
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
class LogoResizerApp:
def __init__(self, root):
self.root = root
self.root.title("Logo尺寸转换器")
self.root.geometry("500x300")
# 创建界面
self.create_widgets()
def create_widgets(self):
# 主框架
main_frame = ttk.Frame(self.root, padding="20")
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# 标题
title_label = ttk.Label(main_frame, text="Logo图片尺寸转换器",
font=("Arial", 16, "bold"))
title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))
# 选择文件按钮
self.file_button = ttk.Button(main_frame, text="选择单个文件",
command=self.select_file)
self.file_button.grid(row=1, column=0, padx=5, pady=10, sticky=tk.W+tk.E)
# 选择目录按钮
self.dir_button = ttk.Button(main_frame, text="选择目录批量处理",
command=self.select_directory)
self.dir_button.grid(row=1, column=1, padx=5, pady=10, sticky=tk.W+tk.E)
# 输出目录选择
self.output_button = ttk.Button(main_frame, text="选择输出目录",
command=self.select_output_dir)
self.output_button.grid(row=1, column=2, padx=5, pady=10, sticky=tk.W+tk.E)
# 文件路径显示
self.path_label = ttk.Label(main_frame, text="未选择文件或目录",
wraplength=400)
self.path_label.grid(row=2, column=0, columnspan=3, pady=10)
# 输出目录显示
self.output_label = ttk.Label(main_frame, text="输出目录: resized_logos")
self.output_label.grid(row=3, column=0, columnspan=3, pady=5)
# 进度条
self.progress = ttk.Progressbar(main_frame, mode='indeterminate')
self.progress.grid(row=4, column=0, columnspan=3, sticky=tk.W+tk.E, pady=10)
# 开始转换按钮
self.convert_button = ttk.Button(main_frame, text="开始转换",
command=self.start_conversion)
self.convert_button.grid(row=5, column=0, columnspan=3, pady=20, sticky=tk.W+tk.E)
# 状态标签
self.status_label = ttk.Label(main_frame, text="就绪")
self.status_label.grid(row=6, column=0, columnspan=3)
# 初始化变量
self.input_path = ""
self.output_path = "resized_logos"
self.is_batch = False
def select_file(self):
file_path = filedialog.askopenfilename(
title="选择Logo图片",
filetypes=[("图片文件", "*.jpg *.jpeg *.png *.bmp *.gif *.tiff *.webp")]
)
if file_path:
self.input_path = file_path
self.path_label.config(text=f"选择文件: {file_path}")
self.is_batch = False
def select_directory(self):
dir_path = filedialog.askdirectory(title="选择包含Logo图片的目录")
if dir_path:
self.input_path = dir_path
self.path_label.config(text=f"选择目录: {dir_path}")
self.is_batch = True
def select_output_dir(self):
dir_path = filedialog.askdirectory(title="选择输出目录")
if dir_path:
self.output_path = dir_path
self.output_label.config(text=f"输出目录: {dir_path}")
def resize_logo(self, input_path):
"""调整单个logo尺寸"""
try:
with Image.open(input_path) as img:
if img.mode != 'RGBA':
img = img.convert('RGBA')
filename = os.path.splitext(os.path.basename(input_path))[0]
sizes = [(28, 28), (108, 108)]
for width, height in sizes:
resized_img = img.resize((width, height), Image.Resampling.LANCZOS)
output_filename = f"{filename}_{width}x{height}.png"
output_filepath = os.path.join(self.output_path, output_filename)
resized_img.save(output_filepath, 'PNG')
return True
except Exception as e:
print(f"处理 {input_path} 时出错: {e}")
return False
def start_conversion(self):
if not self.input_path:
messagebox.showerror("错误", "请先选择文件或目录")
return
# 创建输出目录
if not os.path.exists(self.output_path):
os.makedirs(self.output_path)
# 开始进度条
self.progress.start()
self.convert_button.config(state='disabled')
try:
if self.is_batch:
# 批量处理
supported_formats = {'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff', '.webp'}
success_count = 0
total_count = 0
for filename in os.listdir(self.input_path):
file_path = os.path.join(self.input_path, filename)
if (os.path.isfile(file_path) and
os.path.splitext(filename)[1].lower() in supported_formats):
total_count += 1
if self.resize_logo(file_path):
success_count += 1
self.status_label.config(text=f"批量处理完成: {success_count}/{total_count} 个文件成功")
messagebox.showinfo("完成", f"批量处理完成!\n成功: {success_count}/{total_count} 个文件")
else:
# 单个文件处理
if self.resize_logo(self.input_path):
self.status_label.config(text="转换完成")
messagebox.showinfo("完成", "图片转换完成!")
else:
self.status_label.config(text="转换失败")
messagebox.showerror("错误", "图片转换失败")
except Exception as e:
messagebox.showerror("错误", f"处理过程中出错: {e}")
finally:
# 停止进度条
self.progress.stop()
self.convert_button.config(state='normal')
def main():
root = tk.Tk()
app = LogoResizerApp(root)
root.mainloop()
if __name__ == "__main__":
main()
命令行版本(自定义尺寸)
from PIL import Image
import os
def resize_logo(input_path, sizes, output_dir="resized_logos"):
"""
将logo图片转换为指定尺寸的PNG格式图片
参数:
input_path: 输入图片路径
sizes: 尺寸列表,例如 [(28, 28), (108, 108), (200, 100)]
output_dir: 输出目录
"""
try:
# 创建输出目录
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# 打开原始图片
with Image.open(input_path) as img:
# 确保图片是RGBA模式(支持透明度)
if img.mode != 'RGBA':
img = img.convert('RGBA')
# 获取文件名(不含扩展名)
filename = os.path.splitext(os.path.basename(input_path))[0]
# 转换并保存不同尺寸的图片
for width, height in sizes:
# 调整尺寸,使用LANCZOS重采样算法保持质量
resized_img = img.resize((width, height), Image.Resampling.LANCZOS)
# 生成输出文件名
output_filename = f"{filename}_{width}x{height}.png"
output_path = os.path.join(output_dir, output_filename)
# 保存为PNG格式
resized_img.save(output_path, 'PNG')
print(f"已生成: {output_path}")
print(f"所有尺寸转换完成!共生成 {len(sizes)} 个文件")
except FileNotFoundError:
print(f"错误:找不到文件 '{input_path}'")
except Exception as e:
print(f"处理图片时出错: {e}")
def batch_resize_logos(input_dir, sizes, output_dir="resized_logos"):
"""
批量处理目录中的所有图片
参数:
input_dir: 输入图片目录
sizes: 尺寸列表
output_dir: 输出目录
"""
# 支持的图片格式
supported_formats = {'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff', '.webp'}
try:
# 获取目录中的所有文件
files = [f for f in os.listdir(input_dir)
if os.path.isfile(os.path.join(input_dir, f)) and
os.path.splitext(f)[1].lower() in supported_formats]
if not files:
print("目录中没有找到支持的图片文件")
return
print(f"找到 {len(files)} 个图片文件")
for filename in files:
file_path = os.path.join(input_dir, filename)
print(f"\n处理文件: {filename}")
resize_logo(file_path, sizes, output_dir)
except FileNotFoundError:
print(f"错误:找不到目录 '{input_dir}'")
def parse_size_input(size_input):
"""
解析用户输入的尺寸字符串
支持格式: "28x28 108x108 200x100" 或 "28,28 108,108 200,100"
"""
sizes = []
try:
# 按空格分割多个尺寸
size_parts = size_input.strip().split()
for part in size_parts:
# 支持 x 或 , 作为分隔符
if 'x' in part:
w, h = part.split('x')
elif ',' in part:
w, h = part.split(',')
else:
print(f"忽略无效尺寸格式: {part}")
continue
width = int(w.strip())
height = int(h.strip())
if width <= 0 or height <= 0:
print(f"忽略无效尺寸: {width}x{height}")
continue
sizes.append((width, height))
return sizes
except ValueError as e:
print(f"尺寸解析错误: {e}")
return []
def get_custom_sizes():
"""
获取用户自定义尺寸
"""
print("\n请输入您想要的图片尺寸(可以输入多个尺寸)")
print("格式示例:")
print(" - 28x28 108x108 200x100")
print(" - 28,28 108,108 200,100")
print(" - 50x50 100x100 200x200 300x300")
while True:
size_input = input("\n请输入尺寸(直接回车使用默认尺寸 28x28 和 108x108): ").strip()
if not size_input:
# 使用默认尺寸
return [(28, 28), (108, 108)]
sizes = parse_size_input(size_input)
if sizes:
return sizes
else:
print("输入格式有误,请重新输入")
if __name__ == "__main__":
# 获取自定义尺寸
custom_sizes = get_custom_sizes()
print(f"\n将生成以下尺寸的图片:")
for w, h in custom_sizes:
print(f" - {w}x{h}像素")
# 选择处理模式
print("\n请选择处理模式:")
print("1. 处理单个文件")
print("2. 批量处理目录")
choice = input("请输入选择 (1 或 2): ").strip()
if choice == "1":
logo_path = input("请输入logo图片路径: ").strip()
if logo_path and os.path.exists(logo_path):
resize_logo(logo_path, custom_sizes)
else:
print("文件不存在,程序结束")
elif choice == "2":
dir_path = input("请输入包含logo图片的目录路径: ").strip()
if dir_path and os.path.exists(dir_path):
batch_resize_logos(dir_path, custom_sizes)
else:
print("目录不存在,程序结束")
else:
print("无效选择,程序结束")
图形界面版本(支持自定义尺寸)
from PIL import Image
import os
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import re
class LogoResizerApp:
def __init__(self, root):
self.root = root
self.root.title("Logo尺寸转换器 - 自定义尺寸")
self.root.geometry("600x450")
# 初始化变量
self.input_path = ""
self.output_path = "resized_logos"
self.is_batch = False
self.sizes = [(28, 28), (108, 108)] # 默认尺寸
# 创建界面
self.create_widgets()
def create_widgets(self):
# 主框架
main_frame = ttk.Frame(self.root, padding="20")
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# 标题
title_label = ttk.Label(main_frame, text="Logo图片尺寸转换器 - 自定义尺寸",
font=("Arial", 16, "bold"))
title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))
# 尺寸设置区域
size_frame = ttk.LabelFrame(main_frame, text="自定义尺寸设置", padding="10")
size_frame.grid(row=1, column=0, columnspan=3, sticky=tk.W+tk.E, pady=(0, 10))
# 尺寸输入说明
size_help = ttk.Label(size_frame,
text="输入格式: 宽x高,多个尺寸用空格分隔\n示例: 28x28 108x108 200x100 300x150",
foreground="blue")
size_help.grid(row=0, column=0, columnspan=2, sticky=tk.W, pady=(0, 10))
# 尺寸输入框
ttk.Label(size_frame, text="尺寸列表:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.size_entry = ttk.Entry(size_frame, width=40)
self.size_entry.insert(0, "28x28 108x108")
self.size_entry.grid(row=1, column=1, sticky=tk.W+tk.E, padx=(10, 0), pady=5)
# 更新尺寸按钮
self.update_size_button = ttk.Button(size_frame, text="更新尺寸",
command=self.update_sizes)
self.update_size_button.grid(row=1, column=2, padx=(10, 0), pady=5)
# 当前尺寸显示
self.size_display = ttk.Label(size_frame, text="当前尺寸: 28x28, 108x108")
self.size_display.grid(row=2, column=0, columnspan=3, sticky=tk.W, pady=5)
# 文件选择区域
file_frame = ttk.LabelFrame(main_frame, text="文件选择", padding="10")
file_frame.grid(row=2, column=0, columnspan=3, sticky=tk.W+tk.E, pady=10)
# 选择文件按钮
self.file_button = ttk.Button(file_frame, text="选择单个文件",
command=self.select_file)
self.file_button.grid(row=0, column=0, padx=5, pady=5, sticky=tk.W+tk.E)
# 选择目录按钮
self.dir_button = ttk.Button(file_frame, text="选择目录批量处理",
command=self.select_directory)
self.dir_button.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W+tk.E)
# 输出目录选择
self.output_button = ttk.Button(file_frame, text="选择输出目录",
command=self.select_output_dir)
self.output_button.grid(row=0, column=2, padx=5, pady=5, sticky=tk.W+tk.E)
# 文件路径显示
self.path_label = ttk.Label(file_frame, text="未选择文件或目录",
wraplength=500)
self.path_label.grid(row=1, column=0, columnspan=3, pady=5, sticky=tk.W)
# 输出目录显示
self.output_label = ttk.Label(file_frame, text="输出目录: resized_logos")
self.output_label.grid(row=2, column=0, columnspan=3, pady=5, sticky=tk.W)
# 进度条
self.progress = ttk.Progressbar(main_frame, mode='indeterminate')
self.progress.grid(row=3, column=0, columnspan=3, sticky=tk.W+tk.E, pady=10)
# 开始转换按钮
self.convert_button = ttk.Button(main_frame, text="开始转换",
command=self.start_conversion)
self.convert_button.grid(row=4, column=0, columnspan=3, pady=10, sticky=tk.W+tk.E)
# 状态标签
self.status_label = ttk.Label(main_frame, text="就绪")
self.status_label.grid(row=5, column=0, columnspan=3)
# 配置列权重
main_frame.columnconfigure(1, weight=1)
size_frame.columnconfigure(1, weight=1)
file_frame.columnconfigure(0, weight=1)
file_frame.columnconfigure(1, weight=1)
file_frame.columnconfigure(2, weight=1)
def parse_size_input(self, size_input):
"""解析尺寸输入"""
sizes = []
try:
if not size_input.strip():
return [(28, 28), (108, 108)]
# 按空格分割多个尺寸
size_parts = size_input.strip().split()
for part in size_parts:
# 使用正则表达式匹配尺寸格式
match = re.match(r'^(\d+)[x,X](\d+)$', part)
if match:
width = int(match.group(1))
height = int(match.group(2))
if width <= 0 or height <= 0:
continue
sizes.append((width, height))
return sizes
except Exception as e:
print(f"尺寸解析错误: {e}")
return []
def update_sizes(self):
"""更新尺寸列表"""
size_input = self.size_entry.get()
new_sizes = self.parse_size_input(size_input)
if new_sizes:
self.sizes = new_sizes
size_text = ", ".join([f"{w}x{h}" for w, h in self.sizes])
self.size_display.config(text=f"当前尺寸: {size_text}")
messagebox.showinfo("成功", f"已更新尺寸: {size_text}")
else:
messagebox.showerror("错误", "尺寸格式有误,请使用格式: 宽x高,如 28x28 108x108")
def select_file(self):
file_path = filedialog.askopenfilename(
title="选择Logo图片",
filetypes=[("图片文件", "*.jpg *.jpeg *.png *.bmp *.gif *.tiff *.webp")]
)
if file_path:
self.input_path = file_path
self.path_label.config(text=f"选择文件: {file_path}")
self.is_batch = False
def select_directory(self):
dir_path = filedialog.askdirectory(title="选择包含Logo图片的目录")
if dir_path:
self.input_path = dir_path
self.path_label.config(text=f"选择目录: {dir_path}")
self.is_batch = True
def select_output_dir(self):
dir_path = filedialog.askdirectory(title="选择输出目录")
if dir_path:
self.output_path = dir_path
self.output_label.config(text=f"输出目录: {dir_path}")
def resize_logo(self, input_path):
"""调整单个logo尺寸"""
try:
with Image.open(input_path) as img:
if img.mode != 'RGBA':
img = img.convert('RGBA')
filename = os.path.splitext(os.path.basename(input_path))[0]
output_files = []
for width, height in self.sizes:
resized_img = img.resize((width, height), Image.Resampling.LANCZOS)
output_filename = f"{filename}_{width}x{height}.png"
output_filepath = os.path.join(self.output_path, output_filename)
resized_img.save(output_filepath, 'PNG')
output_files.append(output_filepath)
return True, output_files
except Exception as e:
print(f"处理 {input_path} 时出错: {e}")
return False, []
def start_conversion(self):
if not self.input_path:
messagebox.showerror("错误", "请先选择文件或目录")
return
# 更新尺寸(确保使用最新的输入)
self.update_sizes()
if not self.sizes:
messagebox.showerror("错误", "没有有效的尺寸设置")
return
# 创建输出目录
if not os.path.exists(self.output_path):
os.makedirs(self.output_path)
# 开始进度条
self.progress.start()
self.convert_button.config(state='disabled')
try:
if self.is_batch:
# 批量处理
supported_formats = {'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff', '.webp'}
success_count = 0
total_count = 0
for filename in os.listdir(self.input_path):
file_path = os.path.join(self.input_path, filename)
if (os.path.isfile(file_path) and
os.path.splitext(filename)[1].lower() in supported_formats):
total_count += 1
success, _ = self.resize_logo(file_path)
if success:
success_count += 1
self.status_label.config(text=f"批量处理完成: {success_count}/{total_count} 个文件成功")
messagebox.showinfo("完成",
f"批量处理完成!\n"
f"成功: {success_count}/{total_count} 个文件\n"
f"生成尺寸: {', '.join([f'{w}x{h}' for w, h in self.sizes])}")
else:
# 单个文件处理
success, output_files = self.resize_logo(self.input_path)
if success:
self.status_label.config(text="转换完成")
file_list = "\n".join([os.path.basename(f) for f in output_files])
messagebox.showinfo("完成",
f"图片转换完成!\n\n生成的文件:\n{file_list}")
else:
self.status_label.config(text="转换失败")
messagebox.showerror("错误", "图片转换失败")
except Exception as e:
messagebox.showerror("错误", f"处理过程中出错: {e}")
finally:
# 停止进度条
self.progress.stop()
self.convert_button.config(state='normal')
def main():
root = tk.Tk()
app = LogoResizerApp(root)
root.mainloop()
if __name__ == "__main__":
main()