Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Image Splitter Pro

A lightweight, modular image processing framework with Blender-like operator philosophy and unified Node Graph execution. Supports grid splitting, custom guide-based cutting, resizing, canvas adjustment, rounded corners, smart crop, borders, and more �?with modern customtkinter GUI and auto-generated UI metadata.

Features

Core Philosophy

  • Unified Node Graph Execution: All processor invocations flow through the same DAG-based Node Graph engine �?single execution path for CLI, GUI, and scripting.
  • Modern GUI: customtkinter with dark theme, framework-agnostic GuiState ViewModel for future Dear PyGui migration.
  • Metadata-Driven UI: GUI auto-generates parameter panels from dataclass field annotations. New features = drop-in plugin.
  • Everything as Operators: Complete decoupling between core logic and UI. Blender-style operator invocation logs and command dispatching.
  • Typed Property System: IntProp, FloatProp, BoolProp, EnumProp, StrProp, ListProp, ColorProp descriptors with coercion, validation, and update callbacks. (Experimental �?reserved for future Node Graph UI.)
  • Image Data Blocks: Named, versioned, reference-counted image containers with class-level registry �?Blender ID-style.
  • Operation History: Undo/Redo stack records every operation, exportable as JSON log.
  • Macro Recording: One-click recording generates reusable Python scripts with restricted execution. Note: the restriction is an anti-footgun guard, not a security boundary �?only play back macros you authored.
  • Parameter Presets: Save/load named parameter presets per operator (CLI --preset and GUI).
  • Visual Pipeline Editor: Compose multi-step operator chains via GUI (Ctrl+P).
  • Interactive Console: Built-in command console with tab completion and history (Ctrl+`).
  • Plugin System: Drop a BaseProcessor subclass in plugins/ and it's auto-discovered.
  • High-Performance Engine: CLI and GUI batch runs share a multi-processing runner (max_workers setting, CPU-core default) with cancel-pending abort semantics.
  • Industrial-Grade Safety: Strict Pillow handle management with Path Traversal interception and cell leak protection.
  • Cross-Platform: Full Windows/macOS/Linux support with platform-aware font loading.
  • Static Type Checking: Full mypy compliance with --ignore-missing-imports �?zero type errors across 44 source files.

Quick Start

Installation

pip install -e .            # CLI only (Pillow-only core)
pip install -e ".[gui]"     # CLI + GUI (adds customtkinter)

Standalone Executable (no Python required)

A single-file desktop build is supported via PyInstaller:

pip install pyinstaller pillow customtkinter
pyinstaller packaging/image_splitter.spec
# �?dist/ImageSplitterPro(.exe)

GUI Mode

python -m image_splitter.gui
# or
image-splitter-gui

CLI Mode

# Split test.png into 3x3 grid with 8 parallel processes
python -m image_splitter.cli test.png -r 3 -c 3 -o ./output -j 8

# Custom guide-based split (arbitrary horizontal/vertical lines)
python -m image_splitter.cli test.png -p custom_splitter --set h_lines=[100,300,500] --set v_lines=[200,400]

# Use a saved preset
python -m image_splitter.cli input.png --preset "my_split"

# Save current parameters as a preset (output_dir/template excluded)
python -m image_splitter.cli input.png -r 3 -c 3 --preset-save "3x3_grid"

# List saved presets (no input required)
python -m image_splitter.cli --preset-list

Script Mode

# Execute script file
python -m image_splitter.cli input.png -s script.txt

# Chain operations
python -m image_splitter.cli input.png --chain "resizer(width=0.5)|grid_splitter(rows=2,cols=2)"

# Custom splitter in chain (arbitrary guide positions)
python -m image_splitter.cli input.png --chain "custom_splitter(h_lines=[100,300],v_lines=[200,400])|resizer(width=0.5)"

Chain semantics (V15): operators apply per image with flat-map fan-out. A splitter in the middle of a chain fans out �?every following operator is applied to each cell and all results are collected:

# 2x2 split �?each cell resized �?4 outputs (not 1)
python -m image_splitter.cli input.png --chain "grid_splitter(rows=2,cols=2)|resizer(width=0.5)"

Available Processors

Processor Description
grid_splitter Split image into uniform grid (rows x cols)
custom_splitter Custom guide-based splitting �?arbitrary h_lines + v_lines at any pixel positions
resizer Proportional image scaling
canvas_adjuster Canvas padding, cropping, background fill
format_converter WebP/JPEG/PNG/BMP format conversion with quality control
geometry Rotation (90/180/270) and flip operations
filters Grayscale and invert filters
color_adjuster Brightness, contrast, sharpness, saturation tuning
metadata_cleaner Strip EXIF/GPS privacy data
text_watermark Add semi-transparent text watermark
rounded_corner Rounded corner crop with configurable radius
border Add solid/dashed/double border with configurable width and color
smart_crop Content-aware crop using alpha channel or luminance edge detection (background-agnostic: works on dark and light backgrounds)

Template Placeholders

Placeholder Description
{filename} Original filename without extension
{row} / {col} Current row/column number (1-based)
{index} Global sequence number (01-based, zero-padded)
{batch} 1-based sequence of the input file within the batch �?use it to disambiguate files that share a stem ({index} resets per file)
{w} Processed image width in pixels
{h} Processed image height in pixels
{ext} File extension
{anchor} Anchor position (TL, TR, BL, BR, C)
{text} Watermark text content
{quality} Export quality parameter

Configuration

Settings are persisted to ~/.image_splitter/settings.json:

{
    "output_dir": "./output",
    "default_processor": "grid_splitter",
    "template": "{filename}_{index}",
    "max_workers": 0,
    "default_rows": 3,
    "default_cols": 3,
    "window_geometry": "1100x820"
}

default_rows / default_cols are the CLI grid fallbacks (explicit -r/-c and presets take precedence); template is the GUI's startup filename template; window_geometry restores the GUI window size. max_workers controls batch concurrency for both CLI (-j default) and GUI batch runs (0 = CPU core count). GUI diagnostics are additionally logged to ~/.image_splitter/logs/gui.log (rotating, 1 MB × 3 backups).

Batch Semantics

  • Concurrency: CLI and GUI share one parallel runner (core.run_parallel_batch). GUI batch runs are parallel by default; Abort cancels pending files and lets the in-flight file finish.
  • Same-stem safety: files that share a stem produce colliding output names ({index} resets per file). The CLI warns about this at pre-flight; add {batch} to your template to keep every file's output distinct.

Keybindings

Default keybindings in ~/.image_splitter/keymap.json:

{
    "global": {
        "<Control-o>": "select_files",
        "<Control-Return>": "run_batch",
        "<Delete>": "remove_selected",
        "<Control-Shift-Delete>": "clear_list",
        "<Control-grave>": "toggle_console",
        "<Control-p>": "toggle_pipeline",
        "<Control-Shift-R>": "toggle_macro_record",
        "<Control-z>": "undo_history",
        "<Control-Shift-Z>": "redo_history",
        "<Control-e>": "open_output_dir",
        "<Escape>": "stop_tasks"
    }
}
Shortcut Action
Ctrl+O Open images
Ctrl+Enter Run batch processing
Delete Remove selected file
Ctrl+Shift+Delete Clear file list
Ctrl+P Toggle pipeline editor
Ctrl+Shift+R Start/stop macro recording
Ctrl+Z Undo last operation
Ctrl+Shift+Z Redo last operation
Ctrl+E Open output directory
Escape Abort current task
Ctrl+` Toggle command console

Architecture

image_splitter/                # repository root
├── pyproject.toml             # Package configuration
├── image_splitter/            # the package
�?  ├── py.typed               # PEP 561 type marker
�?  ├── cli.py                # CLI entry point (multiprocessing + presets)
�?  ├── gui.py                # GUI entry point (customtkinter + GuiState ViewModel)
�?  ├── core.py               # Core processing pipeline + unified Node Graph execution
�?  ├── settings.py           # User settings persistence
�?  ├── keymap.py             # Keybinding system
�?  ├── script_engine.py      # Batch scripting engine
�?  ├── logging_config.py     # Logging configuration
�?  ├── models.py             # Configuration dataclasses (13 models)
�?  ├── engine/
�?  �?  ├── base.py           # BaseProcessor abstract class
�?  �?  ├── registry.py       # Processor registry (thread-safe singleton)
�?  �?  ├── dispatcher.py     # Command dispatcher + chain execution
�?  �?  ├── config_coercion.py # Parameter type coercion (int/float/bool/enum/list/str)
�?  �?  ├── history.py        # Operation history stack (undo/redo)
�?  �?  ├── macro.py          # Macro recording & sandboxed playback
�?  �?  ├── presets.py        # Parameter presets (save/load/import/export)
�?  �?  ├── props.py          # Typed Property descriptor system (Blender bpy.props style) �?Experimental
�?  �?  ├── data_blocks.py    # ImageDataBlock (named, versioned, ref-counted)
�?  �?  ├── nodes.py          # DAG node graph (Socket, BaseNode, 4 concrete nodes)
�?  �?  ├── evaluator.py      # NodeGraph evaluator + LRU EvaluationCache
�?  �?  ├── legacy_adapter.py # ProcessorNodeAdapter + ChainAsGraph (unified execution bridge)
�?  �?  └── _ui_metadata_util.py # Auto-generate UI metadata from dataclass field annotations
�?  ├── processors/           # Processor plugins (13 built-in)
�?  ├── plugins/              # User plugin directory (auto-discovered)
�?  �?  └── example_plugin.py # Example: invert colors plugin
�?  └── ui/
�?      ├── _state.py         # GuiState �?framework-agnostic ViewModel
�?      ├── console.py        # Interactive command console panel (customtkinter)
�?      ├── pipeline.py       # Visual pipeline chain editor (customtkinter)
�?      └── param_widgets.py  # Shared parameter widget factory (customtkinter)
├── .github/workflows/
�?  └── ci.yml                # CI/CD pipeline (multi-OS, Python 3.10-3.13)
└── tests/                    # Test suite (498 tests, 41 files)

Engine Layer

The engine layer provides a Blender-inspired foundation with unified execution:

Module Purpose
_ui_metadata_util.py Auto-generates get_ui_metadata() from dataclass field(metadata={"label": ...}) �?single source of truth
props.py Typed Property descriptors (Experimental �?reserved for future Node Graph UI)
data_blocks.py ImageDataBlock �?named, versioned, reference-counted image containers
nodes.py DAG primitives: SocketType, Socket, Connection, BaseNode, concrete nodes
evaluator.py NodeGraph �?topological evaluation, dirty propagation; EvaluationCache �?LRU cache
legacy_adapter.py ProcessorNodeAdapter wraps processors as nodes; ChainAsGraph �?unified chain execution

All processor invocations use _execute_via_graph() �?a single Node Graph path shared by process_image() and ChainAsGraph.execute_chain().

Development

This project supports plugin development. Simply inherit from BaseProcessor and implement your logic to automatically get CLI support and GUI panel generation.

See DEVELOPER.md for details and TECHNICAL.md for a comprehensive technical guide.

Requirements

  • Python 3.10+
  • Pillow 10.2.0+
  • customtkinter 5.2.0+ (GUI only �?optional)

License

MIT

Test Suite

The project includes 498 tests across 41 test files:

Test File Description
conftest.py Shared fixtures: BaseTest, test images, color constants
test_adjuster.py Canvas adjuster: padding, cropping, ratio, fail-fast validation
test_bug_fixes.py Regression tests for all confirmed bug fixes (30 tests)
test_chain_as_graph_all.py ChainAsGraph vs CommandDispatcher pixel-identical for all 13 processors (22 tests)
test_cli.py CLI mode: basic flow, recursive discovery, concurrency, error handling
test_config_coercion.py Parameter type coercion for all supported types
test_console_panel.py UI: interactive command console panel (customtkinter)
test_custom_splitter.py Custom line splitter: simple, irregular, out-of-bounds, negative rejection
test_data_blocks.py ImageDataBlock: name registry, version tracking, ref counting, clone, metadata (22 tests)
test_dispatcher.py Command parsing + chain execution with coercion and extra_config
test_edge_cases.py Edge case tests for all processors: 1x1, tiny ratios, empty text, P-mode
test_engine_v4.py Registry integrity, processor smoke test, path security, format adaptation
test_error_paths.py Error handling: missing files, invalid templates, bad enum/list values
test_execute_via_graph.py Unified execution path: _execute_via_graph() for single/multi-output and context
test_gui_param_sync.py UI: GUI widget→state parameter synchronization data flow
test_gui_smoke.py GUI initialization, file selection, processor switching, stop/cancel
test_gui_state.py GuiState ViewModel: processor selection, progress tracking, param values
test_gui_workflows.py GUI workflow: full parameter coercion and batch run verification
test_history.py History system: push, undo, redo, clear, max-depth, export log
test_integration.py End-to-end: full pipeline, RGBA/L-mode smoke, CLI chain, template vars
test_keymap.py Keybinding: bind/unbind/lookup, import/export, reset, multiple contexts
test_legacy_adapter.py Legacy Adapter: ChainAsGraph vs CommandDispatcher pixel-identical output (15 tests)
test_macro.py Macro recording: record, stop, generate script, playback, save
test_new_processors.py New processor coverage: metadata P-mode, border styles, smart crop edge cases
test_node_graph.py Node Graph + Evaluator: DAG topology, dirty propagation, cache, end-to-end (35 tests)
test_operator_compliance.py Compliance audit + parameter contract for all processors
test_param_widgets.py UI: shared parameter widget factory (customtkinter)
test_pipeline_editor.py UI: visual pipeline chain editor (customtkinter)
test_plugin.py Plugin system: auto-discovery, metadata, functional inversion
test_presets.py Presets: save/load/list/delete/export/import + CLI integration (14 tests)
test_processors_expanded.py Deep: rounding consistency, watermark positioning, pixel accuracy, stress
test_props.py Property System: coercion, validation, update callbacks, ui_metadata (30 tests)
test_save_compatibility.py Save: ICC profile preservation, format conversion extension changes
test_script_engine.py Script engine: process, chain, batch script, error handling, operators list
test_settings.py Settings: defaults, save/load roundtrip, merge, get/set, corrupted JSON
test_ui_metadata_util.py UI metadata auto-generation from dataclass fields
test_ui_preview.py Preview rendering: all processor draw_preview, graceful dirty-data handling
test_v13_fixes.py V13 audit regressions: packaging, keymap coverage, border double, console chain, CLI dir expansion, preset precedence, chain format (17 tests)
test_v14_fixes.py V14 audit regressions: border dashed, macro chain playback, keymap typing guard, graph cleanup, CLI settings defaults, chain ICC, preset sanitization (22 tests)
test_v15_fixes.py V15 audit regressions: chain fan-out, copy-count reduction, GUI startup param panel, config robustness, smart_crop light backgrounds, import_preset guard (16 tests)
test_v16_fixes.py V16 deployability regressions: parallel runner semantics, {batch} placeholder, case-insensitive discovery, duplicate-stem warning, registry policy, BlendNode hardening, cache close consistency, console reject suppression (17 tests)
test_workflow.py Full end-to-end workflows: chains, batch, presets+macro+history, boundary values

Run tests:

# Full suite (GUI tests skip automatically if the [gui] extra is absent)
python -m pytest tests/ -v

# Type check
python -m mypy image_splitter --ignore-missing-imports

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages