본문 바로가기
  • 야근없는 삶을 위하여
파이썬

Python 이미지 세로로 합치기 - 16 (실행 파일 만들기)

by 우당코 2024. 3. 15.
반응형

실행 파일을 만들어서 쉽게 사용해 보자

완료 및 오류 창을 띄우는 작업까지 해 보았다.

이대로 사용해도 되지만 매번 파이참을 띄우기 번거로우니 실행 파일을 만들어 보자.

 

아직 완료 및 오류 창을 띄우지 못했다면 아래 링크 참고

 

Python 이미지 세로로 합치기 - 15 (완료 및 오류 창 띄우기)

넓이와 파일명을 입력하도록 창을 띄워서 유도해 보자 넓이와 파일명 둘 중 하나라도 입력하지 않으면 작동하지 않는다. 사용자가 입력하도록 오류 창을 띄워서 입력하도록 유도하자. 아직 리

udangco-coding-record.tistory.com

 

아직 pyinstaller 라이브러리를 설치 하지 않았다면 설치해 놓자.

잘 따라왔다면 익숙한 화면

 

1. 실행파일 만들기

이전에 실행파일 만들기를 참고해 보자.

 

Python excel 열 추출하기 - 6 (실행파일 만들기)

Python excel 열 추출하기 - 5 (반복문) Python excel 열 추출하기 - 4 (excel 파일 만들기) Python excel 열 추출하기 - 3 (excel 파일 수정하기) Python excel 열 추출하기 - 2 (excel 파일 열기) 이제 엑셀 파일을 열어보

udangco-coding-record.tistory.com

아이콘으로 사용할 파일을 프로젝트 폴더에 준비해 두고 터미널에 아래 코드를 입력하자.

pyinstaller -F -w -i "ico.ico" image_merge.py

 

-F: 한 파일로 만들어라

-w: 콘솔창을 띄우지 말아라

-i "ico.ico": ico.ico 파일을 아이콘으로 만들어라.

image_merge.py: 내가 작성한 코드가 있는 파일

 

이렇게 만들고 실행을 하면 이전에 설정했던 배경 이미지가 적용되지 않는다.

 

2. 배경 이미지 적용한 실행파일 만들기

배경이미지를 적용 하려면 pyinstaller에 배경파일을 직접 넣어줘야 한다.

pyinstaller -F -w --add-data "bg.jpg;." -i "ico.ico" image_merge.py

 

--add-data "bg.jpg;." : bg.jpg를 실행파일에 포함시켜라!

 

3. 완료 파일 확인

dist 폴더에 완료된 exe 파일이 생성될 것이다.

 

실행해서 테스트 해보면 리스트위젯에 배경도 들어가고 문제 없이 잘 동작한다.

완료되었다

 

4. 추가 - 윈도우 아이콘 변경

기본 아이콘

기본 아이콘이 보기 싫다면 내가 원하는 아이콘으로 변경해 보자.

그냥 만족하고 사용해도 상관없다.

 

a. 파이썬 코드 작성

bg_img 아래에 아이콘을 불러오자.

bg_img = resource_path('bg.jpg').replace('\\', '/')
ico_img = resource_path('ico.ico').replace('\\', '/')

 

def retranslateUi(self, Dialog) 아래에 아이콘을 적용시키자.

def retranslateUi(self, Dialog):
    _translate = QtCore.QCoreApplication.translate
    Dialog.setWindowIcon(QIcon(ico_img))  # 아이콘 표시

Dialog.setWindowIcon(QIcon(ico_img)) 로 아이콘을 표시하면 된다.

 

b. 실행파일에 아이콘 파일 추가

터미널에 가서 --add-data "ico.ico;." 를 추가한 명령어를 입력하자.

pyinstaller -F -w --add-data "bg.jpg;." --add-data "ico.ico;." -i "ico.ico" image_merge.py

 

완료되면 파일을 실행해서 확인하자.

성공

 

 

 

전체코드

import os
import PyQt5
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import QSize, Qt, QMimeDatabase
from PyQt5.QtWidgets import QMainWindow, QMessageBox, QListWidget
import mimetypes
from PIL import Image


# 배경이미지
def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

bg_img = resource_path('bg.jpg').replace('\\', '/')
ico_img = resource_path('ico.ico').replace('\\', '/')


# drag and drop event. 파일 위치 경로를 가져오기
class ListBoxWidget(QListWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAcceptDrops(True)
        self.setIconSize(QSize(50, 50))
        self.setStyleSheet(''' border-image: url(''' + bg_img + '''); ''') # 배경 이미지 생성

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls:
            event.accept()
        else:
            event.ignore()

    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls():
            event.setDropAction(Qt.CopyAction)
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        img_file = self.find_img(event.mimeData())
        if img_file:
            if event.mimeData().hasUrls():
                event.setDropAction(Qt.CopyAction)
                event.accept()
                self.setStyleSheet('''border-image: url();''')  # 배경 삭제
                for file in img_file:
                    icon = QtGui.QIcon(str(file.toLocalFile()))  # 아이콘 형태로 이미지 가져오기
                    show_file = QtWidgets.QListWidgetItem(icon, str(file.toLocalFile()))
                    self.addItem(show_file)
            else:
                event.ignore()
        else:
            event.ignore()

    def find_img(self, mimedata):
        file_list = list()
        db = QMimeDatabase()
        for file in mimedata.urls():
            mimetype = db.mimeTypeForUrl(file)  # pyqt mimetype 이용
            mimetype_e = mimetypes.guess_type(file.toString())[0]

            if (mimetype.name() == "image/bmp") or (mimetype.name() == "image/gif") or (mimetype.name() == "image/jpeg") or (mimetype.name() == "image/png"):
                file_list.append(file)
            elif (mimetype_e == "image/bmp") or (mimetype_e == "image/gif") or (mimetype_e == "image/jpeg") or (mimetype_e == "image/png"):
                file_list.append(file)
            else:
                pass
        return file_list


class Ui_Dialog(QMainWindow):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(690, 641)

        # 넓이 그룹 박스
        self.groupBox = QtWidgets.QGroupBox(Dialog)
        self.groupBox.setGeometry(QtCore.QRect(30, 30, 631, 51))
        self.groupBox.setObjectName("groupBox")

        # 넓이 입력 칸
        self.lineEdit = QtWidgets.QLineEdit(self.groupBox)
        self.lineEdit.setGeometry(QtCore.QRect(10, 20, 151, 20))
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit.setText("1024")

        # 파일 이름 그룹 박스
        self.groupBox_2 = QtWidgets.QGroupBox(Dialog)
        self.groupBox_2.setGeometry(QtCore.QRect(30, 90, 631, 51))
        self.groupBox_2.setObjectName("groupBox_2")

        # 파일 이름 입력 칸
        self.lineEdit_2 = QtWidgets.QLineEdit(self.groupBox_2)
        self.lineEdit_2.setGeometry(QtCore.QRect(10, 20, 541, 20))
        self.lineEdit_2.setObjectName("lineEdit_2")

        # 이미지 그룹 박스
        self.groupBox_3 = QtWidgets.QGroupBox(Dialog)
        self.groupBox_3.setGeometry(QtCore.QRect(30, 150, 631, 411))
        self.groupBox_3.setObjectName("groupBox_3")

        # 이미지 리스트 위젯
        self.listWidget = ListBoxWidget(self.groupBox_3)
        self.listWidget.setGeometry(QtCore.QRect(10, 20, 511, 371))
        self.listWidget.setObjectName("listWidget")

        # 위로 버튼
        self.pushButton = QtWidgets.QPushButton(self.groupBox_3)
        self.pushButton.setGeometry(QtCore.QRect(540, 20, 75, 23))
        self.pushButton.setObjectName("pushButton")
        self.pushButton.clicked.connect(self.up_btn)  # 위로 이동 버튼 연결

        # 아래로 버튼
        self.pushButton_2 = QtWidgets.QPushButton(self.groupBox_3)
        self.pushButton_2.setGeometry(QtCore.QRect(540, 50, 75, 23))
        self.pushButton_2.setObjectName("pushButton_2")
        self.pushButton_2.clicked.connect(self.down_btn)  # 아래로 이동 버튼 연결

        # 제거 버튼
        self.pushButton_3 = QtWidgets.QPushButton(self.groupBox_3)
        self.pushButton_3.setGeometry(QtCore.QRect(540, 80, 75, 23))
        self.pushButton_3.setObjectName("pushButton_3")
        self.pushButton_3.clicked.connect(self.del_btn)  # 제거 버튼 연결

        # 합치기 버튼
        self.pushButton_4 = QtWidgets.QPushButton(Dialog)
        self.pushButton_4.setGeometry(QtCore.QRect(40, 570, 511, 41))
        self.pushButton_4.setObjectName("pushButton_4")
        self.pushButton_4.clicked.connect(self.merge_img)  # 합치기 버튼 연결

        # 초기화 버튼
        self.pushButton_5 = QtWidgets.QPushButton(Dialog)
        self.pushButton_5.setGeometry(QtCore.QRect(570, 570, 71, 41))
        self.pushButton_5.setObjectName("pushButton_5")
        self.pushButton_5.clicked.connect(self.set_init)  # 초기화 버튼 연결

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowIcon(QIcon(ico_img))  # 아이콘 표시
        Dialog.setWindowTitle(_translate("Dialog", "이미지 합치기 v1.0"))
        self.groupBox.setTitle(_translate("Dialog", "가로 사이즈 (px)"))
        self.groupBox_2.setTitle(_translate("Dialog", "파일명"))
        self.lineEdit_2.setPlaceholderText(_translate("Dialog", "확장자를 제외한 파일명을 입력해 주세요."))
        self.groupBox_3.setTitle(_translate("Dialog", "이미지"))
        self.pushButton.setText(_translate("Dialog", "위 이동"))
        self.pushButton_2.setText(_translate("Dialog", "아래 이동"))
        self.pushButton_3.setText(_translate("Dialog", "제거"))
        self.pushButton_4.setText(_translate("Dialog", "합치기"))
        self.pushButton_5.setText(_translate("Dialog", "초기화"))

    # 버튼 함수
    def up_btn(self):  # 위로 이동
        row = self.listWidget.currentRow()
        if row > 0:
            self.listWidget.insertItem(row - 1, self.listWidget.takeItem(row))
            self.listWidget.setCurrentRow(row - 1)

    def down_btn(self):  # 아래로 이동
        row = self.listWidget.currentRow()
        if row < self.listWidget.count() - 1:
            self.listWidget.insertItem(row + 1, self.listWidget.takeItem(row))
            self.listWidget.setCurrentRow(row + 1)

    def del_btn(self):  # 삭제
        self.listWidget.takeItem(self.listWidget.currentRow())
        if self.listWidget.count() == 0:
            self.listWidget.setStyleSheet(''' border-image: url(''' + bg_img + '''); ''')  # 배경 이미지 생성
        else:
            pass

    def set_init(self):  # 초기화
        self.listWidget.clear()  # 리스트 위젯 리스트 삭제
        self.lineEdit.clear()  # 넓이 칸 텍스트 삭제
        self.lineEdit_2.clear()  # 파일명 칸 텍스트 삭제
        self.listWidget.setStyleSheet(''' border-image: url(''' + bg_img + '''); ''')  # 배경 이미지 생성

    # 이미지 합치기 버튼
    def merge_img(self):
        count1 = self.listWidget.count()
        new_width = int(self.lineEdit.text())  # 변경 이미지 넓이
        file_name = self.lineEdit_2.text()  # 파일 이름

        if len(file_name) < 1:
            QMessageBox.warning(self, 'Warning: 오류가 발생했습니다', '파일명을 입력하세요.')
        else:
            try:
                if count1 > 0:
                    new_height = 0
                    # 빈 이미지 만들기
                    for i in range(0, count1):
                        img = self.listWidget.item(i)
                        image = Image.open(img.text())  # 이미지 열기
                        image_width = image.size[0]  # 원본 이미지 넓이
                        image_height = image.size[1]  # 원본 이미지 높이
                        new_image = image.resize((new_width, int((image_height * new_width) / image_width)))  # 이미지 비율 변경
                        new_height += new_image.size[1]  # 이미지 높이 구하기

                    empty_img = Image.new('RGB', (new_width, new_height), '#FFFFFF')

                    # 이미지 합치기
                    merge_height = 0

                    for i in range(0, count1):
                        img = self.listWidget.item(i)
                        image = Image.open(img.text())  # 이미지 열기
                        # 하단 부터 동일
                        image_width = image.size[0]  # 원본 이미지 넓이
                        image_height = image.size[1]  # 원본 이미지 높이
                        new_image = image.resize((new_width, int((image_height * new_width) / image_width)))  # 이미지 비율 변경
                        empty_img.paste(new_image, (0, merge_height))  # 이미지 합치기
                        merge_height += new_image.size[1]  # 이미지 높이 구하기

                    empty_img.save(file_name + '.jpg')
                    QMessageBox.information(self, '완료', '완료되었습니다.')  # 완료 창 띄우기
                else:
                    pass
            except Exception as e:
                QMessageBox.warning(self, 'Warning: 오류가 발생했습니다', e)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Dialog = QtWidgets.QDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(app.exec_())

 

이제 여러분은 힘들게 포토샵을 열어서 작업할 필요가 없게 되었다.

 

칼퇴를 응원한다.

 

반응형