diff --git a/CHANGELOG.md b/CHANGELOG.md index fc1eb38..4bab113 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,27 @@ # Changelog -## 0.1.0 +## 0.2.x +### 0.2.2 +- Moved processing images into a different thread, making the UI responsiable while processing + +### 0.2.1 +- Insert exif to image file (i.e. without changing the file). + +### 0.2.0 +- Now spaces in rename string are replaces with `_`. +- version check of `optima35`, incase pip did not update it. +- Sorting entries from exif file. + +### 0.2.0-a1 +- Main UI received a facelift. +- Added a new experimental preview window to display an image and show how changing values affects it. +- Programm now warns for potential overwrite of existing files. + +## 0.1.x +### 0.1.1 +- Update metadata, preview, readme, bump in version for pip + +### 0.1.0 - Preserved the current working GUI by pinning `optima35` to a specific version for guaranteed compatibility. ## 0.0.x diff --git a/README.md b/README.md index 1a985c8..b627649 100644 --- a/README.md +++ b/README.md @@ -31,22 +31,27 @@ pip install OptimaLab35 - **TUI**: Fallback if **PySide6** is missing or can be explicitly started using the `--tui` flag. ### Preview GUI +**PREVIEW** might be out of date. **Main tab** -![main](https://gitlab.com/CodeByMrFinchum/OptimaLab35/-/raw/0.1.1/media/main_tab.png){width=40%} +![main](https://gitlab.com/CodeByMrFinchum/OptimaLab35/-/raw/feature/enhancing/media/main_tab.png){width=40%} + +**Preview window** + +![main](https://gitlab.com/CodeByMrFinchum/OptimaLab35/-/raw/feature/enhancing/media/preview_window.png){width=40%} **Exif tab** -![main](https://gitlab.com/CodeByMrFinchum/OptimaLab35/-/raw/0.1.1/media/exif_tab.png){width=40%} +![main](https://gitlab.com/CodeByMrFinchum/OptimaLab35/-/raw/feature/enhancing/media/exif_tab.png){width=40%} **Exif editor** -![main](https://gitlab.com/CodeByMrFinchum/OptimaLab35/-/raw/0.1.1/media/exif_editor.png){width=40%} +![main](https://gitlab.com/CodeByMrFinchum/OptimaLab35/-/raw/feature/enhancing/media/exif_editor.png){width=40%} **Info window** -![main](https://gitlab.com/CodeByMrFinchum/OptimaLab35/-/raw/0.1.1/media/info_window.png){width=40%} +![main](https://gitlab.com/CodeByMrFinchum/OptimaLab35/-/raw/feature/enhancing/media/info_window.png){width=40%} ## **Features** diff --git a/media/OptimaLab35.ico b/media/OptimaLab35.ico new file mode 100644 index 0000000..3f664a9 Binary files /dev/null and b/media/OptimaLab35.ico differ diff --git a/media/main_tab.png b/media/main_tab.png index 16a65b4..3c0ebf6 100644 Binary files a/media/main_tab.png and b/media/main_tab.png differ diff --git a/media/preview_window.png b/media/preview_window.png new file mode 100644 index 0000000..2057ce4 Binary files /dev/null and b/media/preview_window.png differ diff --git a/pip_README.md b/pip_README.md new file mode 100644 index 0000000..f36b255 --- /dev/null +++ b/pip_README.md @@ -0,0 +1,4 @@ +OptimaLab35 is in active development, and even *stable* versions may produce errors in unexpected situations. It is a GUI for optima35. +Please visit [OptimaLab35](https://gitlab.com/CodeByMrFinchum/OptimaLab35/-/blob/main/media/exif_editor.png?ref_type=heads) gitlab page for more information. + +Uses [optima35](https://gitlab.com/CodeByMrFinchum/optima35) to modify images. diff --git a/pyproject.toml b/pyproject.toml index 5f83abc..b2796d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,10 +6,10 @@ build-backend = "hatchling.build" name = "OptimaLab35" dynamic = ["version"] authors = [{ name = "Mr. Finchum" }] -description = "User interface for OPTIMA35." -readme = "README.md" +description = "User interface for optima35." +readme = "pip_README.md" requires-python = ">=3.8" -dependencies = ["optima35==0.6.4", "pyside6", "PyYAML"] +dependencies = ["optima35>=0.6.6", "pyside6", "PyYAML", "packaging"] classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", diff --git a/src/OptimaLab35/__init__.py b/src/OptimaLab35/__init__.py index 485f44a..b5fdc75 100644 --- a/src/OptimaLab35/__init__.py +++ b/src/OptimaLab35/__init__.py @@ -1 +1 @@ -__version__ = "0.1.1" +__version__ = "0.2.2" diff --git a/src/OptimaLab35/gui.py b/src/OptimaLab35/gui.py index 19294fd..ce99d86 100644 --- a/src/OptimaLab35/gui.py +++ b/src/OptimaLab35/gui.py @@ -2,13 +2,18 @@ import sys import os from datetime import datetime +import time + from optima35.core import OptimaManager from OptimaLab35.utils.utility import Utilities from OptimaLab35.ui.main_window import Ui_MainWindow +from OptimaLab35.ui.preview_window import Ui_Preview_Window from OptimaLab35.ui.exif_handler_window import ExifEditor from OptimaLab35.ui.simple_dialog import SimpleDialog # Import the SimpleDialog class from OptimaLab35 import __version__ +from PySide6.QtCore import QRunnable, QThreadPool, Signal, QObject + from PySide6 import QtWidgets from PySide6.QtWidgets import ( QMessageBox, @@ -23,8 +28,110 @@ from PySide6.QtWidgets import ( QFileDialog, QHBoxLayout, QSpinBox, + QProgressBar, ) +from PySide6.QtGui import QPixmap, QIcon + +class PreviewWindow(QMainWindow, Ui_Preview_Window): + values_selected = Signal(int, int, bool) + + def __init__(self): + super(PreviewWindow, self).__init__() + self.ui = Ui_Preview_Window() + self.ui.setupUi(self) + self.o = OptimaManager() + ## Ui interaction + self.ui.load_Button.clicked.connect(self._browse_file) + self.ui.update_Button.clicked.connect(self._update_preview) + self.ui.close_Button.clicked.connect(self._close_window) + + self.ui.reset_brightness_Button.clicked.connect(lambda: self.ui.brightness_spinBox.setValue(0)) + self.ui.reset_contrast_Button.clicked.connect(lambda: self.ui.contrast_spinBox.setValue(0)) + self.preview_image = None + + def _browse_file(self): + file = QFileDialog.getOpenFileName(self, caption = "Select File", filter = ("Images (*.png *.webp *.jpg *.jpeg)")) + if file[0]: + self.ui.image_path_lineEdit.setText(file[0]) + self._update_preview() + + def _update_preview(self): + path = self.ui.image_path_lineEdit.text() + if not os.path.isfile(path): + return + try: + img = self.o.process_image( + save = False, + image_input_file = path, + image_output_file = "", + grayscale = self.ui.grayscale_checkBox.isChecked(), + brightness = int(self.ui.brightness_spinBox.text()), + contrast = int(self.ui.contrast_spinBox.text()) + ) + except Exception as e: + QMessageBox.warning(self, "Warning", "Error loading image...") + print(f"Error loading image...\n{e}") + return + + self.preview_image = QPixmap.fromImage(img) + self.ui.QLabel.setPixmap(self.preview_image) + + def _close_window(self): + # Emit the signal with the values from the spinboxes and checkbox + if self.ui.checkBox.isChecked(): + self.values_selected.emit(self.ui.brightness_spinBox.value(), self.ui.contrast_spinBox.value(), self.ui.grayscale_checkBox.isChecked()) + self.close() + +class WorkerSignals(QObject): + # ChatGPT + progress = Signal(int) + finished = Signal() + +class ImageProcessorRunnable(QRunnable): + # ChatGPT gave rough function layout + def __init__(self, image_files, settings, progress_callback): + super().__init__() + self.image_files = image_files + self.settings = settings + self.signals = WorkerSignals() + self.signals.progress.connect(progress_callback) + self.o = OptimaManager() + self.u = Utilities() + + def run(self): + input_folder = self.settings["input_folder"] + output_folder = self.settings["output_folder"] + + for i, image_file in enumerate(self.image_files, start=1): + input_path = os.path.join(input_folder, image_file) + if self.settings["new_file_names"] != False: + image_name = self.u.append_number_to_name(self.settings["new_file_names"], i, len(self.image_files), self.settings["invert_image_order"]) + else: + image_name = os.path.splitext(image_file)[0] + output_path = os.path.join(output_folder, image_name) + + self.o.process_image( + image_input_file = input_path, + image_output_file = output_path, + file_type = self.settings["file_format"], + quality = self.settings["jpg_quality"], + compressing = self.settings["png_compression"], + optimize = self.settings["optimize"], + resize = self.settings["resize"], + watermark = self.settings["watermark"], + font_size = self.settings["font_size"], + grayscale = self.settings["grayscale"], + brightness = self.settings["brightness"], + contrast = self.settings["contrast"], + dict_for_exif = self.settings["user_selected_exif"], + gps = self.settings["gps"], + copy_exif = self.settings["copy_exif"] + ) + self.signals.progress.emit(int((i / len(self.image_files)) * 100)) + + self.signals.finished.emit() + class OptimaLab35(QMainWindow, Ui_MainWindow): def __init__(self): super(OptimaLab35, self).__init__() @@ -33,6 +140,7 @@ class OptimaLab35(QMainWindow, Ui_MainWindow): self.ui = Ui_MainWindow() self.ui.setupUi(self) self.o = OptimaManager() + self.check_version() self.u = Utilities() self.u.program_configs() self.exif_file = os.path.expanduser("~/.config/OptimaLab35/exif.yaml") @@ -44,14 +152,31 @@ class OptimaLab35(QMainWindow, Ui_MainWindow): self.sd = SimpleDialog() self._change_statusbar(f"Using {self.o.name} v{self.o.version}", 5000) + # Instantiate the second window + self.preview_window = PreviewWindow() + self.thread_pool = QThreadPool() # multi thread ChatGPT + + def open_preview_window(self): + self.preview_window.values_selected.connect(self.update_values) + self.preview_window.show() + + def update_values(self, value1, value2, checkbox_state): + # Update main window's widgets with the received values + # ChatGPT + self.ui.brightness_spinBox.setValue(value1) + self.ui.contrast_spinBox.setValue(value2) + self.ui.grayscale_checkBox.setChecked(checkbox_state) def _default_ui_layout(self): self.ui.png_quality_spinBox.setVisible(False) + self.ui.png_quality_Slider.setVisible(False) + self.ui.quality_label_2.setVisible(False) def _define_gui_interaction(self): self.ui.input_folder_button.clicked.connect(self._browse_input_folder) self.ui.output_folder_button.clicked.connect(self._browse_output_folder) - self.ui.start_button.clicked.connect(self._process) + self.ui.start_button.clicked.connect(self._start_process) + self.ui.insert_exif_Button.clicked.connect(self._start_insert_exif) self.ui.image_type.currentIndexChanged.connect(self._update_quality_options) self.ui.exif_checkbox.stateChanged.connect( @@ -60,68 +185,147 @@ class OptimaLab35(QMainWindow, Ui_MainWindow): self.ui.tabWidget.currentChanged.connect(self._on_tab_changed) self.ui.edit_exif_button.clicked.connect(self._open_exif_editor) - self.ui.actionInfo.triggered.connect(self._info_window) + self.ui.actionAbout.triggered.connect(self._info_window) + self.ui.actionPreview.triggered.connect(self.open_preview_window) + self.ui.preview_Button.clicked.connect(self.open_preview_window) def _info_window(self): + # ChatGPT, mainly info_text = f"""

