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>
This commit is contained in:
149
src/cli/CliRunner.cpp
Normal file
149
src/cli/CliRunner.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
#include "CliRunner.h"
|
||||
#include "../converter/rawloader/RawLoader.h"
|
||||
#include "../converter/preprocess/Preprocessor.h"
|
||||
#include "../converter/negative/NegativeDetector.h"
|
||||
#include "../converter/invert/Inverter.h"
|
||||
#include "../converter/color/ColorCorrector.h"
|
||||
#include "../converter/crop/CropProcessor.h"
|
||||
#include "../converter/output/OutputWriter.h"
|
||||
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
|
||||
namespace photoconv {
|
||||
|
||||
std::expected<CliRunner::Config, Error> CliRunner::parse_args(int argc, char* argv[]) {
|
||||
Config config;
|
||||
bool reading_inputs = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string arg{argv[i]};
|
||||
|
||||
if (arg == "-i" || arg == "--input") {
|
||||
reading_inputs = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-o" || arg == "--output") {
|
||||
reading_inputs = false;
|
||||
if (i + 1 < argc) {
|
||||
config.output_dir = argv[++i];
|
||||
} else {
|
||||
return std::unexpected(make_error(
|
||||
ErrorCode::InvalidArgument, "Missing value for --output"));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (arg == "--format") {
|
||||
reading_inputs = false;
|
||||
if (i + 1 < argc) {
|
||||
config.output_format = argv[++i];
|
||||
} else {
|
||||
return std::unexpected(make_error(
|
||||
ErrorCode::InvalidArgument, "Missing value for --format"));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (arg == "--quality") {
|
||||
reading_inputs = false;
|
||||
if (i + 1 < argc) {
|
||||
config.jpeg_quality = std::stoi(argv[++i]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (arg == "-v" || arg == "--verbose") {
|
||||
config.verbose = true;
|
||||
reading_inputs = false;
|
||||
continue;
|
||||
}
|
||||
if (arg == "--cli") {
|
||||
reading_inputs = false;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-h" || arg == "--help") {
|
||||
std::cout <<
|
||||
"Usage: photo-converter --cli -i <files...> -o <output_dir> [options]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -i, --input <files...> Input image files (RAW or standard)\n"
|
||||
" -o, --output <dir> Output directory (default: output/)\n"
|
||||
" --format <fmt> Output format: png16, png8, tiff16, jpeg\n"
|
||||
" --quality <0-100> JPEG quality (default: 95)\n"
|
||||
" -v, --verbose Verbose output\n"
|
||||
" -h, --help Show this help\n"
|
||||
<< std::endl;
|
||||
return std::unexpected(make_error(ErrorCode::InvalidArgument, "Help requested"));
|
||||
}
|
||||
|
||||
// If reading inputs or no flag active, treat as input file
|
||||
if (reading_inputs || arg[0] != '-') {
|
||||
config.input_files.emplace_back(arg);
|
||||
reading_inputs = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.input_files.empty()) {
|
||||
return std::unexpected(make_error(
|
||||
ErrorCode::InvalidArgument, "No input files specified. Use -i <files...>"));
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
std::expected<int, Error> CliRunner::run(const Config& config) const {
|
||||
// Determine output format
|
||||
OutputFormat fmt = OutputFormat::PNG_16bit;
|
||||
if (config.output_format == "png8") fmt = OutputFormat::PNG_8bit;
|
||||
else if (config.output_format == "tiff16") fmt = OutputFormat::TIFF_16bit;
|
||||
else if (config.output_format == "jpeg") fmt = OutputFormat::JPEG;
|
||||
|
||||
// Build pipeline
|
||||
Pipeline pipeline;
|
||||
pipeline.add_stage(std::make_unique<Preprocessor>());
|
||||
pipeline.add_stage(std::make_unique<NegativeDetector>());
|
||||
pipeline.add_stage(std::make_unique<Inverter>());
|
||||
pipeline.add_stage(std::make_unique<ColorCorrector>());
|
||||
pipeline.add_stage(std::make_unique<CropProcessor>());
|
||||
pipeline.add_stage(std::make_unique<OutputWriter>(
|
||||
OutputConfig{config.output_dir, fmt, config.jpeg_quality}));
|
||||
|
||||
RawLoader loader;
|
||||
int success_count = 0;
|
||||
|
||||
for (const auto& file : config.input_files) {
|
||||
std::cout << std::format("\n[CLI] Processing: {}", file.string()) << std::endl;
|
||||
|
||||
auto load_result = loader.load(file);
|
||||
if (!load_result.has_value()) {
|
||||
std::cerr << std::format("[CLI] Load failed: {}",
|
||||
load_result.error().format()) << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto result = pipeline.execute(std::move(load_result.value()));
|
||||
if (!result.has_value()) {
|
||||
std::cerr << std::format("[CLI] Pipeline failed: {}",
|
||||
result.error().format()) << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
++success_count;
|
||||
}
|
||||
|
||||
std::cout << std::format("\n[CLI] Done: {}/{} files processed successfully",
|
||||
success_count, config.input_files.size()) << std::endl;
|
||||
|
||||
return success_count;
|
||||
}
|
||||
|
||||
std::expected<int, Error> CliRunner::parse_format(const std::string& fmt_str) {
|
||||
if (fmt_str == "png16") return static_cast<int>(OutputFormat::PNG_16bit);
|
||||
if (fmt_str == "png8") return static_cast<int>(OutputFormat::PNG_8bit);
|
||||
if (fmt_str == "tiff16") return static_cast<int>(OutputFormat::TIFF_16bit);
|
||||
if (fmt_str == "jpeg") return static_cast<int>(OutputFormat::JPEG);
|
||||
|
||||
return std::unexpected(make_error(
|
||||
ErrorCode::InvalidArgument,
|
||||
std::format("Unknown output format: '{}'. Use: png16, png8, tiff16, jpeg", fmt_str)));
|
||||
}
|
||||
|
||||
} // namespace photoconv
|
||||
Reference in New Issue
Block a user