From 5d30b7b958ba5f1198614e7285e89f7a468d8d70 Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Sat, 28 Mar 2026 09:49:25 +1300 Subject: [PATCH 1/3] [feat] implement aliases Signed-off-by: Anton Dukhovnikov --- include/rawtoaces/rawtoaces_core.h | 19 ++ src/rawtoaces_core/rawtoaces_core.cpp | 147 ++++++++++++++- src/rawtoaces_util/CMakeLists.txt | 1 + src/rawtoaces_util/image_converter.cpp | 77 +++++++- src/rawtoaces_util/rawtoaces_util_priv.h | 3 + tests/test_image_converter.cpp | 227 ++++++++++++++++++++++- tests/test_utils.cpp | 79 ++++++++ tests/test_utils.h | 10 + 8 files changed, 558 insertions(+), 5 deletions(-) diff --git a/include/rawtoaces/rawtoaces_core.h b/include/rawtoaces/rawtoaces_core.h index 7f6ee673..fd758416 100644 --- a/include/rawtoaces/rawtoaces_core.h +++ b/include/rawtoaces/rawtoaces_core.h @@ -91,6 +91,25 @@ class SpectralSolver std::vector collect_data_files( const std::string &type ) const; + /// A helper method collecting aliases of a given type from the database. + /// This function searches through the configured search directories to + /// find all make/model aliases of the specified type ("camera" is the only + /// currently supported type). + /// + /// @param type type of the aliases to search for (e.g., "camera") + /// @param make_aliases output parameter referencing the map + /// to be filled with the found make aliases. + /// @param model_aliases output parameter referencing the map + /// to be filled with the found model aliases. + /// @return `true` on success. + bool collect_aliases( + const std::string &type, + std::map &make_aliases, + std::map< + std::string, + std::map>> + &model_aliases ) const; + /// A helper method loading the spectral data for a file at the given path. /// This function loads spectral data from a file, handling both absolute and relative paths. /// For relative paths, it searches through all configured search directories. diff --git a/src/rawtoaces_core/rawtoaces_core.cpp b/src/rawtoaces_core/rawtoaces_core.cpp index dec09949..48bc370c 100644 --- a/src/rawtoaces_core/rawtoaces_core.cpp +++ b/src/rawtoaces_core/rawtoaces_core.cpp @@ -2,6 +2,10 @@ // Copyright Contributors to the rawtoaces Project. #include + +#include +#include + #include "rawtoaces_core_priv.h" #include "mathOps.h" #include "define.h" @@ -266,6 +270,91 @@ SpectralSolver::collect_data_files( const std::string &type ) const return result; } +bool SpectralSolver::collect_aliases( + const std::string &type, + std::map &make_aliases, + std::map< + std::string, + std::map>> + &model_aliases ) const +{ + for ( const auto &directory: _search_directories ) + { + std::filesystem::path path( directory ); + path.append( "aliases.json" ); + + if ( std::filesystem::exists( path ) ) + { + std::ifstream ifstream( path ); + if ( !ifstream.is_open() ) + { + std::cerr << "Warning: cannot open file " << path.string() + << "." << std::endl; + continue; + } + + nlohmann::json file_data = nlohmann::json::parse( ifstream ); + + if ( !file_data.contains( "data" ) ) + { + std::cerr << "Warning: the alias file " << path.string() + << " must contain the 'data' section." << std::endl; + continue; + } + + const auto &mapping_data = file_data["data"]; + + if ( !mapping_data.contains( type ) ) + { + continue; + } + + const auto &type_mapping = mapping_data[type]; + + if ( type_mapping.contains( "make" ) ) + { + const auto &make_mapping = type_mapping["make"]; + for ( auto &[src_make, dst_make]: make_mapping.items() ) + { + if ( make_aliases.find( src_make ) == make_aliases.end() ) + { + make_aliases[src_make] = dst_make; + } + } + } + + if ( type_mapping.contains( "model" ) ) + { + const auto &model_mapping = type_mapping["model"]; + for ( auto &[src_make, models]: model_mapping.items() ) + { + for ( auto &[src_model, dst]: models.items() ) + { + const std::string src_make_str = src_make; + const std::string src_model_str = src_model; + if ( model_aliases.find( src_make_str ) != + model_aliases.end() && + model_aliases[src_make_str].find( + src_model_str ) != + model_aliases[src_make_str].end() ) + { + continue; + } + + const std::string dst_make_str = dst["make"]; + const std::string dst_model_str = dst["model"]; + model_aliases[src_make_str][src_model_str] = { + dst_make_str, dst_model_str + }; + } + } + } + } + } + + return true; +} + bool SpectralSolver::load_spectral_data( const std::string &file_path, SpectralData &out_data ) { @@ -304,15 +393,69 @@ bool SpectralSolver::find_camera( return true; } + std::string dst_make = make; + std::string dst_model = model; + + std::map make_aliases; + std::map< + std::string, + std::map>> + model_aliases; + + if ( collect_aliases( "camera", make_aliases, model_aliases ) ) + { + + bool found_make_alias = false; + for ( const auto &[alias_src_make, alias_dst_make]: make_aliases ) + { + if ( is_not_equal_insensitive( make, alias_src_make ) ) + continue; + + dst_make = alias_dst_make; + found_make_alias = true; + break; + } + + bool found_model_alias = false; + for ( const auto &[alias_src_make, alias_src_dict]: model_aliases ) + { + if ( is_not_equal_insensitive( dst_make, alias_src_make ) ) + continue; + + for ( const auto &[alias_src_model, alias_dst_pair]: + alias_src_dict ) + { + if ( is_not_equal_insensitive( model, alias_src_model ) ) + continue; + dst_make = alias_dst_pair.first; + dst_model = alias_dst_pair.second; + found_model_alias = true; + break; + } + + if ( found_model_alias ) + break; + } + + if ( found_make_alias || found_model_alias ) + { + if ( !is_not_equal_insensitive( camera.manufacturer, dst_make ) && + !is_not_equal_insensitive( camera.model, dst_model ) ) + { + return true; + } + } + } + auto camera_files = collect_data_files( "camera" ); for ( const auto &camera_file: camera_files ) { camera.load( camera_file ); - if ( is_not_equal_insensitive( camera.manufacturer, make ) ) + if ( is_not_equal_insensitive( camera.manufacturer, dst_make ) ) continue; - if ( is_not_equal_insensitive( camera.model, model ) ) + if ( is_not_equal_insensitive( camera.model, dst_model ) ) continue; return true; } diff --git a/src/rawtoaces_util/CMakeLists.txt b/src/rawtoaces_util/CMakeLists.txt index d76d9a42..0b9d0df7 100644 --- a/src/rawtoaces_util/CMakeLists.txt +++ b/src/rawtoaces_util/CMakeLists.txt @@ -21,6 +21,7 @@ add_library ( ${RAWTOACES_UTIL_LIB} ${DO_SHARED} colour_transforms.h exiftool.cpp exiftool.h + rawtoaces_util_priv.h $<$: lens_correction.cpp diff --git a/src/rawtoaces_util/image_converter.cpp b/src/rawtoaces_util/image_converter.cpp index e376522b..f4b96512 100644 --- a/src/rawtoaces_util/image_converter.cpp +++ b/src/rawtoaces_util/image_converter.cpp @@ -1409,6 +1409,38 @@ std::vector ImageConverter::get_supported_illuminants() const return result; } +std::string +combine_camera_name( const std::string &make, const std::string &model ) +{ + bool has_prefix = true; + + if ( make.length() <= model.length() ) + { + size_t i; + for ( i = 0; i < make.length(); i++ ) + { + if ( std::tolower( make[i] ) != std::tolower( model[i] ) ) + { + has_prefix = false; + break; + } + } + if ( has_prefix && ( i < model.length() ) ) + { + has_prefix = model[i] == ' '; + } + } + else + { + has_prefix = false; + } + + if ( has_prefix ) + return model; + else + return make + " " + model; +} + std::vector ImageConverter::get_supported_cameras() const { std::vector result; @@ -1420,11 +1452,54 @@ std::vector ImageConverter::get_supported_cameras() const core::SpectralData data; if ( data.load( file, false ) ) { - std::string name = data.manufacturer + " / " + data.model; + std::string name = + combine_camera_name( data.manufacturer, data.model ); result.push_back( name ); } } + std::map make_aliases; + std::map< + std::string, + std::map>> + model_aliases; + if ( solver.collect_aliases( "camera", make_aliases, model_aliases ) ) + { + std::vector parsed_aliases; + for ( auto &[src_make, src_models]: model_aliases ) + { + for ( auto &[src_model, dst]: src_models ) + { + const std::string &dst_make = dst.first; + const std::string &dst_model = dst.second; + const std::string dst_make_model = + combine_camera_name( dst_make, dst_model ); + const std::string src_make_model = + combine_camera_name( src_make, src_model ); + + if ( std::find( + result.begin(), result.end(), dst_make_model ) != + result.end() ) + { + const std::string entry = + src_make_model + " (alias for " + dst_make_model + ")"; + parsed_aliases.push_back( entry ); + } + else + { + std::cerr << "Warning: the alias " << src_make_model + << " points to a missing camera " + << dst_make_model << std::endl; + } + } + } + + result.insert( + result.end(), parsed_aliases.begin(), parsed_aliases.end() ); + } + + std::sort( result.begin(), result.end() ); + return result; } diff --git a/src/rawtoaces_util/rawtoaces_util_priv.h b/src/rawtoaces_util/rawtoaces_util_priv.h index 9c5b3717..bd5497b0 100644 --- a/src/rawtoaces_util/rawtoaces_util_priv.h +++ b/src/rawtoaces_util/rawtoaces_util_priv.h @@ -24,6 +24,9 @@ std::vector database_paths( const std::string &override_path = "" ); void fix_metadata( OIIO::ImageSpec &spec ); +std::string +combine_camera_name( const std::string &make, const std::string &model ); + bool fetch_missing_metadata( const std::string &input_path, const ImageConverter::Settings &settings, diff --git a/tests/test_image_converter.cpp b/tests/test_image_converter.cpp index 727eb397..fc1cc758 100644 --- a/tests/test_image_converter.cpp +++ b/tests/test_image_converter.cpp @@ -636,6 +636,222 @@ void test_fix_metadata_unsupported_type() OIIO_CHECK_EQUAL( spec.find_attribute( "Make" ), nullptr ); } +void test_combine_camera_name() +{ + std::cout << "\n" << __FUNCTION__ << std::endl; + + std::string result = combine_camera_name( "MAKE", "MODEL" ); + OIIO_CHECK_EQUAL( result, "MAKE MODEL" ); + + result = combine_camera_name( "Make", "MAKE MODEL" ); + OIIO_CHECK_EQUAL( result, "MAKE MODEL" ); + + result = combine_camera_name( "MAKE", "MAKEMODEL" ); + OIIO_CHECK_EQUAL( result, "MAKE MAKEMODEL" ); + + result = combine_camera_name( "MAKE_LONGER_THEN_MODEL", "MODEL" ); + OIIO_CHECK_EQUAL( result, "MAKE_LONGER_THEN_MODEL MODEL" ); +} + +void test_empty_aliases() +{ + std::cout << "\n" << __FUNCTION__ << std::endl; + + TestFixture fixture; + auto &test_dir = fixture.with_camera( "Canon", "EOS_R6" ) + .with_aliases( {}, {}, true ) + .without_training() + .without_observer() + .build(); + + rta::core::SpectralSolver solver( + { "/bad/path", test_dir.get_database_path() } ); + + std::map make_aliases; + std::map< + std::string, + std::map>> + model_aliases; + + bool result; + auto output = capture_stderr( [&]() { + result = + solver.collect_aliases( "camera", make_aliases, model_aliases ); + } ); + + OIIO_CHECK_ASSERT( result ); + OIIO_CHECK_ASSERT( make_aliases.empty() ); + OIIO_CHECK_ASSERT( model_aliases.empty() ); + ASSERT_CONTAINS( output, "Warning: the alias file " ); + ASSERT_CONTAINS( output, " must contain the 'data' section." ); +} + +void test_collect_aliases() +{ + std::cout << "\n" << __FUNCTION__ << std::endl; + + TestFixture fixture1; + auto &test_dir1 = fixture1.with_camera( "Canon", "EOS_R6" ) + .with_aliases( {}, {} ) + .without_training() + .without_observer() + .build(); + + TestFixture fixture2; + auto &test_dir2 = + fixture2.with_camera( "Canon", "EOS_R6" ) + .with_aliases( + { { "camera", "MAKE_SRC_MAKE", "MAKE_DST_MAKE" } }, + { { "camera", + "MODEL_SRC_MAKE", + "MODEL_SRC_MODEL", + "MODEL_DST_MAKE", + "MODEL_DST_MODEL" } } ) + .without_training() + .without_observer() + .build(); + + TestFixture fixture3; + auto &test_dir3 = + fixture3.with_camera( "Canon", "EOS_R6" ) + .with_aliases( + { { "camera", "MAKE_SRC_MAKE", "MAKE_DST_MAKE_skip" } }, + { { "camera", + "MODEL_SRC_MAKE", + "MODEL_SRC_MODEL", + "MODEL_DST_MAKE", + "MODEL_DST_MODEL_skip" } } ) + .without_training() + .without_observer() + .build(); + + rta::core::SpectralSolver solver( { "/bad/path", + test_dir1.get_database_path(), + test_dir2.get_database_path(), + test_dir3.get_database_path() } ); + + std::map make_aliases; + std::map< + std::string, + std::map>> + model_aliases; + bool result = + solver.collect_aliases( "camera", make_aliases, model_aliases ); + + OIIO_CHECK_ASSERT( result ); + OIIO_CHECK_EQUAL( make_aliases.size(), 1 ); + OIIO_CHECK_EQUAL( make_aliases["MAKE_SRC_MAKE"], "MAKE_DST_MAKE" ); + OIIO_CHECK_EQUAL( model_aliases.size(), 1 ); + OIIO_CHECK_EQUAL( model_aliases["MODEL_SRC_MAKE"].size(), 1 ); + OIIO_CHECK_EQUAL( + model_aliases["MODEL_SRC_MAKE"]["MODEL_SRC_MODEL"].first, + "MODEL_DST_MAKE" ); + OIIO_CHECK_EQUAL( + model_aliases["MODEL_SRC_MAKE"]["MODEL_SRC_MODEL"].second, + "MODEL_DST_MODEL" ); +} + +void test_get_supported_cameras( bool bad_alias ) +{ + std::cout << "\n" << __FUNCTION__ << std::endl; + + std::string dst_make = bad_alias ? "missing_make" : "Canon"; + std::string dst_model = bad_alias ? "missing_model" : "EOS_R6"; + + // Create test directory with dynamic database + // Store TestFixture to keep it alive for the test duration + TestFixture fixture; + auto &test_dir = fixture.with_camera( "Canon", "EOS_R6" ) + .with_camera( "Mamiya", "Mamiya 7" ) + .with_aliases( + {}, + { { "camera", + "ALIAS_MAKE", + "ALIAS_MODEL", + dst_make, + dst_model } } ) + .without_training() + .without_observer() + .build(); + + ImageConverter converter; + converter.settings.database_directories = { test_dir.get_database_path() }; + + std::vector supported_cameras; + + auto output = capture_stderr( + [&]() { supported_cameras = converter.get_supported_cameras(); } ); + + // Check that both cameras are present (order doesn't matter) + bool found_canon = false; + bool found_mamiya = false; + bool found_alias = false; + for ( auto &camera: supported_cameras ) + { + if ( camera == "Canon EOS_R6" ) + found_canon = true; + if ( camera == "Mamiya 7" ) + found_mamiya = true; + if ( camera == "ALIAS_MAKE ALIAS_MODEL (alias for Canon EOS_R6)" ) + found_alias = true; + } + + OIIO_CHECK_EQUAL( supported_cameras.size(), bad_alias ? 2 : 3 ); + OIIO_CHECK_EQUAL( found_canon, true ); + OIIO_CHECK_EQUAL( found_mamiya, true ); + OIIO_CHECK_NE( found_alias, bad_alias ); + + if ( bad_alias ) + { + ASSERT_CONTAINS( + output, + "Warning: the alias ALIAS_MAKE ALIAS_MODEL " + "points to a missing camera missing_make " + "missing_model" ); + } +} + +void test_find_camera_alias() +{ + std::cout << "\n" << __FUNCTION__ << std::endl; + + // Create test directory with dynamic database + // Store TestFixture to keep it alive for the test duration + TestFixture fixture; + auto &test_dir = fixture.with_camera( "Canon", "EOS_R6" ) + .with_aliases( + { { "camera", "ALIAS_MAKE_1", "ALIAS_MAKE_2" }, + { "camera", "ALIAS_MAKE_3", "ALIAS_MAKE_4" } }, + { { "camera", + "ALIAS_MAKE_2", + "ALIAS_MODEL_1", + "some_make", + "some_model" }, + { "camera", + "ALIAS_MAKE_4", + "ALIAS_MODEL_2", + "Canon", + "EOS_R6" } } ) + .without_training() + .without_observer() + .build(); + + rta::core::SpectralSolver solver( { test_dir.get_database_path() } ); + bool result = solver.find_camera( "ALIAS_MAKE_3", "ALIAS_MODEL_2" ); + + OIIO_CHECK_ASSERT( result ); + OIIO_CHECK_EQUAL( solver.camera.manufacturer, "Canon" ); + OIIO_CHECK_EQUAL( solver.camera.model, "EOS_R6" ); + + // Searching for a camera if already pre-selected follows a different + // code path. + result = solver.find_camera( "ALIAS_MAKE_3", "ALIAS_MODEL_2" ); + + OIIO_CHECK_ASSERT( result ); + OIIO_CHECK_EQUAL( solver.camera.manufacturer, "Canon" ); + OIIO_CHECK_EQUAL( solver.camera.model, "EOS_R6" ); +} + std::string run_rawtoaces_with_data_dir( std::vector args, // Pass by value to avoid modifying original TestDirectory &test_dir, @@ -732,9 +948,9 @@ void test_parse_parameters_list_cameras( bool use_dir_path_arg = false ) bool found_canon = false, found_mamiya = false; for ( size_t i = 1; i < lines.size(); ++i ) { - if ( lines[i] == "Canon / EOS_R6" ) + if ( lines[i] == "Canon EOS_R6" ) found_canon = true; - if ( lines[i] == "Mamiya / Mamiya 7" ) + if ( lines[i] == "Mamiya 7" ) found_mamiya = true; } OIIO_CHECK_EQUAL( found_canon, true ); @@ -2734,6 +2950,13 @@ int main( int, char ** ) test_fetch_missing_metadata(); + test_combine_camera_name(); + test_empty_aliases(); + test_collect_aliases(); + test_get_supported_cameras( false ); + test_get_supported_cameras( true ); + test_find_camera_alias(); + // Tests for parse_parameters test_parse_parameters_list_formats(); test_parse_parameters_list_cameras(); diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp index 3cd766ea..fff3b764 100644 --- a/tests/test_utils.cpp +++ b/tests/test_utils.cpp @@ -314,6 +314,28 @@ std::string TestDirectory::create_test_data_file( return file_path; } +std::string +TestDirectory::create_aliases_file( const nlohmann::json &header_data ) +{ + // Create target directory dynamically based on type + std::string target_dir = database_dir; + std::filesystem::create_directories( target_dir ); + + // Use expected filename for specific types, random for others + std::string filename = "aliases.json"; + std::string file_path = target_dir + "/" + filename; + + // Create minimal JSON structure with only what's actually used + nlohmann::json json_data = header_data; + + // Write to file with pretty formatting + std::ofstream file( file_path ); + file << json_data.dump( 4 ) << std::endl; + file.close(); + + return file_path; +} + // ============================================================================ // TestFixture Implementation // ============================================================================ @@ -344,6 +366,63 @@ TestFixture &TestFixture::with_camera( return *this; } +TestFixture &TestFixture::with_aliases( + const std::vector> &make_aliases, + const std::vector> &model_aliases, + bool empty ) +{ + nlohmann::json json_data = nlohmann::json::object(); + + if ( !empty ) + { + json_data["data"] = nlohmann::json::object(); + + for ( auto &make_alias: make_aliases ) + { + const auto &type = make_alias[0]; + const auto &src_make = make_alias[1]; + const auto &dst_make = make_alias[2]; + + if ( !json_data["data"].contains( type ) ) + json_data["data"][type] = nlohmann::json::object(); + + if ( !json_data["data"][type].contains( "make" ) ) + json_data["data"][type]["make"] = nlohmann::json::object(); + + if ( !json_data["data"][type]["make"].contains( src_make ) ) + json_data["data"][type]["make"][src_make] = dst_make; + } + + for ( auto &model_alias: model_aliases ) + { + const auto &type = model_alias[0]; + const auto &src_make = model_alias[1]; + const auto &src_model = model_alias[2]; + const auto &dst_make = model_alias[3]; + const auto &dst_model = model_alias[4]; + + if ( !json_data["data"].contains( type ) ) + json_data["data"][type] = nlohmann::json::object(); + + if ( !json_data["data"][type].contains( "model" ) ) + json_data["data"][type]["model"] = nlohmann::json::object(); + + if ( !json_data["data"][type]["model"].contains( src_make ) ) + json_data["data"][type]["model"][src_make] = + nlohmann::json::object(); + + if ( !json_data["data"][type]["model"][src_make].contains( + src_model ) ) + json_data["data"][type]["model"][src_make][src_model] = { + { "make", dst_make }, { "model", dst_model } + }; + } + } + + test_dir_->create_aliases_file( json_data ); + return *this; +} + TestFixture &TestFixture::without_training() { /// Exclude training from defaults diff --git a/tests/test_utils.h b/tests/test_utils.h index 389a0114..9295d6c4 100644 --- a/tests/test_utils.h +++ b/tests/test_utils.h @@ -45,6 +45,11 @@ class TestDirectory const std::optional &data_main_override = std::nullopt ); + /// Creates a test aliases file with the specified data + /// @param data The aliases data to be put into the file + /// @return The full path to the created file + std::string create_aliases_file( const nlohmann::json &data ); + private: std::string test_dir; std::string database_dir; @@ -109,6 +114,11 @@ class TestFixture const std::optional &data_main_override = std::nullopt ); + TestFixture &with_aliases( + const std::vector> &make_aliases, + const std::vector> &model_aliases, + bool empty = false ); + /// Remove training data file (training is included by default) TestFixture &without_training(); From f111253494de0e7e2aa193b179882b32daa16a69 Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Mon, 30 Mar 2026 16:11:37 +1300 Subject: [PATCH 2/3] address the review comments Signed-off-by: Anton Dukhovnikov --- src/rawtoaces_core/rawtoaces_core.cpp | 19 ++++++++++++++++++- src/rawtoaces_util/image_converter.cpp | 13 +++++++++---- src/rawtoaces_util/rawtoaces_util_priv.h | 2 +- tests/test_image_converter.cpp | 12 ++++++------ 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/rawtoaces_core/rawtoaces_core.cpp b/src/rawtoaces_core/rawtoaces_core.cpp index 48bc370c..1e53f9b1 100644 --- a/src/rawtoaces_core/rawtoaces_core.cpp +++ b/src/rawtoaces_core/rawtoaces_core.cpp @@ -285,6 +285,11 @@ bool SpectralSolver::collect_aliases( if ( std::filesystem::exists( path ) ) { + // For now we consider the aliases files optional. + // In a case of error, we just skip the file and process the next + // one. We still want to report warnings to let the user a chance + // to fix broken files. + std::ifstream ifstream( path ); if ( !ifstream.is_open() ) { @@ -293,7 +298,19 @@ bool SpectralSolver::collect_aliases( continue; } - nlohmann::json file_data = nlohmann::json::parse( ifstream ); + nlohmann::json file_data; + + try + { + file_data = nlohmann::json::parse( ifstream ); + } + catch ( const std::exception &error ) + { + std::cerr << "Warning: JSON parsing of the alias file " + << path.string() << " failed with error: " + << error.what() << "." << std::endl; + continue; + } if ( !file_data.contains( "data" ) ) { diff --git a/src/rawtoaces_util/image_converter.cpp b/src/rawtoaces_util/image_converter.cpp index f4b96512..9c2275eb 100644 --- a/src/rawtoaces_util/image_converter.cpp +++ b/src/rawtoaces_util/image_converter.cpp @@ -1409,8 +1409,13 @@ std::vector ImageConverter::get_supported_illuminants() const return result; } +/// Combine the make and model strings together, unless they are the same, +/// or the model name starts with the make followed by a whitespace. +/// "Canon" + "Canon R5" = "Canon R5" +/// "Canon R5" + "Canon R5" = "Canon R5" +/// "Canon" + "Canon_R5" = "Canon Canon_R5" std::string -combine_camera_name( const std::string &make, const std::string &model ) +combine_make_model( const std::string &make, const std::string &model ) { bool has_prefix = true; @@ -1453,7 +1458,7 @@ std::vector ImageConverter::get_supported_cameras() const if ( data.load( file, false ) ) { std::string name = - combine_camera_name( data.manufacturer, data.model ); + combine_make_model( data.manufacturer, data.model ); result.push_back( name ); } } @@ -1473,9 +1478,9 @@ std::vector ImageConverter::get_supported_cameras() const const std::string &dst_make = dst.first; const std::string &dst_model = dst.second; const std::string dst_make_model = - combine_camera_name( dst_make, dst_model ); + combine_make_model( dst_make, dst_model ); const std::string src_make_model = - combine_camera_name( src_make, src_model ); + combine_make_model( src_make, src_model ); if ( std::find( result.begin(), result.end(), dst_make_model ) != diff --git a/src/rawtoaces_util/rawtoaces_util_priv.h b/src/rawtoaces_util/rawtoaces_util_priv.h index bd5497b0..406f4309 100644 --- a/src/rawtoaces_util/rawtoaces_util_priv.h +++ b/src/rawtoaces_util/rawtoaces_util_priv.h @@ -25,7 +25,7 @@ std::vector void fix_metadata( OIIO::ImageSpec &spec ); std::string -combine_camera_name( const std::string &make, const std::string &model ); +combine_make_model( const std::string &make, const std::string &model ); bool fetch_missing_metadata( const std::string &input_path, diff --git a/tests/test_image_converter.cpp b/tests/test_image_converter.cpp index fc1cc758..c60e72e0 100644 --- a/tests/test_image_converter.cpp +++ b/tests/test_image_converter.cpp @@ -636,20 +636,20 @@ void test_fix_metadata_unsupported_type() OIIO_CHECK_EQUAL( spec.find_attribute( "Make" ), nullptr ); } -void test_combine_camera_name() +void test_combine_make_model() { std::cout << "\n" << __FUNCTION__ << std::endl; - std::string result = combine_camera_name( "MAKE", "MODEL" ); + std::string result = combine_make_model( "MAKE", "MODEL" ); OIIO_CHECK_EQUAL( result, "MAKE MODEL" ); - result = combine_camera_name( "Make", "MAKE MODEL" ); + result = combine_make_model( "Make", "MAKE MODEL" ); OIIO_CHECK_EQUAL( result, "MAKE MODEL" ); - result = combine_camera_name( "MAKE", "MAKEMODEL" ); + result = combine_make_model( "MAKE", "MAKEMODEL" ); OIIO_CHECK_EQUAL( result, "MAKE MAKEMODEL" ); - result = combine_camera_name( "MAKE_LONGER_THEN_MODEL", "MODEL" ); + result = combine_make_model( "MAKE_LONGER_THEN_MODEL", "MODEL" ); OIIO_CHECK_EQUAL( result, "MAKE_LONGER_THEN_MODEL MODEL" ); } @@ -2950,7 +2950,7 @@ int main( int, char ** ) test_fetch_missing_metadata(); - test_combine_camera_name(); + test_combine_make_model(); test_empty_aliases(); test_collect_aliases(); test_get_supported_cameras( false ); From 8d640c2c86ddb60fcd1d4443089681d16f5b6895 Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Mon, 30 Mar 2026 16:13:49 +1300 Subject: [PATCH 3/3] fix formatting Signed-off-by: Anton Dukhovnikov --- src/rawtoaces_core/rawtoaces_core.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rawtoaces_core/rawtoaces_core.cpp b/src/rawtoaces_core/rawtoaces_core.cpp index 1e53f9b1..0bef55c9 100644 --- a/src/rawtoaces_core/rawtoaces_core.cpp +++ b/src/rawtoaces_core/rawtoaces_core.cpp @@ -307,8 +307,9 @@ bool SpectralSolver::collect_aliases( catch ( const std::exception &error ) { std::cerr << "Warning: JSON parsing of the alias file " - << path.string() << " failed with error: " - << error.what() << "." << std::endl; + << path.string() + << " failed with error: " << error.what() << "." + << std::endl; continue; }