{self.name} v{self.version}

+

(C) 2024-2025 Mr. Finchum aka CodeByMrFinchum

{self.name} is a GUI for {self.o.name} (v{self.o.version}).

-

For more details, visit:

+

Both projects are in active development, for more details, visit:

""" self.sd.show_dialog(f"{self.name} v{self.version}", info_text) - def _process(self): - self.ui.start_button.setEnabled(False) - self._update_settings() # Get all user selected data - input_folder_valid = os.path.exists(self.settings["input_folder"]) - output_folder_valid = os.path.exists(self.settings["output_folder"]) - if not input_folder_valid or not output_folder_valid: - QMessageBox.warning(self, "Warning", f"Input location {input_folder_valid}\nOutput folder {output_folder_valid}...") - return + def _prepear_image(self): + pass + def _image_list_from_folder(self, path): + image_files = [ + f for f in os.listdir(path) if f.lower().endswith((".png", ".jpg", ".jpeg", ".webp")) + ] + return image_files + + def _start_process(self): + self._toggle_buttons(False) + self._update_settings() # Get all user selected data input_folder = self.settings["input_folder"] output_folder = self.settings["output_folder"] + if not input_folder or not output_folder: + QMessageBox.warning(self, "Warning", "Input or output folder not selected") + self._toggle_buttons(True) + return + + input_folder_valid = os.path.exists(input_folder) + output_folder_valid = os.path.exists(output_folder) + if not input_folder_valid or not output_folder_valid: + QMessageBox.warning(self, "Warning", f"Input location {input_folder_valid}\nOutput folder {output_folder_valid}...") + self._toggle_buttons(True) + return + + image_list = self._image_list_from_folder(input_folder) + if len(image_list) == 0: + QMessageBox.warning(self, "Warning", "Selected folder has no supported files.") + self._toggle_buttons(True) + return + + if len(self._image_list_from_folder(output_folder)) != 0: + reply = QMessageBox.question( + self, + "Confirmation", + "Output folder containes images, which might get overritten, continue?", + QMessageBox.Yes | QMessageBox.No, + ) + + if reply == QMessageBox.No: + self._toggle_buttons(True) + return + + # Create a worker ChatGPT + worker = ImageProcessorRunnable(image_list, self.settings, self._handle_qprogressbar) + worker.signals.finished.connect(self._on_processing_finished) + # Start worker in thread pool ChatGPT + self.thread_pool.start(worker) + + def _handle_qprogressbar(self, value): + self.ui.progressBar.setValue(value) + + def _on_processing_finished(self): + self._toggle_buttons(True) + self._handle_qprogressbar(0) + QMessageBox.information(self, "Information", "Finished!") + + def _toggle_buttons(self, state): + self.ui.start_button.setEnabled(state) + + if self.ui.exif_checkbox.isChecked(): + self.ui.insert_exif_Button.setEnabled(state) + + def _insert_exif(self, image_files): + input_folder = self.settings["input_folder"] - image_files = [ - f for f in os.listdir(input_folder) if f.lower().endswith((".png", ".jpg", ".jpeg", ".webp")) - ] i = 1 for image_file in image_files: - input_path = os.path.join(input_folder, image_file) - if self.settings["new_file_names"] != False: - image_name = self.u.append_number_to_name(self.settings["new_file_names"], i, len(image_files), self.settings["invert_image_order"]) - else: - image_name = os.path.splitext(image_file)[0] - output_path = os.path.join(output_folder, image_name) - self.o.process_image( - image_input_file = input_path, - image_output_file = output_path, - file_type = self.settings["file_format"], - quality = self.settings["jpg_quality"], - compressing = self.settings["png_compression"], - optimize = self.ui.optimize_checkBox.isChecked(), - resize = self.settings["resize"], - watermark = self.settings["watermark"], - font_size = self.settings["font_size"], - grayscale = self.settings["grayscale"], - brightness = self.settings["brightness"], - contrast = self.settings["contrast"], - dict_for_exif = self.user_selected_exif, - gps = self.settings["gps"], - copy_exif = self.settings["copy_exif"]) - self._handle_qprogressbar(i, len(image_files)) + input_path = os.path.join(input_folder, image_file) + + self.o.insert_dict_to_image( + exif_dict = self.settings["user_selected_exif"], + image_path = input_path, + gps = self.settings["gps"]) + self._change_statusbar(image_file, 100) + self._handle_qprogressbar(int((i / len(image_files)) * 100)) i += 1 - QMessageBox.information(self, "Information", "Finished") - self.ui.start_button.setEnabled(True) self.ui.progressBar.setValue(0) + def _start_insert_exif(self): + self._toggle_buttons(False) + self._update_settings() # Get all user selected data + input_folder = self.settings["input_folder"] + output_folder = self.settings["output_folder"] + if not input_folder: + QMessageBox.warning(self, "Warning", "Input not selected") + self._toggle_buttons(True) + return + + if output_folder: + reply = QMessageBox.question( + self, + "Confirmation", + "Output folder selected, but insert exif is done to images in input folder, Continue?", + QMessageBox.Yes | QMessageBox.No, + ) + + if reply == QMessageBox.No: + self._toggle_buttons(True) + return + + input_folder_valid = os.path.exists(input_folder) + if not input_folder_valid : + QMessageBox.warning(self, "Warning", f"Input location {input_folder_valid}") + self._toggle_buttons(True) + return + + image_list = self._image_list_from_folder(input_folder) + if len(image_list) == 0: + QMessageBox.warning(self, "Warning", "Selected folder has no supported files.") + self._toggle_buttons(True) + return + + self._insert_exif(image_list) + + self._toggle_buttons(True) + QMessageBox.information(self, "Information", "Finished") + + def _open_exif_editor(self): """Open the EXIF Editor.""" self.exif_editor = ExifEditor(self.available_exif_data) @@ -146,9 +350,27 @@ class OptimaLab35(QMainWindow, Ui_MainWindow): elif index == 0: # Main Tab self._handle_exif_file("write") + def _sort_dict_of_lists(self, input_dict): + # Partily ChatGPT + sorted_dict = {} + for key, lst in input_dict.items(): + # Sort alphabetically for strings, numerically for numbers + if key == "iso": + lst = [int(x) for x in lst] + lst = sorted(lst) + lst = [str(x) for x in lst] + sorted_dict["iso"] = lst + + elif all(isinstance(x, str) for x in lst): + sorted_dict[key] = sorted(lst, key=str.lower) # Case-insensitive sort for strings + + return sorted_dict + + def _handle_exif_file(self, do): if do == "read": - self.available_exif_data = self.u.read_yaml(self.exif_file) + file_dict = self.u.read_yaml(self.exif_file) + self.available_exif_data = self._sort_dict_of_lists(file_dict) elif do == "write": self.u.write_yaml(self.exif_file, self.available_exif_data) @@ -165,6 +387,7 @@ class OptimaLab35(QMainWindow, Ui_MainWindow): "artist": self.ui.artist_comboBox, "copyright_info": self.ui.copyright_info_comboBox, } + self._populate_comboboxes(combo_mapping) def _populate_comboboxes(self, combo_mapping): @@ -181,13 +404,23 @@ class OptimaLab35(QMainWindow, Ui_MainWindow): # Hide all quality settings self.ui.png_quality_spinBox.setVisible(False) self.ui.jpg_quality_spinBox.setVisible(False) + self.ui.jpg_quality_Slider.setVisible(False) + self.ui.png_quality_Slider.setVisible(False) + self.ui.quality_label_1.setVisible(False) + self.ui.quality_label_2.setVisible(False) # Show relevant settings if selected_format == "jpg": self.ui.jpg_quality_spinBox.setVisible(True) + self.ui.jpg_quality_Slider.setVisible(True) + self.ui.quality_label_1.setVisible(True) elif selected_format == "webp": self.ui.jpg_quality_spinBox.setVisible(True) + self.ui.jpg_quality_Slider.setVisible(True) + self.ui.quality_label_1.setVisible(True) elif selected_format == "png": self.ui.png_quality_spinBox.setVisible(True) + self.ui.png_quality_Slider.setVisible(True) + self.ui.quality_label_2.setVisible(True) def _browse_input_folder(self): folder = QFileDialog.getExistingDirectory(self, "Select Input Folder") @@ -202,10 +435,6 @@ class OptimaLab35(QMainWindow, Ui_MainWindow): def _change_statusbar(self, msg, timeout = 500): self.ui.statusBar.showMessage(msg, timeout) - def _handle_qprogressbar(self, current, total): - progress = int((100 / total) * current) - self.ui.progressBar.setValue(progress) - def _get_checkbox_value(self, checkbox, default=None): """Helper function to get the value of a checkbox or a default value.""" return checkbox.isChecked() if checkbox else default @@ -251,18 +480,20 @@ class OptimaLab35(QMainWindow, Ui_MainWindow): self.settings["own_date"] = self._get_checkbox_value(self.ui.add_date_checkBox) # Conditional settings with logic - self.settings["resize"] = self._get_spinbox_value(self.ui.resize_spinBox) if self.ui.resize_checkbox.isChecked() else None - self.settings["brightness"] = self._get_spinbox_value(self.ui.brightness_spinBox) if self.ui.brightness_checkbox.isChecked() else None - self.settings["contrast"] = self._get_spinbox_value(self.ui.contrast_spinBox) if self.ui.contrast_checkbox.isChecked() else None + self.settings["resize"] = int(self.ui.resize_spinBox.text()) if self.ui.resize_spinBox.text() != "100" else None + self.settings["brightness"] = int(self.ui.brightness_spinBox.text()) if self.ui.brightness_spinBox.text() != "0" else None + self.settings["contrast"] = int(self.ui.contrast_spinBox.text()) if self.ui.contrast_spinBox.text() != "0" else None - self.settings["new_file_names"] = self._get_text_value(self.ui.filename, False) if self.ui.rename_checkbox.isChecked() else False - self.settings["watermark"] = self._get_text_value(self.ui.watermark_lineEdit) if self.ui.watermark_checkbox.isChecked() else None + new_name = self._get_text_value(self.ui.filename, False) if self.ui.rename_checkbox.isChecked() else False + if isinstance(new_name, str): new_name = new_name.replace(" ", "_") + self.settings["new_file_names"] = new_name + self.settings["watermark"] = self.ui.watermark_lineEdit.text() if len(self.ui.watermark_lineEdit.text()) != 0 else None # Handle EXIF data selection if self.settings["own_exif"]: - self.user_selected_exif = self._get_selected_exif() + self.settings["user_selected_exif"] = self._get_selected_exif() else: - self.user_selected_exif = None + self.settings["user_selected_exif"] = None self.settings["gps"] = None def _get_date(self): @@ -280,9 +511,27 @@ class OptimaLab35(QMainWindow, Ui_MainWindow): user_data["user_comment"] = self.ui.user_comment_comboBox.currentText() user_data["artist"] = self.ui.artist_comboBox.currentText() user_data["copyright_info"] = self.ui.copyright_info_comboBox.currentText() - user_data["software"] = f"{self.o.name} {self.o.version}" + user_data["software"] = f"{self.name} {self.version} with {self.o.name} {self.o.version}" return user_data + def closeEvent(self, event): + self.preview_window.close() + + def check_version(self, min_version="0.6.6"): + # Mainly ChatGPT + from packaging import version # Use `packaging` for robust version comparison + + current_version = self.o.version + if version.parse(current_version) < version.parse(min_version): + msg = ( + f"optima35 version {current_version} detected.\n" + f"Minimum required version is {min_version}.\n" + "Please update the core package to continue.\n" + "https://pypi.org/project/optima35/" + ) + QMessageBox.critical(None, "Version Error", msg) + sys.exit(1) + def main(): app = QtWidgets.QApplication(sys.argv) window = OptimaLab35() diff --git a/src/OptimaLab35/ui/exif_handler_window.py b/src/OptimaLab35/ui/exif_handler_window.py index 8564cba..930fb51 100644 --- a/src/OptimaLab35/ui/exif_handler_window.py +++ b/src/OptimaLab35/ui/exif_handler_window.py @@ -69,7 +69,7 @@ class ExifEditor(QMainWindow): self.list_widget.addItem(new_item) self.line_edit.clear() else: - QMessageBox.warning(self, "Warning", "Cannot add an empty item.") + QMessageBox.warning(self, "Warning", f"Cannot add an empty item.\nDelete {self.exif_file}...") def delete_item(self): """Delete the selected item from the list.""" diff --git a/src/OptimaLab35/ui/main_window.py b/src/OptimaLab35/ui/main_window.py index 890eb7f..9738dc7 100644 --- a/src/OptimaLab35/ui/main_window.py +++ b/src/OptimaLab35/ui/main_window.py @@ -20,18 +20,23 @@ from PySide6.QtWidgets import (QApplication, QCheckBox, QComboBox, QDateEdit, QFrame, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit, QMainWindow, QMenu, QMenuBar, QProgressBar, QPushButton, QSizePolicy, - QSpinBox, QStatusBar, QTabWidget, QVBoxLayout, - QWidget) + QSlider, QSpinBox, QStatusBar, QTabWidget, + QVBoxLayout, QWidget) class Ui_MainWindow(object): def setupUi(self, MainWindow): if not MainWindow.objectName(): MainWindow.setObjectName(u"MainWindow") - MainWindow.resize(450, 708) + MainWindow.setWindowModality(Qt.NonModal) + MainWindow.resize(440, 756) MainWindow.setMinimumSize(QSize(350, 677)) - MainWindow.setMaximumSize(QSize(500, 1000)) + MainWindow.setMaximumSize(QSize(1000, 1000)) self.actionInfo = QAction(MainWindow) self.actionInfo.setObjectName(u"actionInfo") + self.actionPreview = QAction(MainWindow) + self.actionPreview.setObjectName(u"actionPreview") + self.actionAbout = QAction(MainWindow) + self.actionAbout.setObjectName(u"actionAbout") self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName(u"centralwidget") self.gridLayout = QGridLayout(self.centralwidget) @@ -48,25 +53,28 @@ class Ui_MainWindow(object): self.folder_group.setMaximumSize(QSize(400, 16777215)) self.gridLayout_5 = QGridLayout(self.folder_group) self.gridLayout_5.setObjectName(u"gridLayout_5") + self.input_folder_button = QPushButton(self.folder_group) + self.input_folder_button.setObjectName(u"input_folder_button") + self.input_folder_button.setMinimumSize(QSize(70, 0)) + self.input_folder_button.setFlat(False) + + self.gridLayout_5.addWidget(self.input_folder_button, 0, 1, 1, 1) + + self.output_path = QLineEdit(self.folder_group) + self.output_path.setObjectName(u"output_path") + + self.gridLayout_5.addWidget(self.output_path, 0, 2, 1, 1) + self.input_path = QLineEdit(self.folder_group) self.input_path.setObjectName(u"input_path") self.gridLayout_5.addWidget(self.input_path, 0, 0, 1, 1) - self.output_path = QLineEdit(self.folder_group) - self.output_path.setObjectName(u"output_path") - - self.gridLayout_5.addWidget(self.output_path, 0, 1, 1, 1) - - self.input_folder_button = QPushButton(self.folder_group) - self.input_folder_button.setObjectName(u"input_folder_button") - - self.gridLayout_5.addWidget(self.input_folder_button, 1, 0, 1, 1) - self.output_folder_button = QPushButton(self.folder_group) self.output_folder_button.setObjectName(u"output_folder_button") + self.output_folder_button.setMinimumSize(QSize(70, 0)) - self.gridLayout_5.addWidget(self.output_folder_button, 1, 1, 1, 1) + self.gridLayout_5.addWidget(self.output_folder_button, 0, 3, 1, 1) self.verticalLayout_10.addWidget(self.folder_group) @@ -76,36 +84,38 @@ class Ui_MainWindow(object): self.groupBox.setMaximumSize(QSize(400, 16777215)) self.gridLayout_4 = QGridLayout(self.groupBox) self.gridLayout_4.setObjectName(u"gridLayout_4") - self.resize_checkbox = QCheckBox(self.groupBox) - self.resize_checkbox.setObjectName(u"resize_checkbox") + self.quality_label_2 = QLabel(self.groupBox) + self.quality_label_2.setObjectName(u"quality_label_2") - self.gridLayout_4.addWidget(self.resize_checkbox, 0, 0, 1, 1) - - self.resize_spinBox = QSpinBox(self.groupBox) - self.resize_spinBox.setObjectName(u"resize_spinBox") - self.resize_spinBox.setEnabled(False) - self.resize_spinBox.setMinimum(1) - self.resize_spinBox.setMaximum(200) - self.resize_spinBox.setSingleStep(1) - self.resize_spinBox.setValue(80) - - self.gridLayout_4.addWidget(self.resize_spinBox, 0, 1, 1, 1) - - self.image_type = QComboBox(self.groupBox) - self.image_type.addItem(u"jpg") - self.image_type.addItem(u"png") - self.image_type.addItem(u"webp") - self.image_type.setObjectName(u"image_type") - - self.gridLayout_4.addWidget(self.image_type, 1, 0, 1, 1) + self.gridLayout_4.addWidget(self.quality_label_2, 4, 0, 1, 1) self.jpg_quality_spinBox = QSpinBox(self.groupBox) self.jpg_quality_spinBox.setObjectName(u"jpg_quality_spinBox") self.jpg_quality_spinBox.setMinimum(1) self.jpg_quality_spinBox.setMaximum(100) - self.jpg_quality_spinBox.setValue(80) + self.jpg_quality_spinBox.setValue(90) - self.gridLayout_4.addWidget(self.jpg_quality_spinBox, 1, 1, 1, 1) + self.gridLayout_4.addWidget(self.jpg_quality_spinBox, 3, 3, 1, 1) + + self.label_11 = QLabel(self.groupBox) + self.label_11.setObjectName(u"label_11") + + self.gridLayout_4.addWidget(self.label_11, 0, 0, 1, 1) + + self.optimize_checkBox = QCheckBox(self.groupBox) + self.optimize_checkBox.setObjectName(u"optimize_checkBox") + + self.gridLayout_4.addWidget(self.optimize_checkBox, 0, 3, 1, 1) + + self.png_quality_Slider = QSlider(self.groupBox) + self.png_quality_Slider.setObjectName(u"png_quality_Slider") + self.png_quality_Slider.setMinimum(1) + self.png_quality_Slider.setMaximum(9) + self.png_quality_Slider.setPageStep(1) + self.png_quality_Slider.setSliderPosition(6) + self.png_quality_Slider.setOrientation(Qt.Horizontal) + + self.gridLayout_4.addWidget(self.png_quality_Slider, 4, 2, 1, 1) self.png_quality_spinBox = QSpinBox(self.groupBox) self.png_quality_spinBox.setObjectName(u"png_quality_spinBox") @@ -114,72 +124,140 @@ class Ui_MainWindow(object): self.png_quality_spinBox.setMaximum(9) self.png_quality_spinBox.setValue(6) - self.gridLayout_4.addWidget(self.png_quality_spinBox, 1, 2, 1, 1) + self.gridLayout_4.addWidget(self.png_quality_spinBox, 4, 3, 1, 1) - self.optimize_checkBox = QCheckBox(self.groupBox) - self.optimize_checkBox.setObjectName(u"optimize_checkBox") + self.quality_label_1 = QLabel(self.groupBox) + self.quality_label_1.setObjectName(u"quality_label_1") - self.gridLayout_4.addWidget(self.optimize_checkBox, 0, 2, 1, 1) + self.gridLayout_4.addWidget(self.quality_label_1, 3, 0, 1, 1) + + self.image_type = QComboBox(self.groupBox) + self.image_type.addItem(u"jpg") + self.image_type.addItem(u"png") + self.image_type.addItem(u"webp") + self.image_type.setObjectName(u"image_type") + + self.gridLayout_4.addWidget(self.image_type, 0, 2, 1, 1) + + self.jpg_quality_Slider = QSlider(self.groupBox) + self.jpg_quality_Slider.setObjectName(u"jpg_quality_Slider") + self.jpg_quality_Slider.setMinimum(1) + self.jpg_quality_Slider.setMaximum(100) + self.jpg_quality_Slider.setSliderPosition(90) + self.jpg_quality_Slider.setOrientation(Qt.Horizontal) + + self.gridLayout_4.addWidget(self.jpg_quality_Slider, 3, 2, 1, 1) + + self.label_13 = QLabel(self.groupBox) + self.label_13.setObjectName(u"label_13") + + self.gridLayout_4.addWidget(self.label_13, 5, 0, 1, 1) + + self.resize_Slider = QSlider(self.groupBox) + self.resize_Slider.setObjectName(u"resize_Slider") + self.resize_Slider.setMinimum(1) + self.resize_Slider.setMaximum(200) + self.resize_Slider.setValue(100) + self.resize_Slider.setOrientation(Qt.Horizontal) + + self.gridLayout_4.addWidget(self.resize_Slider, 5, 2, 1, 1) + + self.resize_spinBox = QSpinBox(self.groupBox) + self.resize_spinBox.setObjectName(u"resize_spinBox") + self.resize_spinBox.setEnabled(True) + self.resize_spinBox.setMinimum(1) + self.resize_spinBox.setMaximum(200) + self.resize_spinBox.setSingleStep(1) + self.resize_spinBox.setValue(100) + + self.gridLayout_4.addWidget(self.resize_spinBox, 5, 3, 1, 1) - self.png_quality_spinBox.raise_() - self.resize_checkbox.raise_() - self.resize_spinBox.raise_() - self.image_type.raise_() - self.jpg_quality_spinBox.raise_() - self.optimize_checkBox.raise_() self.verticalLayout_10.addWidget(self.groupBox) self.groupBox_2 = QGroupBox(self.tab_1) self.groupBox_2.setObjectName(u"groupBox_2") self.groupBox_2.setMaximumSize(QSize(400, 16777215)) + self.groupBox_2.setMouseTracking(False) self.gridLayout_3 = QGridLayout(self.groupBox_2) self.gridLayout_3.setObjectName(u"gridLayout_3") - self.watermark_lineEdit = QLineEdit(self.groupBox_2) - self.watermark_lineEdit.setObjectName(u"watermark_lineEdit") - self.watermark_lineEdit.setEnabled(False) + self.label_9 = QLabel(self.groupBox_2) + self.label_9.setObjectName(u"label_9") - self.gridLayout_3.addWidget(self.watermark_lineEdit, 3, 0, 1, 3) + self.gridLayout_3.addWidget(self.label_9, 1, 0, 1, 1) - self.brightness_checkbox = QCheckBox(self.groupBox_2) - self.brightness_checkbox.setObjectName(u"brightness_checkbox") + self.brightness_horizontalSlider = QSlider(self.groupBox_2) + self.brightness_horizontalSlider.setObjectName(u"brightness_horizontalSlider") + self.brightness_horizontalSlider.setMinimum(-100) + self.brightness_horizontalSlider.setMaximum(100) + self.brightness_horizontalSlider.setOrientation(Qt.Horizontal) - self.gridLayout_3.addWidget(self.brightness_checkbox, 0, 0, 1, 1) + self.gridLayout_3.addWidget(self.brightness_horizontalSlider, 1, 1, 1, 1) + + self.brightness_spinBox = QSpinBox(self.groupBox_2) + self.brightness_spinBox.setObjectName(u"brightness_spinBox") + self.brightness_spinBox.setEnabled(True) + self.brightness_spinBox.setMinimum(-100) + self.brightness_spinBox.setMaximum(100) + self.brightness_spinBox.setValue(0) + + self.gridLayout_3.addWidget(self.brightness_spinBox, 1, 2, 1, 1) + + self.contrast_spinBox = QSpinBox(self.groupBox_2) + self.contrast_spinBox.setObjectName(u"contrast_spinBox") + self.contrast_spinBox.setEnabled(True) + self.contrast_spinBox.setMinimum(-100) + self.contrast_spinBox.setMaximum(100) + self.contrast_spinBox.setValue(0) + + self.gridLayout_3.addWidget(self.contrast_spinBox, 4, 2, 1, 1) + + self.label_10 = QLabel(self.groupBox_2) + self.label_10.setObjectName(u"label_10") + + self.gridLayout_3.addWidget(self.label_10, 4, 0, 1, 1) + + self.contrast_horizontalSlider = QSlider(self.groupBox_2) + self.contrast_horizontalSlider.setObjectName(u"contrast_horizontalSlider") + self.contrast_horizontalSlider.setMinimum(-100) + self.contrast_horizontalSlider.setMaximum(100) + self.contrast_horizontalSlider.setOrientation(Qt.Horizontal) + + self.gridLayout_3.addWidget(self.contrast_horizontalSlider, 4, 1, 1, 1) self.grayscale_checkBox = QCheckBox(self.groupBox_2) self.grayscale_checkBox.setObjectName(u"grayscale_checkBox") - self.gridLayout_3.addWidget(self.grayscale_checkBox, 0, 2, 1, 1) + self.gridLayout_3.addWidget(self.grayscale_checkBox, 5, 0, 1, 2) - self.contrast_spinBox = QSpinBox(self.groupBox_2) - self.contrast_spinBox.setObjectName(u"contrast_spinBox") - self.contrast_spinBox.setEnabled(False) - self.contrast_spinBox.setMinimum(-100) - self.contrast_spinBox.setMaximum(100) - self.contrast_spinBox.setValue(10) + self.preview_Button = QPushButton(self.groupBox_2) + self.preview_Button.setObjectName(u"preview_Button") - self.gridLayout_3.addWidget(self.contrast_spinBox, 1, 1, 1, 1) + self.gridLayout_3.addWidget(self.preview_Button, 5, 2, 1, 1) - self.watermark_checkbox = QCheckBox(self.groupBox_2) - self.watermark_checkbox.setObjectName(u"watermark_checkbox") - self.gridLayout_3.addWidget(self.watermark_checkbox, 2, 0, 1, 1) + self.verticalLayout_10.addWidget(self.groupBox_2) - self.brightness_spinBox = QSpinBox(self.groupBox_2) - self.brightness_spinBox.setObjectName(u"brightness_spinBox") - self.brightness_spinBox.setEnabled(False) - self.brightness_spinBox.setMinimum(-100) - self.brightness_spinBox.setMaximum(100) - self.brightness_spinBox.setValue(-10) + self.groupBox_3 = QGroupBox(self.tab_1) + self.groupBox_3.setObjectName(u"groupBox_3") + self.groupBox_3.setEnabled(True) + self.groupBox_3.setFlat(False) + self.groupBox_3.setCheckable(False) + self.groupBox_3.setChecked(False) + self.horizontalLayout_5 = QHBoxLayout(self.groupBox_3) + self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") + self.watermark_lineEdit = QLineEdit(self.groupBox_3) + self.watermark_lineEdit.setObjectName(u"watermark_lineEdit") + self.watermark_lineEdit.setEnabled(True) - self.gridLayout_3.addWidget(self.brightness_spinBox, 0, 1, 1, 1) + self.horizontalLayout_5.addWidget(self.watermark_lineEdit) - self.contrast_checkbox = QCheckBox(self.groupBox_2) - self.contrast_checkbox.setObjectName(u"contrast_checkbox") + self.label_12 = QLabel(self.groupBox_3) + self.label_12.setObjectName(u"label_12") - self.gridLayout_3.addWidget(self.contrast_checkbox, 1, 0, 1, 1) + self.horizontalLayout_5.addWidget(self.label_12) - self.font_size_comboBox = QComboBox(self.groupBox_2) + self.font_size_comboBox = QComboBox(self.groupBox_3) self.font_size_comboBox.addItem("") self.font_size_comboBox.addItem("") self.font_size_comboBox.addItem("") @@ -187,10 +265,10 @@ class Ui_MainWindow(object): self.font_size_comboBox.addItem("") self.font_size_comboBox.setObjectName(u"font_size_comboBox") - self.gridLayout_3.addWidget(self.font_size_comboBox, 2, 1, 1, 1) + self.horizontalLayout_5.addWidget(self.font_size_comboBox) - self.verticalLayout_10.addWidget(self.groupBox_2) + self.verticalLayout_10.addWidget(self.groupBox_3) self.rename_group = QGroupBox(self.tab_1) self.rename_group.setObjectName(u"rename_group") @@ -234,6 +312,12 @@ class Ui_MainWindow(object): self.horizontalLayout_3.addWidget(self.start_button) + self.insert_exif_Button = QPushButton(self.widget_9) + self.insert_exif_Button.setObjectName(u"insert_exif_Button") + self.insert_exif_Button.setEnabled(False) + + self.horizontalLayout_3.addWidget(self.insert_exif_Button) + self.verticalLayout_10.addWidget(self.widget_9) @@ -465,29 +549,41 @@ class Ui_MainWindow(object): MainWindow.setStatusBar(self.statusBar) self.menuBar = QMenuBar(MainWindow) self.menuBar.setObjectName(u"menuBar") - self.menuBar.setGeometry(QRect(0, 0, 450, 27)) - self.menuInfo = QMenu(self.menuBar) - self.menuInfo.setObjectName(u"menuInfo") + self.menuBar.setGeometry(QRect(0, 0, 440, 27)) + self.menuSettings = QMenu(self.menuBar) + self.menuSettings.setObjectName(u"menuSettings") + self.menuHelp = QMenu(self.menuBar) + self.menuHelp.setObjectName(u"menuHelp") MainWindow.setMenuBar(self.menuBar) - self.menuBar.addAction(self.menuInfo.menuAction()) - self.menuInfo.addAction(self.actionInfo) + self.menuBar.addAction(self.menuSettings.menuAction()) + self.menuBar.addAction(self.menuHelp.menuAction()) + self.menuSettings.addAction(self.actionPreview) + self.menuHelp.addAction(self.actionAbout) self.retranslateUi(MainWindow) - self.resize_checkbox.toggled.connect(self.resize_spinBox.setEnabled) - self.brightness_checkbox.toggled.connect(self.brightness_spinBox.setEnabled) - self.contrast_checkbox.toggled.connect(self.contrast_spinBox.setEnabled) - self.watermark_checkbox.toggled.connect(self.watermark_lineEdit.setEnabled) self.rename_checkbox.toggled.connect(self.filename.setEnabled) self.exif_checkbox.toggled.connect(self.exif_options_group.setEnabled) - self.exif_checkbox.toggled.connect(self.exif_copy_checkBox.setDisabled) + self.jpg_quality_Slider.valueChanged.connect(self.jpg_quality_spinBox.setValue) self.exif_copy_checkBox.toggled.connect(self.exif_checkbox.setDisabled) + self.exif_checkbox.toggled.connect(self.exif_copy_checkBox.setDisabled) + self.resize_spinBox.valueChanged.connect(self.resize_Slider.setValue) + self.png_quality_spinBox.valueChanged.connect(self.png_quality_Slider.setValue) + self.contrast_horizontalSlider.valueChanged.connect(self.contrast_spinBox.setValue) + self.resize_Slider.valueChanged.connect(self.resize_spinBox.setValue) + self.brightness_horizontalSlider.valueChanged.connect(self.brightness_spinBox.setValue) + self.exif_checkbox.toggled.connect(self.date_groupBox.setEnabled) + self.png_quality_Slider.valueChanged.connect(self.png_quality_spinBox.setValue) + self.gps_checkBox.toggled.connect(self.lat_lineEdit.setEnabled) + self.exif_checkbox.toggled.connect(self.insert_exif_Button.setEnabled) + self.gps_checkBox.toggled.connect(self.long_lineEdit.setEnabled) + self.brightness_spinBox.valueChanged.connect(self.brightness_horizontalSlider.setValue) + self.resize_Slider.valueChanged.connect(self.resize_spinBox.setValue) + self.exif_checkbox.toggled.connect(self.gps_groupBox.setEnabled) + self.contrast_spinBox.valueChanged.connect(self.contrast_horizontalSlider.setValue) self.exif_checkbox.toggled.connect(self.edit_exif_button.setEnabled) self.add_date_checkBox.toggled.connect(self.dateEdit.setEnabled) - self.exif_checkbox.toggled.connect(self.date_groupBox.setEnabled) - self.exif_checkbox.toggled.connect(self.gps_groupBox.setEnabled) - self.gps_checkBox.toggled.connect(self.lat_lineEdit.setEnabled) - self.gps_checkBox.toggled.connect(self.long_lineEdit.setEnabled) + self.jpg_quality_spinBox.valueChanged.connect(self.jpg_quality_Slider.setValue) self.tabWidget.setCurrentIndex(0) self.font_size_comboBox.setCurrentIndex(2) @@ -497,25 +593,32 @@ class Ui_MainWindow(object): # setupUi def retranslateUi(self, MainWindow): - MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"OPTIMA-35", None)) - self.actionInfo.setText(QCoreApplication.translate("MainWindow", u"Info", None)) - self.input_path.setText("") - self.input_path.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Enter input folder", None)) + MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"OptimaLab35", None)) + self.actionInfo.setText(QCoreApplication.translate("MainWindow", u"About", None)) + self.actionPreview.setText(QCoreApplication.translate("MainWindow", u"Preview image", None)) + self.actionAbout.setText(QCoreApplication.translate("MainWindow", u"About", None)) + self.input_folder_button.setText(QCoreApplication.translate("MainWindow", u"Input", None)) self.output_path.setText("") - self.output_path.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Enter output folder", None)) - self.input_folder_button.setText(QCoreApplication.translate("MainWindow", u"input", None)) - self.output_folder_button.setText(QCoreApplication.translate("MainWindow", u"output", None)) + self.output_path.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Output folder", None)) + self.input_path.setText("") + self.input_path.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Input folder", None)) + self.output_folder_button.setText(QCoreApplication.translate("MainWindow", u"Output", None)) self.groupBox.setTitle(QCoreApplication.translate("MainWindow", u"Essential group", None)) - self.resize_checkbox.setText(QCoreApplication.translate("MainWindow", u"Resize", None)) - + self.quality_label_2.setText(QCoreApplication.translate("MainWindow", u"Quality", None)) + self.label_11.setText(QCoreApplication.translate("MainWindow", u"Export Format", None)) self.optimize_checkBox.setText(QCoreApplication.translate("MainWindow", u"optimize", None)) + self.quality_label_1.setText(QCoreApplication.translate("MainWindow", u"Quality", None)) + + self.label_13.setText(QCoreApplication.translate("MainWindow", u"Resize", None)) self.groupBox_2.setTitle(QCoreApplication.translate("MainWindow", u"Extra stuff", None)) + self.label_9.setText(QCoreApplication.translate("MainWindow", u"Brightness", None)) + self.label_10.setText(QCoreApplication.translate("MainWindow", u"Contrast", None)) + self.grayscale_checkBox.setText(QCoreApplication.translate("MainWindow", u"Turn image to Black and White", None)) + self.preview_Button.setText(QCoreApplication.translate("MainWindow", u"Preview", None)) + self.groupBox_3.setTitle(QCoreApplication.translate("MainWindow", u"Watermark", None)) self.watermark_lineEdit.setText("") self.watermark_lineEdit.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Enter Watermark", None)) - self.brightness_checkbox.setText(QCoreApplication.translate("MainWindow", u"Brightness", None)) - self.grayscale_checkBox.setText(QCoreApplication.translate("MainWindow", u"Grayscale", None)) - self.watermark_checkbox.setText(QCoreApplication.translate("MainWindow", u"Watermark", None)) - self.contrast_checkbox.setText(QCoreApplication.translate("MainWindow", u"Contrast", None)) + self.label_12.setText(QCoreApplication.translate("MainWindow", u"Size", None)) self.font_size_comboBox.setItemText(0, QCoreApplication.translate("MainWindow", u"Tiny", None)) self.font_size_comboBox.setItemText(1, QCoreApplication.translate("MainWindow", u"Small", None)) self.font_size_comboBox.setItemText(2, QCoreApplication.translate("MainWindow", u"Normal", None)) @@ -529,11 +632,12 @@ class Ui_MainWindow(object): self.filename.setText("") self.filename.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Enter file name", None)) self.start_button.setText(QCoreApplication.translate("MainWindow", u"Convert", None)) + self.insert_exif_Button.setText(QCoreApplication.translate("MainWindow", u"Insert Exif", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_1), QCoreApplication.translate("MainWindow", u"Main", None)) self.exif_group.setTitle(QCoreApplication.translate("MainWindow", u"EXIF EXPERIMENTAL", None)) self.exif_checkbox.setText(QCoreApplication.translate("MainWindow", u"own exif", None)) self.exif_copy_checkBox.setText(QCoreApplication.translate("MainWindow", u"copy exif", None)) - self.edit_exif_button.setText(QCoreApplication.translate("MainWindow", u"edit exif", None)) + self.edit_exif_button.setText(QCoreApplication.translate("MainWindow", u"Edit Exif", None)) self.exif_options_group.setTitle(QCoreApplication.translate("MainWindow", u"Must", None)) self.label_7.setText(QCoreApplication.translate("MainWindow", u"Artist", None)) self.label_4.setText(QCoreApplication.translate("MainWindow", u"ISO", None)) @@ -554,6 +658,7 @@ class Ui_MainWindow(object): self.date_groupBox.setTitle(QCoreApplication.translate("MainWindow", u"Optional", None)) self.add_date_checkBox.setText(QCoreApplication.translate("MainWindow", u"add date", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), QCoreApplication.translate("MainWindow", u"EXIF", None)) - self.menuInfo.setTitle(QCoreApplication.translate("MainWindow", u"Info", None)) + self.menuSettings.setTitle(QCoreApplication.translate("MainWindow", u"Settings", None)) + self.menuHelp.setTitle(QCoreApplication.translate("MainWindow", u"Help", None)) # retranslateUi diff --git a/src/OptimaLab35/ui/main_window.ui b/src/OptimaLab35/ui/main_window.ui index b75e88f..1466580 100644 --- a/src/OptimaLab35/ui/main_window.ui +++ b/src/OptimaLab35/ui/main_window.ui @@ -2,12 +2,15 @@ MainWindow + + Qt::NonModal + 0 0 - 450 - 708 + 440 + 756 @@ -18,12 +21,12 @@ - 500 + 1000 1000 - OPTIMA-35 + OptimaLab35 @@ -52,37 +55,52 @@ + + + + + 70 + 0 + + + + Input + + + false + + + + + + + + + + Output folder + + + - Enter input folder + Input folder - - - - - - - Enter output folder - - - - - - - input - - - - + + + + 70 + 0 + + - output + Output @@ -101,33 +119,83 @@ Essential group - - + + - Resize + Quality - - + + + + 1 + + + 100 + + + 90 + + + + + + + Export Format + + + + + + + optimize + + + + + + + 1 + + + 9 + + + 1 + + + 6 + + + Qt::Horizontal + + + + + - false + true 1 - 200 - - - 1 + 9 - 80 + 6 - + + + + Quality + + + + @@ -146,21 +214,47 @@ - - + + 1 100 - - 80 + + 90 + + + Qt::Horizontal - - + + + + Resize + + + + + + + 1 + + + 200 + + + 100 + + + Qt::Horizontal + + + + + true @@ -168,27 +262,17 @@ 1 - 9 + 200 + + + 1 - 6 - - - - - - - optimize + 100 - png_quality_spinBox - resize_checkbox - resize_spinBox - image_type - jpg_quality_spinBox - optimize_checkBox @@ -199,14 +283,124 @@ 16777215 + + false + Extra stuff - + + + + Brightness + + + + + + + -100 + + + 100 + + + Qt::Horizontal + + + + + + + true + + + -100 + + + 100 + + + 0 + + + + + + + true + + + -100 + + + 100 + + + 0 + + + + + + + Contrast + + + + + + + -100 + + + 100 + + + Qt::Horizontal + + + + + + + Turn image to Black and White + + + + + + + Preview + + + + + + + + + + true + + + Watermark + + + false + + + false + + + false + + + - false + true @@ -216,67 +410,14 @@ - - + + - Brightness + Size - - - - Grayscale - - - - - - - false - - - -100 - - - 100 - - - 10 - - - - - - - Watermark - - - - - - - false - - - -100 - - - 100 - - - -10 - - - - - - - Contrast - - - - + Normal @@ -385,6 +526,16 @@ + + + + false + + + Insert Exif + + + @@ -424,7 +575,7 @@ false - edit exif + Edit Exif @@ -671,90 +822,43 @@ 0 0 - 450 + 440 27 - + - Info + Settings - + - + + + Help + + + + + - Info + About + + + + + Preview image + + + + + About - - resize_checkbox - toggled(bool) - resize_spinBox - setEnabled(bool) - - - 75 - 96 - - - 196 - 118 - - - - - brightness_checkbox - toggled(bool) - brightness_spinBox - setEnabled(bool) - - - 83 - 363 - - - 83 - 399 - - - - - contrast_checkbox - toggled(bool) - contrast_spinBox - setEnabled(bool) - - - 185 - 363 - - - 185 - 399 - - - - - watermark_checkbox - toggled(bool) - watermark_lineEdit - setEnabled(bool) - - - 83 - 435 - - - 237 - 435 - - - rename_checkbox toggled(bool) @@ -788,18 +892,18 @@ - exif_checkbox - toggled(bool) - exif_copy_checkBox - setDisabled(bool) + jpg_quality_Slider + valueChanged(int) + jpg_quality_spinBox + setValue(int) - 130 - 105 + 218 + 289 - 332 - 105 + 380 + 289 @@ -819,6 +923,246 @@ + + exif_checkbox + toggled(bool) + exif_copy_checkBox + setDisabled(bool) + + + 130 + 105 + + + 332 + 105 + + + + + resize_spinBox + valueChanged(int) + resize_Slider + setValue(int) + + + 380 + 252 + + + 218 + 252 + + + + + png_quality_spinBox + valueChanged(int) + png_quality_Slider + setValue(int) + + + 380 + 326 + + + 218 + 326 + + + + + contrast_horizontalSlider + valueChanged(int) + contrast_spinBox + setValue(int) + + + 187 + 458 + + + 378 + 458 + + + + + resize_Slider + valueChanged(int) + resize_spinBox + setValue(int) + + + 218 + 252 + + + 380 + 252 + + + + + brightness_horizontalSlider + valueChanged(int) + brightness_spinBox + setValue(int) + + + 187 + 393 + + + 378 + 393 + + + + + exif_checkbox + toggled(bool) + date_groupBox + setEnabled(bool) + + + 126 + 103 + + + 224 + 589 + + + + + png_quality_Slider + valueChanged(int) + png_quality_spinBox + setValue(int) + + + 218 + 326 + + + 380 + 326 + + + + + gps_checkBox + toggled(bool) + lat_lineEdit + setEnabled(bool) + + + 72 + 547 + + + 192 + 547 + + + + + exif_checkbox + toggled(bool) + insert_exif_Button + setEnabled(bool) + + + 92 + 130 + + + 369 + 684 + + + + + gps_checkBox + toggled(bool) + long_lineEdit + setEnabled(bool) + + + 72 + 547 + + + 344 + 547 + + + + + brightness_spinBox + valueChanged(int) + brightness_horizontalSlider + setValue(int) + + + 378 + 393 + + + 187 + 393 + + + + + resize_Slider + valueChanged(int) + resize_spinBox + setValue(int) + + + 218 + 252 + + + 380 + 252 + + + + + exif_checkbox + toggled(bool) + gps_groupBox + setEnabled(bool) + + + 94 + 103 + + + 224 + 535 + + + + + contrast_spinBox + valueChanged(int) + contrast_horizontalSlider + setValue(int) + + + 378 + 458 + + + 187 + 458 + + + exif_checkbox toggled(bool) @@ -852,66 +1196,18 @@ - exif_checkbox - toggled(bool) - date_groupBox - setEnabled(bool) + jpg_quality_spinBox + valueChanged(int) + jpg_quality_Slider + setValue(int) - 126 - 103 + 380 + 289 - 224 - 589 - - - - - exif_checkbox - toggled(bool) - gps_groupBox - setEnabled(bool) - - - 94 - 103 - - - 224 - 535 - - - - - gps_checkBox - toggled(bool) - lat_lineEdit - setEnabled(bool) - - - 72 - 547 - - - 192 - 547 - - - - - gps_checkBox - toggled(bool) - long_lineEdit - setEnabled(bool) - - - 72 - 547 - - - 344 - 547 + 218 + 289 diff --git a/src/OptimaLab35/ui/preview_window.py b/src/OptimaLab35/ui/preview_window.py new file mode 100644 index 0000000..00f5cad --- /dev/null +++ b/src/OptimaLab35/ui/preview_window.py @@ -0,0 +1,191 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'preview_window.ui' +## +## Created by: Qt User Interface Compiler version 6.8.1 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QApplication, QCheckBox, QFrame, QHBoxLayout, + QLabel, QLineEdit, QMainWindow, QMenuBar, + QPushButton, QSizePolicy, QSlider, QSpinBox, + QVBoxLayout, QWidget) + +class Ui_Preview_Window(object): + def setupUi(self, Preview_Window): + if not Preview_Window.objectName(): + Preview_Window.setObjectName(u"Preview_Window") + Preview_Window.resize(803, 700) + Preview_Window.setMinimumSize(QSize(800, 700)) + self.centralwidget = QWidget(Preview_Window) + self.centralwidget.setObjectName(u"centralwidget") + self.horizontalLayout = QHBoxLayout(self.centralwidget) + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.QLabel = QLabel(self.centralwidget) + self.QLabel.setObjectName(u"QLabel") + self.QLabel.setMinimumSize(QSize(628, 628)) + self.QLabel.setFrameShape(QFrame.Box) + self.QLabel.setScaledContents(True) + + self.horizontalLayout.addWidget(self.QLabel) + + self.widget = QWidget(self.centralwidget) + self.widget.setObjectName(u"widget") + self.widget.setMinimumSize(QSize(140, 628)) + self.widget.setMaximumSize(QSize(140, 16777215)) + self.verticalLayout_3 = QVBoxLayout(self.widget) + self.verticalLayout_3.setObjectName(u"verticalLayout_3") + self.image_path_lineEdit = QLineEdit(self.widget) + self.image_path_lineEdit.setObjectName(u"image_path_lineEdit") + + self.verticalLayout_3.addWidget(self.image_path_lineEdit) + + self.load_Button = QPushButton(self.widget) + self.load_Button.setObjectName(u"load_Button") + + self.verticalLayout_3.addWidget(self.load_Button) + + self.widget_2 = QWidget(self.widget) + self.widget_2.setObjectName(u"widget_2") + self.widget_2.setMaximumSize(QSize(16777215, 120)) + self.verticalLayout = QVBoxLayout(self.widget_2) + self.verticalLayout.setObjectName(u"verticalLayout") + self.label = QLabel(self.widget_2) + self.label.setObjectName(u"label") + + self.verticalLayout.addWidget(self.label) + + self.brightness_spinBox = QSpinBox(self.widget_2) + self.brightness_spinBox.setObjectName(u"brightness_spinBox") + self.brightness_spinBox.setMinimum(-100) + self.brightness_spinBox.setMaximum(100) + + self.verticalLayout.addWidget(self.brightness_spinBox) + + self.brightness_Slider = QSlider(self.widget_2) + self.brightness_Slider.setObjectName(u"brightness_Slider") + self.brightness_Slider.setMinimum(-100) + self.brightness_Slider.setMaximum(100) + self.brightness_Slider.setOrientation(Qt.Horizontal) + + self.verticalLayout.addWidget(self.brightness_Slider) + + self.reset_brightness_Button = QPushButton(self.widget_2) + self.reset_brightness_Button.setObjectName(u"reset_brightness_Button") + + self.verticalLayout.addWidget(self.reset_brightness_Button) + + + self.verticalLayout_3.addWidget(self.widget_2) + + self.widget_3 = QWidget(self.widget) + self.widget_3.setObjectName(u"widget_3") + self.widget_3.setMaximumSize(QSize(16777215, 120)) + self.verticalLayout_2 = QVBoxLayout(self.widget_3) + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.label_2 = QLabel(self.widget_3) + self.label_2.setObjectName(u"label_2") + + self.verticalLayout_2.addWidget(self.label_2) + + self.contrast_spinBox = QSpinBox(self.widget_3) + self.contrast_spinBox.setObjectName(u"contrast_spinBox") + self.contrast_spinBox.setMinimum(-100) + self.contrast_spinBox.setMaximum(100) + + self.verticalLayout_2.addWidget(self.contrast_spinBox) + + self.contrast_Slider = QSlider(self.widget_3) + self.contrast_Slider.setObjectName(u"contrast_Slider") + self.contrast_Slider.setMinimum(-100) + self.contrast_Slider.setMaximum(100) + self.contrast_Slider.setOrientation(Qt.Horizontal) + + self.verticalLayout_2.addWidget(self.contrast_Slider) + + self.reset_contrast_Button = QPushButton(self.widget_3) + self.reset_contrast_Button.setObjectName(u"reset_contrast_Button") + + self.verticalLayout_2.addWidget(self.reset_contrast_Button) + + + self.verticalLayout_3.addWidget(self.widget_3) + + self.grayscale_checkBox = QCheckBox(self.widget) + self.grayscale_checkBox.setObjectName(u"grayscale_checkBox") + + self.verticalLayout_3.addWidget(self.grayscale_checkBox) + + self.update_Button = QPushButton(self.widget) + self.update_Button.setObjectName(u"update_Button") + + self.verticalLayout_3.addWidget(self.update_Button) + + self.widget_4 = QWidget(self.widget) + self.widget_4.setObjectName(u"widget_4") + self.verticalLayout_4 = QVBoxLayout(self.widget_4) + self.verticalLayout_4.setObjectName(u"verticalLayout_4") + self.label_3 = QLabel(self.widget_4) + self.label_3.setObjectName(u"label_3") + self.label_3.setScaledContents(False) + self.label_3.setWordWrap(True) + + self.verticalLayout_4.addWidget(self.label_3) + + self.checkBox = QCheckBox(self.widget_4) + self.checkBox.setObjectName(u"checkBox") + self.checkBox.setChecked(True) + + self.verticalLayout_4.addWidget(self.checkBox) + + self.close_Button = QPushButton(self.widget_4) + self.close_Button.setObjectName(u"close_Button") + + self.verticalLayout_4.addWidget(self.close_Button) + + + self.verticalLayout_3.addWidget(self.widget_4) + + + self.horizontalLayout.addWidget(self.widget) + + Preview_Window.setCentralWidget(self.centralwidget) + self.menubar = QMenuBar(Preview_Window) + self.menubar.setObjectName(u"menubar") + self.menubar.setGeometry(QRect(0, 0, 803, 27)) + Preview_Window.setMenuBar(self.menubar) + + self.retranslateUi(Preview_Window) + self.brightness_Slider.valueChanged.connect(self.brightness_spinBox.setValue) + self.brightness_spinBox.valueChanged.connect(self.brightness_Slider.setValue) + self.contrast_Slider.valueChanged.connect(self.contrast_spinBox.setValue) + self.contrast_spinBox.valueChanged.connect(self.contrast_Slider.setValue) + + QMetaObject.connectSlotsByName(Preview_Window) + # setupUi + + def retranslateUi(self, Preview_Window): + Preview_Window.setWindowTitle(QCoreApplication.translate("Preview_Window", u"OptimaLab35 - Preview", None)) + self.QLabel.setText("") + self.image_path_lineEdit.setPlaceholderText(QCoreApplication.translate("Preview_Window", u"Path to image", None)) + self.load_Button.setText(QCoreApplication.translate("Preview_Window", u"Select image", None)) + self.label.setText(QCoreApplication.translate("Preview_Window", u"Brightness", None)) + self.reset_brightness_Button.setText(QCoreApplication.translate("Preview_Window", u"Reset", None)) + self.label_2.setText(QCoreApplication.translate("Preview_Window", u"Contrast", None)) + self.reset_contrast_Button.setText(QCoreApplication.translate("Preview_Window", u"Reset", None)) + self.grayscale_checkBox.setText(QCoreApplication.translate("Preview_Window", u"Grayscale", None)) + self.update_Button.setText(QCoreApplication.translate("Preview_Window", u"Update preview", None)) + self.label_3.setText(QCoreApplication.translate("Preview_Window", u"Copy values to main window when closing", None)) + self.checkBox.setText(QCoreApplication.translate("Preview_Window", u"Copy Values", None)) + self.close_Button.setText(QCoreApplication.translate("Preview_Window", u"Close", None)) + # retranslateUi + diff --git a/src/OptimaLab35/ui/preview_window.ui b/src/OptimaLab35/ui/preview_window.ui new file mode 100644 index 0000000..29a8057 --- /dev/null +++ b/src/OptimaLab35/ui/preview_window.ui @@ -0,0 +1,303 @@ + + + Preview_Window + + + + 0 + 0 + 803 + 700 + + + + + 800 + 700 + + + + OptimaLab35 - Preview + + + + + + + + 628 + 628 + + + + QFrame::Box + + + + + + true + + + + + + + + 140 + 628 + + + + + 140 + 16777215 + + + + + + + Path to image + + + + + + + Select image + + + + + + + + 16777215 + 120 + + + + + + + Brightness + + + + + + + -100 + + + 100 + + + + + + + -100 + + + 100 + + + Qt::Horizontal + + + + + + + Reset + + + + + + + + + + + 16777215 + 120 + + + + + + + Contrast + + + + + + + -100 + + + 100 + + + + + + + -100 + + + 100 + + + Qt::Horizontal + + + + + + + Reset + + + + + + + + + + Grayscale + + + + + + + Update preview + + + + + + + + + + Copy values to main window when closing + + + false + + + true + + + + + + + Copy Values + + + true + + + + + + + Close + + + + + + + + + + + + + + + 0 + 0 + 803 + 27 + + + + + + + + brightness_Slider + valueChanged(int) + brightness_spinBox + setValue(int) + + + 720 + 311 + + + 706 + 282 + + + + + brightness_spinBox + valueChanged(int) + brightness_Slider + setValue(int) + + + 706 + 282 + + + 720 + 311 + + + + + contrast_Slider + valueChanged(int) + contrast_spinBox + setValue(int) + + + 720 + 454 + + + 699 + 425 + + + + + contrast_spinBox + valueChanged(int) + contrast_Slider + setValue(int) + + + 699 + 425 + + + 720 + 454 + + + + + diff --git a/src/OptimaLab35/update_ui.sh b/src/OptimaLab35/update_ui.sh new file mode 100755 index 0000000..d533d7a --- /dev/null +++ b/src/OptimaLab35/update_ui.sh @@ -0,0 +1,6 @@ +#!/bin/bash +echo "Update .ui files with pyside" +echo "Update main window." +pyside6-uic OptimaLab35/ui/main_window.ui -o OptimaLab35/ui/main_window.py +echo "Update preview window." +pyside6-uic OptimaLab35/ui/preview_window.ui -o OptimaLab35/ui/preview_window.py