tkinter로 이미지 합치기 프로그램 만들기
설계, 완성된 프로그램
이미지를 합치는 프로그램의 완성 사진이다. 기능은 단순하게 이 정도가 있다
- 파일을 추가해서 리스트에 넣기
- 파일을 삭제하기
- 저장 경로 지정해주기
- 옵션 1 : 이미지 크기 조정하기
- 옵션 2 : 이미지 간격 조정하기
- 옵션 3 : FORMAT(PNG, JPG, BMP) 형식 지정하기
- 프로그레스 바 연동하기
이미지를 조정해주고 추가해주기 위해서 Pillow 모듈을 사용했다.
레이아웃을 먼저 짜고 그 이후에 기능을 추가했다.
완성된 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
from tkinter import *
import tkinter.ttk as ttk
import tkinter.messagebox as msgbox
from tkinter import filedialog
from PIL import Image
import os
root = Tk()
PVERSION = "1.0"
PROGRAM_NAME = "IMAGE COMBINE PROGRAM - {}".format(PVERSION)
FIRST_SAVE_PATH = "C:/"
root.title("{}".format(PROGRAM_NAME))
def add_file():
files = filedialog.askopenfilenames(
title="IMAGE SELECT",
filetypes=(("PNG", "*.png"), ("JPG", "*.jpg"), ("BMP", "*.bmp"), ("All file", "*.*")),
initialdir="PythonWorkspace/game_basic",
)
# LIST_FILE
for file in files:
list_file.insert(END, file)
def del_file():
for i in reversed(list_file.curselection()):
list_file.delete(i)
def save_path():
path = filedialog.askdirectory(title="SAVE PATH")
print(path)
if path == "":
return
txt_save_path.delete(0, END)
txt_save_path.insert(0, path)
def start():
try:
print(
"WIDTH = {}\nDISTANCE = {}\nFORMAT = {}\n\nSAVE PATH = {}\n".format(
cbbox_width.get(), cbbox_distance.get(), cbbox_format.get(), txt_save_path.get()
)
)
if list_file.size() == 0: # IF EMPTY FILE LIST
msgbox.showerror("NO FILE", "Please add file")
return
if len(txt_save_path.get()) == 0: # IF EMPTY SAVE PATH
msgbox.showerror("NO SAVE PATH", "Please specify path")
return
# IMAGE COMBINE
img_combine()
msgbox.showinfo("DONE")
except Exception as err:
msgbox.showerror("ERR", err)
def img_combine():
images = [Image.open(x) for x in list_file.get(0, END)] # FROM list_file SAVE images
img_width = cbbox_width.get()
image_sizes = []
if img_width == "Keep size":
img_width = -1
else:
img_width = int(img_width)
if img_width > -1:
image_sizes = [(int(img_width), int(img_width * x.size[1] / x.size[0])) for x in images]
else:
image_sizes = [(x.size[0], x.size[1]) for x in images]
widths, heights = zip(*(image_sizes))
total_distance = 0
type_distance = 0
if cbbox_distance.get() == "NONE": # OPTION2 DISTANCE
pass
elif cbbox_distance.get() == "Narrow":
for i in range(0, list_file.size()):
total_distance += 20
type_distance = 20
elif cbbox_distance.get() == "Normal":
for i in range(0, list_file.size()):
total_distance += 40
type_distance = 40
elif cbbox_distance.get() == "Wide":
for i in range(0, list_file.size()):
total_distance += 80
type_distance = 80
print(list_file.size())
print(type(list_file.size()))
print("{} / {}".format(widths, heights))
max_width, total_height = max(widths), sum(heights) + total_distance
print("{} / {}".format(max_width, total_height))
result_img = Image.new("RGB", (max_width, total_height), (255, 255, 255))
y_offset = 0 # pos y location
for idx, img in enumerate(images):
if img_width > -1:
img = img.resize(image_sizes[idx])
result_img.paste(img, (0, y_offset))
y_offset += img.size[1] + type_distance
progress = (idx + 1) / len(images) * 100
p_var.set(progress)
progress_bar.update()
save_combine_image_path = os.path.join(
txt_save_path.get(), "combine_img.{}".format(cbbox_format.get().lower())
)
result_img.save(save_combine_image_path)
# FILE FRAME
file_frame = Frame(root)
file_frame.pack(fill=X, padx=5, pady=5)
btn_add_file = Button(file_frame, text="ADD FILE", padx=5, pady=5, width=12, command=add_file)
btn_add_file.pack(side="left")
btn_del_file = Button(file_frame, text="DELETE", padx=5, pady=5, width=12, command=del_file)
btn_del_file.pack(side="right")
# LIST FRAME
list_frame = Frame(root)
list_frame.pack(fill=BOTH, padx=5, pady=5)
scrollbar = Scrollbar(root)
scrollbar.pack(side=RIGHT, fill=Y)
list_file = Listbox(list_frame, selectmode=EXTENDED, height=15, yscrollcommand=scrollbar.set)
list_file.pack(side=LEFT, fill=BOTH, expand=True)
scrollbar.config(command=list_file.yview)
# SAVE PATH FRAME
path_frame = LabelFrame(root, text="SAVE PATH")
path_frame.pack(fill=X, padx=5, pady=5)
txt_save_path = Entry(path_frame)
txt_save_path.insert(END, FIRST_SAVE_PATH)
txt_save_path.pack(side=LEFT, fill=X, expand=True, padx=5, pady=5)
btn_save_path = Button(path_frame, text="Browse", width=10, command=save_path)
btn_save_path.pack(side=RIGHT, padx=5, pady=5)
# OPTION FRAME
option_frame = LabelFrame(root, text="OPTION")
option_frame.pack(fill=X, padx=5, pady=5)
lbl_width = Label(option_frame, text="WIDTH", width=8)
lbl_width.pack(side=LEFT, padx=5, pady=5)
cbbox_width_array = ["Keep size", "1024", "800", "640"]
cbbox_width = ttk.Combobox(option_frame, values=cbbox_width_array, state="readonly", width=10)
cbbox_width.current(0)
cbbox_width.pack(side=LEFT, padx=5, pady=5)
lbl_distance = Label(option_frame, text="DISTANCE", width=8)
lbl_distance.pack(side=LEFT, padx=5, pady=5)
cbbox_distance_array = ["NONE", "Narrow", "Normal", "Wide"]
cbbox_distance = ttk.Combobox(option_frame, values=cbbox_distance_array, state="readonly", width=10)
cbbox_distance.current(0)
cbbox_distance.pack(side=LEFT, padx=5, pady=5)
lbl_format = Label(option_frame, text="FORMAT", width=8)
lbl_format.pack(side=LEFT, padx=5, pady=5)
cbbox_format_array = ["PNG", "JPG", "BMP"]
cbbox_format = ttk.Combobox(option_frame, values=cbbox_format_array, state="readonly", width=10)
cbbox_format.current(0)
cbbox_format.pack(side=LEFT, padx=5, pady=5)
# PROGRESS BAR
progress_frame = LabelFrame(root, text="PROGRESS")
progress_frame.pack(fill=X, padx=5, pady=5)
p_var = DoubleVar()
progress_bar = ttk.Progressbar(progress_frame, maximum=100, variable=p_var)
progress_bar.pack(fill=X, padx=5, pady=5)
# RUN FRAME
run_frame = Frame(root)
run_frame.pack(fill=X, padx=5, pady=5)
btn_exit = Button(run_frame, text="EXIT", padx=5, pady=5, width=12, command=quit)
btn_exit.pack(side=RIGHT, padx=5, pady=5)
btn_start = Button(run_frame, text="START", padx=5, pady=5, width=12, command=start)
btn_start.pack(side=RIGHT, padx=5, pady=5)
root.resizable(False, False)
root.mainloop()
만들면서 나온 에러
-
저장경로를 지정해주지 않았을 때
-
저장경로의 permission denied 1, 2는 동시에 try ~ exception 구문을 추가해줘서 에러 메시지를 표시해주는걸로 해결했다.
-
range 안 씀 리스트파일을 for문에서 활용할 때 range()안에 넣지않고 쓰는 바람에 TypeError가 나왔다. range를 써서 해결함.
정리
파이썬의 있던 모듈들을 활용해서 이렇게 간단한 프로그램들을 여럿 만들 수 있다. 난이도도 어렵지 않아서 쉽게 프로그램을 완성했다.
댓글남기기