import
tkinter as tk
import
ttkbootstrap as ttk
from
ttkbootstrap.constants
import
*
from
tkinter
import
filedialog, messagebox
from
PIL
import
Image, ImageTk, UnidentifiedImageError
formats
=
{
"ICO"
:
".ico"
,
"PNG"
:
".png"
,
"JPEG"
:
".jpg"
,
"GIF"
:
".gif"
,
"BMP"
:
".bmp"
,
"TIFF"
:
".tiff"
}
ico_resolutions
=
{
"16x16"
: (
16
,
16
),
"24x24"
: (
24
,
24
),
"32x32"
: (
32
,
32
),
"48x48"
: (
48
,
48
),
"64x64"
: (
64
,
64
),
"128x128"
: (
128
,
128
),
"256x256"
: (
256
,
256
)
}
class
ImageConverterGUI:
def
__init__(
self
, master):
self
.master
=
master
self
.master.title(
"图片格式转换工具 v1.0 — Thebzk"
)
self
.master.geometry(
"600x700"
)
self
.master.resizable(
False
,
False
)
main_frame
=
ttk.Frame(
self
.master, padding
=
20
)
main_frame.pack(fill
=
tk.BOTH, expand
=
True
)
input_frame
=
ttk.Labelframe(main_frame, text
=
"输入文件"
, padding
=
10
)
input_frame.pack(fill
=
tk.X, pady
=
5
)
input_grid
=
ttk.Frame(input_frame)
input_grid.pack(fill
=
tk.X)
ttk.Label(input_grid, text
=
"选择图片文件:"
).grid(row
=
0
, column
=
0
, padx
=
5
)
self
.input_var
=
tk.StringVar()
ttk.Entry(input_grid, textvariable
=
self
.input_var, width
=
40
).grid(row
=
0
, column
=
1
, padx
=
5
)
ttk.Button(
input_grid,
text
=
"选择文件"
,
command
=
self
.choose_input_file,
bootstyle
=
"primary"
,
width
=
12
).grid(row
=
0
, column
=
2
, padx
=
5
)
settings_frame
=
ttk.Labelframe(main_frame, text
=
"转换设置"
, padding
=
10
)
settings_frame.pack(fill
=
tk.X, pady
=
5
)
settings_grid
=
ttk.Frame(settings_frame)
settings_grid.pack(fill
=
tk.X)
ttk.Label(settings_grid, text
=
"输出格式:"
).grid(row
=
0
, column
=
0
, padx
=
5
)
self
.format_var
=
tk.StringVar(value
=
'')
format_combobox
=
ttk.Combobox(
settings_grid,
textvariable
=
self
.format_var,
values
=
list
(formats.keys()),
bootstyle
=
"primary"
,
state
=
"readonly"
,
width
=
12
)
format_combobox.grid(row
=
0
, column
=
1
, padx
=
5
)
self
.ico_resolution_var
=
tk.StringVar(value
=
'')
self
.ico_resolution_box
=
ttk.Combobox(
settings_grid,
textvariable
=
self
.ico_resolution_var,
values
=
list
(ico_resolutions.keys()),
bootstyle
=
"primary"
,
state
=
"disabled"
,
width
=
12
)
self
.ico_resolution_box.grid(row
=
0
, column
=
2
, padx
=
5
)
format_combobox.bind(
"<<ComboboxSelected>>"
,
self
.toggle_ico_resolution)
ttk.Button(
settings_grid,
text
=
"开始转换"
,
command
=
self
.convert,
bootstyle
=
"success"
,
width
=
12
).grid(row
=
0
, column
=
3
, padx
=
5
)
preview_frame
=
ttk.Labelframe(main_frame, text
=
"图片预览"
, padding
=
10
)
preview_frame.pack(fill
=
tk.BOTH, expand
=
True
, pady
=
5
)
self
.preview_canvas
=
ttk.Canvas(preview_frame, bg
=
'#f8f9fa'
)
self
.preview_canvas.pack(fill
=
tk.BOTH, expand
=
True
)
self
.preview_image
=
None
log_frame
=
ttk.Labelframe(main_frame, text
=
"操作日志"
, padding
=
10
)
log_frame.pack(fill
=
tk.X, pady
=
5
)
self
.log_area
=
ttk.Text(
log_frame,
wrap
=
tk.WORD,
font
=
(
"Consolas"
,
9
),
height
=
22
,
bg
=
"#f8f9fa"
,
fg
=
"#495057"
)
self
.log_area.pack(fill
=
tk.BOTH)
def
toggle_ico_resolution(
self
, event):
if
self
.format_var.get()
=
=
"ICO"
:
self
.ico_resolution_box.configure(state
=
"readonly"
)
else
:
self
.ico_resolution_box.configure(state
=
"disabled"
)
def
choose_input_file(
self
):
file_path
=
filedialog.askopenfilename(
filetypes
=
[(
"图片文件"
,
"*.png;*.jpg;*.jpeg;*.gif;*.bmp;*.tiff"
)]
)
if
file_path:
self
.input_var.
set
(file_path)
self
.show_preview(file_path)
def
show_preview(
self
, file_path):
try
:
self
.preview_canvas.delete(
"all"
)
img
=
Image.
open
(file_path)
canvas_width
=
self
.preview_canvas.winfo_width()
-
20
canvas_height
=
self
.preview_canvas.winfo_height()
-
20
img_ratio
=
img.width
/
img.height
canvas_ratio
=
canvas_width
/
canvas_height
if
img_ratio > canvas_ratio:
new_width
=
min
(img.width, canvas_width)
new_height
=
int
(new_width
/
img_ratio)
else
:
new_height
=
min
(img.height, canvas_height)
new_width
=
int
(new_height
*
img_ratio)
img
=
img.resize((new_width, new_height), Image.LANCZOS)
self
.preview_image
=
ImageTk.PhotoImage(img)
x
=
(
self
.preview_canvas.winfo_width()
-
new_width)
/
/
2
y
=
(
self
.preview_canvas.winfo_height()
-
new_height)
/
/
2
self
.preview_canvas.create_image(x, y, anchor
=
tk.NW, image
=
self
.preview_image)
except
Exception as e:
messagebox.showerror(
"错误"
, f
"预览失败: {str(e)}"
)
def
convert(
self
):
input_path
=
self
.input_var.get()
output_format
=
self
.format_var.get()
ico_resolution
=
self
.ico_resolution_var.get()
if
not
input_path:
messagebox.showwarning(
"提示"
,
"请选择输入文件!"
)
return
if
not
output_format:
messagebox.showwarning(
"提示"
,
"请选择输出格式!"
)
return
output_dir
=
filedialog.askdirectory(title
=
"选择输出目录"
)
if
not
output_dir:
messagebox.showwarning(
"提示"
,
"请选择输出目录!"
)
return
try
:
img
=
Image.
open
(input_path)
format_lower
=
output_format.lower()
if
format_lower
=
=
'ico'
:
if
not
ico_resolution:
messagebox.showwarning(
"提示"
,
"请选择ICO分辨率!"
)
return
sizes
=
[ico_resolutions[ico_resolution]]
img.save(f
"{output_dir}/output.{formats[output_format]}"
, format_lower.upper(), sizes
=
sizes)
else
:
img.save(f
"{output_dir}/output.{formats[output_format]}"
, format_lower.upper())
messagebox.showinfo(
"成功"
, f
"图片已成功转换并保存到 {output_dir}/output.{formats[output_format]}"
)
self
.log_message(f
"成功保存到 {output_dir}/output.{formats[output_format]}"
)
except
UnidentifiedImageError:
messagebox.showerror(
"错误"
,
"无法识别图片格式!"
)
self
.log_message(
"无法识别图片格式!"
, level
=
"ERROR"
)
except
Exception as e:
messagebox.showerror(
"错误"
, f
"转换失败: {str(e)}"
)
self
.log_message(f
"转换失败: {str(e)}"
, level
=
"ERROR"
)
def
log_message(
self
, message, level
=
"INFO"
):
self
.log_area.insert(tk.END, f
"[{level}] {message}\n"
)
self
.log_area.see(tk.END)
def
main():
root
=
ttk.Window(themename
=
"cosmo"
)
app
=
ImageConverterGUI(root)
root.mainloop()
if
__name__
=
=
"__main__"
:
main()