# Architecture ## Overview Photo-converter is a C++20 cross-platform desktop application that converts digitized analog film negatives (35mm, 120mm) into digital positives. It supports RAW camera formats (CR2, NEF, ARW, DNG, etc.) and standard image formats (JPG, PNG, TIFF), producing high-quality 16-bit output with automatic film type detection, color correction, and cropping. The architecture follows **Clean Architecture** principles: the core processing logic has zero GUI dependencies and can run in both interactive (Qt GUI) and batch (CLI) modes. ## Component Diagram ``` +------------------------------------------------------------------+ | Application Layer | | | | +------------------+ +------------------+ | | | MainWindow | | CliRunner | | | | (Qt GUI) | | (Batch CLI) | | | +--------+---------+ +--------+---------+ | | | | | +------------|------------------------------|----------------------+ | | v v +------------------------------------------------------------------+ | Pipeline Orchestration | | | | +----------------------------------------------------------+ | | | Pipeline | | | | Owns: vector> | | | | Executes stages in order, propagates errors | | | +----------------------------------------------------------+ | | | +------------------------------------------------------------------+ | v +------------------------------------------------------------------+ | Pipeline Stages | | | | +----------+ +---------+ +--------+ +--------+ +---------+ | | |RawLoader |->|Preproc. |->|Detect |->|Invert |->|Color | | | |(Loader) | | | | | | | |Corrector| | | +----------+ +---------+ +--------+ +--------+ +---------+ | | | | | +-----------v-----+ | | | CropProcessor | | | | (Post-Process) | | | +-----------+-----+ | | | | | +-----------v-----+ | | | OutputWriter | | | +-----------------+ | +------------------------------------------------------------------+ | v +------------------------------------------------------------------+ | Core Data Types | | | | ImageData RawMetadata FilmType Error ErrorCode | | | +------------------------------------------------------------------+ | v +------------------------------------------------------------------+ | External Libraries | | | | OpenCV 4.10+ LibRaw 0.21+ Qt 6.8 LTS | | (imgproc, imgcodecs) (RAW demosaicing) (Widgets, GUI) | | | +------------------------------------------------------------------+ ``` ## Layer Responsibilities ### Application Layer Contains the two entry points (GUI and CLI). This layer is thin -- it constructs the pipeline, feeds it input, and presents results. No image processing logic lives here. - **MainWindow** (Qt): File dialogs, preview, progress bar. Depends on Qt 6.8 Widgets. - **CliRunner**: Command-line argument parsing and batch loop. Zero Qt dependency. ### Pipeline Orchestration The `Pipeline` class owns an ordered sequence of `PipelineStage` objects and executes them sequentially. It implements the **Chain of Responsibility** pattern: each stage either transforms the data and passes it forward, or returns an error that stops the chain. ### Pipeline Stages Each stage implements the `PipelineStage` interface (`process(ImageData) -> StageResult`). Stages are stateless or hold only configuration. This enables the **Strategy** pattern -- stages can be swapped, reordered, or extended without modifying the Pipeline. ### Core Data Types - `ImageData`: The carrier struct flowing through all stages. Always contains a `cv::Mat` in CV_16UC3 format. - `Error` / `ErrorCode`: Structured error with source location for diagnostics. - `StageResult = std::expected`: The universal return type. ## Design Decisions ### 1. std::expected over Exceptions **Decision:** All error handling uses `std::expected`, never exceptions for control flow. **Rationale:** - Explicit error paths in function signatures (self-documenting) - No hidden control flow jumps - Zero-cost when no error occurs - Forces callers to handle errors (compiler warnings with `[[nodiscard]]`) - Consistent with modern C++ idioms (C++23) ### 2. 16-bit Pipeline Throughout **Decision:** All internal processing uses CV_16UC3 (16-bit per channel, 3-channel BGR). **Rationale:** - RAW files contain 12-14 bit data; 8-bit would lose dynamic range - Inversion, color correction, and levels adjustments need headroom - Conversion to 8-bit happens only at the final output stage - No information loss in intermediate stages ### 3. LibRaw RAII Guard **Decision:** LibRaw::recycle() is guaranteed via an RAII guard class (`LibRawGuard`). **Rationale:** - LibRaw requires explicit cleanup; forgetting recycle() leaks memory - RAII ensures cleanup on all paths (success, error, exception) - The guard is a private implementation detail of RawLoader ### 4. Core Library Separation **Decision:** All processing code is in the `converter_core` static library, which has no Qt dependency. **Rationale:** - Enables CLI-only builds without Qt - Makes the core testable without GUI framework - Clean dependency graph: GUI depends on core, never vice versa ### 5. Value Semantics for ImageData **Decision:** `ImageData` is passed by value (moved) through the pipeline. **Rationale:** - `cv::Mat` uses reference counting internally, so copies are shallow - Moving `ImageData` is cheap (Mat header + a few scalars) - Avoids shared mutable state between stages - Each stage owns its input; previous stages cannot interfere ## Directory Structure ``` photo-converter/ +-- CMakeLists.txt Root build configuration +-- CLAUDE.md AI agent instructions +-- docs/ | +-- ARCHITECTURE.md This file | +-- PIPELINE.md Pipeline stage documentation | +-- MODULES.md Module catalog +-- import/ Sample test images (ARW) +-- output/ Default output directory +-- src/ | +-- main.cpp Entry point (GUI/CLI dispatch) | +-- converter/ | | +-- pipeline/ | | | +-- Pipeline.h/.cpp Pipeline orchestrator | | | +-- PipelineStage.h Stage interface (abstract) | | | +-- ImageData.h Core data structure | | | +-- Error.h Error types | | +-- rawloader/ | | | +-- RawLoader.h/.cpp RAW + standard image loading | | +-- preprocess/ | | | +-- Preprocessor.h/.cpp Bit depth validation, deskew | | +-- negative/ | | | +-- NegativeDetector.h/.cpp Film type classification | | +-- invert/ | | | +-- Inverter.h/.cpp Negative-to-positive inversion | | +-- color/ | | | +-- ColorCorrector.h/.cpp WB, C-41 correction | | +-- crop/ | | | +-- CropProcessor.h/.cpp Auto-crop, levels, sharpen | | +-- output/ | | +-- OutputWriter.h/.cpp File output (PNG/TIFF/JPEG) | +-- gui/ | | +-- MainWindow.h/.cpp Qt GUI main window | +-- cli/ | +-- CliRunner.h/.cpp CLI batch runner +-- tests/ +-- CMakeLists.txt Test build configuration +-- test_pipeline.cpp Pipeline and stage unit tests +-- test_rawloader.cpp RawLoader integration tests ``` ## Cross-Platform Build The project builds on Linux, Windows, and macOS. Platform-specific dependency management: | Platform | Package Manager | Command | |----------|----------------|---------| | Linux | apt | `sudo apt install libopencv-dev libraw-dev libqt6widgets6` | | Windows | vcpkg | `vcpkg install opencv libraw qt6-base` | | macOS | Homebrew | `brew install opencv libraw qt@6` | The CMake build system handles all three platforms with appropriate find_package/pkg_check_modules calls. The `BUILD_GUI` option allows CLI-only builds when Qt is unavailable.