본문 바로가기

python

Python WebP 파일 변환 + 16:9 비율로 사이즈 변환

728x90

Python WebP 파일 변환 + 16:9 비율로 사이즈 변환

 

 

webp_converter.py
0.01MB

 

 

두가지를 설치합니다. PyQt5 / Pillow

pip install PyQt5 Pillow

 

파일을 만듭니다.

webp_converter.py

 

 

import sys
import os
from concurrent.futures import ThreadPoolExecutor
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, 
                             QFileDialog, QProgressBar, QComboBox)
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QDragEnterEvent, QDropEvent
from PIL import Image

class ConversionThread(QThread):
    progress_update = pyqtSignal(int)
    conversion_complete = pyqtSignal(int)
    error_occurred = pyqtSignal(str)

    def __init__(self, files, target_size):
        super().__init__()
        self.files = files
        self.target_size = target_size
        self.converted_count = 0

    def run(self):
        with ThreadPoolExecutor() as executor:
            list(executor.map(self.process_file, enumerate(self.files)))
        self.conversion_complete.emit(self.converted_count)

    def process_file(self, args):
        i, file = args
        if os.path.isfile(file):
            self.convert_image(file)
        elif os.path.isdir(file):
            for root, _, files in os.walk(file):
                for f in files:
                    if f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif', '.webp')):
                        self.convert_image(os.path.join(root, f))
        self.progress_update.emit(i + 1)

    def convert_image(self, input_path):
        try:
            with Image.open(input_path) as img:
                width, height = img.size
                target_ratio = 16 / 9
                current_ratio = width / height

                if current_ratio > target_ratio:
                    new_width = int(height * target_ratio)
                    offset = (width - new_width) // 2
                    img = img.crop((offset, 0, offset + new_width, height))
                else:
                    new_height = int(width / target_ratio)
                    offset = (height - new_height) // 2
                    img = img.crop((0, offset, width, offset + new_height))

                img = img.resize(self.target_size, Image.LANCZOS)

                output_path = os.path.splitext(input_path)[0] + f'_{self.target_size[0]}x{self.target_size[1]}.webp'
                img.save(output_path, 'WEBP')
                self.converted_count += 1
        except Exception as e:
            self.error_occurred.emit(f"Error converting {input_path}: {str(e)}")

class ImageConverterApp(QWidget):
    def __init__(self):
        super().__init__()
        self.resolutions = [
            "160x90", "192x108", "240x135", "320x180", "480x270", "640x360", "720x405", "800x450",
            "960x540", "1120x630", "1280x720", "1440x810", "1600x900", "1920x1080", "3840x2160",
            "7680x4320", "15360x8640"
        ]
        self.initUI()

    def initUI(self):
        layout = QVBoxLayout()

        self.label = QLabel('Drag and drop images or folders here')
        self.label.setAlignment(Qt.AlignCenter)
        self.label.setStyleSheet('''
            QLabel {
                border: 2px dashed #aaa;
                border-radius: 5px;
                padding: 30px;
                background: #f0f0f0;
            }
        ''')
        layout.addWidget(self.label)

        self.progress = QProgressBar(self)
        self.progress.setVisible(False)
        layout.addWidget(self.progress)

        self.status_label = QLabel('')
        self.status_label.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.status_label)

        hbox = QHBoxLayout()
        self.resolution_combo = QComboBox(self)
        self.resolution_combo.addItems(self.resolutions)
        self.resolution_combo.setCurrentText("480x270")  # 기본 선택
        hbox.addWidget(QLabel("Select Resolution:"))
        hbox.addWidget(self.resolution_combo)

        self.button = QPushButton('Select Files', self)
        self.button.clicked.connect(self.select_files)
        hbox.addWidget(self.button)

        layout.addLayout(hbox)

        self.setLayout(layout)
        self.setWindowTitle('Advanced WebP Converter')
        self.setGeometry(300, 300, 400, 300)

        self.setAcceptDrops(True)

    def dragEnterEvent(self, event: QDragEnterEvent):
        if event.mimeData().hasUrls():
            event.acceptProposedAction()

    def dropEvent(self, event: QDropEvent):
        files = [u.toLocalFile() for u in event.mimeData().urls()]
        self.process_files(files)

    def select_files(self):
        files, _ = QFileDialog.getOpenFileNames(self, "Select files")
        if files:
            self.process_files(files)

    def process_files(self, files):
        self.progress.setVisible(True)
        self.progress.setMaximum(len(files))
        self.progress.setValue(0)
        self.status_label.setText("Converting...")

        target_size = tuple(map(int, self.resolution_combo.currentText().split('x')))

        self.conversion_thread = ConversionThread(files, target_size)
        self.conversion_thread.progress_update.connect(self.update_progress)
        self.conversion_thread.conversion_complete.connect(self.conversion_finished)
        self.conversion_thread.error_occurred.connect(self.show_error)
        self.conversion_thread.start()

    def update_progress(self, value):
        self.progress.setValue(value)

    def conversion_finished(self, converted_count):
        self.progress.setVisible(False)
        self.status_label.setText(f"Conversion complete. {converted_count} images processed.")

    def show_error(self, error_message):
        self.status_label.setText(error_message)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = ImageConverterApp()
    ex.show()
    sys.exit(app.exec_())

 

PyQt5로 구현한 고급 WebP 이미지 변환기

PyQt5와 Pillow를 사용하여 구현한 고급 WebP 이미지 변환기

이미지 파일을 WebP 형식으로 변환하고, 원하는 해상도로 리사이즈하는 기능을 제공

주요 기능

  1. 다중 이미지 변환: 여러 이미지를 한 번에 WebP 형식으로 변환
  2. 드래그 앤 드롭 지원: 파일이나 폴더를 쉽게 드래그하여 변환 가능
  3. 해상도 선택: 다양한 표준 해상도 중 선택 가능
  4. 진행 상황 표시: 변환 과정을 실시간으로 확인 가능
  5. 멀티스레딩: 빠른 변환을 위한 병렬 처리 구현

프로그램 구조

이 프로그램은 크게 두 부분으로 나뉩니다:

  1. ConversionThread 클래스: 이미지 변환 로직을 담당
  2. ImageConverterApp 클래스: GUI 및 사용자 상호작용을 관리

ConversionThread 클래스

이 클래스는 QThread를 상속받아 멀티스레딩을 구현합니다.

  • run(): ThreadPoolExecutor를 사용하여 병렬 처리를 구현
  • process_file(): 개별 파일 또는 폴더 처리
  • convert_image(): 실제 이미지 변환 작업 수행

변환 과정에서는 다음과 같은 작업이 이루어집니다:

  1. 이미지를 16:9 비율로 크롭
  2. 선택된 해상도로 리사이즈
  3. WebP 형식으로 저장

ImageConverterApp 클래스

이 클래스는 QWidget을 상속받아 GUI를 구현합니다. 주요 메서드와 기능은 다음과 같습니다:

  • initUI(): GUI 요소 초기화
  • dragEnterEvent(), dropEvent(): 드래그 앤 드롭 기능 구현
  • select_files(): 파일 선택 다이얼로그 구현
  • process_files(): 변환 프로세스 시작
  • update_progress(), conversion_finished(), show_error(): 상태 업데이트 및 에러 처리

 

확장자만 변환 시키려면

아래 코드는 파일과 해당 폴더의 파일까지만 변환시킵니다.

폴더속의 폴더안의 이미지는 해당되지 않습니다.

image_to_format.py

 

import sys
import os
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QDropEvent
from PIL import Image

class ImageConverter(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle('이미지를 WebP로 변환')
        self.setGeometry(300, 300, 300, 150)

        layout = QVBoxLayout()
        label = QLabel('이미지 파일 또는 폴더를 여기에 드래그 앤 드롭하세요')
        label.setAlignment(Qt.AlignCenter)
        layout.addWidget(label)

        self.setLayout(layout)
        self.setAcceptDrops(True)

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

    def dropEvent(self, event: QDropEvent):
        files = [u.toLocalFile() for u in event.mimeData().urls()]
        for file_path in files:
            if os.path.isdir(file_path):
                self.convert_directory(file_path)
            else:
                self.convert_file(file_path)

    def convert_file(self, file_path):
        if file_path.lower().endswith(('.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.gif')):
            try:
                with Image.open(file_path) as img:
                    output_path = os.path.splitext(file_path)[0] + '.webp'
                    img.save(output_path, 'WEBP')
                print(f'변환 완료: {output_path}')
            except Exception as e:
                print(f'변환 실패: {file_path}. 오류: {str(e)}')

    def convert_directory(self, dir_path):
        for root, dirs, files in os.walk(dir_path):
            for file in files:
                file_path = os.path.join(root, file)
                self.convert_file(file_path)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = ImageConverter()
    ex.show()
    sys.exit(app.exec_())

 

드래그 앤 드롭 인터페이스: 사용자가 쉽게 파일이나 폴더를 프로그램에 전달할 수 있습니다.
다양한 이미지 형식 지원: WEBP, PNG, JPG, JPEG, GIF 형식 간의 변환을 지원합니다.
폴더 처리: 폴더를 드롭하면 내부의 모든 이미지 파일을 재귀적으로 처리합니다.
실시간 상태 표시: 변환 중인지, 완료되었는지를 사용자에게 알려줍니다.
간단한 사용법: 복잡한 설정 없이 형식만 선택하고 파일을 드롭하면 됩니다.

이 프로그램은 대량의 이미지 파일을 빠르게 다른 형식으로 변환해야 하는 경우에 유용합니다.

 

 

하위 모든 폴더의 이미지 확장자를 전부 webp로 변환시키려면

 

import sys
import os
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton
from PyQt5.QtCore import Qt
from PIL import Image

class ImageConverterApp(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        layout = QVBoxLayout()

        self.dropLabel = QLabel('여기에 폴더를 드래그 앤 드롭하세요')
        self.dropLabel.setAlignment(Qt.AlignCenter)
        self.dropLabel.setStyleSheet('''
            QLabel {
                border: 2px dashed #aaa;
                border-radius: 5px;
                padding: 30px;
                background: #f0f0f0;
            }
        ''')

        self.statusLabel = QLabel('대기 중...')
        self.statusLabel.setAlignment(Qt.AlignCenter)

        self.convertButton = QPushButton('변환 시작')
        self.convertButton.clicked.connect(self.start_conversion)
        self.convertButton.setEnabled(False)

        layout.addWidget(self.dropLabel)
        layout.addWidget(self.statusLabel)
        layout.addWidget(self.convertButton)

        self.setLayout(layout)
        self.setWindowTitle('이미지 WebP 변환기')
        self.setGeometry(300, 300, 400, 200)

        self.setAcceptDrops(True)

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

    def dropEvent(self, event):
        files = [u.toLocalFile() for u in event.mimeData().urls()]
        for file in files:
            if os.path.isdir(file):
                self.folderPath = file
                self.statusLabel.setText(f'선택된 폴더: {self.folderPath}')
                self.convertButton.setEnabled(True)
                break
        else:
            self.statusLabel.setText('올바른 폴더를 드롭해주세요.')

    def start_conversion(self):
        if hasattr(self, 'folderPath'):
            self.statusLabel.setText('변환 중...')
            QApplication.processEvents()
            self.process_directory(self.folderPath)
            self.statusLabel.setText('변환 완료!')
        else:
            self.statusLabel.setText('폴더를 먼저 선택해주세요.')

    def process_directory(self, directory):
        for root, _, files in os.walk(directory):
            for file in files:
                if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp')):
                    file_path = os.path.join(root, file)
                    self.convert_to_webp(file_path)

    def convert_to_webp(self, file_path):
        try:
            with Image.open(file_path) as img:
                file_name = os.path.splitext(file_path)[0]
                webp_path = f"{file_name}.webp"
                img.save(webp_path, 'webp')
            os.remove(file_path)
            self.statusLabel.setText(f'변환 완료: {file_path}')
            QApplication.processEvents()
        except Exception as e:
            self.statusLabel.setText(f'오류 발생: {file_path} - {str(e)}')
            QApplication.processEvents()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = ImageConverterApp()
    ex.show()
    sys.exit(app.exec_())

 

 

 

 

=============

728x90