Merge branch 'feature/enhance-modularity' into 'main'
Feature/enhance modularity See merge request python_projects3802849/optima-35!7
This commit is contained in:
commit
d99d28c4c0
20 changed files with 1122 additions and 554 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -3,4 +3,5 @@ debug.*
|
|||
debug_log/
|
||||
.ropeproject/
|
||||
__pycache__/
|
||||
config/settings.yaml
|
||||
config/tui_settings.yaml
|
||||
config/exif.yaml
|
||||
|
|
26
CHANGELOG.md
26
CHANGELOG.md
|
@ -1,7 +1,31 @@
|
|||
# Changelog
|
||||
|
||||
## 0.3.x
|
||||
## 0.4.x
|
||||
### 0.4.1: Finished GUI and TUI
|
||||
- Both **GUI** and **TUI** now fully utilize the `optima35` class for core functionality.
|
||||
- All planned features are operational and integrated into both interfaces.
|
||||
- **Next Step**: Bug hunting and optimization.
|
||||
- The fork `optima-35-tui` has been deleted, as **OPTIMA-35** now includes both **TUI** and **GUI** versions within the same project.
|
||||
|
||||
### 0.4.0: Splitting into Classes
|
||||
- **Code Organization:**
|
||||
- Core functionality for **Optima-35** is now refactored into `optima35.py` for better separation of logic and reusability.
|
||||
- The **GUI code** is moved to `gui.py` for a cleaner structure and maintainability.
|
||||
- The **TUI logic** will be moved into `tui.py`, making it modular and focused.
|
||||
- The original TUI fork will be deleted to streamline operations.
|
||||
|
||||
- **Main File Enhancements:**
|
||||
- `main.py` is now the entry point of the application and determines whether to start the GUI or TUI based on:
|
||||
- Operating system.
|
||||
- The presence of required dependencies (e.g., PySide for GUI).
|
||||
- Command-line arguments (`--tui` flag).
|
||||
|
||||
- **Benefits:**
|
||||
- Clear separation of concerns between GUI, TUI, and core functionalities.
|
||||
- Improved readability, maintainability, and scalability of the project.
|
||||
- Easier to test and debug individual components.
|
||||
|
||||
## 0.3.x
|
||||
### 0.3.4: Features Finalized
|
||||
- Core Features Completed:
|
||||
- All functions are now available, though minor bugs may exist.
|
||||
|
|
98
README.md
98
README.md
|
@ -2,56 +2,90 @@
|
|||
|
||||
## Overview
|
||||
|
||||
**OPTIMA-35** (**Organizing, Processing, Tweaking Images and Modifying scanned Analogs from 35mm Film**) is a Python-based project designed to provide a streamlined way to manage and edit metadata and images from analog photography. But can be used for any images.
|
||||
**OPTIMA-35** (**Organizing, Processing, Tweaking Images, and Modifying scanned Analogs from 35mm Film**) is a Python-based project designed to streamline the management and editing of metadata and images from analog photography. While it was created with analog photography in mind, it is versatile enough to handle any type of images.
|
||||
|
||||
This project is a *port* of my earlier work, an collection of [bash script](https://gitlab.com/sf-bashscripts/analogphotography), transitioning functionality to a more modular and maintainable design.
|
||||
This project replaces my earlier [analogphotography](https://gitlab.com/sf-bashscripts/analogphotography) bash script collection, which has now been archived in favor of OPTIMA-35.
|
||||
|
||||
**Please check** if a new branch is available and read the **changelog** to see the progress and current features of the program. The README might sometimes lag behind.
|
||||
|
||||
OPTIMA-35 is evolving! The project is transitioning from a terminal-based user interface (TUI) to a graphical user interface (GUI) using Qt (via PySide6). First TUI version was forked to [OPTIMA-35 TUI](https://gitlab.com/python_projects3802849/optima-35-tui). I intend to keep the TUI version functional since it is usefull for headless setup.
|
||||
|
||||
**GUI for OPTIMA-35 v0.3.4** with KvArcDark theme
|
||||
|
||||
*Last preview until GUI is finished.*
|
||||
**OPTIMA-35** is a cross-platform program. The **GUI** works on Linux and Windows (tested) and is expected to run on macOS. The **TUI** is currently Linux-only, as its dependency is exclusive to Linux.
|
||||
|
||||
|
||||
{width=40%}
|
||||
{width=40%}
|
||||
{width=40%}
|
||||
## **Current Status**
|
||||
**The README is temporarily outdated** while the GUI version is under development. For the latest updates, please check the **changelog**—I always maintain a detailed log of changes.
|
||||
## Current Status
|
||||
|
||||
### PLEASE NOTE
|
||||
The project is under active development. As a result:
|
||||
- The README may sometimes be outdated.
|
||||
- I encourage you to check for new branches and read the **CHANGELOG**, which is consistently updated and well-documented.
|
||||
- Bugs or unforeseen behavior may occur.
|
||||
|
||||
**OPTIMA-35** supports two modes: **GUI** and **TUI**.
|
||||
- The **GUI** is loaded by default if **PySide6** is available.
|
||||
- The **TUI** serves as a fallback when **PySide6** is unavailable or can be started explicitly using the `--tui` option with `main.py`.
|
||||
|
||||
While all features are implemented and functional, the designs of both the GUI and TUI are not yet finalized. Some safety checks are still under development.
|
||||
|
||||
|
||||
### Available Features:
|
||||
- Core features:
|
||||
- resizing
|
||||
- renaming
|
||||
- grayscale
|
||||
- Change brightness
|
||||
- Change contrast
|
||||
- Exif management
|
||||
- Add watermark
|
||||
|
||||
**Implemented Features:**
|
||||
- **Image Processing:**
|
||||
- Resizing
|
||||
- Renaming with order adjustment
|
||||
- Grayscale conversion
|
||||
- Brightness adjustment
|
||||
- Contrast adjustment
|
||||
- **EXIF Management:**
|
||||
- Copy EXIF data
|
||||
- Add custom EXIF information
|
||||
- Add GPS data
|
||||
- Add a date to EXIF
|
||||
- Remove EXIF
|
||||
- **Watermarking**
|
||||
|
||||
|
||||
### Preview GUI
|
||||
**GUI for OPTIMA-35** with KvArcDark theme on Linux
|
||||
|
||||
**Main windows**
|
||||
{width=40%}
|
||||
|
||||
**Exif tab when opened, settings disabled by default**
|
||||
{width=40%}
|
||||
|
||||
**Exif tab after enabeling own exif data**
|
||||
{width=40%}
|
||||
|
||||
**Dialog window to modify exif file without need to open yaml file**
|
||||
{width=40%}
|
||||
|
||||
### Preview TUI
|
||||
**asciinema recording for TUI**
|
||||
|
||||

|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
To run **OPTIMA-35**, the following Python libraries are required:
|
||||
**OPTIMA-35** has two modes: **GUI** and **TUI**. Each mode has its own set of dependencies, so you don’t need to install TUI dependencies if you only plan to use the GUI (and vice versa).
|
||||
|
||||
- **pyyaml**: To handle YAML files for configuration and settings.
|
||||
- **piexif**: To read, modify, and write EXIF metadata.
|
||||
- **Pillow**: For image processing.
|
||||
- **pyside6**: GUI
|
||||
**Required Dependencies:**
|
||||
- **pyyaml**: For handling YAML files (configuration and settings).
|
||||
- **piexif**: For reading, modifying, and writing EXIF metadata.
|
||||
- **pillow**: For image processing.
|
||||
- **pyside6**: For the GUI mode.
|
||||
- **simple_term_menu**: For the TUI mode.
|
||||
|
||||
### Installing Dependencies
|
||||
|
||||
You can install the dependencies using `pip`:
|
||||
You can install the dependencies using the respective requirements file for your desired mode (**TUI** or **GUI**).
|
||||
|
||||
Using `pip`:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
pip install -r requirements_gui.txt
|
||||
```
|
||||
|
||||
Alternatively, you can use `conda` or its alternatives (`anaconda`, `mamba`, `micromamba`):
|
||||
|
||||
Alternatively, if you use **conda** or its alternatives (**anaconda**, **mamba**, **micromamba**), run:
|
||||
```bash
|
||||
conda install -c conda-forge --file requirements.txt
|
||||
conda install -c conda-forge --file requirements_gui.txt
|
||||
```
|
||||
|
||||
# Use of LLMs
|
||||
|
|
|
@ -1,35 +1,34 @@
|
|||
# Example file
|
||||
artist:
|
||||
- Mr. Finchum
|
||||
- John Doe
|
||||
- Mr. Finchum
|
||||
- John Doe
|
||||
copyright_info:
|
||||
- All Rights Reserved
|
||||
- CC BY-NC 4.0
|
||||
- No Copyright
|
||||
- All Rights Reserved
|
||||
- CC BY-NC 4.0
|
||||
- No Copyright
|
||||
image_description:
|
||||
- ILFORD DELTA 3200
|
||||
- ILFORD ILFOCOLOR
|
||||
- LomoChrome Turquoise
|
||||
- Kodak 200
|
||||
- ILFORD DELTA 3200
|
||||
- ILFORD ILFOCOLOR
|
||||
- LomoChrome Turquoise
|
||||
- Kodak 200
|
||||
iso:
|
||||
- "100"
|
||||
- "200"
|
||||
- "400"
|
||||
- "800"
|
||||
- "1000"
|
||||
- "1600"
|
||||
- "3200"
|
||||
- '100'
|
||||
- '200'
|
||||
- '400'
|
||||
- '800'
|
||||
- '1000'
|
||||
- '1600'
|
||||
- '3200'
|
||||
lens:
|
||||
- Nikon LENS SERIES E 50mm
|
||||
- AF NIKKOR 35-70mm
|
||||
- Canon FD 50mm f/1.4 S.S.C
|
||||
- Nikon LENS SERIES E 50mm
|
||||
- AF NIKKOR 35-70mm
|
||||
- Canon FD 50mm f/1.4 S.S.C
|
||||
make:
|
||||
- Nikon
|
||||
- Canon
|
||||
- Nikon
|
||||
- Canon
|
||||
model:
|
||||
- FG
|
||||
- F50
|
||||
- AE-1
|
||||
- FG
|
||||
- F50
|
||||
- AE-1
|
||||
user_comment:
|
||||
- Scanner.NORITSU-KOKI
|
||||
- Scanner.NA
|
||||
- Scanner.NORITSU-KOKI
|
||||
- Scanner.NA
|
||||
|
|
275
gui.py
Normal file
275
gui.py
Normal file
|
@ -0,0 +1,275 @@
|
|||
import sys
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
from optima.optima35 import OPTIMA35
|
||||
from utils.utility import Utilities
|
||||
from ui.main_window import Ui_MainWindow
|
||||
from ui.exif_handler_window import ExifEditor
|
||||
|
||||
from PySide6 import QtWidgets
|
||||
from PySide6.QtWidgets import (
|
||||
QMessageBox,
|
||||
QApplication,
|
||||
QMainWindow,
|
||||
QWidget,
|
||||
QVBoxLayout,
|
||||
QLabel,
|
||||
QLineEdit,
|
||||
QPushButton,
|
||||
QCheckBox,
|
||||
QFileDialog,
|
||||
QHBoxLayout,
|
||||
QSpinBox,
|
||||
)
|
||||
|
||||
class Optima35GUI(QMainWindow, Ui_MainWindow):
|
||||
def __init__(self, exif_file):
|
||||
super(Optima35GUI, self).__init__()
|
||||
self.ui = Ui_MainWindow()
|
||||
self.ui.setupUi(self)
|
||||
self.o = OPTIMA35()
|
||||
self.u = Utilities()
|
||||
self.exif_file = exif_file
|
||||
self.exif_data = None
|
||||
|
||||
self.setWindowTitle(f"{self.o.name} {self.o.version}")
|
||||
self.default_ui_layout()
|
||||
self.define_gui_interaction()
|
||||
|
||||
if exif_file == "config/exif_example.yaml":
|
||||
self.change_statusbar("Using example exif...", 10000)
|
||||
|
||||
def default_ui_layout(self):
|
||||
self.ui.png_quality_spinBox.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.image_type.currentIndexChanged.connect(self.update_quality_options)
|
||||
|
||||
self.ui.exif_checkbox.stateChanged.connect(
|
||||
lambda state: self.handle_checkbox_state(state, 2, self.populate_exif)
|
||||
)
|
||||
self.ui.tabWidget.currentChanged.connect(self.on_tab_changed)
|
||||
self.ui.edit_exif_button.clicked.connect(self.open_exif_editor)
|
||||
self.ui.restart_button.clicked.connect(self.restart_app)
|
||||
|
||||
def process(self):
|
||||
#self.ui.start_button.setEnabled(False)
|
||||
#self.ui.restart_button.setEnabled(False)
|
||||
self.check_options() # Get all user selected data
|
||||
input_folder_valid = os.path.exists(self.o.settings["input_folder"])
|
||||
output_folder_valid = os.path.exists(self.o.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
|
||||
|
||||
input_folder = self.o.settings["input_folder"]
|
||||
output_folder = self.o.settings["output_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.o.settings["new_file_names"] != False:
|
||||
image_name = self.o.name_images(self.o.settings["new_file_names"], i, len(image_files), self.o.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(input_path, output_path)
|
||||
self.handle_qprogressbar(i, len(image_files))
|
||||
i += 1
|
||||
|
||||
QMessageBox.information(self, "Information", "Finished")
|
||||
#self.ui.start_button.setEnabled(True)
|
||||
#self.ui.restart_button.setEnabled(True)
|
||||
self.ui.progressBar.setValue(0)
|
||||
|
||||
def open_exif_editor(self):
|
||||
"""Open the EXIF Editor."""
|
||||
self.exif_editor = ExifEditor(self.exif_data)
|
||||
self.exif_editor.exif_data_updated.connect(self.update_exif_data)
|
||||
self.exif_editor.show()
|
||||
|
||||
def update_exif_data(self, updated_exif_data):
|
||||
"""Update the EXIF data."""
|
||||
self.exif_data = updated_exif_data
|
||||
self.populate_exif()
|
||||
|
||||
def handle_checkbox_state(self, state, desired_state, action):
|
||||
"""Perform an action based on the checkbox state and a desired state. Have to use lambda when calling."""
|
||||
if state == desired_state:
|
||||
action()
|
||||
|
||||
def on_tab_changed(self, index):
|
||||
"""Handle tab changes."""
|
||||
# chatgpt
|
||||
if index == 1: # EXIF Tab
|
||||
self.handle_exif_file("read")
|
||||
elif index == 0: # Main Tab
|
||||
self.handle_exif_file("write")
|
||||
|
||||
def handle_exif_file(self, do):
|
||||
if do == "read":
|
||||
self.exif_data = self.u.read_yaml(self.exif_file)
|
||||
elif do == "write":
|
||||
self.u.write_yaml(self.exif_file, self.exif_data)
|
||||
|
||||
def populate_exif(self):
|
||||
# partly chatGPT
|
||||
# Mapping of EXIF fields to comboboxes in the UI
|
||||
combo_mapping = {
|
||||
"make": self.ui.make_comboBox,
|
||||
"model": self.ui.model_comboBox,
|
||||
"lens": self.ui.lens_comboBox,
|
||||
"iso": self.ui.iso_comboBox,
|
||||
"image_description": self.ui.image_description_comboBox,
|
||||
"user_comment": self.ui.user_comment_comboBox,
|
||||
"artist": self.ui.artist_comboBox,
|
||||
"copyright_info": self.ui.copyright_info_comboBox,
|
||||
}
|
||||
self.populate_comboboxes(combo_mapping)
|
||||
|
||||
def populate_comboboxes(self, combo_mapping):
|
||||
"""Populate comboboxes with EXIF data."""
|
||||
# ChatGPT
|
||||
for field, comboBox in combo_mapping.items():
|
||||
comboBox.clear() # Clear existing items
|
||||
comboBox.addItems(map(str, self.exif_data.get(field, [])))
|
||||
|
||||
def update_quality_options(self):
|
||||
"""Update visibility of quality settings based on selected format."""
|
||||
# ChatGPT
|
||||
selected_format = self.ui.image_type.currentText()
|
||||
# Hide all quality settings
|
||||
self.ui.png_quality_spinBox.setVisible(False)
|
||||
self.ui.jpg_quality_spinBox.setVisible(False)
|
||||
# Show relevant settings
|
||||
if selected_format == "jpg":
|
||||
self.ui.jpg_quality_spinBox.setVisible(True)
|
||||
elif selected_format == "webp":
|
||||
self.ui.jpg_quality_spinBox.setVisible(True)
|
||||
elif selected_format == "png":
|
||||
self.ui.png_quality_spinBox.setVisible(True)
|
||||
|
||||
def browse_input_folder(self):
|
||||
folder = QFileDialog.getExistingDirectory(self, "Select Input Folder")
|
||||
if folder:
|
||||
self.ui.input_path.setText(folder)
|
||||
|
||||
def browse_output_folder(self):
|
||||
folder = QFileDialog.getExistingDirectory(self, "Select Output Folder")
|
||||
if folder:
|
||||
self.ui.output_path.setText(folder)
|
||||
|
||||
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 check_options(self):
|
||||
try:
|
||||
self.o.settings["input_folder"] = self.ui.input_path.text()
|
||||
self.o.settings["output_folder"] = self.ui.output_path.text()
|
||||
self.o.settings["file_format"] = self.ui.image_type.currentText()
|
||||
self.o.settings["jpg_quality"] = int(self.ui.jpg_quality_spinBox.text())
|
||||
self.o.settings["png_compression"] = int(self.ui.png_quality_spinBox.text())
|
||||
self.o.settings["invert_image_order"] = self.ui.revert_checkbox.isChecked()
|
||||
self.o.settings["grayscale"] = self.ui.grayscale_checkBox.isChecked()
|
||||
self.o.settings["copy_exif"] = self.ui.exif_copy_checkBox.isChecked()
|
||||
self.o.settings["own_exif"] = self.ui.exif_checkbox.isChecked()
|
||||
self.o.settings["font_size"] = self.ui.font_size_comboBox.currentIndex() + 1
|
||||
self.o.settings["optimize"] = self.ui.optimize_checkBox.isChecked()
|
||||
self.o.settings["own_date"] = self.ui.add_date_checkBox.isChecked()
|
||||
|
||||
if self.ui.resize_checkbox.isChecked():
|
||||
self.o.settings["resize"] = int(self.ui.resize_spinBox.text())
|
||||
|
||||
if self.ui.brightness_checkbox.isChecked():
|
||||
self.o.settings["brightness"] = int(self.ui.brightness_spinBox.text())
|
||||
|
||||
if self.ui.contrast_checkbox.isChecked():
|
||||
self.o.settings["contrast"] = int(self.ui.contrast_spinBox.text())
|
||||
|
||||
if self.ui.rename_checkbox.isChecked():
|
||||
if self.ui.filename.text() != "":
|
||||
self.o.settings["new_file_names"] = self.ui.filename.text()
|
||||
else:
|
||||
self.o.settings["new_file_names"] = False
|
||||
else:
|
||||
self.o.settings["new_file_names"] = False
|
||||
|
||||
|
||||
if self.ui.watermark_checkbox.isChecked():
|
||||
if self.ui.watermark_lineEdit.text() != "":
|
||||
self.o.settings["watermark"] = self.ui.watermark_lineEdit.text()
|
||||
else:
|
||||
self.o.settings["watermark"] = False
|
||||
else:
|
||||
self.o.settings["watermark"] = False
|
||||
|
||||
if self.o.settings["own_exif"]:
|
||||
self.o.selected_exif = self.collect_selected_exif()
|
||||
if self.ui.add_date_checkBox.isChecked():
|
||||
self.o.selected_exif["date_time_original"] = self.get_date()
|
||||
if self.ui.gps_checkBox.isChecked():
|
||||
self.o.settings["gps"] = [self.ui.lat_lineEdit.text(), self.ui.long_lineEdit.text()]
|
||||
else:
|
||||
self.o.settings["gps"] = False
|
||||
|
||||
except Exception as e:
|
||||
print(f"Whoops: {e}")
|
||||
|
||||
def get_date(self):
|
||||
date_input = self.ui.dateEdit.date().toString("yyyy-MM-dd")
|
||||
new_date = datetime.strptime(date_input, "%Y-%m-%d")
|
||||
return new_date.strftime("%Y:%m:%d 00:00:00")
|
||||
|
||||
def collect_selected_exif(self):
|
||||
user_data = {}
|
||||
user_data["make"] = self.ui.make_comboBox.currentText()
|
||||
user_data["model"] = self.ui.model_comboBox.currentText()
|
||||
user_data["lens"] = self.ui.lens_comboBox.currentText()
|
||||
user_data["iso"] = self.ui.iso_comboBox.currentText()
|
||||
user_data["image_description"] = self.ui.image_description_comboBox.currentText()
|
||||
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}"
|
||||
return user_data
|
||||
|
||||
def rebuild_ui(self):
|
||||
# Define the bash script to execute
|
||||
bash_script = "/home/sam/git/gitlab_public/optima-35/rebuild_ui.sh"
|
||||
os.system(bash_script)
|
||||
|
||||
def restart_app(self):
|
||||
"""Restarts the application."""
|
||||
self.rebuild_ui()
|
||||
# chatGPT
|
||||
python = sys.executable # Path to the Python interpreter
|
||||
os.execv(python, [python] + sys.argv)
|
||||
|
||||
def main(exif_file):
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
window = Optima35GUI(exif_file=exif_file)
|
||||
window.show()
|
||||
app.exec()
|
||||
|
||||
if __name__ == "__main__":
|
||||
if os.path.isfile("config/exif.yaml"):
|
||||
exif_file = "config/exif.yaml"
|
||||
print("Fall back to exif example file...")
|
||||
elif os.path.isfile("config/exif_example.yaml"):
|
||||
exif_file = "config/exif_example.yaml"
|
||||
else:
|
||||
print("Exif file missing, please ensure an exif file exist in config folder (exif.yaml, or exif_example_yaml)\nExiting...")
|
||||
exit()
|
||||
main(exif_file)
|
388
main.py
388
main.py
|
@ -1,361 +1,53 @@
|
|||
import sys
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
from utils.utility import Utilities
|
||||
from utils.image_handler import ImageProcessor, ExifHandler
|
||||
from argparse import ArgumentParser
|
||||
|
||||
from ui.main_window import Ui_MainWindow
|
||||
from ui.exif_handler_window import ExifEditor
|
||||
|
||||
from PySide6 import QtWidgets
|
||||
from PySide6.QtWidgets import (
|
||||
QMessageBox,
|
||||
QApplication,
|
||||
QMainWindow,
|
||||
QWidget,
|
||||
QVBoxLayout,
|
||||
QLabel,
|
||||
QLineEdit,
|
||||
QPushButton,
|
||||
QCheckBox,
|
||||
QFileDialog,
|
||||
QHBoxLayout,
|
||||
QSpinBox,
|
||||
)
|
||||
|
||||
class Optima35QT6(QMainWindow, Ui_MainWindow):
|
||||
def __init__(self, exif_file, version):
|
||||
super(Optima35QT6, self).__init__()
|
||||
self.ui = Ui_MainWindow()
|
||||
self.ui.setupUi(self)
|
||||
|
||||
self.define_settings(exif_file, version)
|
||||
self.setWindowTitle(f"{self.name} v{self.version}")
|
||||
self.default_ui_layout()
|
||||
self.define_gui_interaction()
|
||||
# GUI
|
||||
def default_ui_layout(self):
|
||||
self.ui.png_quality_spinBox.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.image_type.currentIndexChanged.connect(self.update_quality_options)
|
||||
|
||||
self.ui.exif_checkbox.stateChanged.connect(
|
||||
lambda state: self.handle_checkbox_state(state, 2, self.populate_exif)
|
||||
)
|
||||
|
||||
self.ui.tabWidget.currentChanged.connect(self.on_tab_changed)
|
||||
self.ui.edit_exif_button.clicked.connect(self.open_exif_editor)
|
||||
self.ui.restart_button.clicked.connect(self.restart_app)
|
||||
|
||||
def open_exif_editor(self):
|
||||
"""Open the EXIF Editor."""
|
||||
self.exif_editor = ExifEditor(self.exif_data)
|
||||
self.exif_editor.exif_data_updated.connect(self.update_exif_data)
|
||||
self.exif_editor.show()
|
||||
|
||||
def update_exif_data(self, updated_exif_data):
|
||||
"""Update the EXIF data."""
|
||||
self.exif_data = updated_exif_data
|
||||
self.populate_exif()
|
||||
|
||||
def handle_checkbox_state(self, state, desired_state, action):
|
||||
"""Perform an action based on the checkbox state and a desired state. Have to use lambda when calling."""
|
||||
# improved by chatGPT
|
||||
if state == desired_state:
|
||||
action()
|
||||
|
||||
def on_tab_changed(self, index):
|
||||
"""Handle tab changes."""
|
||||
# chatgpt
|
||||
if index == 1: # EXIF Tab
|
||||
self.handle_exif_file("read")
|
||||
elif index == 0: # Main Tab
|
||||
self.handle_exif_file("write")
|
||||
|
||||
def handle_exif_file(self, do):
|
||||
if do == "read":
|
||||
self.exif_data = self.utilities.read_yaml(self.exif_file)
|
||||
elif do == "write":
|
||||
self.utilities.write_yaml(self.exif_file, self.exif_data)
|
||||
|
||||
def populate_exif(self):
|
||||
# partly chatGPT
|
||||
# Mapping of EXIF fields to comboboxes in the UI
|
||||
combo_mapping = {
|
||||
"make": self.ui.make_comboBox,
|
||||
"model": self.ui.model_comboBox,
|
||||
"lens": self.ui.lens_comboBox,
|
||||
"iso": self.ui.iso_comboBox,
|
||||
"image_description": self.ui.image_description_comboBox,
|
||||
"user_comment": self.ui.user_comment_comboBox,
|
||||
"artist": self.ui.artist_comboBox,
|
||||
"copyright_info": self.ui.copyright_info_comboBox,
|
||||
}
|
||||
self.populate_comboboxes(combo_mapping)
|
||||
|
||||
def populate_comboboxes(self, combo_mapping):
|
||||
"""Populate comboboxes with EXIF data."""
|
||||
# ChatGPT
|
||||
for field, comboBox in combo_mapping.items():
|
||||
comboBox.clear() # Clear existing items
|
||||
comboBox.addItems(map(str, self.exif_data.get(field, [])))
|
||||
|
||||
def update_quality_options(self):
|
||||
"""Update visibility of quality settings based on selected format."""
|
||||
# ChatGPT
|
||||
selected_format = self.ui.image_type.currentText()
|
||||
# Hide all quality settings
|
||||
self.ui.png_quality_spinBox.setVisible(False)
|
||||
self.ui.jpg_quality_spinBox.setVisible(False)
|
||||
# Show relevant settings
|
||||
if selected_format == "jpg":
|
||||
self.ui.jpg_quality_spinBox.setVisible(True)
|
||||
elif selected_format == "webp":
|
||||
self.ui.jpg_quality_spinBox.setVisible(True)
|
||||
elif selected_format == "png":
|
||||
self.ui.png_quality_spinBox.setVisible(True)
|
||||
|
||||
def browse_input_folder(self):
|
||||
folder = QFileDialog.getExistingDirectory(self, "Select Input Folder")
|
||||
if folder:
|
||||
self.ui.input_path.setText(folder)
|
||||
|
||||
def browse_output_folder(self):
|
||||
folder = QFileDialog.getExistingDirectory(self, "Select Output Folder")
|
||||
if folder:
|
||||
self.ui.output_path.setText(folder)
|
||||
|
||||
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 check_options(self):
|
||||
# Mainly from ChatGPT
|
||||
def check_pyside_installed():
|
||||
try:
|
||||
self.settings["input_folder"] = self.ui.input_path.text()
|
||||
self.settings["output_folder"] = self.ui.output_path.text()
|
||||
self.settings["file_format"] = self.ui.image_type.currentText()
|
||||
self.settings["jpg_quality"] = int(self.ui.jpg_quality_spinBox.text())
|
||||
self.settings["png_compression"] = int(self.ui.png_quality_spinBox.text())
|
||||
self.settings["invert_image_order"] = self.ui.revert_checkbox.isChecked()
|
||||
self.settings["grayscale"] = self.ui.grayscale_checkBox.isChecked()
|
||||
self.settings["copy_exif"] = self.ui.exif_copy_checkBox.isChecked()
|
||||
self.settings["own_exif"] = self.ui.exif_checkbox.isChecked()
|
||||
self.settings["font_size"] = self.ui.font_size_comboBox.currentIndex() + 1
|
||||
self.settings["optimize"] = self.ui.optimize_checkBox.isChecked()
|
||||
self.settings["own_date"] = self.ui.add_date_checkBox.isChecked()
|
||||
import PySide6 # Replace with PySide2 if using that version
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
if self.ui.resize_checkbox.isChecked():
|
||||
self.settings["resize_percentage"] = int(self.ui.resize_spinBox.text())
|
||||
def start_gui():
|
||||
import gui
|
||||
gui.main(exif_file)
|
||||
|
||||
if self.ui.brightness_checkbox.isChecked():
|
||||
self.settings["brightness_percentage"] = int(self.ui.brightness_spinBox.text())
|
||||
def start_tui():
|
||||
import tui
|
||||
tui.main(exif_file, tui_settings_file)
|
||||
|
||||
if self.ui.contrast_checkbox.isChecked():
|
||||
self.settings["contrast_percentage"] = int(self.ui.contrast_spinBox.text())
|
||||
def main():
|
||||
parser = ArgumentParser(description="Start the Optima35 application.")
|
||||
parser.add_argument("--tui", action="store_true", help="Start in terminal UI mode.")
|
||||
args = parser.parse_args()
|
||||
|
||||
if self.ui.rename_checkbox.isChecked() and self.ui.filename.text() != "":
|
||||
self.settings["new_file_names"] = self.ui.filename.text()
|
||||
|
||||
if self.ui.watermark_checkbox.isChecked() and self.ui.watermark_lineEdit.text() != "":
|
||||
self.settings["watermark"] = self.ui.watermark_lineEdit.text()
|
||||
|
||||
if self.settings["own_exif"]:
|
||||
self.selected_exif = self.collect_selected_exif()
|
||||
if self.ui.add_date_checkBox.isChecked():
|
||||
self.selected_exif["date_time_original"] = self.get_date()
|
||||
if self.ui.gps_checkBox.isChecked():
|
||||
self.settings["gps"] = [self.ui.lat_lineEdit.text(), self.ui.long_lineEdit.text()]
|
||||
else:
|
||||
self.settings["gps"] = False
|
||||
|
||||
except Exception as e:
|
||||
print(f"Whoops: {e}")
|
||||
|
||||
def get_date(self):
|
||||
date_input = self.ui.dateEdit.date().toString("yyyy-MM-dd")
|
||||
new_date = datetime.strptime(date_input, "%Y-%m-%d")
|
||||
return new_date.strftime("%Y:%m:%d 00:00:00")
|
||||
|
||||
def collect_selected_exif(self):
|
||||
user_data = {}
|
||||
user_data["make"] = self.ui.make_comboBox.currentText()
|
||||
user_data["model"] = self.ui.model_comboBox.currentText()
|
||||
user_data["lens"] = self.ui.lens_comboBox.currentText()
|
||||
user_data["iso"] = self.ui.iso_comboBox.currentText()
|
||||
user_data["image_description"] = self.ui.image_description_comboBox.currentText()
|
||||
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"OPTIMA-35 {self.version}"
|
||||
return user_data
|
||||
|
||||
def rebuild_ui(self):
|
||||
# Define the bash script to execute
|
||||
print("Rebuild function disabled")
|
||||
return
|
||||
bash_script = "rebuild_ui.sh"
|
||||
os.system(bash_script)
|
||||
|
||||
def restart_app(self):
|
||||
"""Restarts the application."""
|
||||
self.rebuild_ui()
|
||||
# chatGPT
|
||||
python = sys.executable # Path to the Python interpreter
|
||||
os.execv(python, [python] + sys.argv)
|
||||
|
||||
# core
|
||||
def define_settings(self, exif_file, version):
|
||||
self.name = "OPTIMA-35"
|
||||
self.version = version
|
||||
self.utilities = Utilities()
|
||||
self.image_processor = ImageProcessor()
|
||||
self.exif_handler = ExifHandler()
|
||||
self.exif_file = exif_file
|
||||
self.settings = {
|
||||
"input_folder": None,
|
||||
"output_folder": None,
|
||||
"file_format": None,
|
||||
"resize_percentage": False,
|
||||
"contrast_percentage": False,
|
||||
"brightness_percentage": False,
|
||||
"new_file_names": False,
|
||||
"invert_image_order": False,
|
||||
"copy_exif": False,
|
||||
"own_exif": False,
|
||||
"watermark": False,
|
||||
"grayscale": False,
|
||||
"jpg_quality": None,
|
||||
"png_compression": None,
|
||||
"font_size": None,
|
||||
"optimize": False,
|
||||
"gps": False
|
||||
}
|
||||
self.exif_data = None
|
||||
|
||||
def modify_timestamp_in_exif(self, exif_data, filename):
|
||||
""""Takes exif data and adjust time to fit ending of filename."""
|
||||
try:
|
||||
last_tree = filename[-3:len(filename)]
|
||||
total_seconds = int(re.sub(r'\D+', '', last_tree))
|
||||
minutes = total_seconds // 60
|
||||
seconds = total_seconds % 60
|
||||
time = datetime.strptime(exif_data["date_time_original"], "%Y:%m:%d %H:%M:%S") # change date time string back to an time object for modification
|
||||
new_time = time.replace(hour=12, minute=minutes, second=seconds)
|
||||
exif_data["date_time_original"] = new_time.strftime("%Y:%m:%d %H:%M:%S")
|
||||
return exif_data
|
||||
|
||||
except ValueError:
|
||||
print("Modifying date went wrong, exiting...")
|
||||
exit()
|
||||
|
||||
def process(self):
|
||||
self.ui.start_button.setEnabled(False)
|
||||
self.ui.restart_button.setEnabled(False)
|
||||
self.check_options() # 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}...")
|
||||
if args.tui:
|
||||
print("Starting TUI...")
|
||||
start_tui()
|
||||
return
|
||||
|
||||
input_folder = self.settings["input_folder"]
|
||||
output_folder = self.settings["output_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.name_images(self.settings["new_file_names"], i, len(image_files), self.settings["invert_image_order"])
|
||||
# Check OS and start GUI if on Windows
|
||||
if os.name == "nt":
|
||||
print("Detected Windows. Starting GUI...")
|
||||
start_gui()
|
||||
else:
|
||||
image_name = os.path.splitext(image_file)[0]
|
||||
|
||||
output_path = os.path.join(output_folder, image_name)
|
||||
|
||||
with self.image_processor.open_image(input_path) as img:
|
||||
processed_img = img
|
||||
|
||||
if self.settings["resize_percentage"] != False:
|
||||
processed_img = self.image_processor.resize_image(
|
||||
image = processed_img, percent = self.settings["resize_percentage"]
|
||||
)
|
||||
if self.settings["watermark"] != False:
|
||||
processed_img = self.image_processor.add_watermark(processed_img, self.settings["watermark"], int(self.settings["font_size"]))
|
||||
if self.settings["grayscale"] != False: # There is a problem, if we first to grayscale and then watermark it braeks
|
||||
processed_img = self.image_processor.grayscale(processed_img)
|
||||
if self.settings["brightness_percentage"] != False: # Does the order of brightness and contrast matter?
|
||||
processed_img = self.image_processor.change_brightness(processed_img, self.settings["brightness_percentage"])
|
||||
if self.settings["contrast_percentage"] != False: # Does the order of brightness and contrast matter?
|
||||
processed_img = self.image_processor.change_contrast(processed_img, self.settings["contrast_percentage"])
|
||||
|
||||
if self.settings["own_exif"] != False:
|
||||
selected_exif = self.selected_exif
|
||||
if "date_time_original" in self.selected_exif:
|
||||
selected_exif = self.modify_timestamp_in_exif(selected_exif, image_name)
|
||||
exif_data = self.exif_handler.build_exif_dict(selected_exif, self.image_processor.get_image_size(processed_img))
|
||||
if self.settings["gps"] != False:
|
||||
latitude = float(self.settings["gps"][0])
|
||||
longitude = float(self.settings["gps"][1])
|
||||
exif_data = self.exif_handler.add_geolocation_to_exif(exif_data, latitude, longitude)
|
||||
|
||||
elif self.settings["copy_exif"] == True:
|
||||
# When copying exif from original, make sure to change Piexel X & Y Dimension to fit new size
|
||||
try:
|
||||
og_exif = self.exif_handler.get_exif_info(img)
|
||||
og_exif["Exif"][40962], og_exif["Exif"][40963] = self.image_processor.get_image_size(processed_img)
|
||||
exif_data = og_exif
|
||||
except Exception:
|
||||
# If an error happends it is because the picture does not have exif data
|
||||
self.change_statusbar("Copying EXIF data selected, but no EXIF data is available in the original image file.")
|
||||
exif_data = None
|
||||
elif self.settings["copy_exif"] == False:
|
||||
exif_data = None
|
||||
self.change_statusbar(f"exif data: {exif_data}")
|
||||
|
||||
self.image_processor.save_image(
|
||||
image = processed_img,
|
||||
path = output_path,
|
||||
exif_data = exif_data,
|
||||
file_type = self.settings["file_format"],
|
||||
jpg_quality = self.settings["jpg_quality"],
|
||||
png_compressing = self.settings["png_compression"],
|
||||
optimize = self.settings["optimize"]
|
||||
)
|
||||
|
||||
self.handle_qprogressbar(i, len(image_files))
|
||||
i += 1
|
||||
QMessageBox.information(self, "Information", "Finished")
|
||||
self.ui.start_button.setEnabled(True)
|
||||
self.ui.restart_button.setEnabled(True)
|
||||
self.ui.progressBar.setValue(0)
|
||||
|
||||
def name_images(self, base_name, current_image, total_images, invert):
|
||||
""""Returns name, combination of base_name and ending number."""
|
||||
total_digits = len(str(total_images))
|
||||
if invert:
|
||||
ending_number = total_images - (current_image - 1)
|
||||
# Non-Windows: Check if PySide is installed
|
||||
if check_pyside_installed():
|
||||
print("PySide detected. Starting GUI...")
|
||||
start_gui()
|
||||
else:
|
||||
ending_number = current_image
|
||||
ending = f"{ending_number:0{total_digits}}"
|
||||
return f"{base_name}_{ending}"
|
||||
print("PySide is not installed. Falling back to TUI...")
|
||||
start_tui()
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
|
||||
window = Optima35QT6(exif_file = "local_files/exif.yaml", version = "0.3.4")
|
||||
window.show()
|
||||
app.exec()
|
||||
if os.path.isfile("config/exif.yaml"):
|
||||
exif_file = "config/exif.yaml"
|
||||
elif os.path.isfile("config/exif_example.yaml"):
|
||||
exif_file = "config/exif_example.yaml"
|
||||
print("Fall back to exif example file...")
|
||||
else:
|
||||
print("Exif file missing, please ensure an exif file exist in config folder (exif.yaml, or exif_example_yaml)\nExiting...")
|
||||
exit()
|
||||
tui_settings_file = "config/tui_settings.yaml"
|
||||
main()
|
||||
|
|
372
media/demo_v041.cast
Normal file
372
media/demo_v041.cast
Normal file
|
@ -0,0 +1,372 @@
|
|||
{"version": 2, "width": 80, "height": 24, "timestamp": 1735643611, "env": {"SHELL": "/bin/zsh", "TERM": "xterm-256color"}}
|
||||
[0.677329, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
|
||||
[0.678152, "o", "\u001b]2;sam@potatohead:~/git/gitlab_public/optima-35\u0007\u001b]1;..lic/optima-35\u0007"]
|
||||
[0.680479, "o", "\u001b]7;file://potatohead/home/sam/git/gitlab_public/optima-35\u0007"]
|
||||
[0.743392, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[47m\u001b[38;5;30m \u001b[0m\u001b[38;5;30m\u001b[47m\u001b[47m\u001b[38;5;30m \u001b[0m\u001b[38;5;30m\u001b[47m\u001b[48;5;30m\u001b[37m\u001b[0m\u001b[37m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m \u001b[1m\u001b[38;5;254m\u001b[48;5;30m\u001b[38;5;255m~\u001b[0m\u001b[38;5;255m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m/\u001b[38;5;250mgi\u001b[0m\u001b[38;5;250m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m/\u001b[38;5;250mg\u001b[0m\u001b[38;5;250m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m/\u001b[1m\u001b[38;5;254m\u001b[48;5;30m\u001b[38;5;255moptima-35\u001b[0m\u001b[38;5;255m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m\u001b[0m\u001b[38;5;254m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m \u001b[0m\u001b[38;5;254m\u001b[48;5;30m\u001b[43m\u001b[38;5;30m\u001b[0m\u001b[38;5;30m\u001b[43m\u001b[43m\u001b[30m \u001b[30m feature/enhance-modularity \u001b[30m!5 \u001b[30m?2\u001b[0m\u001b[30m\u001b[43m\u001b[43m\u001b[30m \u001b[0m\u001b[30m\u001b[43m\u001b[49m\u001b[33m\u001b[0m\u001b[33m\u001b[49m\u001b[39m \u001b[0m\u001b[49m\u001b[39m\u001b[K\u001b[1C\u001b[0m\u001b[49m\u001b[30m\u001b[0m\u001b[30m\u001b[40m\u001b[32m \u001b[0m\u001b[32m\u001b[40m\u001b[40m\u001b[32m✔\u001b[0m\u001b[32m\u001b[40m\u001b[40m\u001b[32m \u001b[0m\u001b[32m\u001b[40m\u001b[40m\u001b[32m\u001b[34m\u001b[0m\u001b[34m\u001b[40m\u001b[44m\u001b[30m base\u001b[0m\u001b[30m\u001b[44m\u001b[44m\u001b[30m \u001b[0m\u001b[30m\u001b[44m\u001b[44m\u001b[30m \u001b[0m\u001b[30m\u001b[44m\u001b[49m\u001b[39m\u001b[14D"]
|
||||
[0.744052, "o", "\u001b[?2004h"]
|
||||
[1.448961, "o", "m\u001b[K"]
|
||||
[1.45588, "o", "\b\u001b[4mm\u001b[24m"]
|
||||
[1.456369, "o", "\b\u001b[4mm\u001b[24m\u001b[38;5;244micromamba acti\u001b[38;5;244mv\u001b[38;5;244mate optima35\u001b[39m\u001b[K\u001b[A\u001b[53C"]
|
||||
[1.524001, "o", "\b\u001b[4mm\u001b[39m\u001b[4mi\u001b[24m"]
|
||||
[1.538941, "o", "\b\b\u001b[24m\u001b[1m\u001b[31mm\u001b[24m\u001b[1m\u001b[31mi\u001b[0m\u001b[39m"]
|
||||
[1.64567, "o", "\b\b\u001b[1m\u001b[31mm\u001b[1m\u001b[31mi\u001b[1m\u001b[31mc\u001b[0m\u001b[39m"]
|
||||
[1.823061, "o", "\b\u001b[1m\u001b[31mc\u001b[1m\u001b[31mr\u001b[0m\u001b[39m"]
|
||||
[1.936561, "o", "\b\u001b[1m\u001b[31mr\u001b[1m\u001b[31mo\u001b[0m\u001b[39m"]
|
||||
[1.941248, "o", "\b\b\b\b\b\u001b[0m\u001b[32mm\u001b[0m\u001b[32mi\u001b[0m\u001b[32mc\u001b[0m\u001b[32mr\u001b[0m\u001b[32mo\u001b[39m"]
|
||||
[2.275468, "o", "\u001b[39mm\u001b[39ma\u001b[39mm\u001b[39mb\u001b[39ma\u001b[39m \u001b[39ma\u001b[39mc\u001b[39mt\u001b[39miv\u001b[39ma\u001b[39mt\u001b[39me\u001b[39m \u001b[39mo\u001b[39mp\u001b[39mt\u001b[39mi\u001b[39mm\u001b[39ma\u001b[39m3\u001b[39m5"]
|
||||
[2.283536, "o", "\u001b[A\u001b[56C\u001b[32mo\u001b[32mm\u001b[32ma\u001b[32mm\u001b[32mb\u001b[32ma\u001b[39m\u001b[1B\u001b[62D"]
|
||||
[2.684344, "o", "\u001b[?2004l\r\r\n"]
|
||||
[2.686472, "o", "\u001b]2;micromamba activate optima35\u0007\u001b]1;\u0007"]
|
||||
[2.719122, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
|
||||
[2.719308, "o", "\u001b]2;sam@potatohead:~/git/gitlab_public/optima-35\u0007\u001b]1;..lic/optima-35\u0007"]
|
||||
[2.722384, "o", "\u001b]7;file://potatohead/home/sam/git/gitlab_public/optima-35\u0007"]
|
||||
[2.8234, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[47m\u001b[38;5;30m \u001b[0m\u001b[38;5;30m\u001b[47m\u001b[47m\u001b[38;5;30m \u001b[0m\u001b[38;5;30m\u001b[47m\u001b[48;5;30m\u001b[37m\u001b[0m\u001b[37m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m \u001b[1m\u001b[38;5;254m\u001b[48;5;30m\u001b[38;5;255m~\u001b[0m\u001b[38;5;255m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m/\u001b[38;5;250mgi\u001b[0m\u001b[38;5;250m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m/\u001b[38;5;250mg\u001b[0m\u001b[38;5;250m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m/\u001b[1m\u001b[38;5;254m\u001b[48;5;30m\u001b[38;5;255moptima-35\u001b[0m\u001b[38;5;255m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m\u001b[0m\u001b[38;5;254m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m \u001b[0m\u001b[38;5;254m\u001b[48;5;30m\u001b[43m\u001b[38;5;30m\u001b[0m\u001b[38;5;30m\u001b[43m\u001b[43m\u001b[30m \u001b[30m feature/enhance-modularity \u001b[30m!5 \u001b[30m?2\u001b[0m\u001b[30m\u001b[43m\u001b[43m\u001b[30m \u001b[0m\u001b[30m\u001b[43m\u001b[49m\u001b[33m\u001b[0m\u001b[33m\u001b[49m\u001b[39m \u001b[0m\u001b[49m\u001b[39m\u001b[K"]
|
||||
[2.824436, "o", "\u001b[?2004h"]
|
||||
[3.546197, "o", "p"]
|
||||
[3.552859, "o", "\b\u001b[1m\u001b[31mp\u001b[0m\u001b[39m"]
|
||||
[3.553263, "o", "\b\u001b[1m\u001b[31mp\u001b[0m\u001b[39m\u001b[38;5;244myside6-uic ui/\u001b[38;5;244mm\u001b[38;5;244main_window.ui -o ui/main_window.py \u001b[39m\u001b[K\u001b[A\u001b[30C"]
|
||||
[3.775027, "o", "\b\u001b[1m\u001b[31mp\u001b[1m\u001b[31my\u001b[0m\u001b[39m"]
|
||||
[3.978262, "o", "\b\b\u001b[1m\u001b[31mp\u001b[1m\u001b[31my\u001b[1m\u001b[31mt\u001b[0m\u001b[39m\u001b[K\u001b[1B\r\u001b[K\u001b[A\u001b[68C"]
|
||||
[3.996697, "o", "\u001b[38;5;244mhon main.py\u001b[39m\u001b[11D"]
|
||||
[4.104095, "o", "\b\u001b[1m\u001b[31mt\u001b[1m\u001b[31mh\u001b[0m\u001b[39m"]
|
||||
[4.51609, "o", "\b\u001b[1m\u001b[31mh\u001b[1m\u001b[31mo\u001b[0m\u001b[39m"]
|
||||
[4.898228, "o", "\u001b[39mn\u001b[39m \u001b[39mm\u001b[39ma\u001b[39mi\u001b[39mn\u001b[39m.\u001b[39mp\u001b[39my"]
|
||||
[4.916302, "o", "\u001b[14D\u001b[0m\u001b[32mp\u001b[0m\u001b[32my\u001b[0m\u001b[32mt\u001b[0m\u001b[32mh\u001b[0m\u001b[32mo\u001b[32mn\u001b[39m \u001b[4mm\u001b[4ma\u001b[4mi\u001b[4mn\u001b[4m.\u001b[4mp\u001b[4my\u001b[24m"]
|
||||
[5.403027, "o", "\b\u001b[4my\u001b[4m \u001b[24m \r\u001b[K"]
|
||||
[5.409587, "o", "\u001b[A\u001b[78C\u001b[4my\u001b[24m\u001b[24m \u001b[K\r"]
|
||||
[5.40996, "o", "\u001b[38;5;244m-\u001b[38;5;244m-\u001b[38;5;244mt\u001b[38;5;244mu\u001b[38;5;244mi\u001b[39m\r"]
|
||||
[5.601688, "o", "\u001b[39m-"]
|
||||
[5.722974, "o", "\r-\u001b[39m-"]
|
||||
[6.026401, "o", "\u001b[39mt"]
|
||||
[6.161384, "o", "\u001b[39mu"]
|
||||
[6.217467, "o", "\u001b[39mi"]
|
||||
[6.589968, "o", "\u001b[?2004l\r\r\n"]
|
||||
[6.59058, "o", "\u001b]2;python main.py --tui\u0007\u001b]1;\u0007"]
|
||||
[6.617562, "o", "Fall back to exif example file...\r\n"]
|
||||
[6.622191, "o", "Starting TUI...\r\n"]
|
||||
[6.716642, "o", "Settings file empty.\r\nNo settings found...\r\nAsking for new settings...\r\n\r\nDefault resize percentage (below 100 downscale, above upscale): "]
|
||||
[9.164618, "o", "8"]
|
||||
[9.248071, "o", "0"]
|
||||
[9.743554, "o", "\r\n"]
|
||||
[9.743735, "o", "Default contrast percentage (negative = decrease, positive = increase): "]
|
||||
[10.78209, "o", "1"]
|
||||
[10.867213, "o", "0"]
|
||||
[11.206582, "o", "\r\n"]
|
||||
[11.206816, "o", "Default brighness percentage (negative = decrease, positive = increase): "]
|
||||
[11.714352, "o", "-"]
|
||||
[12.073169, "o", "1"]
|
||||
[12.167016, "o", "0"]
|
||||
[12.597502, "o", "\r\n"]
|
||||
[12.597744, "o", "JPEG quality (1-100, 80 default): "]
|
||||
[13.650373, "o", "8"]
|
||||
[13.712797, "o", "0"]
|
||||
[13.941506, "o", "\r\n"]
|
||||
[13.941706, "o", "PNG compression level (0-9, 6 default): "]
|
||||
[14.539469, "o", "6"]
|
||||
[14.796779, "o", "\r\n"]
|
||||
[14.938909, "o", "\u001b[?1h\u001b=\u001b[?25l\r\n"]
|
||||
[14.942831, "o", "\u001b[A\rOptimize images i.e. compressing? \r\n\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b[34my\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \u001b(B\u001b[m\u001b[47m\u001b[30myes\u001b(B\u001b[m \r\n"]
|
||||
[14.943016, "o", "\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b[34mn\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m no \r\u001b[A"]
|
||||
[14.946002, "o", "\u001b(B\u001b[m\u001b[31m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\u001b[A"]
|
||||
[15.919041, "o", "\u001b[A\u001b[M\u001b[M\u001b[M\u001b[?12l\u001b[?25h\u001b[?1l\u001b>"]
|
||||
[15.922308, "o", "New settings saved successfully.\r\nEnter path of input folder: "]
|
||||
[17.083508, "o", "o"]
|
||||
[17.413375, "o", "\b \b"]
|
||||
[17.597213, "o", "l"]
|
||||
[17.763659, "o", "o"]
|
||||
[17.829166, "o", "c"]
|
||||
[17.907582, "o", "a"]
|
||||
[18.018695, "o", "l"]
|
||||
[18.219882, "o", "_"]
|
||||
[18.597998, "o", "f"]
|
||||
[18.684139, "o", "i"]
|
||||
[18.854542, "o", "l"]
|
||||
[18.910718, "o", "e"]
|
||||
[19.116207, "o", "s"]
|
||||
[19.29677, "o", "/"]
|
||||
[19.606841, "o", "i"]
|
||||
[19.67462, "o", "m"]
|
||||
[19.7635, "o", "g"]
|
||||
[19.92206, "o", "\r\n"]
|
||||
[19.922244, "o", "Enter path of output folder: "]
|
||||
[20.173606, "o", "l"]
|
||||
[20.321372, "o", "o"]
|
||||
[20.383433, "o", "c"]
|
||||
[20.463172, "o", "a"]
|
||||
[20.555845, "o", "l"]
|
||||
[20.752791, "o", "_"]
|
||||
[20.975923, "o", "f"]
|
||||
[21.051336, "o", "i"]
|
||||
[21.212242, "o", "l"]
|
||||
[21.277781, "o", "e"]
|
||||
[21.473246, "o", "s"]
|
||||
[21.804064, "o", "/"]
|
||||
[22.106301, "o", "o"]
|
||||
[22.201691, "o", "u"]
|
||||
[22.269246, "o", "t"]
|
||||
[22.601648, "o", "\r\n"]
|
||||
[22.601885, "o", "Enter export file format (jpg, png, webp): "]
|
||||
[24.083726, "o", "j"]
|
||||
[24.127736, "o", "p"]
|
||||
[24.264589, "o", "g"]
|
||||
[24.57916, "o", "\r\n"]
|
||||
[24.598678, "o", "\u001b[?1h\u001b=\u001b[?25l\r\n\r\n\r\n"]
|
||||
[24.607614, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mResize image\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n"]
|
||||
[24.607794, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n"]
|
||||
[24.608348, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[24.616611, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r"]
|
||||
[24.616839, "o", "\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\r\n \r"]
|
||||
[24.617428, "o", "\r\n \r\r\n \r\r\n \r"]
|
||||
[24.619314, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C"]
|
||||
[24.619478, "o", "\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[26.660369, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mChange EXIF\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n"]
|
||||
[26.660559, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n"]
|
||||
[26.66109, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[26.6667, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r"]
|
||||
[26.666875, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[26.789333, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mConvert to grayscale\u001b(B\u001b[m \r\n"]
|
||||
[26.789529, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n"]
|
||||
[26.789664, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[26.797578, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r"]
|
||||
[26.798309, "o", "\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r"]
|
||||
[26.798751, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[26.929884, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n"]
|
||||
[26.930073, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mChange contrast\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n"]
|
||||
[26.930199, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[26.937997, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"]
|
||||
[26.938647, "o", "\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\r\n \r"]
|
||||
[26.939112, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[27.212356, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n"]
|
||||
[27.212564, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mChange brightness\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[27.22141, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"]
|
||||
[27.221766, "o", "\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r"]
|
||||
[27.221985, "o", "\r\n \r\r\n \r"]
|
||||
[27.222796, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[27.344641, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n"]
|
||||
[27.345282, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mRename images\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n"]
|
||||
[27.345758, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[27.354429, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r"]
|
||||
[27.35514, "o", "\r\n \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[27.616497, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n"]
|
||||
[27.616697, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mInvert image order\u001b(B\u001b[m \r\n"]
|
||||
[27.617352, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[27.623229, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r"]
|
||||
[27.623463, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[27.778389, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n"]
|
||||
[27.778648, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n"]
|
||||
[27.779389, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mAdd Watermark\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[27.787995, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"]
|
||||
[27.788617, "o", "\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r"]
|
||||
[27.788866, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n"]
|
||||
[27.789448, "o", "\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[28.089642, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n"]
|
||||
[28.089921, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n"]
|
||||
[28.090473, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n"]
|
||||
[28.09084, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mAdd Watermark\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[28.096658, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"]
|
||||
[28.096769, "o", "\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r"]
|
||||
[28.096929, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[28.244958, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n"]
|
||||
[28.245236, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n"]
|
||||
[28.245441, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n"]
|
||||
[28.246239, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mInvert image order\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[28.254857, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"]
|
||||
[28.255412, "o", "\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n"]
|
||||
[28.255651, "o", " \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n"]
|
||||
[28.255861, "o", "\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n"]
|
||||
[28.256065, "o", "\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[28.538276, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n"]
|
||||
[28.53847, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mRename images\u001b(B\u001b[m \r\n"]
|
||||
[28.539087, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[28.547915, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"]
|
||||
[28.54851, "o", "\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r"]
|
||||
[28.549125, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C"]
|
||||
[28.549609, "o", "\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[28.635635, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n"]
|
||||
[28.636112, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mRename images\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[28.645078, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"]
|
||||
[28.645679, "o", "\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r"]
|
||||
[28.646141, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C"]
|
||||
[28.646396, "o", "\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[29.060214, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n"]
|
||||
[29.060392, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n"]
|
||||
[29.060994, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mInvert image order\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[29.066936, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r"]
|
||||
[29.06701, "o", "\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n"]
|
||||
[29.06705, "o", " \r"]
|
||||
[29.067299, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[29.305548, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n"]
|
||||
[29.305754, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mInvert image order\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[29.314491, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r"]
|
||||
[29.314678, "o", "\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r"]
|
||||
[29.315449, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[29.476124, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n"]
|
||||
[29.476376, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n"]
|
||||
[29.476945, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n"]
|
||||
[29.477451, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mRename images\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[29.485916, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"]
|
||||
[29.486211, "o", "\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n"]
|
||||
[29.48687, "o", " \r"]
|
||||
[29.487248, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[29.645362, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n"]
|
||||
[29.645617, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n"]
|
||||
[29.646303, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mChange brightness\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[29.655419, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"]
|
||||
[29.655923, "o", "\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r"]
|
||||
[29.656398, "o", "\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r"]
|
||||
[29.656619, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n"]
|
||||
[29.656796, "o", "\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[29.832918, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n"]
|
||||
[29.83311, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mChange brightness\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[29.842077, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"]
|
||||
[29.842286, "o", "\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r"]
|
||||
[29.842422, "o", "\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n"]
|
||||
[29.842576, "o", " \r\r\n \r\r\n \r"]
|
||||
[29.843329, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n"]
|
||||
[29.843799, "o", "\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[29.976699, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n"]
|
||||
[29.976948, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mChange contrast\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[29.985854, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r"]
|
||||
[29.98636, "o", "\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\r\n \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n"]
|
||||
[29.986765, "o", "\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[30.109772, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n"]
|
||||
[30.109978, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mChange contrast\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[30.118884, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r"]
|
||||
[30.119119, "o", "\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\r\n \r"]
|
||||
[30.119814, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[30.230951, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n"]
|
||||
[30.231215, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mConvert to grayscale\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n"]
|
||||
[30.231425, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n"]
|
||||
[30.231688, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[30.240842, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"]
|
||||
[30.241119, "o", "\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r"]
|
||||
[30.241323, "o", "\r\n \r\r\n \r"]
|
||||
[30.242531, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[30.360245, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n"]
|
||||
[30.360539, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mConvert to grayscale\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n"]
|
||||
[30.360826, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[30.36533, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n \r\r\n"]
|
||||
[30.365472, "o", "\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r"]
|
||||
[30.365943, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[30.50115, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n"]
|
||||
[30.501599, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mChange EXIF\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n"]
|
||||
[30.502022, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[30.510559, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r"]
|
||||
[30.510805, "o", "\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n"]
|
||||
[30.510971, "o", " \r\r\n \r\r\n \r\r\n \r\r\n \r"]
|
||||
[30.511911, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[30.685517, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CResize image \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mChange EXIF\u001b(B\u001b[m \r\n"]
|
||||
[30.685758, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n"]
|
||||
[30.685952, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[30.694848, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r"]
|
||||
[30.695365, "o", "\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r"]
|
||||
[30.695848, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C"]
|
||||
[30.696368, "o", "\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[30.83141, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mResize image\u001b(B\u001b[m \r\n"]
|
||||
[30.831678, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n"]
|
||||
[30.831884, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n"]
|
||||
[30.832089, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n"]
|
||||
[30.832289, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[30.84096, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r"]
|
||||
[30.84152, "o", "\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m \u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n"]
|
||||
[30.841772, "o", "\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n"]
|
||||
[30.841971, "o", "\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[31.156421, "o", "\u001b[A\u001b[A\u001b[A\r \r\nOPTIMA-35 v.0.4.1 \r\nSelect what you want to do (esc or q to exit) \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mResize image\u001b(B\u001b[m \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange EXIF \r\n"]
|
||||
[31.156634, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CConvert to grayscale \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange contrast \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CChange brightness \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CRename images \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CInvert image order \r\n\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[CAdd Watermark \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[31.163125, "o", "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b(B\u001b[m\u001b[33m\u001b[40m\rPress <space>, <tab> for multi-selection and <enter> to select and accept \r\u001b(B\u001b[m\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\r\n"]
|
||||
[31.163206, "o", " \r\r\n \r"]
|
||||
[31.163253, "o", "\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C"]
|
||||
[31.163314, "o", "\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\n"]
|
||||
[31.16336, "o", "\r\u001b[C\u001b[C\u001b(B\u001b[m\u001b[37m[\u001b(B\u001b[m\u001b(B\u001b[m\u001b[33m\u001b[1m*\u001b(B\u001b[m\u001b(B\u001b[m\u001b[37m]\u001b(B\u001b[m \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[31.51079, "o", "\u001b[A\u001b[A\u001b[A\u001b[M\u001b[M\u001b[M\u001b[M\u001b[M\u001b[M\u001b[M\u001b[M\u001b[M\u001b[M\u001b[M\u001b[M\u001b[?12l\u001b[?25h\u001b[?1l\u001b>"]
|
||||
[31.510988, "o", "What should be the name for the new images? "]
|
||||
[33.593907, "o", "e"]
|
||||
[33.888461, "o", "\b \b"]
|
||||
[33.989013, "o", "d"]
|
||||
[34.134175, "o", "e"]
|
||||
[34.173323, "o", "m"]
|
||||
[34.24098, "o", "o"]
|
||||
[34.728246, "o", "\r\n"]
|
||||
[34.728423, "o", "Enter text for watermark. "]
|
||||
[35.633165, "o", "D"]
|
||||
[35.803621, "o", "e"]
|
||||
[35.845136, "o", "m"]
|
||||
[35.914241, "o", "o"]
|
||||
[36.168864, "o", " "]
|
||||
[36.853512, "o", "\b \b"]
|
||||
[37.105764, "o", "\r\n"]
|
||||
[37.12281, "o", "\u001b[?1h\u001b=\u001b[?25l\r\n"]
|
||||
[37.130101, "o", "\u001b[A\rEnter Make \r\n\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mNikon\u001b(B\u001b[m \r\n"]
|
||||
[37.130252, "o", "\u001b[C\u001b[CCanon \r\u001b[A"]
|
||||
[37.137636, "o", "\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\u001b[A"]
|
||||
[38.366811, "o", "\u001b[A\u001b[M\u001b[M\u001b[M\u001b[?12l\u001b[?25h\u001b[?1l\u001b>"]
|
||||
[38.377981, "o", "\u001b[?1h\u001b=\u001b[?25l\r\n"]
|
||||
[38.38132, "o", "\u001b[A\rEnter Model \r\n\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mFG\u001b(B\u001b[m \r\n\u001b[C\u001b[CF50 \r\n\u001b[C\u001b[CAE-1 \r\u001b[A\u001b[A"]
|
||||
[38.384958, "o", "\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\u001b[A\u001b[A"]
|
||||
[38.874015, "o", "\u001b[A\u001b[M\u001b[M\u001b[M\u001b[M"]
|
||||
[38.874229, "o", "\u001b[?12l\u001b[?25h\u001b[?1l\u001b>"]
|
||||
[38.886354, "o", "\u001b[?1h\u001b=\u001b[?25l\r\n"]
|
||||
[38.889292, "o", "\u001b[A\rEnter Lens \r\n\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mNikon LENS SERIES E 50mm\u001b(B\u001b[m \r\n\u001b[C\u001b[CAF NIKKOR 35-70mm \r\n"]
|
||||
[38.889375, "o", "\u001b[C\u001b[CCanon FD 50mm f/1.4 S.S.C \r\u001b[A\u001b[A"]
|
||||
[38.892151, "o", "\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\u001b[A\u001b[A"]
|
||||
[39.594436, "o", "\u001b[A\u001b[M\u001b[M\u001b[M\u001b[M\u001b[?12l\u001b[?25h\u001b[?1l\u001b>"]
|
||||
[39.60723, "o", "\u001b[?1h\u001b=\u001b[?25l\r\n"]
|
||||
[39.610311, "o", "\u001b[A\rEnter Iso \r\n\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30m100\u001b(B\u001b[m \r\n\u001b[C\u001b[C200 \r\n"]
|
||||
[39.610499, "o", "\u001b[C\u001b[C400 \r\n\u001b[C\u001b[C800 \r\n\u001b[C\u001b[C1000 \r\n\u001b[C\u001b[C1600 \r\n\u001b[C\u001b[C3200 \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[39.613514, "o", "\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\r\n \r"]
|
||||
[39.613654, "o", "\r\n \r\r\n \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[40.285396, "o", "\u001b[A\rEnter Iso \r\n\u001b[C\u001b[C100 \r\n\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30m200\u001b(B\u001b[m \r\n\u001b[C\u001b[C400 \r\n\u001b[C\u001b[C800 \r\n"]
|
||||
[40.285634, "o", "\u001b[C\u001b[C1000 \r\n\u001b[C\u001b[C1600 \r\n\u001b[C\u001b[C3200 \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[40.290088, "o", " \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\r\n \r\r\n \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[40.486366, "o", "\u001b[A\rEnter Iso \r\n\u001b[C\u001b[C100 \r\n\u001b[C\u001b[C200 \r\n"]
|
||||
[40.486584, "o", "\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30m400\u001b(B\u001b[m \r\n\u001b[C\u001b[C800 \r\n\u001b[C\u001b[C1000 \r\n\u001b[C\u001b[C1600 \r\n\u001b[C\u001b[C3200 \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[40.49292, "o", " \r\r\n \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\r\n \r\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A\u001b[A"]
|
||||
[41.095691, "o", "\u001b[A\u001b[M\u001b[M\u001b[M\u001b[M\u001b[M\u001b[M\u001b[M\u001b[M\u001b[?12l\u001b[?25h\u001b[?1l\u001b>"]
|
||||
[41.107748, "o", "\u001b[?1h\u001b=\u001b[?25l\r\n"]
|
||||
[41.11136, "o", "\u001b[A\rEnter Image Description \r\n\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mILFORD DELTA 3200\u001b(B\u001b[m \r\n\u001b[C\u001b[CILFORD ILFOCOLOR \r\n\u001b[C\u001b[CLomoChrome Turquoise \r\n\u001b[C\u001b[CKodak 200 \r\u001b[A\u001b[A\u001b[A"]
|
||||
[41.115136, "o", "\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\r\n \r\u001b[A\u001b[A\u001b[A"]
|
||||
[42.008703, "o", "\u001b[A\rEnter Image Description \r\n\u001b[C\u001b[CILFORD DELTA 3200 \r\n\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mILFORD ILFOCOLOR\u001b(B\u001b[m \r\n"]
|
||||
[42.008925, "o", "\u001b[C\u001b[CLomoChrome Turquoise \r\n\u001b[C\u001b[CKodak 200 \r\u001b[A\u001b[A\u001b[A"]
|
||||
[42.015056, "o", " \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\u001b[A\u001b[A\u001b[A"]
|
||||
[42.414356, "o", "\u001b[A\u001b[M\u001b[M\u001b[M\u001b[M\u001b[M\u001b[?12l\u001b[?25h\u001b[?1l\u001b>"]
|
||||
[42.431029, "o", "\u001b[?1h\u001b=\u001b[?25l\r\n"]
|
||||
[42.43832, "o", "\u001b[A\rEnter User Comment \r\n\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mScanner.NORITSU-KOKI\u001b(B\u001b[m \r\n"]
|
||||
[42.438554, "o", "\u001b[C\u001b[CScanner.NA \r\u001b[A"]
|
||||
[42.445809, "o", "\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\u001b[A"]
|
||||
[43.147181, "o", "\u001b[A\u001b[M\u001b[M\u001b[M\u001b[?12l\u001b[?25h\u001b[?1l\u001b>"]
|
||||
[43.1585, "o", "\u001b[?1h\u001b=\u001b[?25l\r\n"]
|
||||
[43.161793, "o", "\u001b[A\rEnter Artist \r\n\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mMr. Finchum\u001b(B\u001b[m \r\n"]
|
||||
[43.16201, "o", "\u001b[C\u001b[CJohn Doe \r\u001b[A"]
|
||||
[43.16618, "o", "\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\u001b[A"]
|
||||
[43.620173, "o", "\u001b[A\u001b[M\u001b[M\u001b[M\u001b[?12l\u001b[?25h\u001b[?1l\u001b>"]
|
||||
[43.631543, "o", "\u001b[?1h\u001b=\u001b[?25l\r\n"]
|
||||
[43.63482, "o", "\u001b[A\rEnter Copyright Info \r\n\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mAll Rights Reserved\u001b(B\u001b[m \r\n\u001b[C\u001b[CCC BY-NC 4.0 \r\n\u001b[C\u001b[CNo Copyright \r\u001b[A\u001b[A"]
|
||||
[43.638191, "o", "\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\r\n \r\u001b[A\u001b[A"]
|
||||
[44.39754, "o", "\u001b[A\rEnter Copyright Info \r\n\u001b[C\u001b[CAll Rights Reserved \r\n"]
|
||||
[44.397768, "o", "\u001b[C\u001b[C\u001b(B\u001b[m\u001b[47m\u001b[30mCC BY-NC 4.0\u001b(B\u001b[m \r\n\u001b[C\u001b[CNo Copyright \r\u001b[A\u001b[A"]
|
||||
[44.404144, "o", " \r\r\n\u001b(B\u001b[m\u001b[37m\u001b[1m> \u001b(B\u001b[m\r\r\n \r\u001b[A\u001b[A"]
|
||||
[44.707673, "o", "\u001b[A\u001b[M\u001b[M\u001b[M\u001b[M"]
|
||||
[44.707849, "o", "\u001b[?12l\u001b[?25h\u001b[?1l\u001b>Enter a date (yyyy-mm-dd): "]
|
||||
[45.955851, "o", "2"]
|
||||
[46.054154, "o", "0"]
|
||||
[46.404177, "o", "2"]
|
||||
[46.497714, "o", "4"]
|
||||
[47.123881, "o", "-"]
|
||||
[47.416185, "o", "1"]
|
||||
[47.489983, "o", "2"]
|
||||
[47.757033, "o", "-"]
|
||||
[48.21329, "o", "3"]
|
||||
[48.282472, "o", "1"]
|
||||
[49.029909, "o", "\r\n"]
|
||||
[49.036256, "o", "Enter Latitude (xx.xxxxxx): "]
|
||||
[49.59262, "o", "\r\n"]
|
||||
[49.773864, "o", "1|------------> |4\r"]
|
||||
[49.844145, "o", "2|-------------------------> |4\r"]
|
||||
[49.917126, "o", "3|-------------------------------------> |4\r"]
|
||||
[49.992149, "o", "4|-------------------------------------------------->|4\r\r\nDone\r\n"]
|
||||
[50.012799, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
|
||||
[50.013073, "o", "\u001b]2;sam@potatohead:~/git/gitlab_public/optima-35\u0007\u001b]1;..lic/optima-35\u0007"]
|
||||
[50.016341, "o", "\u001b]7;file://potatohead/home/sam/git/gitlab_public/optima-35\u0007"]
|
||||
[50.047409, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[47m\u001b[38;5;30m \u001b[0m\u001b[38;5;30m\u001b[47m\u001b[47m\u001b[38;5;30m \u001b[0m\u001b[38;5;30m\u001b[47m\u001b[48;5;30m\u001b[37m\u001b[0m\u001b[37m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m \u001b[1m\u001b[38;5;254m\u001b[48;5;30m\u001b[38;5;255m~\u001b[0m\u001b[38;5;255m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m/\u001b[38;5;250mgi\u001b[0m\u001b[38;5;250m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m/\u001b[38;5;250mg\u001b[0m\u001b[38;5;250m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m/\u001b[1m\u001b[38;5;254m\u001b[48;5;30m\u001b[38;5;255moptima-35\u001b[0m\u001b[38;5;255m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m\u001b[0m\u001b[38;5;254m\u001b[48;5;30m\u001b[48;5;30m\u001b[38;5;254m \u001b[0m\u001b[38;5;254m\u001b[48;5;30m\u001b[43m\u001b[38;5;30m\u001b[0m\u001b[38;5;30m\u001b[43m\u001b[43m\u001b[30m \u001b[30m feature/enhance-modularity \u001b[30m!5 \u001b[30m?2\u001b[0m\u001b[30m\u001b[43m\u001b[43m\u001b[30m \u001b[0m\u001b[30m\u001b[43m\u001b[49m\u001b[33m\u001b[0m\u001b[33m\u001b[49m\u001b[39m \u001b[0m\u001b[49m\u001b[39m\u001b[K"]
|
||||
[50.0481, "o", "\u001b[?2004h"]
|
||||
[52.228733, "o", "\u001b[?2004l\r\r\n"]
|
BIN
media/demo_v041.gif
Normal file
BIN
media/demo_v041.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 218 KiB |
Binary file not shown.
Before Width: | Height: | Size: 188 KiB |
BIN
media/exif_tab_disabled.png
Normal file
BIN
media/exif_tab_disabled.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 123 KiB |
BIN
media/exif_tab_enabled.png
Normal file
BIN
media/exif_tab_enabled.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 187 KiB |
Binary file not shown.
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 171 KiB |
0
optima/__init__.py
Normal file
0
optima/__init__.py
Normal file
113
optima/optima35.py
Normal file
113
optima/optima35.py
Normal file
|
@ -0,0 +1,113 @@
|
|||
import re
|
||||
import os
|
||||
from datetime import datetime
|
||||
# My packages
|
||||
from utils.image_handler import ImageProcessor, ExifHandler
|
||||
|
||||
class OPTIMA35:
|
||||
def __init__(self):
|
||||
self.name = "OPTIMA-35"
|
||||
self.version = "0.4.1"
|
||||
self.image_processor = ImageProcessor()
|
||||
self.exif_handler = ExifHandler()
|
||||
self.settings = {
|
||||
"input_folder": None,
|
||||
"output_folder": None,
|
||||
"file_format": None,
|
||||
"resize": False,
|
||||
"contrast": False,
|
||||
"brightness": False,
|
||||
"new_file_names": False,
|
||||
"invert_image_order": False,
|
||||
"copy_exif": False,
|
||||
"own_exif": False,
|
||||
"watermark": False,
|
||||
"grayscale": False,
|
||||
"jpg_quality": None,
|
||||
"png_compression": None,
|
||||
"font_size": None,
|
||||
"optimize": False,
|
||||
"gps": False
|
||||
}
|
||||
self.selected_exif = {}
|
||||
|
||||
def modify_timestamp_in_exif(self, exif_data, filename):
|
||||
""""Takes exif data and adjust time to fit ending of filename."""
|
||||
try:
|
||||
last_tree = filename[-3:len(filename)]
|
||||
total_seconds = int(re.sub(r'\D+', '', last_tree))
|
||||
minutes = total_seconds // 60
|
||||
seconds = total_seconds % 60
|
||||
time = datetime.strptime(exif_data["date_time_original"], "%Y:%m:%d %H:%M:%S") # change date time string back to an time object for modification
|
||||
new_time = time.replace(hour=12, minute=minutes, second=seconds)
|
||||
exif_data["date_time_original"] = new_time.strftime("%Y:%m:%d %H:%M:%S")
|
||||
return exif_data
|
||||
|
||||
except ValueError:
|
||||
print("Modifying date went wrong, exiting...")
|
||||
exit()
|
||||
|
||||
def process(self, image_input_file, image_output_file):
|
||||
with self.image_processor.open_image(image_input_file) as img:
|
||||
processed_img = img
|
||||
image_name = os.path.basename(image_output_file)
|
||||
|
||||
if self.settings["resize"] != False:
|
||||
processed_img = self.image_processor.resize_image(
|
||||
image = processed_img, percent = self.settings["resize"]
|
||||
)
|
||||
if self.settings["watermark"] != False:
|
||||
processed_img = self.image_processor.add_watermark(processed_img, self.settings["watermark"], int(self.settings["font_size"]))
|
||||
if self.settings["grayscale"] != False: # There is a problem, if we first to grayscale and then watermark it braeks
|
||||
processed_img = self.image_processor.grayscale(processed_img)
|
||||
if self.settings["brightness"] != False: # Does the order of brightness and contrast matter?
|
||||
processed_img = self.image_processor.change_brightness(processed_img, self.settings["brightness"])
|
||||
if self.settings["contrast"] != False: # Does the order of brightness and contrast matter?
|
||||
processed_img = self.image_processor.change_contrast(processed_img, self.settings["contrast"])
|
||||
|
||||
if self.settings["own_exif"] != False:
|
||||
selected_exif = self.selected_exif
|
||||
if "date_time_original" in self.selected_exif:
|
||||
selected_exif = self.modify_timestamp_in_exif(selected_exif, image_name)
|
||||
exif_data = self.exif_handler.build_exif_dict(selected_exif, self.image_processor.get_image_size(processed_img))
|
||||
if self.settings["gps"] != False:
|
||||
latitude = float(self.settings["gps"][0])
|
||||
longitude = float(self.settings["gps"][1])
|
||||
exif_data = self.exif_handler.add_geolocation_to_exif(exif_data, latitude, longitude)
|
||||
|
||||
elif self.settings["copy_exif"] == True:
|
||||
# When copying exif from original, make sure to change Piexel X & Y Dimension to fit new size
|
||||
try:
|
||||
og_exif = self.exif_handler.get_exif_info(img)
|
||||
og_exif["Exif"][40962], og_exif["Exif"][40963] = self.image_processor.get_image_size(processed_img)
|
||||
exif_data = og_exif
|
||||
except Exception:
|
||||
# If an error happends it is because the picture does not have exif data
|
||||
print("Copying EXIF data selected, but no EXIF data is available in the original image file.")
|
||||
exif_data = None
|
||||
elif self.settings["copy_exif"] == False:
|
||||
exif_data = None
|
||||
|
||||
self.image_processor.save_image(
|
||||
image = processed_img,
|
||||
path = image_output_file,
|
||||
exif_data = exif_data,
|
||||
file_type = self.settings["file_format"],
|
||||
jpg_quality = self.settings["jpg_quality"],
|
||||
png_compressing = self.settings["png_compression"],
|
||||
optimize = self.settings["optimize"]
|
||||
)
|
||||
|
||||
def name_images(self, base_name, current_image, total_images, invert):
|
||||
""""Returns name, combination of base_name and ending number."""
|
||||
total_digits = len(str(total_images))
|
||||
if invert:
|
||||
ending_number = total_images - (current_image - 1)
|
||||
else:
|
||||
ending_number = current_image
|
||||
ending = f"{ending_number:0{total_digits}}"
|
||||
return f"{base_name}_{ending}"
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Please load OPTIMA35 into the ui class...")
|
||||
exit()
|
4
requirements_tui.txt
Normal file
4
requirements_tui.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
pyyaml
|
||||
piexif
|
||||
pillow
|
||||
simple_term_menu
|
|
@ -1,46 +1,134 @@
|
|||
import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
# my packages
|
||||
from optima.optima35 import OPTIMA35
|
||||
from utils.utility import Utilities
|
||||
from utils.image_handler import ImageProcessor, ExifHandler
|
||||
from ui.tui import SimpleTUI
|
||||
# legacy code, will be removed with then next minor version
|
||||
class Optima35:
|
||||
# The layout of class Optima35 was originally made by ChatGPT, but major adjustments have been made. To remain transparent, I disclose this.
|
||||
def __init__(self, settings_file, exif_options_file):
|
||||
self.name = "OPTIMA-35"
|
||||
self.version = "0.2.1"
|
||||
self.utilities = Utilities()
|
||||
self.image_processor = ImageProcessor()
|
||||
self.exif_handler = ExifHandler()
|
||||
from ui.simple_tui import SimpleTUI
|
||||
|
||||
class Optima35TUI():
|
||||
def __init__(self, exif_file, settings_file):
|
||||
self.o = OPTIMA35()
|
||||
self.u = Utilities()
|
||||
self.tui = SimpleTUI()
|
||||
self.exif_file = exif_file
|
||||
self.exif_data = self.u.read_yaml(exif_file)
|
||||
self.setting_file = settings_file
|
||||
self.settings = {
|
||||
"input_folder": None,
|
||||
"output_folder": None,
|
||||
"file_format": None,
|
||||
"resize_percentage": None,
|
||||
"resize": None,
|
||||
"copy_exif": None,
|
||||
"contrast_percentage": None,
|
||||
"brightness_percentage": None,
|
||||
"contrast": None,
|
||||
"brightness": None,
|
||||
"new_file_names": None,
|
||||
"invert_image_order": False,
|
||||
"watermark_text": None,
|
||||
"watermark": None,
|
||||
"gps": None,
|
||||
"modifications": [],
|
||||
}
|
||||
self.settings_to_save = [
|
||||
"resize_percentage",
|
||||
"resize",
|
||||
"jpg_quality",
|
||||
"png_compression",
|
||||
"web_optimize",
|
||||
"contrast_percentage",
|
||||
"brightness_percentage"
|
||||
"optimize",
|
||||
"contrast",
|
||||
"brightness"
|
||||
]
|
||||
self.exif_choices = self.utilities.read_yaml(exif_options_file)
|
||||
self.setting_file = settings_file
|
||||
|
||||
def process(self):
|
||||
if "Change EXIF" in self.settings["modifications"]:
|
||||
self.selected_exif = self.collect_exif_data()
|
||||
self.check_options() # Get all user selected data
|
||||
input_folder_valid = os.path.exists(self.o.settings["input_folder"])
|
||||
output_folder_valid = os.path.exists(self.o.settings["output_folder"])
|
||||
if not input_folder_valid or not output_folder_valid:
|
||||
print("Warning", f"Input location {input_folder_valid}\nOutput folder {output_folder_valid}...")
|
||||
return
|
||||
|
||||
input_folder = self.o.settings["input_folder"]
|
||||
output_folder = self.o.settings["output_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.o.settings["new_file_names"] != False:
|
||||
image_name = self.o.name_images(self.o.settings["new_file_names"], i, len(image_files), self.o.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(input_path, output_path)
|
||||
self.u.progress_bar(i, len(image_files))
|
||||
i += 1
|
||||
|
||||
def check_options(self):
|
||||
try:
|
||||
if "Resize image" in self.settings["modifications"]:
|
||||
self.o.settings["resize"] = self.settings["resize"]
|
||||
else:
|
||||
self.o.settings["resize"] = False
|
||||
|
||||
if "Convert to grayscale" in self.settings["modifications"]:
|
||||
self.o.settings["grayscale"] = True
|
||||
else:
|
||||
self.o.settings["grayscale"] = False
|
||||
|
||||
if "Change contrast" in self.settings["modifications"]:
|
||||
self.o.settings["contrast"] = self.settings["contrast"]
|
||||
else:
|
||||
self.o.settings["contrast"] = False
|
||||
|
||||
if "Change brightness" in self.settings["modifications"]:
|
||||
self.o.settings["brightness"] = self.settings["brightness"]
|
||||
else:
|
||||
self.o.settings["brightness"] = False
|
||||
|
||||
if "Rename images" in self.settings["modifications"]:
|
||||
self.o.settings["new_file_names"] = self.settings["new_file_names"]
|
||||
else:
|
||||
self.o.settings["new_file_names"] = False
|
||||
|
||||
if "Invert image order" in self.settings["modifications"]:
|
||||
self.o.settings["invert_image_order"] = True
|
||||
else:
|
||||
self.o.settings["invert_image_order"] = False
|
||||
|
||||
if "Add Watermark" in self.settings["modifications"]:
|
||||
self.o.settings["watermark"] = self.settings["watermark"]
|
||||
else:
|
||||
self.o.settings["watermark"] = False
|
||||
|
||||
self.o.settings["optimize"] = self.settings["optimize"]
|
||||
self.o.settings["png_compression"] = self.settings["png_compression"]
|
||||
self.o.settings["jpg_quality"] = self.settings["jpg_quality"]
|
||||
|
||||
self.o.settings["input_folder"] = self.settings["input_folder"]
|
||||
self.o.settings["output_folder"] = self.settings["output_folder"]
|
||||
self.o.settings["file_format"] = self.settings["file_format"]
|
||||
self.o.settings["font_size"] = 2 # need to add option to select size
|
||||
|
||||
self.o.settings["copy_exif"] = self.settings["copy_exif"]
|
||||
|
||||
if "Change EXIF" in self.settings["modifications"]: #missing
|
||||
self.o.selected_exif = self.selected_exif #
|
||||
self.o.settings["own_exif"] = True
|
||||
if self.settings["gps"] != None:
|
||||
self.o.settings["gps"] = self.settings["gps"]
|
||||
else:
|
||||
self.o.settings["gps"] = False
|
||||
else:
|
||||
self.o.settings["own_exif"] = False
|
||||
|
||||
except Exception as e:
|
||||
print(f"Whoops: {e}")
|
||||
|
||||
def load_or_ask_settings(self):
|
||||
"""Load settings from a YAML file or ask the user if not present or incomplete."""
|
||||
# Partially ChatGPT
|
||||
try:
|
||||
if self.read_settings(self.settings_to_save):
|
||||
for item in self.settings_to_save:
|
||||
print(f"{item}: {self.settings[item]}")
|
||||
|
@ -49,14 +137,19 @@ class Optima35:
|
|||
return
|
||||
else:
|
||||
print("No settings found...")
|
||||
self.ask_for_settings()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
self.ask_for_settings()
|
||||
|
||||
def ask_for_settings(self):
|
||||
print("Asking for new settings...\n")
|
||||
self.settings["resize_percentage"] = self.take_input_and_validate(question = "Default resize percentage (below 100 downscale, above upscale): ", accepted_type = int, min_value = 1, max_value = 200)
|
||||
self.settings["contrast_percentage"] = self.take_input_and_validate(question = "Default contrast percentage (negative = decrease, positive = increase): ", accepted_type = int, min_value = -100, max_value = 100)
|
||||
self.settings["brightness_percentage"] = self.take_input_and_validate(question = "Default brighness percentage (negative = decrease, positive = increase): ", accepted_type = int, min_value = -100, max_value = 100)
|
||||
self.settings["resize"] = self.take_input_and_validate(question = "Default resize percentage (below 100 downscale, above upscale): ", accepted_type = int, min_value = 10, max_value = 200)
|
||||
self.settings["contrast"] = self.take_input_and_validate(question = "Default contrast percentage (negative = decrease, positive = increase): ", accepted_type = int, min_value = -100, max_value = 100)
|
||||
self.settings["brightness"] = self.take_input_and_validate(question = "Default brighness percentage (negative = decrease, positive = increase): ", accepted_type = int, min_value = -100, max_value = 100)
|
||||
self.settings["jpg_quality"] = self.take_input_and_validate(question = "JPEG quality (1-100, 80 default): ", accepted_type = int, min_value = 1, max_value = 100)
|
||||
self.settings["png_compression"] = self.take_input_and_validate(question = "PNG compression level (0-9, 6 default): ", accepted_type = int, min_value = 0, max_value = 9)
|
||||
self.settings["web_optimize"] = self.tui.yes_no_menu("Optimize images i.e. compressing?")
|
||||
self.settings["optimize"] = self.tui.yes_no_menu("Optimize images i.e. compressing?")
|
||||
|
||||
self.write_settings(self.settings_to_save)
|
||||
|
||||
|
@ -64,7 +157,7 @@ class Optima35:
|
|||
""""Write self.setting, but only specific values"""
|
||||
keys = keys_to_save
|
||||
filtered_settings = {key: self.settings[key] for key in keys if key in self.settings}
|
||||
self.utilities.write_yaml(self.setting_file, filtered_settings)
|
||||
self.u.write_yaml(self.setting_file, filtered_settings)
|
||||
print("New settings saved successfully.")
|
||||
|
||||
def read_settings(self, keys_to_load):
|
||||
|
@ -75,7 +168,7 @@ class Optima35:
|
|||
# First draft by ChatGPT, adjusted to fit my needs.
|
||||
keys = keys_to_load
|
||||
if os.path.exists(self.setting_file):
|
||||
loaded_settings = self.utilities.read_yaml(self.setting_file)
|
||||
loaded_settings = self.u.read_yaml(self.setting_file)
|
||||
for key in keys:
|
||||
if key in loaded_settings:
|
||||
self.settings[key] = loaded_settings[key]
|
||||
|
@ -93,17 +186,32 @@ class Optima35:
|
|||
"user_comment", "artist", "copyright_info"
|
||||
]
|
||||
for field in fields:
|
||||
choise = self.tui.choose_menu(f"Enter {field.replace('_', ' ').title()}", self.exif_choices[field])
|
||||
user_data[field] = choise.encode("utf-8")
|
||||
|
||||
user_data["software"] = f"OPTIMA-35 {self.version}".encode("utf-8")
|
||||
choise = self.tui.choose_menu(f"Enter {field.replace('_', ' ').title()}", self.exif_data[field])
|
||||
user_data[field] = choise
|
||||
|
||||
user_data["software"] = f"{self.o.name} {self.o.version}"
|
||||
new_date = self.get_date_input()
|
||||
|
||||
if new_date:
|
||||
user_data["date_time_original"] = new_date
|
||||
|
||||
self.settings["gps"] = self.get_gps_input(user_data)
|
||||
|
||||
return user_data
|
||||
|
||||
def get_gps_input(self, test_exif):
|
||||
while True:
|
||||
lat = input("Enter Latitude (xx.xxxxxx): ")
|
||||
if lat == "":
|
||||
return False
|
||||
long = input("Enter Longitude (xx.xxxxxx): ")
|
||||
try:
|
||||
self.o.exif_handler.add_geolocation_to_exif(test_exif, float(lat), float(long))
|
||||
return [lat, long]
|
||||
except Exception:
|
||||
print("Invalid GPS formate, try again...")
|
||||
|
||||
def get_date_input(self):
|
||||
# Partially chatGPT
|
||||
while True:
|
||||
|
@ -133,17 +241,24 @@ class Optima35:
|
|||
self.settings["output_folder"] = input("Enter path of output folder: ").strip()
|
||||
self.settings["file_format"] = self.take_input_and_validate(question = "Enter export file format (jpg, png, webp): ", accepted_input = ["jpg", "png", "webp"], accepted_type = str)
|
||||
self.settings["modifications"] = self.tui.multi_select_menu(
|
||||
f"\n{self.name} v.{self.version} \nSelect what you want to do (esc or q to exit)",
|
||||
f"\n{self.o.name} v.{self.o.version} \nSelect what you want to do (esc or q to exit)",
|
||||
menu_options
|
||||
)
|
||||
if "Change EXIF" not in self.settings["modifications"]:
|
||||
self.settings["copy_exif"] = self.tui.yes_no_menu("Do you want to copy exif info from original file?")
|
||||
if "Rename images" in self.settings["modifications"]:
|
||||
self.settings["new_file_names"] = input("What should be the name for the new images? ") # Need
|
||||
else:
|
||||
self.settings["new_file_names"] = False
|
||||
if "Invert image order" in self.settings["modifications"]:
|
||||
self.settings["invert_image_order"] = True
|
||||
else:
|
||||
self.settings["invert_image_order"] = False
|
||||
if "Add Watermark" in self.settings["modifications"]:
|
||||
self.settings["watermark_text"] = input("Enter text for watermark. ")
|
||||
self.settings["watermark"] = input("Enter text for watermark. ")
|
||||
else:
|
||||
self.settings["watermark"] = False
|
||||
|
||||
os.makedirs(self.settings["output_folder"], exist_ok = True)
|
||||
|
||||
def take_input_and_validate(self, question, accepted_input = None, accepted_type = str, min_value = None, max_value = None):
|
||||
|
@ -187,106 +302,26 @@ class Optima35:
|
|||
except ValueError:
|
||||
print(f"Invalid input. Must be of type {accepted_type.__name__}.")
|
||||
|
||||
def process_images(self):
|
||||
"""Process images based on user settings."""
|
||||
input_folder = self.settings["input_folder"]
|
||||
output_folder = self.settings["output_folder"]
|
||||
|
||||
image_files = [
|
||||
f for f in os.listdir(input_folder) if f.lower().endswith((".png", ".jpg", ".jpeg", ".webp"))
|
||||
]
|
||||
if "Change EXIF" in self.settings["modifications"]:
|
||||
selected_exif = self.collect_exif_data()
|
||||
i = 1
|
||||
for image_file in image_files:
|
||||
input_path = os.path.join(input_folder, image_file)
|
||||
|
||||
if "Rename images" in self.settings["modifications"]:
|
||||
image_name = self.name_images(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)
|
||||
|
||||
with self.image_processor.open_image(input_path) as img:
|
||||
processed_img = img
|
||||
for mod in self.settings["modifications"]:
|
||||
if mod == "Resize image":
|
||||
processed_img = self.image_processor.resize_image(
|
||||
image = processed_img, percent = self.settings["resize_percentage"], resample = True
|
||||
)
|
||||
elif mod == "Change EXIF" and selected_exif:
|
||||
if "date_time_original" in selected_exif:
|
||||
selected_exif = self.modify_timestamp_in_exif(selected_exif, image_name)
|
||||
exif_data = self.exif_handler.build_exif_dict(selected_exif, self.image_processor.get_image_size(processed_img))
|
||||
elif mod == "Convert to grayscale":
|
||||
processed_img = self.image_processor.grayscale(processed_img)
|
||||
elif mod == "Change contrast":
|
||||
processed_img = self.image_processor.change_contrast(processed_img, self.settings["contrast_percentage"])
|
||||
elif mod == "Change brightness":
|
||||
processed_img = self.image_processor.change_brightness(processed_img, self.settings["brightness_percentage"])
|
||||
elif mod == "Add Watermark":
|
||||
processed_img = self.image_processor.add_watermark(processed_img, self.settings["watermark_text"])
|
||||
|
||||
if self.settings["copy_exif"]:
|
||||
# When copying exif from original, make sure to change Piexel X & Y Dimension to fit new size
|
||||
try:
|
||||
og_exif = self.exif_handler.get_exif_info(img)
|
||||
og_exif["Exif"][40962], og_exif["Exif"][40963] = self.image_processor.get_image_size(processed_img)
|
||||
exif_data = og_exif
|
||||
except Exception:
|
||||
# If an error happends it is because the picture does not have exif data
|
||||
print("Copying EXIF data selected, but no EXIF data is available in the original image file.")
|
||||
exif_data = None
|
||||
elif "Change EXIF" not in self.settings["modifications"]:
|
||||
exif_data = None
|
||||
|
||||
self.image_processor.save_image(
|
||||
image = processed_img,
|
||||
path = output_path,
|
||||
exif_data = exif_data,
|
||||
file_type = self.settings["file_format"],
|
||||
jpg_quality = self.settings["jpg_quality"],
|
||||
png_compressing = self.settings["png_compression"],
|
||||
optimize = self.settings["web_optimize"]
|
||||
)
|
||||
self.utilities.progress_bar(i, len(image_files))
|
||||
i += 1
|
||||
|
||||
def name_images(self, base_name, current_image, total_images, invert):
|
||||
""""Returns name, combination of base_name and ending number."""
|
||||
total_digits = len(str(total_images))
|
||||
if invert:
|
||||
ending_number = total_images - (current_image - 1)
|
||||
else:
|
||||
ending_number = current_image
|
||||
ending = f"{ending_number:0{total_digits}}"
|
||||
return f"{base_name}_{ending}"
|
||||
|
||||
def modify_timestamp_in_exif(self, exif_data, filename):
|
||||
""""Takes exif data and adjust time to fit ending of filename."""
|
||||
try:
|
||||
last_tree = filename[-3:len(filename)]
|
||||
total_seconds = int(re.sub(r'\D+', '', last_tree))
|
||||
|
||||
minutes = total_seconds // 60
|
||||
seconds = total_seconds % 60
|
||||
time = datetime.strptime(exif_data["date_time_original"], "%Y:%m:%d %H:%M:%S") # change date time string back to an time object for modification
|
||||
new_time = time.replace(hour=12, minute=minutes, second=seconds)
|
||||
exif_data["date_time_original"] = new_time.strftime("%Y:%m:%d %H:%M:%S")
|
||||
return exif_data
|
||||
|
||||
except ValueError:
|
||||
print("Modifying date went wrong, exiting...")
|
||||
exit()
|
||||
|
||||
def run(self):
|
||||
"""Run the main program."""
|
||||
self.load_or_ask_settings()
|
||||
self.get_user_settings()
|
||||
self.process_images()
|
||||
self.process()
|
||||
print("Done")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = Optima35("config/settings.yaml", "config/exif_options.yaml")
|
||||
|
||||
|
||||
def main(exif_file, config_file):
|
||||
app = Optima35TUI(exif_file, config_file)
|
||||
app.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
if os.path.isfile("config/exif.yaml"):
|
||||
exif_file = "config/exif.yaml"
|
||||
elif os.path.isfile("config/exif_example.yaml"):
|
||||
exif_file = "config/exif_example.yaml"
|
||||
print("Fall back to exif example file...")
|
||||
else:
|
||||
print("Exif file missing, please ensure an exif file exist in config folder (exif.yaml, or exif_example_yaml)\nExiting...")
|
||||
exit()
|
||||
main(exif_file, "config/tui_settings.yaml")
|
|
@ -220,6 +220,7 @@ class Ui_MainWindow(object):
|
|||
self.restart_button = QPushButton(self.widget_9)
|
||||
self.restart_button.setObjectName(u"restart_button")
|
||||
self.restart_button.setEnabled(False)
|
||||
self.restart_button.setFlat(False)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.restart_button)
|
||||
|
||||
|
@ -450,6 +451,7 @@ class Ui_MainWindow(object):
|
|||
self.dateEdit = QDateEdit(self.date_groupBox)
|
||||
self.dateEdit.setObjectName(u"dateEdit")
|
||||
self.dateEdit.setEnabled(False)
|
||||
self.dateEdit.setDateTime(QDateTime(QDate(2025, 1, 1), QTime(0, 0, 0)))
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.dateEdit)
|
||||
|
||||
|
@ -483,6 +485,7 @@ class Ui_MainWindow(object):
|
|||
|
||||
self.tabWidget.setCurrentIndex(0)
|
||||
self.font_size_comboBox.setCurrentIndex(2)
|
||||
self.restart_button.setDefault(False)
|
||||
|
||||
|
||||
QMetaObject.connectSlotsByName(MainWindow)
|
||||
|
@ -490,9 +493,9 @@ class Ui_MainWindow(object):
|
|||
|
||||
def retranslateUi(self, MainWindow):
|
||||
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"OPTIMA-35", None))
|
||||
self.input_path.setText(QCoreApplication.translate("MainWindow", u"local_files/img", None))
|
||||
self.input_path.setText("")
|
||||
self.input_path.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Enter input folder", None))
|
||||
self.output_path.setText(QCoreApplication.translate("MainWindow", u"local_files/out", 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))
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
<item row="0" column="0">
|
||||
<widget class="QLineEdit" name="input_path">
|
||||
<property name="text">
|
||||
<string>local_files/img</string>
|
||||
<string/>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Enter input folder</string>
|
||||
|
@ -65,7 +65,7 @@
|
|||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="output_path">
|
||||
<property name="text">
|
||||
<string>local_files/out</string>
|
||||
<string/>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Enter output folder</string>
|
||||
|
@ -373,6 +373,12 @@
|
|||
<property name="text">
|
||||
<string>Restart</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -654,6 +660,16 @@
|
|||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="dateTime">
|
||||
<datetime>
|
||||
<hour>0</hour>
|
||||
<minute>0</minute>
|
||||
<second>0</second>
|
||||
<year>2025</year>
|
||||
<month>1</month>
|
||||
<day>1</day>
|
||||
</datetime>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue