Parto (پرتو — Ray / Beam of Light) is a fast, modern, and lightweight desktop image editor designed for daily image tasks without the bloat, slow startup, or visual clutter of heavyweight software.
Release Line: v0.4.0 (Active Development — Localization Core & Architecture 2.0)
Current Package Version: v0.3.1 (Latest tagged package)
-
Action + Command + History Architecture 2.0 Finalization:
- Full consolidation and enforcement of the standard production pipeline:
User Interface -> Action Subsystem -> Controller / Facade -> Command Subsystem -> History Subsystem -> Domain Model. -
Eliminated Snapshot Bypasses: Removed legacy
create_snapshot()andrecord_operation()bypasses fromLayersPanel, routing continuous layer opacity throughChangeLayerOpacityCommandwith seamless history coalescing. -
Isolated Layer Brush Strokes: Replaced whole-document snapshots in
BrushDocumentAdapterwith layer-isolated state capturing (before_imageandafter_image), preserving byte-for-byte fidelity across Undo/Redo cycles without memory bloat. -
Encapsulated Transform History: Replaced ad-hoc controller snapshots with encapsulated
TransformCommand, ensuring state and dirty tracking remain strictly consistent. -
Standardized Invocation Paths: Unified keyboard shortcuts and Command Palette invocations through
ActionManagerand authoritativeDocumentController/HistoryManagerpathways.
- Full consolidation and enforcement of the standard production pipeline:
-
Modular Document Domain Subsystem (
parto/document/):- Independent, engineering-grade domain architecture separating state, engines, persistence, transactions, and presentation.
-
State Model (
DocumentState): Authoritative container managing canvas dimensions, file path, modified tracking, and layer stack ownership. -
Engines (
DocumentEngine,TransformEngine,CompositingEngine): Thin domain coordinators delegating to underlying image and geometry routines without duplicating image processing logic. -
Persistence (
DocumentStorageAdapter): Decoupled file I/O handling format resolution, memory copying, and EXIF orientation normalization. -
History Integration (
TransactionCoordinator): Deep snapshotting, strict equality comparison, and atomic undo/redo restoration. -
Controller & Facade (
DocumentController,Document): High-level domain boundary providing reactive Qt signals (document_changed,layer_selection_changed,modified_changed) while ensuring the domain core remains GUI-independent. -
Full Backward Compatibility: Seamless re-export shim via
parto/editor/document.pyandEditorEngine.
-
Contextual Brush Studio Architecture:
- Context-aware menu integration: Brush Studio is no longer exposed as a static global View menu item.
- When the Brush Tool (
B) is selected, a dedicated contextual Brush menu (&Brush) dynamically appears in the menu bar, exposing Brush Studio (F9), preset navigation (Ctrl+Shift+B), tip property focus (Alt+B), mode cycling (Shift+B), defaults reset (Shift+F9), and size/hardness controls. - Navigating to Move, Crop, or Eyedropper tools automatically withdraws the contextual menu and studio dock while strictly preserving all active brush settings (size, opacity, hardness, color palette, eraser mode).
-
Professional Brush Studio Subsystem (
parto/brush/,parto/ui/panels/brush/):- Modular studio dock (
BrushStudioDock) with live-rendered dab preview, current preset summary, and quick action drawer. - Interactive preset grid (
PresetGridWidget) with live stroke thumbnails, search filtering, category tabs, right-click context menu, and single-preset JSON import/export. - 14 factory presets categorized across Basic, Pencil, Ink, Paint, Airbrush, Marker, Texture, and Eraser.
- Tip properties with synced sliders and spinboxes: Size (1–500 px), Hardness (0–100%), Spacing (5–200%), Tip Rotation Angle (0–360°), and Tip Roundness (1–100%).
- Dynamics modulation engine for Size, Opacity, Flow, and Angle targeting Pressure, Velocity, Tilt, and Random jitter.
- Interactive Color management with live foreground and background chips, color swap (
X), color reset (D), and 8-color quick palette swatches. - Anti-aliased stroke smoothing and scatter jitter controls.
- Modular studio dock (
-
Multi-Layer System (
parto/image/layers.py):- Non-destructive RGBA layer stack with per-layer opacity, vector eye visibility toggles, duplication, reordering, and visibility-aware merge down operations.
- Interactive Layers Panel (
F7) with continuous opacity slider history coalescing (one undo step per drag gesture). - Panels closed by default on startup for maximum canvas workspace.
-
Live Non-Destructive Adjustments Panel (
F8):- Real-time color tuning: Brightness, Contrast, Saturation, and Sharpness with live preview and "Hold to Compare Original" inspection.
-
Normalized, Zero-Conflict Keyboard Shortcuts:
- Fully audited and normalized keyboard shortcut registry managed via singleton
ShortcutManager. - Searchable Shortcuts & Preferences dialog (
parto.ui.dialogs.shortcuts_dialog) with real-time category filtering and collision-aware remapping. - Dynamic Command Palette (
Ctrl+K).
- Fully audited and normalized keyboard shortcut registry managed via singleton
-
Dynamic Theming & 200ms Crossfade Transitions:
- 5 curated palettes: Dark, Light, Graphite, Midnight, and Nord.
- Smooth 200ms crossfade animation (
transition_theme) usingQGraphicsOpacityEffectandQPropertyAnimation.
-
Localization Core Subsystem (
parto/localization/,docs/LOCALIZATION.md):- Independent, UI-decoupled internationalization service managing runtime locale switching, catalog discovery, translation fallback chains, and layout direction synchronization.
- Bundled factory catalogs for English (LTR) and Persian / فارسی (RTL), each with 191 verified translation keys and 100% key parity.
- Dynamic layout direction synchronization updating
QApplication.setLayoutDirectionand top-level windows (Qt.LeftToRight$\leftrightarrow$ Qt.RightToLeft). - Atomic runtime switching: validates candidate catalogs prior to commit, preserving previous valid locale and text direction if candidate validation fails.
- Explicit persistence failure contract: default resilient mode (
strict_persistence=False) keeps the active session in the new locale while displaying a notification toast; strict mode (strict_persistence=True) atomically rolls back locale and layout direction. - Subscriber and UI refresh isolation: exceptions in individual widget retranslation callbacks are isolated and recorded in diagnostics (
last_listener_failures,last_refresh_completed) without aborting other subscribers. - Future Intent Subsystem integration contract via
format_intent_response()for localized messages in background and automation tasks. -
Verification Status: Core localization logic verified with 26 unit tests passing. Qt-dependent integration test (
test_locale_state_preservation.py) verification is pending in environments without PySide6. Seedocs/LOCALIZATION.mdfor full documentation.
-
High-DPI Vector Icon System:
- Resolution-independent icons rendered via
QPainterpaths with canonical alias normalization.
- Resolution-independent icons rendered via
-
Automated QA & Test Suite (357 Test Cases):
- 357 test cases defined across 44 test files validating document state isolation, transform engines, compositing, storage adapters, brush studio properties, presets, dab generation, layers, command history, shortcuts, localization catalogs, failure rollback, state preservation, and theme palettes. (Full suite passes in headless Qt environments; pure Python/headless unit tests run without Qt).
Parto supports a wide range of standard and modern image formats through Pillow and pillow-heif:
| Format | Extension | Read | Write | Notes |
|---|---|---|---|---|
| PNG | .png |
Yes | Yes | Full transparency support |
| JPEG | .jpg, .jpeg |
Yes | Yes | Safe alpha compositing with matte |
| WebP | .webp |
Yes | Yes | High compression & quality (lossy/lossless) |
| BMP | .bmp |
Yes | Yes | Bitmap images |
| TIFF | .tiff, .tif |
Yes | Yes | High dynamic range & print |
| HEIC | .heic |
Yes | No | Apple device photos |
Parto is organized into focused, single-responsibility subsystems with strict unidirectional dependencies:
Parto
│
┌─────────────┼─────────────┐
│ │ │
▼ ▼ ▼
Document Brush UI
│ │
┌─────┼─────┐ │
│ │ │ │
▼ ▼ ▼ ▼
State Layers History Brush Engine
│ │ │ │
└─────┼─────┘ │
▼ │
Document Engine │
│ │
└──────┬──────┘
▼
Image Processing
│
▼
Pillow
- Document Subsystem (
parto/document/):models/: AuthoritativeDocumentStateandDocumentMetadata.engine/:DocumentEngineorchestratingTransformEngineandCompositingEngine.adapters/:DocumentStorageAdapterfor format I/O and EXIF normalization.history/:TransactionCoordinatormanaging state snapshots, dirty detection, and command dispatch.controller/:DocumentControllerexecuting domain actions and driving signals.document.py: CentralDocumentdomain model and Qt reactive facade.
- Brush Subsystem (
parto/brush/):- Pure domain
BrushSettings, preset management, dab generation, stroke execution, and document integration adapter.
- Pure domain
- Layers Subsystem (
parto/image/layers.py):- Authoritative
LayerandLayerStackcollections, blend modes, and Porter-Duff compositing.
- Authoritative
- History Subsystem (
parto/history/):- Command pattern execution, revision numbering, clean save-point markers, and undo/redo stacks.
- Image Processing Subsystem (
parto/image/):- Low-level transformations (
transforms.py), photographic filters (filters.py), and color processing (processing.py).
- Low-level transformations (
- UI Subsystem (
parto/ui/):- Main window orchestration, contextual tool menus, toolbars, statusbar, and dock animators.
Parto/
├── main.py # Application entry point, High-DPI configuration & ThemeManager bootstrap
├── window.py # Backward-compatibility re-export shim for MainWindow
├── editor.py # Backward-compatibility re-export shim for EditorEngine
├── image.py # Backward-compatibility re-export shim for conversions & metadata
├── icons.py # Backward-compatibility re-export shim for vector icons
├── parto/ # Core application package
│ ├── document/ # Modular Document Domain Subsystem
│ │ ├── models/ # DocumentState, DocumentMetadata
│ │ ├── engine/ # DocumentEngine, TransformEngine, CompositingEngine
│ │ ├── adapters/ # DocumentStorageAdapter
│ │ ├── history/ # TransactionCoordinator, snapshots_equal
│ │ ├── controller/ # DocumentController
│ │ ├── geometry.py # Coordinate math & offset-aware layer transforms
│ │ └── document.py # Authoritative Document domain model & facade
│ ├── brush/ # Professional Brush Subsystem
│ │ ├── models/ # BrushSettings, BrushPreset, enums (BlendMode, DynamicsControl)
│ │ ├── engine/ # DabGenerator, BrushRenderer, BrushEngine
│ │ ├── presets/ # Builtin presets factory, PresetManager, PresetStorage (JSON)
│ │ ├── controller/ # BrushController & StrokeController
│ │ ├── input/ # PointerState & InputNormalizer
│ │ ├── document_adapter.py# Document and LayerStack integration boundary
│ │ └── tools/ # BrushTool
│ ├── editor/ # Canvas, SelectionBox geometry & EditorEngine compatibility shim
│ ├── image/ # Layers, LayerStack, Filters, Transforms & Safe Export
│ ├── history/ # Command pattern base, SnapshotCommand, HistoryManager
│ ├── shortcuts/ # Centralized ShortcutManager & ShortcutDefinition registry
│ ├── tools/ # BaseTool, MoveTool, CropTool, BrushTool, EyedropperTool
│ ├── themes/ # ThemeManager singleton & dynamic palettes (Dark, Light, Graphite, Midnight, Nord)
│ ├── workers/ # ImageWorkerThread with cancellation and Qt signals
│ ├── resources/ # High-DPI QPainter vector icons and logo loader
│ ├── ui/ # MainWindow, ToolBar, StatusBar, Menus, Panels & Dialogs
│ │ ├── panels/ # Layers, Adjustments, and Brush Studio dock
│ │ │ └── brush/ # BrushStudioDock: Header, Presets, Properties, Dynamics, Color, Blend, Advanced
│ │ └── dialogs/ # Shortcuts, About, Resize, Image Info, Filter Gallery, Command Palette
│ └── utils/ # Path helpers, settings persistence & error formatting
├── tests/ # Automated unit, integration, regression, and UI test suites (357 test cases)
├── requirements.txt # Python package dependencies
├── logo.png # Parto application branding icon
├── LICENSE # MIT License
├── CHANGELOG.md # Release notes and version history
└── README.md # Project documentation
- Python 3.10 or newer
- Virtual environment (recommended)
-
Clone the repository:
git clone https://github.com/MRThugh/Parto.git cd Parto -
Create and activate a virtual environment:
python3 -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
-
Launch the application:
python main.py
Parto features a normalized, zero-conflict shortcut system registered through ShortcutManager:
| Shortcut | Action | Description |
|---|---|---|
Ctrl+N |
New Canvas | Create a blank canvas with custom dimensions |
Ctrl+O |
Open Image | Open image file from disk |
Ctrl+S |
Save Image | Save active image in-place |
Ctrl+Shift+S |
Save As... | Save copy with format selection |
Ctrl+Shift+E |
Export As... | Fast export to WebP, JPEG, PNG, or TIFF |
Ctrl+I |
Properties & Metadata | Inspect technical image specifications |
Ctrl+K |
Command Palette | Search and launch any action instantly |
F1 |
Shortcut Reference | Searchable cheat sheet reference dialog |
F11 |
Fullscreen | Toggle fullscreen mode |
Ctrl+Q |
Exit | Safely quit Parto (with unsaved changes prompt) |
| Shortcut | Action | Description |
|---|---|---|
B |
Brush Tool | Freehand painting on active layer |
[ / ] |
Brush Size | Decrease / increase brush radius (1–500 px) |
Shift+[ / Shift+] |
Brush Hardness | Decrease / increase radial hardness (0–100%) |
Ctrl+[ / Ctrl+] |
Brush Opacity | Decrease / increase stroke opacity (0–100%) |
Shift+B |
Cycle Brush Mode | Toggle between Paint and Eraser mode |
X |
Swap Brush Colors | Swap active foreground and background colors |
D |
Reset Brush Colors | Reset colors to standard default black & white |
F9 |
Toggle Brush Studio | Show/hide Brush Studio dock panel |
Shift+F9 |
Reset Brush Defaults | Reset all brush parameters to factory defaults |
Ctrl+Shift+B |
Focus Preset Search | Quick-focus search input in Brush Studio |
Alt+B |
Focus Tip Properties | Quick-focus tip properties in Brush Studio |
| Shortcut | Action | Description |
|---|---|---|
V |
Pan / Move Tool | Pan canvas viewport and drag content |
C |
Crop Tool | Interactive 8-handle crop selection |
I |
Eyedropper Tool | Inspect and sample canvas pixel color |
Enter |
Apply Crop | Execute crop with active bounding box |
Esc |
Cancel / Dismiss | Cancel crop or close interactive dialogs |
Ctrl+Z |
Undo | Revert last action or stroke |
Ctrl+Y |
Redo | Reapply previously undone action |
Ctrl+Alt+I |
Resize Image... | Resample canvas dimensions |
| Shortcut | Action | Description |
|---|---|---|
F7 |
Toggle Layers Panel | Show/hide multi-layer management dock |
F8 |
Toggle Adjustments | Show/hide real-time color adjustments dock |
Ctrl+Shift+N |
New Layer | Create a new transparent layer |
Ctrl+J |
Duplicate Layer | Duplicate active layer |
Delete |
Delete Layer | Remove active layer from stack |
Ctrl+Up / Ctrl+Down |
Reorder Layer | Move layer higher or lower in stack |
Ctrl+E |
Merge Down | Merge active layer onto layer beneath |
Ctrl+= / Ctrl++ |
Zoom In | Increase canvas zoom factor |
Ctrl+- |
Zoom Out | Decrease canvas zoom factor |
Ctrl+0 |
Fit on Screen | Fit entire canvas inside viewport |
Ctrl+1 |
100% Actual Pixels | View image at 1:1 pixel scale |
| Shortcut | Action | Description |
|---|---|---|
Ctrl+R |
Rotate 90° CW | Rotate canvas 90 degrees clockwise |
Ctrl+Shift+R |
Rotate 90° CCW | Rotate canvas 90 degrees counter-clockwise |
Ctrl+Alt+R |
Rotate 180° | Flip canvas upside down |
Ctrl+H |
Flip Horizontal | Mirror canvas horizontally |
Ctrl+Shift+H |
Flip Vertical | Mirror canvas vertically |
Ctrl+Shift+F |
Filter Gallery | Open interactive filter gallery dialog |
Parto maintains an automated test suite containing 357 test cases across 44 test files covering image processing routines, document state isolation, transform engines, compositing, storage adapters, brush studio properties, dab generation, presets, layers, command history, dialogs, format conversions, localization catalogs, failure rollback, state preservation, and theme transitions.
- Localization Core Unit Suite (
tests/unit/test_localization_core.py): 26 unit tests verifying catalog loading, validation, pluralization, safe interpolation, fallback resolution, subscriber isolation, and rollback semantics. Runs in pure Python environments without Qt. - Editor State Preservation Integration Suite (
tests/integration/test_locale_state_preservation.py): 2 end-to-end integration tests verifying preservation of document identity, dirty modification flag, layer stacks, undo/redo history, brush settings, active tools, zoom factors, and themes across language switches. Requires PySide6 and Pillow; verification is pending in environments lacking GUI dependencies. - Full Regression Suite: 357 test cases verified passing in full CI environments (Ubuntu 22.04 with PySide6, Pillow, NumPy, and offscreen Qt).
# Run localization core unit tests (pure Python / headless fallback, 26 tests)
python3 -m pytest tests/unit/test_localization_core.py -v
# Run editor state preservation integration tests (requires PySide6 and Pillow)
QT_QPA_PLATFORM=offscreen python3 -m pytest tests/integration/test_locale_state_preservation.py -v
# Run full test suite (requires PySide6, Pillow, NumPy, and pytest)
QT_QPA_PLATFORM=offscreen python3 -m pytestSee tests/README.md for complete details on test layout, environment requirements, and execution guidelines.
- Author: Ali Kamrani (علی کامرانی) / MRThugh
- GitHub: @MRThugh
- Profile: https://github.com/MRThugh
- Repository: https://github.com/MRThugh/Parto
This project is licensed under the MIT License — see the LICENSE file for details.