diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5643294..c103ff4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,14 @@
# Changelog
-## 0.6.x
-### 0.6.0: Initial Flatpak Support
+## 0.7.x
+### 0.7.0: Enhanced Preview
+- Images loaded into the preview window are now scaled while maintaining aspect ratio.
+- Added live updates: changes to brightness, contrast, or grayscale are applied immediately.
+ - ⚠ This may crush the system depending on image size and system specifications.
+- Removed Settings from menuBar, and extended the about window.
+---
+
+## 0.6.0: Initial Flatpak Support
- Started Flatpak package building.
- Not added to Flathub yet, as only stable software is hosted there.
- Not fully completed, icon, name, and description are included, but the version is missing for some reason.
@@ -10,14 +17,12 @@
---
-## 0.5.x
-### 0.5.0
+## 0.5.0
- Removed all leftover of tui code that was hiding in some classes.
---
-## 0.4.x
-### 0.4.0
+## 0.4.0
- Fixed a critical issue that prevented the program from functioning.
- Updated compatibility to align with the **upcoming** optima35 **release**.
diff --git a/src/OptimaLab35/gui.py b/src/OptimaLab35/gui.py
index 4fc4afb..1194845 100644
--- a/src/OptimaLab35/gui.py
+++ b/src/OptimaLab35/gui.py
@@ -10,7 +10,7 @@ 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, QRegularExpression
+from PySide6.QtCore import QRunnable, QThreadPool, Signal, QObject, QRegularExpression, Qt
from PySide6 import QtWidgets
from PySide6.QtWidgets import (
@@ -75,7 +75,6 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
self.ui.edit_exif_button.clicked.connect(self.open_exif_editor)
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)
regex = QRegularExpression(r"^\d{1,2}\.\d{1,6}$")
@@ -88,7 +87,7 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
# UI related function, changing parts, open, etc.
def open_preview_window(self):
self.preview_window.values_selected.connect(self.update_values)
- self.preview_window.show()
+ self.preview_window.showMaximized()
def update_values(self, value1, value2, checkbox_state):
# Update main window's widgets with the received values
@@ -98,12 +97,20 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
self.ui.grayscale_checkBox.setChecked(checkbox_state)
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}).
- Both projects are in active development, for more details, visit:
+ (C) 2024-2025 Mr Finchum aka CodeByMrFinchum
+ {self.name} is a GUI for {self.o.name} (v{self.o.version}), enhancing its functionality with a\nuser-friendly interface for efficient image and metadata management.
+
+ Features:
+
+ - Image processing: resize, grayscale, brightness/contrast adjustments
+ - Live image preview: see changes before applying
+ - EXIF management: add, copy, remove metadata, GPS support
+ - Watermarking: add custom text-based watermarks
+
+
+ For more details, visit:
- OptimaLab35 GitLab
- optima35 GitLab
@@ -455,6 +462,7 @@ class PreviewWindow(QMainWindow, Ui_Preview_Window):
self.ui = Ui_Preview_Window()
self.ui.setupUi(self)
self.o = OptimaManager()
+ self.ui.QLabel.setAlignment(Qt.AlignCenter)
## Ui interaction
self.ui.load_Button.clicked.connect(self.browse_file)
self.ui.update_Button.clicked.connect(self.update_preview)
@@ -462,7 +470,22 @@ class PreviewWindow(QMainWindow, Ui_Preview_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
+
+ # Connect UI elements to `on_ui_change`
+ self.ui.brightness_spinBox.valueChanged.connect(self.on_ui_change)
+ self.ui.brightness_Slider.valueChanged.connect(self.on_ui_change)
+ #self.ui.reset_brightness_Button.clicked.connect(self.on_ui_change)
+
+ self.ui.contrast_spinBox.valueChanged.connect(self.on_ui_change)
+ self.ui.contrast_Slider.valueChanged.connect(self.on_ui_change)
+ #self.ui.reset_contrast_Button.clicked.connect(self.on_ui_change)
+
+ self.ui.grayscale_checkBox.stateChanged.connect(self.on_ui_change)
+
+ def on_ui_change(self):
+ """Triggers update only if live update is enabled."""
+ if self.ui.live_update.isChecked():
+ self.update_preview()
def browse_file(self):
file = QFileDialog.getOpenFileName(self, caption = "Select File", filter = ("Images (*.png *.webp *.jpg *.jpeg)"))
@@ -470,29 +493,61 @@ class PreviewWindow(QMainWindow, Ui_Preview_Window):
self.ui.image_path_lineEdit.setText(file[0])
self.update_preview()
- def update_preview(self):
- path = self.ui.image_path_lineEdit.text()
+ def process_image(self, path):
+ """Loads and processes the image with modifications."""
+ # Refactored by ChatGPT
if not os.path.isfile(path):
- return
+ return None
+
try:
img = self.o.process_image_object(
- image_input_file = path,
- resize = 50,
- watermark = "PREVIEW",
- grayscale = self.ui.grayscale_checkBox.isChecked(),
- brightness = int(self.ui.brightness_spinBox.text()),
- contrast = int(self.ui.contrast_spinBox.text())
+ image_input_file=path, # Example: resize percentage
+ watermark="PREVIEW",
+ resize = 100,
+ grayscale=self.ui.grayscale_checkBox.isChecked(),
+ brightness=int(self.ui.brightness_spinBox.text()),
+ contrast=int(self.ui.contrast_spinBox.text())
)
+ return QPixmap.fromImage(img)
except Exception as e:
QMessageBox.warning(self, "Warning", "Error loading image...")
print(f"Error loading image...\n{e}")
+ return None
+
+ def display_image(self, pixmap):
+ """Adjusts the image to fit within the QLabel."""
+ # ChatGPT
+ if pixmap is None:
return
- self.preview_image = QPixmap.fromImage(img)
- self.ui.QLabel.setPixmap(self.preview_image)
+ # Get max available size (QLabel size)
+ max_size = self.ui.QLabel.size()
+ max_width = max_size.width()
+ max_height = max_size.height()
+
+ # Scale image to fit within the available space while maintaining aspect ratio
+ scaled_pixmap = pixmap.scaled(
+ max_width, max_height,
+ Qt.KeepAspectRatio,
+ Qt.SmoothTransformation
+ )
+
+ # Set the scaled image
+ self.ui.QLabel.setPixmap(scaled_pixmap)
+
+ # Adjust QLabel size to match image
+ self.ui.QLabel.resize(scaled_pixmap.size())
+
+ def update_preview(self):
+ """Handles loading and displaying the image."""
+ # ChatGPT
+ path = self.ui.image_path_lineEdit.text()
+ pixmap = self.process_image(path)
+ self.display_image(pixmap)
def close_window(self):
# Emit the signal with the values from the spinboxes and checkbox
+ # chatgpt
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()
diff --git a/src/OptimaLab35/ui/main_window.py b/src/OptimaLab35/ui/main_window.py
index c0e4990..5af0bc9 100644
--- a/src/OptimaLab35/ui/main_window.py
+++ b/src/OptimaLab35/ui/main_window.py
@@ -553,15 +553,11 @@ class Ui_MainWindow(object):
self.menuBar = QMenuBar(MainWindow)
self.menuBar.setObjectName(u"menuBar")
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.menuSettings.menuAction())
self.menuBar.addAction(self.menuHelp.menuAction())
- self.menuSettings.addAction(self.actionPreview)
self.menuHelp.addAction(self.actionAbout)
self.retranslateUi(MainWindow)
@@ -661,7 +657,6 @@ 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.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 59d707a..3779add 100644
--- a/src/OptimaLab35/ui/main_window.ui
+++ b/src/OptimaLab35/ui/main_window.ui
@@ -835,19 +835,12 @@
27
-
-
diff --git a/src/OptimaLab35/ui/preview_window.py b/src/OptimaLab35/ui/preview_window.py
index 00f5cad..f9f6d3e 100644
--- a/src/OptimaLab35/ui/preview_window.py
+++ b/src/OptimaLab35/ui/preview_window.py
@@ -24,7 +24,7 @@ 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.resize(803, 775)
Preview_Window.setMinimumSize(QSize(800, 700))
self.centralwidget = QWidget(Preview_Window)
self.centralwidget.setObjectName(u"centralwidget")
@@ -34,7 +34,7 @@ class Ui_Preview_Window(object):
self.QLabel.setObjectName(u"QLabel")
self.QLabel.setMinimumSize(QSize(628, 628))
self.QLabel.setFrameShape(QFrame.Box)
- self.QLabel.setScaledContents(True)
+ self.QLabel.setScaledContents(False)
self.horizontalLayout.addWidget(self.QLabel)
@@ -130,6 +130,24 @@ class Ui_Preview_Window(object):
self.verticalLayout_3.addWidget(self.update_Button)
+ self.widget_5 = QWidget(self.widget)
+ self.widget_5.setObjectName(u"widget_5")
+ self.verticalLayout_5 = QVBoxLayout(self.widget_5)
+ self.verticalLayout_5.setObjectName(u"verticalLayout_5")
+ self.label_4 = QLabel(self.widget_5)
+ self.label_4.setObjectName(u"label_4")
+ self.label_4.setWordWrap(True)
+
+ self.verticalLayout_5.addWidget(self.label_4)
+
+ self.live_update = QCheckBox(self.widget_5)
+ self.live_update.setObjectName(u"live_update")
+
+ self.verticalLayout_5.addWidget(self.live_update)
+
+
+ self.verticalLayout_3.addWidget(self.widget_5)
+
self.widget_4 = QWidget(self.widget)
self.widget_4.setObjectName(u"widget_4")
self.verticalLayout_4 = QVBoxLayout(self.widget_4)
@@ -184,6 +202,8 @@ class Ui_Preview_Window(object):
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_4.setText(QCoreApplication.translate("Preview_Window", u"Update preview live might have large impact on system, especilly if image is large.", None))
+ self.live_update.setText(QCoreApplication.translate("Preview_Window", u"Live update", 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))
diff --git a/src/OptimaLab35/ui/preview_window.ui b/src/OptimaLab35/ui/preview_window.ui
index 29a8057..6bd17b7 100644
--- a/src/OptimaLab35/ui/preview_window.ui
+++ b/src/OptimaLab35/ui/preview_window.ui
@@ -7,7 +7,7 @@
0
0
803
- 700
+ 775
@@ -36,7 +36,7 @@
- true
+ false
@@ -181,6 +181,29 @@
+ -
+
+
+
-
+
+
+ Update preview live might have large impact on system, especilly if image is large.
+
+
+ true
+
+
+
+ -
+
+
+ Live update
+
+
+
+
+
+
-
diff --git a/src/OptimaLab35/ui/simple_dialog.py b/src/OptimaLab35/ui/simple_dialog.py
index b4a230b..019877a 100644
--- a/src/OptimaLab35/ui/simple_dialog.py
+++ b/src/OptimaLab35/ui/simple_dialog.py
@@ -1,17 +1,22 @@
-from PySide6.QtWidgets import QApplication, QDialog, QVBoxLayout, QLineEdit, QPushButton, QLabel
-# ChatGPT
+from PySide6.QtWidgets import QApplication, QDialog, QVBoxLayout, QLabel, QPushButton
+from PySide6.QtCore import Qt
+
class SimpleDialog(QDialog):
def __init__(self):
super().__init__()
# Set default properties
- self.setGeometry(100, 100, 300, 100)
+ self.setWindowTitle("Information")
+ self.setGeometry(100, 100, 400, 100) # Default size
# Create the layout
layout = QVBoxLayout()
# Create the label for the message
self.message_label = QLabel(self)
+ self.message_label.setWordWrap(True) # Enable word wrapping
+ self.message_label.setAlignment(Qt.AlignLeft | Qt.AlignTop) # Align text
+ self.message_label.setMaximumWidth(400) # Set max width so it wraps text
# Create the close button
close_button = QPushButton("Close", self)
@@ -27,4 +32,5 @@ class SimpleDialog(QDialog):
def show_dialog(self, title: str, message: str):
self.setWindowTitle(title) # Set the window title
self.message_label.setText(message) # Set the message text
+ self.adjustSize() # Adjust window height dynamically based on text content
self.exec() # Open the dialog as a modal window