diff --git a/CHANGELOG.md b/CHANGELOG.md
index 06ccaf9..242aaa0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,66 @@
+## Version 3.0
+
+**Release date:** 16 July 2025
+
+### 1. Major Features & Core Capabilities
+
+#### 1.1 **AI-Powered Face Restoration (GFPGAN)**
+
+- **New `AI_face_restoration` Class**: A new, specialized class has been implemented to handle face restoration models. This class is architected to manage the unique preprocessing and post-processing requirements of models like GFPGAN, distinct from standard upscaling models.
+- **GFPGAN Model Integration**: The GFPGAN v1.4 model has been added to the AI model repository and is now selectable from the UI. It is listed under a new `Face_restoration_models_list` category. The main orchestrator (`upscale_orchestrator`) now detects when a face restoration model is selected and routes the task to the appropriate `AI_face_restoration` instance.
+- **Specialized Processing Pipeline**: The new class introduces a dedicated pipeline for face enhancement. This includes resizing the input image to the model's required dimensions (e.g., 512x512 for GFPGAN), handling color channel conversions, and post-processing the output to restore the image to its original dimensions.
+
+### 2. UI/UX Modernisation
+
+#### 2.1 **Complete Thematic Redesign**
+
+- The application has undergone a significant visual overhaul with a new, professionally designed color scheme to improve aesthetics and user comfort during long sessions. The new theme provides better contrast and a more modern look.
+
+| Element | New Value (v3.0) | Old Value (v2.2) |
+| :---------------- | :--------------------- | :------------------------ |
+| Background | `#1A1A1A` (Deep Black) | `#000000` (Pure Black) |
+| App Name Color | `#FF4444` (Bright Red) | `#FF0000` (Pure Red) |
+| Widget Background | `#2D2D2D` (Dark Grey) | `#5A5A5A` (Grey) |
+| Accent/Border | `#FFD700` (Gold) | Gold & Red |
+| Button Hover | `#FF6666` (Light Red) | `background_color` |
+| Info Button | `#B22222` (Dark Red) | `widget_background_color` |
+
+#### 2.2 **Enhanced Splash Screen**
+
+- **Dynamic Progress Bar**: The splash screen now features a `CTkProgressBar` to provide visual feedback on the application's loading status, enhancing the startup experience.
+- **Smooth Fade-Out Animation**: A new `fade_out` method using a cosine function has been implemented for a smooth, animated exit transition instead of an abrupt disappearance.
+- **Improved Information Display**: The splash screen now prominently displays the application version number.
+
+#### 2.3 **Redesigned and Resizable Message Boxes**
+
+- The `MessageBox` class was significantly improved to handle large blocks of text, such as detailed error messages. It now implements a `CTkScrollableFrame`, ensuring that content is always accessible without forcing the dialog to an unmanageable size.
+- The dialogs now have defined `minsize` and `maxsize` properties for better window management.
+
+#### 2.4 **Improved UI Readability**
+
+- The main AI model dropdown menu is now logically grouped by model type (Upscaling, Denoising, Face Restoration, Interpolation), with a `MENU_LIST_SEPARATOR` between categories. This makes it easier for users to find and select the appropriate AI model for their task.
+
+### 3. Performance and Code Optimisation
+
+#### 3.1 **Memory Optimisation with Contiguous Arrays**
+
+- Widespread use of `numpy.ascontiguousarray` has been implemented across the codebase. This is applied during critical image handling steps in `AI_upscale.preprocess_image`, `AI_interpolation.concatenate_images`, and the new `AI_face_restoration.preprocess_face_image` class. This ensures data is aligned in memory, which can significantly speed up operations in backend libraries like OpenCV and ONNX Runtime.
+
+#### 3.2 **Refined Data Type Handling**
+
+- The `AI_upscale` class now explicitly ensures input images are converted to `float32` before normalization, improving precision and preventing potential data type mismatches during inference.
+- The `AI_face_restoration` class is configured to intelligently select between `float16` and `float32` based on the specific model's requirements (`fp16: True` in config), further optimizing performance and VRAM usage for compatible models.
+
+### 4. Codebase Health and Maintainability
+
+#### 4.1 **Specialised Class for Face Restoration**
+
+- The logic for face restoration has been fully encapsulated within the new `AI_face_restoration` class, separating it from the general-purpose `AI_upscale` class. This object-oriented approach makes the code more modular, readable, and easier to extend with different face enhancement models in the future.
+
+#### 4.2 **Robust BGRA to BGR Conversion**
+
+- The application now explicitly handles images with an alpha channel (4-channel BGRA) when using face restoration models. A new import for `COLOR_BGRA2BGR` was added, and it is used within `preprocess_face_image` to convert images to the 3-channel BGR format expected by the GFPGAN model. This prevents runtime errors and ensures correct processing of PNGs or other images with transparency.
+
## Version 2.2
**Release date:** 7 July 2025
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..c5714ba
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 Iván Eduardo Chavez Ayub
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the “Software”), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/License.txt b/License.txt
new file mode 100644
index 0000000..5536fa1
--- /dev/null
+++ b/License.txt
@@ -0,0 +1,121 @@
+SOFTWARE LICENSE AGREEMENT AND TERMS OF USE FOR WARLOCK-STUDIO 3.0
+
+---
+
+PREAMBLE
+
+This Software License Agreement ("Agreement") constitutes a legally binding
+contract between you, either as an individual or on behalf of an entity
+("USER"), and Iván Eduardo Chavez Ayub ("AUTHOR"), regarding the
+Warlock-Studio 3.0 software and all its associated files, documentation,
+and materials (collectively, the "SOFTWARE").
+By installing, copying, downloading, accessing, or otherwise using the
+SOFTWARE, the USER expressly consents to and agrees to be bound by all
+terms and conditions stipulated in this Agreement.
+IF THE USER DOES NOT AGREE WITH ALL THE TERMS OF THIS AGREEMENT, THEY MUST
+NOT INSTALL, USE, OR COPY THE SOFTWARE AND MUST IMMEDIATELY CANCEL THE
+INSTALLATION PROCESS.
+
+---
+
+SECTION I: THE MIT LICENSE
+
+The original and legally binding text of the MIT License is presented below.
+This text governs the use of the core SOFTWARE.
+
+MIT License
+
+Copyright (c) 2025 Iván Eduardo Chavez Ayub
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+---
+
+SECTION II: ADDITIONAL TERMS, NOTICES, AND ACKNOWLEDGEMENTS
+
+1. Project Description
+ Warlock-Studio is a software application developed by Iván Eduardo Chavez
+ Ayub (GitHub profile: @Ivan-Ayub97).
+ The project is based on open-source
+ tools such as QualityScaler, FluidFrames, and RealScaler, originally
+ developed by Djdefrag (GitHub profile: @Djdefrag).
+ The main objective of
+ Warlock-Studio is to provide an intuitive graphical interface for
+ enhancing and upscaling image resolution through the use of artificial
+ intelligence models.
+2. Third-Party Components and Applicable Licenses
+ The SOFTWARE integrates various third-party technologies and components.
+ The use of the SOFTWARE is conditioned not only on compliance with this
+ Agreement but also with the license terms of each of these components.
+ The following is a list of components and their respective licenses:
+
+ - QualityScaler, RealScaler, FluidFrames: MIT License (Djdefrag)
+ - RIFE: Apache 2.0 License (hzwer, Megvii Research)
+ - Real-ESRGAN, RealESRGAN-G, RealESR-Anime, RealESR-Net: BSD 3-Clause /
+ Apache 2.0 License (Xintao Wang)
+ - GFPGAN: MIT License (TencentARC, Xintao Wang)
+ - SRGAN: CC BY-NC-SA 4.0 License (TensorLayer Community)
+ - BSRGAN: Apache 2.0 License (Kai Zhang)
+ - IRCNN: BSD / Mixed License (Kai Zhang)
+ - Anime4K: MIT License (Tianyang Zhang / bloc97)
+ - ONNX Runtime: MIT License (Microsoft)
+ - PyTorch: BSD 3-Clause License (Meta AI)
+ - FFmpeg: LGPL-2.1 / GPL License (FFmpeg Team)
+ - ExifTool: Perl Artistic License (Phil Harvey)
+ - DirectML: MIT License (Microsoft)
+ - Python: PSF License (Python Software Foundation)
+ - PyInstaller: GPLv2+ License (PyInstaller Team)
+ - Inno Setup: Custom Inno License (Jordan Russell)
+
+2. Limitation of Liability Clause (Extended)
+ TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL THE
+ AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES; INCLUDING, BUT NOT LIMITED
+ TO, LOSS OF DATA, BUSINESS INTERRUPTION, OR HARDWARE OR SYSTEM FAILURE
+ ARISING FROM THE USE, MISUSE, OR INABILITY TO USE THE SOFTWARE.
+ THIS SOFTWARE IS PROVIDED FOR EDUCATIONAL, CREATIVE, AND RESEARCH PURPOSES.
+ IT IS NOT CERTIFIED FOR IMPLEMENTATION IN CRITICAL OR COMMERCIAL
+ INFRASTRUCTURES WITHOUT PRIOR INDEPENDENT VALIDATION.
+ THE USER ASSUMES
+ ALL RISK ASSOCIATED WITH ITS USE.
+4. Intellectual Property Notice
+ The brand, the name "Warlock-Studio" and its associated logos are the
+ exclusive intellectual property of Iván Eduardo Chavez Ayub.
+The use of
+ these elements for commercial purposes is strictly prohibited without the
+ prior written consent of the AUTHOR.
+ Any redistribution or modification of
+ the source code must preserve the original copyright notices and all
+ references to the licenses contained herein.
+5. Acceptance of Terms
+ By proceeding with the installation and by using the SOFTWARE, the USER
+ acknowledges having read, understood, and accepted all the terms set forth
+ in the MIT License (Section I) and the Additional Terms (Section II) of
+ this Agreement.
+
+---
+
+CONTACT INFORMATION
+
+For any inquiries or communications related to this Agreement or the SOFTWARE,
+you may contact the Author:
+
+Name: Iván Eduardo Chavez Ayub
+Email: negroayub97@gmail.com
+GitHub: [https://github.com/Ivan-Ayub97](https://github.com/Ivan-Ayub97)
\ No newline at end of file
diff --git a/README.md b/README.md
index e6e5fa4..41d465d 100644
--- a/README.md
+++ b/README.md
@@ -1,70 +1,55 @@

-
-
-# Download
-### Get Warlock-Studio Installer
+
+
+
+
-You can download the installer (latest version **2.2**) from any of this platforms:
+AI Media Enhancement Suite
+
+**Warlock-Studio** is a powerful, open-source desktop application for Windows that integrates state-of-the-art AI models for video and image enhancement. Inspired by the work of [Djdefrag](https://github.com/Djdefrag) on tools like **QualityScaler** and **FluidFrames**, this suite provides a unified, high-performance interface for upscaling, restoration, and frame interpolation.
+
+Version 3.0 marks a major evolution, introducing **AI-powered face restoration**, a completely modernized user interface, and significant performance optimizations to deliver professional-grade results to everyone.
+
+---
+
+### ► Download Installer (v3.0)
+
+Get the latest stable release from any of the following platforms:
- |
-
+ |
+
- |
+ |
+
-
|
-
-
+ |
+
|
-
-
---
-### AI-Powered Media Enhancement & Upscaling Suite 2.2
-
-**Warlock-Studio** is a powerful **open-source desktop application** inspired by the remarkable work of [Djdefrag](https://github.com/Djdefrag), integrating tools like **QualityScaler**, **RealScaler**, and **FluidFrames**. Built with performance and usability in mind, Warlock-Studio brings together the best of these technologies into a unified and user-friendly interface.
-
----
-
-It features integration with state-of-the-art models for upscaling, restoration, and frame interpolation—all within an intuitive and streamlined user interface. Warlock-Studio delivers **professional-grade media processing** capabilities to everyone.
-
-Version 2.2 introduces critical improvements focused on reliability and performance:
-
-- **Comprehensive Logging System** for easier debugging.
-- **Proactive Environment Validation** to prevent common errors.
-- **Resilient Video Encoding** with automatic codec and audio fallbacks.
-- **Aggressive Memory Management** and dynamic GPU VRAM recovery to handle long processing tasks without crashing.
-
----
-
-## Interface Previews
-
-### 🔹 Main
-
-
-
-### 🔹 RIFE (Frame Interpolation) Options
-
-
-
----
-
## Key Features
- **State-of-the-Art AI Models**
- Real-ESRGAN, SRGAN, BSRGAN, IRCNN, Waifu2x, Anime4K, **RIFE**, and others for denoising, resolution enhancement, detail restoration, and smooth frame interpolation.
+ A comprehensive suite including Real-ESRGAN, BSRGAN, IRCNN, **GFPGAN**, and **RIFE** for denoising, resolution enhancement, detail restoration, and smooth frame interpolation.
+
+- **AI Face Restoration (New in v3.0)**
+ Restore and enhance faces in old, blurry, or low-quality photos and videos with the integrated GFPGAN model, bringing cherished memories back to life.
- **AI Frame Interpolation & Slow Motion**
- Generate new in-between frames using RIFE to create smooth **2x/4x/8x** motion or dramatic slow-motion effects.
+ Generate new in-between frames using RIFE to create ultra-smooth **2x, 4x, or 8x** motion or dramatic slow-motion effects.
+
+- **Modern & Intuitive Interface**
+ Completely redesigned in v3.0 for a clean, efficient, and user-friendly experience for both beginners and professionals.
- **Batch Processing**
Simultaneously process multiple images or videos—ideal for large-scale media projects.
@@ -72,39 +57,30 @@ Version 2.2 introduces critical improvements focused on reliability and performa
- **Customizable Workflows**
Choose your preferred AI model, output resolution, format (PNG, JPEG, MP4, etc.), and quality settings for full creative control.
-- **Intuitive Interface**
- Designed for both beginners and professionals—simple, clean, and efficient.
-
- **Open-Source & Extensible**
- Licensed under the MIT License. Additional usage terms can be found in the [NOTICE](https://www.google.com/search?q=NOTICE.md) file.
+ Licensed under the MIT License. Contributions are welcome! Additional usage terms can be found in the `NOTICE.md` file.
---
-## Recent Enhancements (v2.2)
+## What's New in Version 3.0
-- ✅ **Stability Overhaul:** Major improvements in error handling, including a comprehensive logging system and proactive environment validation to prevent crashes.
-- ✅ **Resilient Video Processing:** The video encoding pipeline now features automatic fallbacks for hardware codecs and audio stream processing, ensuring a valid output file is always created.
-- ✅ **Performance and Memory Optimization:** Implemented aggressive memory management to handle large video files without crashing and added dynamic GPU VRAM recovery for tiling-based tasks.
-- ✅ **Critical Bug Fixes:** Resolved race conditions in video encoding and GUI status updates, ensuring process integrity and predictable behavior.
-- ✅ **Safe Thread Management:** Upgraded to ensure processes are terminated gracefully and system resources are properly cleaned up on exit.
+- ✅ **AI Face Restoration:** Added support for the GFPGAN model, enabling powerful face enhancement and repair.
+- ✅ **Modernized UI/UX:** Implemented a complete visual redesign with a new, professional color scheme and improved components like a dynamic splash screen and scrollable message boxes.
+- ✅ **Performance Optimisation:** Enhanced memory efficiency by using contiguous arrays and refining data type handling during AI processing, leading to faster and more stable performance.
+- ✅ **Improved Codebase Health:** Refactored the core logic to be more modular by encapsulating face restoration in its own class (`AI_face_restoration`), improving maintainability.
+- ✅ **Increased Robustness:** Added explicit handling for images with transparency (BGRA) to ensure compatibility with models that require 3-channel input (BGR).
----
+---
-## Installation
+## Interface Previews
-To get started with Warlock-Studio:
+### 🔹 Main View (v3.0)
-1. **Run the installer** and follow the setup instructions.
-2. **Launch the application** by opening `Warlock-Studio.exe`.
-3. **Begin enhancing** your images and videos with just a few clicks\!
+
-Warlock-Studio uses [PyInstaller](https://www.pyinstaller.org/) and [Inno Setup](http://www.jrsoftware.org/isinfo.php) for a seamless packaging and installation experience.
+### 🔹 RIFE Option
-### 🔹 Installation Window
-
-## 
-
-## 
+
---
@@ -112,56 +88,87 @@ Warlock-Studio uses [PyInstaller](https://www.pyinstaller.org/) and [Inno Setup]
1. **Run as Administrator** (optional but recommended for optimal performance).
-2. **Load your media**: select your images and videos into the app.
+2. **Load Your Media**: Select your images and videos to import them into the app.
-3. **Configure settings**:
+3. **Configure Settings**:
- - Select an **AI Model** (e.g., Real-ESRGAN, SRGAN, BSRGAN, IRCNN, Waifu2x, Anime4K, RIFE)
- - Set the **output resolution**, **file format**, and toggle features such as **interpolation** or **slow-motion**
+ - Select an **AI Model** (e.g., Real-ESRGAN, BSRGAN, GFPGAN, RIFE).
+ - Set the **input/output resolution**, **file format**, and toggle features like **interpolation** or **blending**.
-4. **Start Processing**: click **"Make Magic"** to begin enhancement.
+4. **Start Processing**: Click **"Make Magic"** to begin the enhancement.
-5. **Retrieve your files**: processed outputs will be saved in your chosen destination folder.
+5. **Retrieve Your Files**: Processed outputs will be saved in your chosen destination folder.
---
-## Quality Comparison
+## AI Model Workflows & Quality Comparison
+
+### Quality Comparison
**Comparison of an enhanced image using the BSRGANx2 model**

----
+### AI Model Workflows
-## AI-Models Workflow
+#### 🔹 GFPGAN (Face Restoration)
-### 🔹 RIFE
+
-
+#### 🔹 RIFE (Frame Interpolation)
-### 🔹 Real-ESRGAN
+
-
+#### 🔹 Real-ESRGAN (Upscaling)
-### 🔹 IRCNN
+
-
+#### 🔹 IRCNN (Denoising)
-### 🔹 BSRGAN
+
-
+#### 🔹 BSRGAN (Upscaling)
+
+
---
-## 🛠️ Development Status — v2.2
+## Installation
-| Component | Status | Notes |
-| :---------------------------------- | :--------------- | :------------------------------------------------------------------------ |
-| **Upscaling Models (ESRGAN, etc.)** | 🟢 **Stable** | Fully integrated with dynamic VRAM recovery for enhanced stability. |
-| **Frame Interpolation (RIFE)** | 🟢 **Stable** | Includes slow-motion and intermediate frame generation capabilities. |
-| **Batch Processing** | 🟢 **Stable** | Reliable processing with improved error handling and resource management. |
-| **User Interface (UI/UX)** | 🟢 **Improved** | Updated color palette and faster start-up time. |
-| **GPU Management** | 🟢 **Optimized** | Dynamic VRAM error recovery and graceful hardware codec fallbacks. |
-| **Installer and Packaging** | 🟢 **Stable** | Easy-to-use installer for Windows platforms. |
+To get started with Warlock-Studio:
+
+1. **Download the installer** from the links at the top of this document.
+2. **Run the installer** and follow the setup instructions.
+3. **Launch the application** from the Start Menu or desktop shortcut.
+
+Warlock-Studio uses [PyInstaller](https://www.pyinstaller.org/) and [Inno Setup](http://www.jrsoftware.org/isinfo.php) for a seamless packaging and installation experience.
+
+### Installation Window Previews
+
+
+
+
+---
+
+## System Requirements
+
+- **Operating System:** Windows 10 or later (64-bit)
+- **Memory (RAM):** 8 GB or more recommended
+- **Graphics Card:** NVIDIA or DirectML-compatible GPU highly recommended for performance
+- **Storage:** Sufficient disk space for input and output media files
+
+---
+
+## Development Status — v3.0-07.25
+
+| Component | Status | Notes |
+| :---------------------------------- | :---------------- | :--------------------------------------------------------------------------------- |
+| **Upscaling Models (ESRGAN, etc.)** | 🟢 **Stable** | Fully integrated with dynamic VRAM recovery for enhanced stability. |
+| **Face Restoration (GFPGAN)** | 🟢 **Stable** | New feature for high-quality face enhancement. |
+| **Frame Interpolation (RIFE)** | 🟢 **Stable** | Includes slow-motion and intermediate frame generation capabilities. |
+| **Batch Processing** | 🟢 **Stable** | Reliable processing with improved error handling and resource management. |
+| **User Interface (UI/UX)** | 🟢 **Modernized** | Complete thematic redesign with a professional color palette and improved dialogs. |
+| **GPU Management** | 🟢 **Optimized** | Dynamic VRAM error recovery and graceful hardware codec fallbacks. |
+| **Installer and Packaging** | 🟢 **Stable** | Easy-to-use installer for Windows platforms. |
---
@@ -173,6 +180,7 @@ Warlock-Studio/
│
└──├──BSRGANx2_fp16.onnx
├──BSRGANx4_fp16.onnx
+ ├──GFPGANv1.4.fp16.onnx
├──IRCNN_Lx1_fp16.onnx
├──IRCNN_Mx1_fp16.onnx
├──RealESR_Animex4_fp16.onnx
@@ -188,8 +196,6 @@ Warlock-Studio/
├──clear_icon.png
├──exiftool.exe
├──ffmpeg.exe
- ├──ffmplay.exe
- ├──ffmprobe.exe
├──info_icon.png
├──logo.ico
├──logo.png
@@ -228,48 +234,38 @@ Warlock-Studio/
├──Manual_EN.pdf
├──Warlock-Studio.py # Main
└──Warlock-Studio.spec
-
```
----
-
-### Integrated Technologies & Licenses
-
-| Technology | License | Author / Maintainer | Source Code / Homepage |
-| :------------ | :------------------------------- | :------------------------------------------------------ | :--------------------------------------------------------- |
-| QualityScaler | MIT | [Djdefrag](https://github.com/Djdefrag) | [GitHub](https://github.com/Djdefrag/QualityScaler) |
-| RealScaler | MIT | [Djdefrag](https://github.com/Djdefrag) | [GitHub](https://github.com/Djdefrag/RealScaler) |
-| FluidFrames | MIT | [Djdefrag](https://github.com/Djdefrag) | [GitHub](https://github.com/Djdefrag/FluidFrames) |
-| Real-ESRGAN | BSD 3-Clause / Apache 2.0 | [Xintao Wang](https://github.com/xinntao) | [GitHub](https://github.com/xinntao/Real-ESRGAN) |
-| RealESRGAN-G | BSD 3-Clause / Apache 2.0 | [Xintao Wang](https://github.com/xinntao) | [GitHub](https://github.com/xinntao/Real-ESRGAN) |
-| RealESR-Anime | BSD 3-Clause / Apache 2.0 | [Xintao Wang](https://github.com/xinntao) | [GitHub](https://github.com/xinntao/Real-ESRGAN) |
-| RealESR-Net | BSD 3-Clause / Apache 2.0 | [Xintao Wang](https://github.com/xinntao) | [GitHub](https://github.com/xinntao/Real-ESRGAN) |
-| RIFE | Apache 2.0 | [hzwer](https://github.com/hzwer) | [GitHub](https://github.com/megvii-research/ECCV2022-RIFE) |
-| SRGAN | CC BY-NC-SA 4.0 (Non-Commercial) | [TensorLayer Community](https://github.com/tensorlayer) | [GitHub](https://github.com/tensorlayer/srgan) |
-| BSRGAN | Apache 2.0 | [Kai Zhang](https://github.com/cszn) | [GitHub](https://github.com/cszn/BSRGAN) |
-| IRCNN | BSD / Mixed | [Kai Zhang](https://github.com/cszn) | [GitHub](https://github.com/cszn/IRCNN) |
-| Anime4K | MIT | [Tianyang Zhang (bloc97)](https://github.com/bloc97) | [GitHub](https://github.com/bloc97/Anime4K) |
-| ONNX Runtime | MIT | [Microsoft](https://github.com/microsoft) | [GitHub](https://github.com/microsoft/onnxruntime) |
-| PyTorch | BSD 3-Clause | [Meta AI](https://pytorch.org/) | [GitHub](https://github.com/pytorch/pytorch) |
-| FFmpeg | LGPL-2.1 / GPL (varies) | [FFmpeg Team](https://ffmpeg.org/) | [Official Site](https://ffmpeg.org) |
-| ExifTool | Perl Artistic License 1.0 | [Phil Harvey](https://exiftool.org/) | [Official Site](https://exiftool.org/) |
-| DirectML | MIT | [Microsoft](https://github.com/microsoft/) | [GitHub](https://github.com/microsoft/DirectML) |
-| Python | Python Software Foundation (PSF) | [Python Software Foundation](https://www.python.org/) | [Official Site](https://www.python.org) |
-| PyInstaller | GPLv2+ | [PyInstaller Team](https://github.com/pyinstaller) | [GitHub](https://github.com/pyinstaller/pyinstaller) |
-| Inno Setup | Custom Inno License | [Jordan Russell](http://www.jrsoftware.org/) | [Official Site](http://www.jrsoftware.org/isinfo.php) |
---
-## System Requirements
-- **Operating System:** Windows 10 or later
-- **Memory (RAM):** Minimum 4 GB (8 GB or more recommended)
-- **Graphics Card:** NVIDIA or DirectML-compatible GPU highly recommended for performance
-- **Storage:** Sufficient disk space for input and output media files
+## Integrated Technologies & Licenses
+
+| Technology | License | Author / Maintainer | Source Code / Homepage |
+| :------------ | :------------------------ | :-------------------------------------------------------- | :--------------------------------------------------------- |
+| QualityScaler | MIT | [Djdefrag](https://github.com/Djdefrag) | [GitHub](https://github.com/Djdefrag/QualityScaler) |
+| RealScaler | MIT | [Djdefrag](https://github.com/Djdefrag) | [GitHub](https://github.com/Djdefrag/RealScaler) |
+| FluidFrames | MIT | [Djdefrag](https://github.com/Djdefrag) | [GitHub](https://github.com/Djdefrag/FluidFrames) |
+| Real-ESRGAN | BSD 3-Clause / Apache 2.0 | [Xintao Wang](https://github.com/xinntao) | [GitHub](https://github.com/xinntao/Real-ESRGAN) |
+| GFPGAN | MIT | [TencentARC / Xintao Wang](https://github.com/TencentARC) | [GitHub](https://github.com/TencentARC/GFPGAN) |
+| RIFE | Apache 2.0 | [hzwer](https://github.com/hzwer) | [GitHub](https://github.com/megvii-research/ECCV2022-RIFE) |
+| SRGAN | CC BY-NC-SA 4.0 | [TensorLayer Community](https://github.com/tensorlayer) | [GitHub](https://github.com/tensorlayer/srgan) |
+| BSRGAN | Apache 2.0 | [Kai Zhang](https://github.com/cszn) | [GitHub](https://github.com/cszn/BSRGAN) |
+| IRCNN | BSD / Mixed | [Kai Zhang](https://github.com/cszn) | [GitHub](https://github.com/cszn/IRCNN) |
+| Anime4K | MIT | [Tianyang Zhang (bloc97)](https://github.com/bloc97) | [GitHub](https://github.com/bloc97/Anime4K) |
+| ONNX Runtime | MIT | [Microsoft](https://github.com/microsoft) | [GitHub](https://github.com/microsoft/onnxruntime) |
+| PyTorch | BSD 3-Clause | [Meta AI](https://pytorch.org/) | [GitHub](https://github.com/pytorch/pytorch) |
+| FFmpeg | LGPL / GPL (varies) | [FFmpeg Team](https://ffmpeg.org/) | [Official Site](https://ffmpeg.org) |
+| ExifTool | Perl Artistic License | [Phil Harvey](https://exiftool.org/) | [Official Site](https://exiftool.org/) |
+| DirectML | MIT | [Microsoft](https://github.com/microsoft/) | [GitHub](https://github.com/microsoft/DirectML) |
+| Python | PSF License | [Python Software Foundation](https://www.python.org/) | [Official Site](https://www.python.org) |
+| PyInstaller | GPLv2+ | [PyInstaller Team](https://github.com/pyinstaller) | [GitHub](https://github.com/pyinstaller/pyinstaller) |
+| Inno Setup | Custom License | [Jordan Russell](http://www.jrsoftware.org/) | [Official Site](http://www.jrsoftware.org/isinfo.php) |
---
## Contributions
-We warmly welcome community contributions\!
+We warmly welcome community contributions!
1. **Fork** this repository.
2. **Create a branch** for your feature or fix.
@@ -277,11 +273,9 @@ We warmly welcome community contributions\!
For bug reports, feature suggestions, or inquiries, contact us at: **[negroayub97@gmail.com](mailto:negroayub97@gmail.com)**
-**Warlock-Studio** merges cutting-edge artificial intelligence with a powerful yet accessible interface—empowering creators to elevate their media effortlessly.
-
---
## License
© 2025 Iván Eduardo Chavez Ayub
-Distributed under the MIT License. Additional terms are available in the [NOTICE.md](https://www.google.com/search?q=NOTICE.md) file.
+Distributed under the MIT License. Additional terms are available in the `NOTICE.md` file.
diff --git a/SECURITY.md b/SECURITY.md
index aafd810..42eeffb 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -6,6 +6,7 @@ We aim to support the most recent stable release of Warlock-Studio. Security upd
| Version | Supported |
| ------- | --------- |
+| 3.0.x | ✅ |
| 2.2.x | ✅ |
| 2.1.x | ✅ |
| 2.0.x | ✅ |
diff --git a/Setup.iss b/Setup.iss
index 2327bfb..302ce3b 100644
--- a/Setup.iss
+++ b/Setup.iss
@@ -1,9 +1,9 @@
; ===================================================================
-; Warlock-Studio 2.2 - Inno Setup Script
+; Warlock-Studio 3.0- Inno Setup Script
; ===================================================================
#define AppName "Warlock-Studio"
-#define AppVersion "2.2"
+#define AppVersion "3.0"
#define AppPublisher "Iván Eduardo Chavez Ayub"
#define AppURL "https://github.com/Ivan-Ayub97/Warlock-Studio"
#define AppExeName "Warlock-Studio.exe"
@@ -56,7 +56,6 @@ Source: "..\Warlock-Studio\{#AppExeName}"; DestDir: "{app}"; Flags: ignoreversio
Source: "..\Warlock-Studio\logo.ico"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\Warlock-Studio\AI-onnx\*"; DestDir: "{app}\AI-onnx"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "..\Warlock-Studio\Assets\*"; DestDir: "{app}\Assets"; Flags: ignoreversion recursesubdirs createallsubdirs
-Source: "..\Warlock-Studio\rsc\*"; DestDir: "{app}\rsc"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "..\Warlock-Studio\LICENSE"; DestDir: "{app}"; DestName: "License.txt"; Flags: ignoreversion
Source: "..\Warlock-Studio\NOTICE.md"; DestDir: "{app}"; Flags: ignoreversion
@@ -72,5 +71,4 @@ Filename: "{app}\{#AppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(
[UninstallDelete]
; --- Limpieza Adicional Durante la Desinstalación ---
Type: filesandordirs; Name: "{app}\AI-onnx"
-Type: filesandordirs; Name: "{app}\Assets"
-Type: filesandordirs; Name: "{app}\rsc"
\ No newline at end of file
+Type: filesandordirs; Name: "{app}\Assets"
\ No newline at end of file
diff --git a/Warlock-Studio.py b/Warlock-Studio.py
index 81c3378..917a36f 100644
--- a/Warlock-Studio.py
+++ b/Warlock-Studio.py
@@ -1,4 +1,3 @@
-
# Standard library imports
import atexit
import gc
@@ -16,7 +15,6 @@ from functools import cache
from itertools import repeat
from json import JSONDecodeError
from json import dumps as json_dumps
-from shutil import copy2
from json import load as json_load
from math import cos, pi # For smooth fade effect
from multiprocessing import Process
@@ -41,6 +39,7 @@ from os.path import getsize as os_path_getsize
from os.path import join as os_path_join
from os.path import splitext as os_path_splitext
from pathlib import Path
+from shutil import copy2
from shutil import move as shutil_move
from shutil import rmtree as remove_directory
from subprocess import CalledProcessError
@@ -54,13 +53,14 @@ from typing import Any, Callable, Dict, List, Optional, Union
from webbrowser import open as open_browser
from customtkinter import (CTk, CTkButton, CTkEntry, CTkFont, CTkFrame,
- CTkImage, CTkLabel, CTkOptionMenu,
+ CTkImage, CTkLabel, CTkOptionMenu, CTkProgressBar,
CTkScrollableFrame, CTkToplevel, filedialog,
set_appearance_mode, set_default_color_theme)
+# CAMBIO 1: Añadir COLOR_BGRA2BGR a la lista
from cv2 import (CAP_PROP_FPS, CAP_PROP_FRAME_COUNT, CAP_PROP_FRAME_HEIGHT,
CAP_PROP_FRAME_WIDTH, COLOR_BGR2RGB, COLOR_BGR2RGBA,
- COLOR_GRAY2RGB, COLOR_RGB2GRAY, IMREAD_UNCHANGED, INTER_AREA,
- INTER_CUBIC)
+ COLOR_BGRA2BGR, COLOR_GRAY2RGB, COLOR_RGB2GRAY,
+ IMREAD_UNCHANGED, INTER_AREA, INTER_CUBIC)
from cv2 import VideoCapture as opencv_VideoCapture
from cv2 import addWeighted as opencv_addWeighted
from cv2 import cvtColor as opencv_cvtColor
@@ -73,7 +73,7 @@ from numpy import ascontiguousarray as numpy_ascontiguousarray
from numpy import clip as numpy_clip
from numpy import concatenate as numpy_concatenate
from numpy import expand_dims as numpy_expand_dims
-from numpy import float32
+from numpy import float16, float32
from numpy import frombuffer as numpy_frombuffer
from numpy import full as numpy_full
from numpy import max as numpy_max
@@ -108,12 +108,22 @@ def find_by_relative_path(relative_path: str) -> str:
app_name = "Warlock-Studio"
-version = "2.2"
+version = "3.0-07.25"
-background_color = "#000000" # Negro grisáceo profundo
-app_name_color = "#FF0000" # Blanco puro para el nombre de la app
-widget_background_color = "#5A5A5A" # Rojo oscuro (Dark Red)
-text_color = "#F4F4F4" # Blanco opaco para texto legible
+
+# Esquema de colores mejorado - Rojo, Gris, Amarillo, Negro, Blanco
+background_color = "#1A1A1A" # Negro profundo
+app_name_color = "#FF4444" # Rojo brillante para el nombre de la app
+widget_background_color = "#2D2D2D" # Gris oscuro para widgets
+text_color = "#FFFFFF" # Blanco puro para texto principal
+secondary_text_color = "#E0E0E0" # Gris claro para texto secundario
+accent_color = "#FFD700" # Amarillo dorado para acentos
+button_hover_color = "#FF6666" # Rojo claro para hover
+border_color = "#404040" # Gris medio para bordes
+info_button_color = "#B22222" # Rojo oscuro para botones de info
+warning_color = "#FF8C00" # Naranja para advertencias
+success_color = "#32CD32" # Verde para éxito
+error_color = "#DC143C" # Rojo carmesí para errores
VRAM_model_usage = {
'RealESR_Gx4': 2.2,
@@ -124,16 +134,19 @@ VRAM_model_usage = {
'RealESRGANx4': 0.6,
'IRCNN_Mx1': 4,
'IRCNN_Lx1': 4,
+ 'GFPGAN': 1.8,
}
MENU_LIST_SEPARATOR = ["----"]
SRVGGNetCompact_models_list = ["RealESR_Gx4", "RealESR_Animex4"]
BSRGAN_models_list = ["BSRGANx4", "BSRGANx2", "RealESRGANx4", "RealESRNetx4"]
IRCNN_models_list = ["IRCNN_Mx1", "IRCNN_Lx1"]
+Face_restoration_models_list = ["GFPGAN"]
RIFE_models_list = ["RIFE", "RIFE_Lite"]
AI_models_list = (SRVGGNetCompact_models_list + MENU_LIST_SEPARATOR + BSRGAN_models_list +
- MENU_LIST_SEPARATOR + IRCNN_models_list + MENU_LIST_SEPARATOR + RIFE_models_list)
+ MENU_LIST_SEPARATOR + IRCNN_models_list + MENU_LIST_SEPARATOR + Face_restoration_models_list +
+ MENU_LIST_SEPARATOR + RIFE_models_list)
frame_interpolation_models_list = RIFE_models_list
frame_generation_options_list = [
"x2", "x4", "x8", "Slowmotion x2", "Slowmotion x4", "Slowmotion x8"
@@ -483,6 +496,8 @@ class AI_upscale:
return normalized_image, range
def preprocess_image(self, image: numpy_ndarray) -> numpy_ndarray:
+ # Optimización: Usar ascontiguousarray para mejor rendimiento de memoria
+ image = numpy_ascontiguousarray(image)
image = numpy_transpose(image, (2, 0, 1))
image = numpy_expand_dims(image, axis=0)
@@ -517,7 +532,8 @@ class AI_upscale:
case _: return (onnx_output * 255).astype(uint8)
def AI_upscale(self, image: numpy_ndarray) -> numpy_ndarray:
- image = image.astype(float32)
+ # Optimización: Usar memoria contigua antes de procesar
+ image = numpy_ascontiguousarray(image, dtype=float32)
image_mode = self.get_image_mode(image)
image, range = self.normalize_image(image)
@@ -715,8 +731,9 @@ class AI_interpolation:
# AI CLASS FUNCTIONS
def concatenate_images(self, image1: numpy_ndarray, image2: numpy_ndarray) -> numpy_ndarray:
- image1 = image1 / 255
- image2 = image2 / 255
+ # Optimización: Normalizar in-place para reducir uso de memoria
+ image1 = numpy_ascontiguousarray(image1, dtype=float32) / 255.0
+ image2 = numpy_ascontiguousarray(image2, dtype=float32) / 255.0
concateneted_image = numpy_concatenate((image1, image2), axis=2)
return concateneted_image
@@ -753,41 +770,281 @@ class AI_interpolation:
# EXTERNAL FUNCTION
- def AI_orchestration(self, image1: numpy_ndarray, image2: numpy_ndarray) -> list[numpy_ndarray]:
- generated_images = []
- # Generate 1 image [image1 / image_A / image2]
- if self.frame_gen_factor == 2:
- image_A = self.AI_interpolation(image1, image2)
- generated_images.append(image_A)
+def AI_orchestration(self, image1: numpy_ndarray, image2: numpy_ndarray) -> list[numpy_ndarray]:
+ generated_images = []
- # Generate 3 images [image1 / image_A / image_B / image_C / image2]
- elif self.frame_gen_factor == 4:
- image_B = self.AI_interpolation(image1, image2)
- image_A = self.AI_interpolation(image1, image_B)
- image_C = self.AI_interpolation(image_B, image2)
- generated_images.append(image_A)
- generated_images.append(image_B)
- generated_images.append(image_C)
+ # Optimización: Usar memoria contigua para las imágenes de entrada
+ image1 = numpy_ascontiguousarray(image1)
+ image2 = numpy_ascontiguousarray(image2)
- # Generate 7 images [image1 / image_A / image_B / image_C / image_D / image_E / image_F / image_G / image2]
- elif self.frame_gen_factor == 8:
- image_D = self.AI_interpolation(image1, image2)
- image_B = self.AI_interpolation(image1, image_D)
- image_A = self.AI_interpolation(image1, image_B)
- image_C = self.AI_interpolation(image_B, image_D)
- image_F = self.AI_interpolation(image_D, image2)
- image_E = self.AI_interpolation(image_D, image_F)
- image_G = self.AI_interpolation(image_F, image2)
- generated_images.append(image_A)
- generated_images.append(image_B)
- generated_images.append(image_C)
- generated_images.append(image_D)
- generated_images.append(image_E)
- generated_images.append(image_F)
- generated_images.append(image_G)
+ # Generate 1 image [image1 / image_A / image2]
+ if self.frame_gen_factor == 2:
+ image_A = self.AI_interpolation(image1, image2)
+ generated_images.append(image_A)
- return generated_images
+ # Generate 3 images [image1 / image_A / image_B / image_C / image2]
+ elif self.frame_gen_factor == 4:
+ image_B = self.AI_interpolation(image1, image2)
+ image_A = self.AI_interpolation(image1, image_B)
+ image_C = self.AI_interpolation(image_B, image2)
+ generated_images.append(image_A)
+ generated_images.append(image_B)
+ generated_images.append(image_C)
+
+ # Generate 7 images [image1 / image_A / image_B / image_C / image_D / image_E / image_F / image_G / image2]
+ elif self.frame_gen_factor == 8:
+ image_D = self.AI_interpolation(image1, image2)
+ image_B = self.AI_interpolation(image1, image_D)
+ image_A = self.AI_interpolation(image1, image_B)
+ image_C = self.AI_interpolation(image_B, image_D)
+ image_F = self.AI_interpolation(image_D, image2)
+ image_E = self.AI_interpolation(image_D, image_F)
+ image_G = self.AI_interpolation(image_F, image2)
+ generated_images.append(image_A)
+ generated_images.append(image_B)
+ generated_images.append(image_C)
+ generated_images.append(image_D)
+ generated_images.append(image_E)
+ generated_images.append(image_F)
+ generated_images.append(image_G)
+
+ return generated_images
+
+
+# AI FACE RESTORATION for face enhancement -----------------
+
+class AI_face_restoration:
+ """
+ Face restoration AI class for model like GFPGAN
+ These model are specialized for face enhancement and restoration tasks.
+ """
+
+ def __init__(
+ self,
+ AI_model_name: str,
+ directml_gpu: str,
+ input_resize_factor: float,
+ output_resize_factor: float,
+ max_resolution: int
+ ):
+ # Passed variables
+ self.AI_model_name = AI_model_name
+ self.directml_gpu = directml_gpu
+ self.input_resize_factor = input_resize_factor
+ self.output_resize_factor = output_resize_factor
+ self.max_resolution = max_resolution
+
+ # Model-specific configurations
+ self.model_configs = {
+ "GFPGAN": {
+ "input_size": (512, 512),
+ "scale_factor": 1,
+ "description": "GFPGAN v1.4 for face restoration",
+ "fp16": True
+ }
+ }
+
+ # Determine model path based on model name
+ self.AI_model_path = self._get_model_path()
+ self.model_config = self.model_configs.get(
+ AI_model_name, self.model_configs["GFPGAN"])
+ self.inferenceSession = None
+
+ def _get_model_path(self) -> str:
+ """
+ Get the appropriate model path based on the model name
+ """
+ if self.AI_model_name == "GFPGAN":
+ return find_by_relative_path(f"AI-onnx{os_separator}GFPGANv1.4.fp16.onnx")
+ else:
+ # Default fallback to GFPGAN
+ return find_by_relative_path(f"AI-onnx{os_separator}GFPGANv1.4.fp16.onnx")
+
+ def _load_inferenceSession(self) -> None:
+ """
+ Load the ONNX inference session for face restoration
+ """
+ try:
+ # Check if model file exists
+ if not os_path_exists(self.AI_model_path):
+ raise FileNotFoundError(
+ f"Face restoration model file not found: {self.AI_model_path}")
+
+ providers = ['DmlExecutionProvider']
+
+ match self.directml_gpu:
+ case 'Auto': provider_options = [{"performance_preference": "high_performance"}]
+ case 'GPU 1': provider_options = [{"device_id": "0"}]
+ case 'GPU 2': provider_options = [{"device_id": "1"}]
+ case 'GPU 3': provider_options = [{"device_id": "2"}]
+ case 'GPU 4': provider_options = [{"device_id": "3"}]
+
+ inference_session = InferenceSession(
+ path_or_bytes=self.AI_model_path,
+ providers=providers,
+ provider_options=provider_options,
+ )
+
+ self.inferenceSession = inference_session
+ print(
+ f"[AI] Successfully loaded face restoration model: {os_path_basename(self.AI_model_path)}")
+
+ except Exception as e:
+ error_msg = f"Failed to load face restoration model {os_path_basename(self.AI_model_path)}: {str(e)}"
+ print(f"[AI ERROR] {error_msg}")
+ raise RuntimeError(error_msg)
+
+ def get_image_mode(self, image: numpy_ndarray) -> str:
+ if image is None:
+ raise ValueError("Image is None")
+ shape = image.shape
+ if len(shape) == 2: # Grayscale: 2D array (rows, cols)
+ return "Grayscale"
+ # RGB: 3D array with 3 channels
+ elif len(shape) == 3 and shape[2] == 3:
+ return "RGB"
+ # RGBA: 3D array with 4 channels
+ elif len(shape) == 3 and shape[2] == 4:
+ return "RGBA"
+ else:
+ raise ValueError(f"Unsupported image shape: {shape}")
+
+ def get_image_resolution(self, image: numpy_ndarray) -> tuple:
+ height = image.shape[0]
+ width = image.shape[1]
+ return height, width
+
+ def resize_with_input_factor(self, image: numpy_ndarray) -> numpy_ndarray:
+ old_height, old_width = self.get_image_resolution(image)
+ new_width = int(old_width * self.input_resize_factor)
+ new_height = int(old_height * self.input_resize_factor)
+
+ new_width = new_width if new_width % 2 == 0 else new_width + 1
+ new_height = new_height if new_height % 2 == 0 else new_height + 1
+
+ if self.input_resize_factor > 1:
+ return opencv_resize(image, (new_width, new_height), interpolation=INTER_CUBIC)
+ elif self.input_resize_factor < 1:
+ return opencv_resize(image, (new_width, new_height), interpolation=INTER_AREA)
+ else:
+ return image
+
+ def resize_with_output_factor(self, image: numpy_ndarray) -> numpy_ndarray:
+ old_height, old_width = self.get_image_resolution(image)
+ new_width = int(old_width * self.output_resize_factor)
+ new_height = int(old_height * self.output_resize_factor)
+
+ new_width = new_width if new_width % 2 == 0 else new_width + 1
+ new_height = new_height if new_height % 2 == 0 else new_height + 1
+
+ if self.output_resize_factor > 1:
+ return opencv_resize(image, (new_width, new_height), interpolation=INTER_CUBIC)
+ elif self.output_resize_factor < 1:
+ return opencv_resize(image, (new_width, new_height), interpolation=INTER_AREA)
+ else:
+ return image
+
+ def preprocess_face_image(self, image: numpy_ndarray) -> numpy_ndarray:
+ """
+ Preprocess image for face restoration models
+ Face restoration models typically expect normalized input in range [0, 1]
+ """
+ # Optimización: Asegurar memoria contigua al inicio
+ image = numpy_ascontiguousarray(image)
+
+ # --- NUEVO CÓDIGO PARA CORREGIR LOS CANALES ---
+ # Si la imagen tiene 4 canales (BGRA), conviértela a 3 (BGR)
+ if image.shape[2] == 4:
+ image = opencv_cvtColor(image, COLOR_BGRA2BGR)
+ # --- FIN DEL NUEVO CÓDIGO ---
+
+ # Resize to model's expected input size
+ target_size = self.model_config["input_size"]
+ image = opencv_resize(image, target_size, interpolation=INTER_AREA)
+
+ # Determinar el tipo de dato correcto (float16 o float32)
+ if self.model_config.get("fp16", False):
+ dtype = float16
+ else:
+ dtype = float32
+
+ # Optimización: Normalizar usando memoria contigua
+ image = numpy_ascontiguousarray(image, dtype=dtype) / 255.0
+
+ # Transpose to CHW format (channels, height, width)
+ image = numpy_transpose(image, (2, 0, 1))
+
+ # Add batch dimension
+ image = numpy_expand_dims(image, axis=0)
+
+ return image
+
+ def postprocess_face_image(self, output: numpy_ndarray, original_size: tuple) -> numpy_ndarray:
+ """
+ Postprocess face restoration model output
+ """
+ # Remove batch dimension
+ output = numpy_squeeze(output, axis=0)
+
+ # Clamp values to [0, 1]
+ output = numpy_clip(output, 0, 1)
+
+ # Transpose back to HWC format
+ output = numpy_transpose(output, (1, 2, 0))
+
+ # Convert back to uint8
+ output = (output * 255).astype(uint8)
+
+ # Resize back to original size
+ if original_size != self.model_config["input_size"]:
+ output = opencv_resize(
+ output, (original_size[1], original_size[0]), interpolation=INTER_CUBIC)
+
+ return output
+
+ def face_restoration(self, image: numpy_ndarray) -> numpy_ndarray:
+ """
+ Perform face restoration on the input image
+ """
+ if self.inferenceSession is None:
+ self._load_inferenceSession()
+
+ # Store original size for later restoration
+ original_size = (image.shape[0], image.shape[1])
+
+ # Apply input resizing
+ image = self.resize_with_input_factor(image)
+
+ # Preprocess for face restoration
+ preprocessed = self.preprocess_face_image(image)
+
+ # Run inference
+ input_name = self.inferenceSession.get_inputs()[0].name
+ output_name = self.inferenceSession.get_outputs()[0].name
+
+ result = self.inferenceSession.run(
+ [output_name], {input_name: preprocessed})[0]
+
+ # Postprocess the result
+ restored_face = self.postprocess_face_image(
+ result, (image.shape[0], image.shape[1]))
+
+ # Apply output resizing
+ restored_face = self.resize_with_output_factor(restored_face)
+
+ return restored_face
+
+ def AI_orchestration(self, image: numpy_ndarray) -> numpy_ndarray:
+ """
+ Main orchestration function for face restoration
+ """
+ try:
+ return self.face_restoration(image)
+ except Exception as e:
+ print(f"[FACE RESTORATION ERROR] {str(e)}")
+ # Return original image if restoration fails
+ return image
# GUI utils ---------------------------
@@ -824,6 +1081,13 @@ class MessageBox(CTkToplevel):
self.resizable(True, True)
self.grab_set() # make other windows not clickable
+ # Set minimum and maximum window sizes for better scrolling
+ self.minsize(700, 500)
+ self.maxsize(1000, 800)
+
+ # Set initial window size based on content
+ self.geometry("750x600")
+
def _ok_event(
self,
event=None
@@ -852,9 +1116,9 @@ class MessageBox(CTkToplevel):
spacingLabel2 = self.createEmptyLabel()
if self._messageType == "info":
- title_subtitle_text_color = "#FFD700" # Amarillo dorado
+ title_subtitle_text_color = accent_color # Amarillo dorado
elif self._messageType == "error":
- title_subtitle_text_color = "#FF3131" # Rojo brillante
+ title_subtitle_text_color = error_color # Rojo brillante
titleLabel = CTkLabel(
master=self,
@@ -874,7 +1138,7 @@ class MessageBox(CTkToplevel):
anchor='w',
justify="left",
fg_color="transparent",
- text_color="#FFD700", # Amarillo dorado
+ text_color=accent_color, # Amarillo dorado
font=bold17,
text=f"Default: {self._default_value}"
)
@@ -911,25 +1175,43 @@ class MessageBox(CTkToplevel):
columnspan=2, padx=0, pady=0, sticky="ew")
def placeInfoMessageOptionsText(self) -> None:
+ # Create a scrollable frame for the options
+ from customtkinter import CTkScrollableFrame
- for option_text in self._option_list:
+ self.scrollable_frame = CTkScrollableFrame(
+ master=self,
+ width=600,
+ height=300, # Fixed height to enable scrolling
+ fg_color="transparent",
+ corner_radius=10,
+ scrollbar_button_color=border_color,
+ scrollbar_button_hover_color=button_hover_color
+ )
+
+ self._ctkwidgets_index += 1
+ self.scrollable_frame.grid(row=self._ctkwidgets_index, column=0,
+ columnspan=2, padx=25, pady=10, sticky="ew")
+
+ # Add options to the scrollable frame
+ for i, option_text in enumerate(self._option_list):
optionLabel = CTkLabel(
- master=self,
- width=600,
- height=45,
+ master=self.scrollable_frame,
+ width=550, # Slightly smaller to account for scrollbar
anchor='w',
justify="left",
text_color=text_color,
- fg_color="#282828",
+ fg_color=widget_background_color,
bg_color="transparent",
font=bold13,
text=option_text,
corner_radius=10,
+ wraplength=530 # Enable text wrapping
)
- self._ctkwidgets_index += 1
- optionLabel.grid(row=self._ctkwidgets_index, column=0,
- columnspan=2, padx=25, pady=4, sticky="ew")
+ optionLabel.grid(row=i, column=0, padx=10, pady=4, sticky="ew")
+
+ # Configure grid weight for the scrollable frame
+ self.scrollable_frame.grid_columnconfigure(0, weight=1)
spacingLabel3 = self.createEmptyLabel()
@@ -948,9 +1230,10 @@ class MessageBox(CTkToplevel):
width=125,
font=bold11,
border_width=1,
- fg_color="#282828",
- text_color="#E0E0E0",
- border_color="#F5E358"
+ fg_color=widget_background_color,
+ text_color=secondary_text_color,
+ border_color=accent_color,
+ hover_color=button_hover_color
)
self._ctkwidgets_index += 1
@@ -1014,7 +1297,7 @@ class FileWidget(CTkScrollableFrame):
self,
text=os_path_basename(file_path),
font=bold14,
- text_color=text_color,
+ text_color=accent_color, # Usar color amarillo para nombres de archivo
compound="left",
anchor="w",
padx=10,
@@ -1035,7 +1318,7 @@ class FileWidget(CTkScrollableFrame):
text=infos,
image=icon,
font=bold12,
- text_color=text_color,
+ text_color=secondary_text_color, # Usar color de texto secundario para info
compound="left",
anchor="w",
padx=10,
@@ -1066,9 +1349,10 @@ class FileWidget(CTkScrollableFrame):
font=bold11,
border_width=1,
corner_radius=1,
- fg_color="#282828",
- text_color="#E0E0E0",
- border_color="#FFD53D"
+ fg_color=widget_background_color,
+ text_color=text_color,
+ border_color=accent_color,
+ hover_color=button_hover_color
)
button.grid(row=0, column=2, pady=(7, 7), padx=(0, 7))
@@ -1080,16 +1364,24 @@ class FileWidget(CTkScrollableFrame):
if check_if_file_is_video(file_path):
video_cap = opencv_VideoCapture(file_path)
_, frame = video_cap.read()
- source_icon = opencv_cvtColor(frame, COLOR_BGR2RGB)
+ if frame is not None:
+ source_icon = opencv_cvtColor(frame, COLOR_BGR2RGB)
+ else:
+ # Fallback para videos problemáticos
+ source_icon = numpy_zeros((60, 60, 3), dtype=uint8)
video_cap.release()
else:
source_icon = opencv_cvtColor(image_read(file_path), COLOR_BGR2RGB)
+ # Optimización: Usar memoria contigua para mejor rendimiento
+ source_icon = numpy_ascontiguousarray(source_icon)
+
ratio = min(
max_size / source_icon.shape[0], max_size / source_icon.shape[1])
new_width = int(source_icon.shape[1] * ratio)
new_height = int(source_icon.shape[0] * ratio)
- source_icon = opencv_resize(source_icon, (new_width, new_height))
+ source_icon = opencv_resize(
+ source_icon, (new_width, new_height), interpolation=INTER_AREA)
ctk_icon = CTkImage(pillow_image_fromarray(
source_icon, mode="RGB"), size=(new_width, new_height))
@@ -1237,10 +1529,11 @@ def create_info_button(command: Callable, text: str, width: int = 200) -> CTkFra
command=command,
font=bold12,
text="?",
- border_color="#ECD125",
+ border_color=accent_color,
border_width=1,
- fg_color=widget_background_color,
- hover_color=background_color,
+ fg_color=info_button_color,
+ hover_color=button_hover_color,
+ text_color=text_color,
width=23,
height=15,
corner_radius=1
@@ -1270,7 +1563,7 @@ def create_option_menu(
command: Callable,
values: list,
default_value: str,
- border_color: str = "#404040",
+ border_color: str = None,
border_width: int = 1,
width: int = 159
) -> CTkFrame:
@@ -1281,6 +1574,10 @@ def create_option_menu(
total_width = (width + 2 * border_width)
total_height = (height + 2 * border_width)
+ # Use default border color if none provided
+ if border_color is None:
+ border_color = accent_color
+
frame = CTkFrame(
master=window,
fg_color=border_color,
@@ -1301,10 +1598,12 @@ def create_option_menu(
font=bold11,
anchor="center",
text_color=text_color,
- fg_color=background_color,
- button_color=background_color,
- button_hover_color=background_color,
- dropdown_fg_color=background_color
+ fg_color=widget_background_color,
+ button_color=widget_background_color,
+ button_hover_color=button_hover_color,
+ dropdown_fg_color=widget_background_color,
+ dropdown_text_color=text_color,
+ dropdown_hover_color=button_hover_color
)
option_menu.place(
@@ -1325,9 +1624,10 @@ def create_text_box(textvariable: StringVar, width: int) -> CTkEntry:
font=bold11,
justify="center",
text_color=text_color,
- fg_color="#000000",
+ fg_color=widget_background_color,
border_width=1,
- border_color="#404040",
+ border_color=accent_color,
+ placeholder_text_color=secondary_text_color
)
@@ -1340,10 +1640,10 @@ def create_text_box_output_path(textvariable: StringVar) -> CTkEntry:
height=28,
font=bold11,
justify="center",
- text_color=text_color,
- fg_color="#000000",
+ text_color=secondary_text_color,
+ fg_color=widget_background_color,
border_width=1,
- border_color="#404040",
+ border_color=border_color,
state=DISABLED
)
@@ -1354,9 +1654,13 @@ def create_active_button(
icon: CTkImage = None,
width: int = 140,
height: int = 30,
- border_color: str = "#C11919"
+ border_color: str = None
) -> CTkButton:
+ # Use default border color if none provided
+ if border_color is None:
+ border_color = accent_color
+
return CTkButton(
master=window,
command=command,
@@ -1367,9 +1671,10 @@ def create_active_button(
font=bold11,
border_width=1,
corner_radius=1,
- fg_color="#282828",
- text_color="#E0E0E0",
- border_color=border_color
+ fg_color=widget_background_color,
+ text_color=text_color,
+ border_color=border_color,
+ hover_color=button_hover_color
)
@@ -3201,11 +3506,19 @@ def upscale_orchestrator(
try:
write_process_status(process_status_q, f"Loading AI model")
- AI_upscale_instance_list = [
- AI_upscale(selected_AI_model, selected_gpu,
- input_resize_factor, output_resize_factor, tiles_resolution)
- for _ in range(selected_AI_multithreading)
- ]
+ # Check if the selected model is a face restoration model
+ if selected_AI_model in Face_restoration_models_list:
+ AI_upscale_instance_list = [
+ AI_face_restoration(selected_AI_model, selected_gpu,
+ input_resize_factor, output_resize_factor, tiles_resolution)
+ for _ in range(selected_AI_multithreading)
+ ]
+ else:
+ AI_upscale_instance_list = [
+ AI_upscale(selected_AI_model, selected_gpu,
+ input_resize_factor, output_resize_factor, tiles_resolution)
+ for _ in range(selected_AI_multithreading)
+ ]
how_many_files = len(selected_file_list)
for file_number in range(how_many_files):
@@ -3831,7 +4144,8 @@ def select_AI_from_menu(selected_option: str) -> None:
# FluidFrames/RIFE: Show frame generation menu, otherwise show blending
if selected_AI_model in RIFE_models_list:
place_frame_generation_menu()
- else:
+ # Face restoration models don't need blending (they work differently)
+ elif selected_AI_model not in Face_restoration_models_list:
place_AI_blending_menu()
# Always restore other key controls
place_AI_multithreading_menu()
@@ -3938,19 +4252,20 @@ def place_loadFile_section():
master=window, fg_color=background_color, corner_radius=1)
text_drop = (" SUPPORTED FILES \n\n "
- + "IMAGES • jpg png tif bmp webp heic \n "
- + "VIDEOS • mp4 webm mkv flv gif avi mov mpg qt 3gp ")
+ + "IMAGES • jpg, png, tif, bmp, webp, heic \n "
+ + "VIDEOS • mp4, webm, mkv, flv, gif, avi, mov, mpg, qt, 3gp ")
input_file_text = CTkLabel(
master=window,
text=text_drop,
- fg_color=background_color,
+ fg_color=widget_background_color,
bg_color=background_color,
- text_color=text_color,
+ text_color=secondary_text_color,
width=300,
height=150,
font=bold13,
- anchor="center"
+ anchor="center",
+ corner_radius=10
)
input_file_button = CTkButton(
@@ -3962,9 +4277,10 @@ def place_loadFile_section():
font=bold12,
border_width=1,
corner_radius=1,
- fg_color="#282828",
- text_color="#E0E0E0",
- border_color="#ECD125"
+ fg_color=widget_background_color,
+ text_color=text_color,
+ border_color=accent_color,
+ hover_color=button_hover_color
)
background.place(relx=0.0, rely=0.0, relwidth=0.5, relheight=1.0)
@@ -3978,7 +4294,7 @@ def place_app_name():
app_name_label = CTkLabel(
master=window,
text=app_name + " " + version,
- fg_color=background_color,
+ fg_color="transparent",
text_color=app_name_color,
font=bold20,
anchor="w"
@@ -4006,6 +4322,12 @@ def place_AI_menu():
" • Year: 2020\n"
" • Function: High-quality upscaling\n",
+ "\n GFPGAN \n"
+ "\n • Generative Face Prior GAN for face restoration\n"
+ " • Year: 2021\n"
+ " • Function: Face restoration and enhancement\n"
+ " • Excellent for old/blurry photos\n",
+
"\n RIFE | RIFE Lite\n" +
" • The complete RIFE AI model & Lite version\n" +
" • Excellent frame generation quality\n" +
@@ -4504,8 +4826,8 @@ def place_message_label():
height=26,
width=200,
font=bold11,
- fg_color="#ffbf00",
- text_color="#000000",
+ fg_color=accent_color,
+ text_color=background_color,
anchor="center",
corner_radius=1
)
@@ -4519,7 +4841,7 @@ def place_stop_button():
icon=stop_icon,
width=140,
height=30,
- border_color="#EC1D1D"
+ border_color=error_color
)
stop_button.place(relx=0.75 - 0.1, rely=0.95, anchor="center")
@@ -4677,7 +4999,8 @@ class SplashScreen(CTkToplevel):
self.geometry(f"{window_width}x{window_height}+{x}+{y}")
# Configure appearance to match app
- self.configure(fg_color="#212325") # background_color
+ # Usar color de fondo definido
+ self.configure(fg_color=background_color)
# Create banner or title
if has_banner:
@@ -4693,14 +5016,14 @@ class SplashScreen(CTkToplevel):
self,
text="Warlock Studio",
font=CTkFont(family="Segoe UI", size=28, weight="bold"),
- text_color="#ECD125" # app_name_color
+ text_color=app_name_color # Usar color del nombre de la app
)
title_label.pack(pady=(50, 20))
# Create status frame with progress messages
status_frame = CTkFrame(
self,
- fg_color="#343638", # widget_background_color
+ fg_color=widget_background_color, # Usar color de widget definido
corner_radius=10
)
status_frame.pack(pady=10, padx=20, fill="x")
@@ -4709,10 +5032,31 @@ class SplashScreen(CTkToplevel):
status_frame,
text="Loading AI-ONNX models...",
font=CTkFont(family="Segoe UI", size=12, weight="bold"),
- text_color="white" # text_color
+ text_color=accent_color # Usar color amarillo para el texto de estado
)
self.status_label.pack(pady=10, padx=10)
+ # Create progress bar
+ self.progress_bar = CTkProgressBar(
+ status_frame,
+ width=400,
+ height=10,
+ progress_color=accent_color, # Usar color amarillo dorado
+ fg_color=border_color, # Usar color de borde
+ border_width=1
+ )
+ self.progress_bar.pack(pady=(0, 10), padx=10)
+ self.progress_bar.set(0) # Start at 0%
+
+ # Create version label
+ version_label = CTkLabel(
+ self,
+ text=f"Version {version}",
+ font=CTkFont(family="Segoe UI", size=10),
+ text_color=secondary_text_color # Usar color de texto secundario
+ )
+ version_label.pack(pady=(0, 10))
+
# Define enough messages to fill 15 seconds (~1.5s por mensaje)
self.messages = [
"Preparing environment...",
@@ -4755,7 +5099,43 @@ class SplashScreen(CTkToplevel):
if __name__ == "__main__":
multiprocessing_freeze_support()
set_appearance_mode("Dark")
- set_default_color_theme("dark-blue")
+
+ # Crear tema personalizado
+ import customtkinter
+ from customtkinter import set_default_color_theme
+
+ # Configurar tema personalizado con colores definidos
+ customtkinter.set_default_color_theme("dark-blue") # Base theme
+
+ # Sobrescribir algunos colores globales de CustomTkinter
+ try:
+ # Aplicar colores personalizados a nivel global
+ customtkinter.ThemeManager.theme["CTkFrame"]["fg_color"] = [
+ widget_background_color, widget_background_color]
+ customtkinter.ThemeManager.theme["CTkButton"]["fg_color"] = [
+ widget_background_color, widget_background_color]
+ customtkinter.ThemeManager.theme["CTkButton"]["hover_color"] = [
+ button_hover_color, button_hover_color]
+ customtkinter.ThemeManager.theme["CTkButton"]["text_color"] = [
+ text_color, text_color]
+ customtkinter.ThemeManager.theme["CTkButton"]["border_color"] = [
+ accent_color, accent_color]
+ customtkinter.ThemeManager.theme["CTkEntry"]["fg_color"] = [
+ widget_background_color, widget_background_color]
+ customtkinter.ThemeManager.theme["CTkEntry"]["text_color"] = [
+ text_color, text_color]
+ customtkinter.ThemeManager.theme["CTkEntry"]["border_color"] = [
+ accent_color, accent_color]
+ customtkinter.ThemeManager.theme["CTkOptionMenu"]["fg_color"] = [
+ widget_background_color, widget_background_color]
+ customtkinter.ThemeManager.theme["CTkOptionMenu"]["text_color"] = [
+ text_color, text_color]
+ customtkinter.ThemeManager.theme["CTkOptionMenu"]["button_hover_color"] = [
+ button_hover_color, button_hover_color]
+ customtkinter.ThemeManager.theme["CTkLabel"]["text_color"] = [
+ text_color, text_color]
+ except Exception as e:
+ print(f"[THEME] Could not apply custom theme: {e}")
process_status_q = multiprocessing_Queue(maxsize=1)
diff --git a/Warlock-Studio.spec b/Warlock-Studio.spec
index 81d98bc..be79e56 100644
--- a/Warlock-Studio.spec
+++ b/Warlock-Studio.spec
@@ -5,14 +5,14 @@ a = Analysis(
['Warlock-Studio.py'],
pathex=[],
binaries=[],
- datas=[('AI-onnx', 'AI-onnx'), ('Assets', 'Assets'), ('rsc', 'rsc')],
+ datas=[('AI-onnx', 'AI-onnx'), ('Assets', 'Assets')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
- optimize=0,
+ optimize=1,
)
pyz = PYZ(a.pure)