- 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>
9.8 KiB
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 |