# Module Catalog ## Module Overview | Module | Location | Responsibility | Dependencies | |--------|----------|---------------|--------------| | Pipeline | `src/converter/pipeline/` | Stage orchestration, data types | OpenCV (core) | | RawLoader | `src/converter/rawloader/` | File loading (RAW + standard) | OpenCV, LibRaw | | Preprocessor | `src/converter/preprocess/` | Format normalization, deskew | OpenCV | | NegativeDetector | `src/converter/negative/` | Film type classification | OpenCV | | Inverter | `src/converter/invert/` | Negative-to-positive inversion | OpenCV | | ColorCorrector | `src/converter/color/` | White balance, C-41 correction | OpenCV | | CropProcessor | `src/converter/crop/` | Auto-crop, levels, sharpening | OpenCV | | OutputWriter | `src/converter/output/` | File output | OpenCV | | MainWindow | `src/gui/` | Qt GUI | Qt 6.8, converter_core | | CliRunner | `src/cli/` | CLI batch processing | converter_core | ## Dependency Graph ``` MainWindow ──> Pipeline ──> PipelineStage (interface) | | ^ | | | v | +--------+--------+--------+--------+--------+--------+ Qt 6.8 | | | | | | | | | Preproc Detect Invert Color Crop Output (future) | | | | | | | +-----+--------+--------+--------+--------+--------+ | v RawLoader | +----+----+ | | LibRaw OpenCV CliRunner ──> Pipeline ──> (same stages as above) | +──> RawLoader ``` ## Module Details --- ### Pipeline Infrastructure (`src/converter/pipeline/`) #### Error.h | Type | Description | |------|-------------| | `enum class ErrorCode` | Error classification (30+ codes across all stages) | | `struct Error` | Error with code, message, and source location | | `make_error()` | Factory function with automatic source_location capture | #### ImageData.h | Type | Description | |------|-------------| | `enum class FilmType` | Film classification: Unknown, ColorNegative, BWNegative, ColorPositive, BWPositive | | `struct RawMetadata` | Camera make/model, ISO, shutter, aperture, WB multipliers, dimensions | | `struct ImageData` | Core carrier: cv::Mat rgb (CV_16UC3), source_path, metadata, film_type, crop_region | #### PipelineStage.h | Type | Description | |------|-------------| | `using StageResult` | `std::expected` | | `class PipelineStage` | Abstract interface: `process(ImageData) -> StageResult`, `name() -> string` | | `using ProgressCallback` | `function` for GUI progress reporting | #### Pipeline.h / Pipeline.cpp | Class | `Pipeline` | |-------|-----------| | **Pattern** | Chain of Responsibility + Strategy | | **Owns** | `vector>` | | **Methods** | | | `add_stage(unique_ptr)` | Append a stage | | `execute(ImageData, ProgressCallback) -> StageResult` | Run all stages sequentially | | `stage_count() -> size_t` | Number of registered stages | | **Thread safety** | Not thread-safe (single-threaded execution) | | **Copyable** | No (deleted copy ctor/assignment) | | **Movable** | Yes | --- ### RawLoader (`src/converter/rawloader/`) | Class | `RawLoader` | |-------|------------| | **Pattern** | Factory Method (routes to load_raw or load_standard) | | **Methods** | | | `load(path) -> expected` | Main entry point | | `load_raw(path)` | LibRaw loader (private) | | `load_standard(path)` | OpenCV loader (private) | | `is_raw_format(path) -> bool` | Extension check (static) | | `is_standard_format(path) -> bool` | Extension check (static) | | `log_metadata(RawMetadata)` | Print metadata to stdout (static) | | **Constants** | | | `kMaxRawFileSize` | 4 GB (4,294,967,296 bytes) | | `kRawExtensions[]` | cr2, cr3, nef, arw, dng, orf, rw2, raf, pef | | `kStandardExtensions[]` | jpg, jpeg, png, tif, tiff | | **Internal** | | | `LibRawGuard` | RAII class ensuring `LibRaw::recycle()` | **LibRaw configuration:** ```cpp params.use_camera_wb = 1; // Use camera white balance params.output_bps = 16; // 16-bit output params.no_auto_bright = 1; // No auto-brightness params.half_size = 0; // Full resolution params.output_color = 1; // sRGB color space ``` --- ### Preprocessor (`src/converter/preprocess/`) | Class | `Preprocessor` : `PipelineStage` | |-------|----------------------------------| | **Stage name** | "Preprocess" | | **Methods** | | | `process(ImageData) -> StageResult` | Validate + deskew | | `validate_and_convert(ImageData)` | Ensure CV_16UC3 (static, private) | | `deskew(ImageData)` | Geometric correction (static, private, TODO) | --- ### NegativeDetector (`src/converter/negative/`) | Class | `NegativeDetector` : `PipelineStage` | |-------|--------------------------------------| | **Stage name** | "Detect" | | **Methods** | | | `process(ImageData) -> StageResult` | Classify film type | | `is_negative_histogram(Mat) -> bool` | Mean intensity analysis (static, private) | | `has_orange_mask(Mat) -> bool` | R/B ratio check (static, private) | | `is_monochrome(Mat) -> bool` | HSV saturation check (static, private) | | **Constants** | | | `kOrangeMaskThreshold` | 1.4f | | `kColorSaturationThreshold` | 15.0f | --- ### Inverter (`src/converter/invert/`) | Class | `Inverter` : `PipelineStage` | |-------|------------------------------| | **Stage name** | "Invert" | | **Methods** | | | `process(ImageData) -> StageResult` | Route by film type | | `invert_color_negative(ImageData)` | Orange mask removal + bitwise_not (static, private) | | `invert_bw_negative(ImageData)` | Simple bitwise_not (static, private) | --- ### ColorCorrector (`src/converter/color/`) | Class | `ColorCorrector` : `PipelineStage` | |-------|-------------------------------------| | **Stage name** | "ColorCorrection" | | **Methods** | | | `process(ImageData) -> StageResult` | Route by film type | | `correct_c41(ImageData)` | C-41 orange cast removal (static, private, TODO) | | `auto_white_balance(ImageData)` | Gray-world AWB (static, private) | | `apply_exif_wb(ImageData)` | EXIF-based WB (static, private) | --- ### CropProcessor (`src/converter/crop/`) | Class | `CropProcessor` : `PipelineStage` | |-------|-------------------------------------| | **Stage name** | "PostProcess" | | **Methods** | | | `process(ImageData) -> StageResult` | Auto-crop + levels + sharpen | | `auto_crop(ImageData)` | Frame detection via contours (static, private, TODO) | | `adjust_levels(ImageData)` | Percentile-based levels (static, private, TODO) | | `sharpen(ImageData)` | Unsharp mask (static, private, TODO) | | **Constants** | | | `kMinFrameAreaRatio` | 0.3 | | `kSharpenSigma` | 1.5 | | `kSharpenStrength` | 0.5 | | `kBlackPointPercentile` | 0.5 | | `kWhitePointPercentile` | 99.5 | --- ### OutputWriter (`src/converter/output/`) | Class | `OutputWriter` : `PipelineStage` | |-------|-----------------------------------| | **Stage name** | "Output" | | **Constructor** | `OutputWriter(OutputConfig config)` | | **Methods** | | | `process(ImageData) -> StageResult` | Write file to disk | | `build_output_path(string) -> path` | Construct output filename (private) | | `format_extension(OutputFormat) -> string` | Map format to extension (static, private) | | **Config** | | | `OutputConfig::output_dir` | Target directory | | `OutputConfig::format` | PNG_16bit, PNG_8bit, TIFF_16bit, JPEG | | `OutputConfig::jpeg_quality` | 0-100 (default 95) | --- ### MainWindow (`src/gui/`) | Class | `MainWindow` : `QMainWindow` | |-------|-------------------------------| | **Qt slots** | | | `on_open_files()` | File dialog with RAW filter | | `on_convert()` | Execute pipeline on all selected files | | `on_select_output_dir()` | Directory picker | | **Private** | | | `setup_ui()` | Construct widgets and layout | | `setup_pipeline()` | Build default pipeline | | `update_preview(Mat)` | Convert 16-bit BGR to QPixmap for display | | **State** | | | `input_files_` | Selected file paths | | `output_dir_` | Chosen output directory | | `pipeline_` | Pipeline instance | --- ### CliRunner (`src/cli/`) | Class | `CliRunner` | |-------|------------| | **Nested types** | `Config` (input_files, output_dir, output_format, jpeg_quality, verbose) | | **Static methods** | | | `parse_args(argc, argv) -> expected` | Parse CLI arguments | | **Methods** | | | `run(Config) -> expected` | Execute batch processing, return success count | **CLI usage:** ``` photo-converter --cli -i file1.arw file2.cr2 -o output/ --format png16 ``` --- ## Build Targets | Target | Type | Sources | Dependencies | |--------|------|---------|-------------| | `converter_core` | Static library | All `src/converter/` + `src/cli/` | OpenCV, LibRaw | | `photo-converter` | Executable | `src/main.cpp` + `src/gui/` | converter_core, Qt6::Widgets | | `test_pipeline` | Test executable | `tests/test_pipeline.cpp` | converter_core, GTest | | `test_rawloader` | Test executable | `tests/test_rawloader.cpp` | converter_core, GTest | ## Implementation Status | Module | Status | Notes | |--------|--------|-------| | Pipeline | Complete | Orchestration, error propagation, progress | | RawLoader | Complete | Full LibRaw + OpenCV loading | | Preprocessor | Skeleton | Validation done, deskew TODO | | NegativeDetector | Functional | Basic histogram + orange mask detection | | Inverter | Skeleton | Basic bitwise_not, C-41 mask removal TODO | | ColorCorrector | Partial | Gray-world AWB implemented, C-41 TODO | | CropProcessor | Skeleton | All sub-stages TODO (pass-through) | | OutputWriter | Complete | All formats supported | | MainWindow | Complete | File dialogs, preview, progress | | CliRunner | Complete | Argument parsing, batch loop |