Files
negative-converter/docs/MODULES.md
Christoph K. 65b411b23d chore: initial project scaffold from architecture design
- Add CLAUDE.md with project overview, tech stack, build commands,
  architecture description, coding standards, and sample images section
- Add full directory structure: src/, docs/, tests/, import/
- Add CMakeLists.txt with C++20, OpenCV/LibRaw/Qt6 dependencies,
  converter_core static lib, optional GUI, and GTest tests
- Add architecture documentation: ARCHITECTURE.md, PIPELINE.md, MODULES.md
- Add source skeletons for all pipeline stages:
  RawLoader, Preprocessor, NegativeDetector, Inverter, ColorCorrector,
  CropProcessor, OutputWriter, Pipeline, MainWindow, CliRunner, main.cpp
- Add initial test stubs for pipeline and rawloader
- Add sample ARW files in import/ for integration testing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 09:28:32 +01:00

9.8 KiB

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<ImageData, Error>
class PipelineStage Abstract interface: process(ImageData) -> StageResult, name() -> string
using ProgressCallback function<void(string, float)> for GUI progress reporting

Pipeline.h / Pipeline.cpp

Class Pipeline
Pattern Chain of Responsibility + Strategy
Owns vector<unique_ptr<PipelineStage>>
Methods
add_stage(unique_ptr<PipelineStage>) 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<ImageData, Error> 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:

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<Config, Error> Parse CLI arguments
Methods
run(Config) -> expected<int, Error> 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