본문 바로가기
코딩 연습

이미지 병합 - 파이썬 Tkinter 활용

by good4me 2022. 12. 28.

goodthings4me.tistory.com

이미지 병합 프로그램이 필요하여 유튜브 검색 중 나도코딩 유튜버님의 영상을 보고 따라하면서 만든 소스 코드이며, pyinstaller로 실행 프로그램을 생성해보았다.

 

 

이미지 병합해주는 프로그램(파이썬 tkinter & pyinstaller 라이브러리 활용)

이미지 병합 프로그램
이미지 병합 프로그램

프로그램 다운로드

(네이버 MyBox 다운로드 비번: 1234)

 

▷ 파이썬 Tkinter 소스코드는 다음과 같다.

## 이미지를 원본 그대로 붙여서 저장하기

import os
import time
import tkinter.ttk as ttk  # 콤보박스
import tkinter.messagebox as msgbox
from tkinter import *
from tkinter import filedialog
from PIL import Image


root = Tk()
root.title('Image Merger')
root.geometry('450x510+700+100')
root.resizable(False, False)

## 파일 추가 함수
def add_file():
    files = filedialog.askopenfilenames(
        title='이미지 파일을 선택하세요.',
        filetypes=(('JPG 파일', '*.jpg'), ('PNG 파일', '*.png'), ('BMP 파일', '*.bmp'), ('모든 파일', '*.*')),
        initialdir='./')

    for file in files:
        # 리스트 영역에 파일명 insert 
        list_file.insert(END, file)


## 선택 파일 삭제 함수
def del_file():
    for idx in reversed(list_file.curselection()):  # 리스트 요소 뒤집기
        list_file.delete(idx)


## 저장 경로 폴더(Path)
def browse_dest_path():
    folder_selected = filedialog.askdirectory()

    # 사용자가 폴더 선택 안하고(취소) 파일 선택창을 닫았을 때
    if folder_selected == '':  # 또는 not folder_selected
        return

    # disable -> normal -> disable 순서로 상태값 변경
    txt_dest_path.configure(state='normal')
    txt_dest_path.delete(0, END) 
    txt_dest_path.insert(0, folder_selected)
    txt_dest_path.configure(state='disable')


## 이미지 통합 
def merge_image():
    try:
        images = [Image.open(x) for x in list_file.get(0, END)]
        widths = [x.size[0] for x in images]  # 이미지의 width 리스트
        heights = [y.size[1] for y in images]  # 이미지의 height 리스트
        max_width, total_height = max(widths), sum(heights)

        # 이미지를 병합할 새 스케치북 준비 ('RGB, (가로크기, 세로크기), 배경색)
        result_img = Image.new('RGB', (max_width, total_height), (255, 255, 255))
        y_offset = 0 

        for idx, img in enumerate(images):
            result_img.paste(img, (0, y_offset))
            y_offset += img.size[1]

            # 이미지 순번 / 전체 이미지수 = 진행 비율 (100% 대비 진행률)
            progress = (idx + 1) / len(images) * 100
            p_var.set(progress)
            progress_bar.update()

        # 병합된 이미지 저장하기
        current_time = time.strftime('%Y%m%d%H%M%S')
        dest_path = os.path.join(txt_dest_path.get(), f'image_merge_{current_time}.jpg')
        result_img.save(dest_path)
        msgbox.showinfo('알림', '이미지 병합 작업이 완료되었습니다!!')

    except Exception as e:
        msgbox.showerror('에러', e)


## 실행 - 시작
def start():
    # 파일 목록 확인
    if not list_file.size():
        msgbox.showwarning('경고', '이미지 파일을 선택하여 추가하세요.')
        return

    # 저장 경로 확인
    if not len(txt_dest_path.get()):
        msgbox.showwarning('경고', '저장 경로를 선택하세요.')
        return

    # 이미지 병합 작업 함수 호출
    merge_image()


## 파일 프레임 (파일 추가, 선택 파일 삭제)
file_frame = Frame(root)
file_frame.pack(fill='x', padx=5, pady=5)

# 버튼
btn_add_file = Button(file_frame, text='파일 추가', padx=5, pady=5, width=12, command=add_file)
btn_add_file.pack(side='left')
btn_del_file = Button(file_frame, text='선택 삭제', padx=5, pady=5, width=12, command=del_file)
btn_del_file.pack(side='right')

## 리스트 프레임
list_frame = Frame(root)
list_frame.pack(fill='both', padx=5, pady=5)

# 우측 스크롤바
scrollbar = Scrollbar(list_frame)
scrollbar.pack(side='right', fill='y')

# 리스트 박스(선택 모드, 높이 15, 우측에 스크롤바 세팅 맵핑)
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)

## 저장 경로 프레임
path_frame = LabelFrame(root, text='저장경로')
path_frame.pack(fill='x', padx=5, pady=5, ipady=5)

# 선택 경로 표시
txt_dest_path = Entry(path_frame)
txt_dest_path.pack(side='left', fill='x', expand=True, padx=5, pady=5, ipady=4)  # ipad : 입력칸 높이
txt_dest_path.configure(state='disable')

# 찾아보기 버튼
btn_dest_path = Button(path_frame, text='찾아보기', width=10, command=browse_dest_path)
btn_dest_path.pack(side='right', padx=5, pady=5)

## 진행 상황 Progress Bar
frame_progress = LabelFrame(root, text='진행상황')
frame_progress.pack(fill='x', padx=5, pady=5, ipady=5)

p_var = DoubleVar()
progress_bar = ttk.Progressbar(frame_progress, maximum=100, variable=p_var)
progress_bar.pack(fill='x', padx=5, pady=5)

## 실행 프레임
frame_run = Frame(root)
frame_run.pack(fill='x', padx=5, pady=5)

btn_start = Button(frame_run, text='닫기', width=12, padx=5, pady=5, command=root.quit)
btn_start.pack(side='right', padx=5, pady=5)
btn_start = Button(frame_run, text='시작', width=12, padx=5, pady=5, command=start)
btn_start.pack(side='right', padx=5, pady=5)


root.mainloop()

 

good4me.co.kr

 

▷ 소스 코드 설명

 

 

[출처] 파이썬 코딩 무료 강의 (활용편2) - GUI 프로그래밍을 배우고 '여러 이미지 합치기' 프로그램을 함께 만들어요. [나도코딩]

※ 영상 2:09:25 부분부터 이미지 병합 프로젝트 시작됨

 

 

 

댓글