analitics

Pages

Wednesday, July 2, 2025

Python Qt6 : ... simple resize image files.

I like the combination of Python development and the inclusion of the PyQt6 module. It is very fast and stable and allows me to create all sorts of tools to use.
Today I will show you another handy script that allows you to read all the image files from a folder and, depending on the selections: height, length, and/or aspect ratio, resize them and then place them in a folder created specifically for the resulting images.
Here is how the script looks, I clearly used artificial intelligence and it didn't take more than a few minutes, my evaluation, testing, and rearranging the interface took longer ...
import sys
import os
from datetime import datetime
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QFileDialog, QLineEdit, QCheckBox, QLabel, QMessageBox
from PyQt6.QtCore import Qt
from PIL import Image

class ResizeApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Image Resizer")
        self.setGeometry(100, 100, 400, 200)

        layout = QVBoxLayout()
        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

        self.folder_button = QPushButton("Select Folder")
        self.folder_button.clicked.connect(self.select_folder)
        layout.addWidget(self.folder_button)

        self.width_edit = QLineEdit("800")
        self.width_edit.setPlaceholderText("Width (px)")
        layout.addWidget(QLabel("Width:"))
        layout.addWidget(self.width_edit)

        self.height_edit = QLineEdit("600")
        self.height_edit.setPlaceholderText("Height (px)")
        layout.addWidget(QLabel("Height:"))
        layout.addWidget(self.height_edit)

        self.aspect_ratio = QCheckBox("Maintain Aspect Ratio")
        self.aspect_ratio.setChecked(True)
        layout.addWidget(self.aspect_ratio)

        self.resize_button = QPushButton("Resize Images")
        self.resize_button.clicked.connect(self.resize_images)
        layout.addWidget(self.resize_button)

        self.folder_path = ""

    def select_folder(self):
        self.folder_path = QFileDialog.getExistingDirectory(self, "Select Image Folder")
        if self.folder_path:
            self.folder_button.setText(f"Selected: {os.path.basename(self.folder_path)}")

    def resize_images(self):
        if not self.folder_path:
            QMessageBox.warning(self, "Error", "Please select a folder.")
            return

        try:
            width = int(self.width_edit.text())
            height = int(self.height_edit.text())
        except ValueError:
            QMessageBox.warning(self, "Error", "Please enter valid width and height.")
            return

        if width <= 0 or height <= 0:
            QMessageBox.warning(self, "Error", "Width and height must be positive.")
            return

        date_str = datetime.now().strftime("%d%m%y_%H%M")
        aspect_str = "asp_on" if self.aspect_ratio.isChecked() else "asp_off"
        output_folder = os.path.join(self.folder_path, f"resized_{date_str}_{height}_{aspect_str}")
        os.makedirs(output_folder, exist_ok=True)

        for file_name in os.listdir(self.folder_path):
            if file_name.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif')):
                image_path = os.path.join(self.folder_path, file_name)
                try:
                    with Image.open(image_path) as img:
                        if self.aspect_ratio.isChecked():
                            img.thumbnail((width, height), Image.Resampling.LANCZOS)
                        else:
                            img = img.resize((width, height), Image.Resampling.LANCZOS)
                        output_path = os.path.join(output_folder, f"resized_{date_str}_{height}_{aspect_str}_{file_name}")
                        img.save(output_path)
                except Exception as e:
                    QMessageBox.warning(self, "Error", f"Failed to process {file_name}: {str(e)}")

        QMessageBox.information(self, "Success", f"Images resized and saved to {output_folder}!")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = ResizeApp()
    window.show()
    sys.exit(app.exec())

Tuesday, July 1, 2025

Python 3.13.5 : use the jupyterlab, notebook and voila - part 001.

JupyterLab is the latest web-based interactive development environment for notebooks, code, and data. Its flexible interface allows users to configure and arrange workflows in data science, scientific computing, computational journalism, and machine learning. A modular design invites extensions to expand and enrich functionality.
Let's test with these python modules: jupyterlab, notebook and voila.
First, I install with pip tool the jupyterlab python module:
pip install jupyterlab
Collecting jupyterlab
...
Successfully installed anyio-4.9.0 argon2-cffi-25.1.0 argon2-cffi-bindings-21.2.0 arrow-1.3.0 asttokens-3.0.0 async-lru-2.0.5
attrs-25.3.0 babel-2.17.0 bleach-6.2.0 cffi-1.17.1 comm-0.2.2 debugpy-1.8.14 defusedxml-0.7.1 executing-2.2.0 
fastjsonschema-2.21.1 fqdn-1.5.1 h11-0.16.0 httpcore-1.0.9 httpx-0.28.1 ipykernel-6.29.5 ipython-9.4.0 
ipython-pygments-lexers-1.1.1 isoduration-20.11.0 jedi-0.19.2 json5-0.12.0 jsonpointer-3.0.0 jsonschema-4.24.0 
jsonschema-specifications-2025.4.1 jupyter-client-8.6.3 jupyter-core-5.8.1 jupyter-events-0.12.0 jupyter-lsp-2.2.5 
jupyter-server-2.16.0 jupyter-server-terminals-0.5.3 jupyterlab-4.4.4 jupyterlab-pygments-0.3.0 jupyterlab-server-2.27.3 
matplotlib-inline-0.1.7 mistune-3.1.3 nbclient-0.10.2 nbconvert-7.16.6 nbformat-5.10.4 nest-asyncio-1.6.0 notebook-shim-0.2.4
overrides-7.7.0 pandocfilters-1.5.1 parso-0.8.4 platformdirs-4.3.8 prometheus-client-0.22.1 prompt_toolkit-3.0.51 
psutil-7.0.0 pure-eval-0.2.3 pycparser-2.22 python-json-logger-3.3.0 pywin32-310 pywinpty-2.0.15 pyyaml-6.0.2 pyzmq-27.0.0
referencing-0.36.2 rfc3339-validator-0.1.4 rfc3986-validator-0.1.1 rpds-py-0.26.0 send2trash-1.8.3 sniffio-1.3.1 
stack_data-0.6.3 terminado-0.18.1 tinycss2-1.4.0 tornado-6.5.1 traitlets-5.14.3 types-python-dateutil-2.9.0.20250516 
uri-template-1.3.0 wcwidth-0.2.13 webcolors-24.11.1 webencodings-0.5.1 websocket-client-1.8.0
Next, the install of the notebook python module
pip install notebook
Collecting notebook
...
Installing collected packages: notebook
Successfully installed notebook-7.4.4
This python package named voila will help us to use online graphic user interfaces:
pip install voila
Collecting voila
...
Successfully installed voila-0.5.8 websockets-15.0.1
The voila package need to work with ipywidgets python package:
pip install ipywidgets
Collecting ipywidgets
...
Successfully installed ipywidgets-8.1.7 jupyterlab_widgets-3.0.15 widgetsnbextension-4.0.14
Let's start the jupiter tool with this command:
jupyter notebook
I used an default python example with a slider:
import ipywidgets as widgets
from IPython.display import display

slider = widgets.IntSlider(value=5, min=0, max=10)
display(slider)
This command will start the web with the slider using the voila command:
voila test.ipynb
The result is this: