From 07fe8b8d0a5f85300f0b23aec35f0862c13a542d Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 5 Jan 2024 18:47:57 -0500 Subject: [PATCH] icc: Add a --debug-roundtrip flag With this, we convert a bunch of random colors to a profile's profile connection space and back, and count how many u8 colors make it through unchanged. With this, you can do something like: for f in ~/Downloads/Adobe\ ICC\ Profiles\ \(end-user\)/*/*.icc; do echo $f Build/lagom/bin/icc --debug-roundtrip $f done to test conversion through a bunch of profiles. These profiles are available at: https://www.adobe.com/support/downloads/iccprofiles/iccprofiles_win.html ...which ultimately leads to: https://download.adobe.com/pub/adobe/iccprofiles/win/AdobeICCProfilesCS4Win_end-user.zip (Or use `Build/lagom/bin/icc --debug-roundtrip -n sRGB` to test the built-in sRGB profile.) --- Userland/Utilities/icc.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Userland/Utilities/icc.cpp b/Userland/Utilities/icc.cpp index 7698f86dc78..12433624caa 100644 --- a/Userland/Utilities/icc.cpp +++ b/Userland/Utilities/icc.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -162,6 +163,31 @@ static ErrorOr out_curves(Vector const& curves) return {}; } +static ErrorOr perform_debug_roundtrip(Gfx::ICC::Profile const& profile) +{ + size_t num_channels = Gfx::ICC::number_of_components_in_color_space(profile.data_color_space()); + Vector input, output; + input.resize(num_channels); + output.resize(num_channels); + + size_t const num_total_roundtrips = 500; + size_t num_lossless_roundtrips = 0; + + for (size_t i = 0; i < num_total_roundtrips; ++i) { + for (size_t j = 0; j < num_channels; ++j) + input[j] = get_random(); + auto color_in_profile_connection_space = TRY(profile.to_pcs(input)); + TRY(profile.from_pcs(profile, color_in_profile_connection_space, output)); + if (input != output) { + outln("roundtrip failed for {} -> {}", input, output); + } else { + ++num_lossless_roundtrips; + } + } + outln("lossless roundtrips: {} / {}", num_lossless_roundtrips, num_total_roundtrips); + return {}; +} + static ErrorOr print_profile_measurement(Gfx::ICC::Profile const& profile) { auto lab_from_rgb = [&profile](u8 r, u8 g, u8 b) { @@ -217,6 +243,9 @@ ErrorOr serenity_main(Main::Arguments arguments) StringView reencode_out_path; args_parser.add_option(reencode_out_path, "Reencode ICC profile to this path", "reencode-to", 0, "FILE"); + bool debug_roundtrip = false; + args_parser.add_option(debug_roundtrip, "Check how many u8 colors roundtrip losslessly through the profile. For debugging.", "debug-roundtrip", 0); + bool measure = false; args_parser.add_option(measure, "For RGB ICC profiles, print perceptually smallest and largest color step", "measure", 0); @@ -272,6 +301,11 @@ ErrorOr serenity_main(Main::Arguments arguments) TRY(output_stream->write_until_depleted(reencoded_bytes)); } + if (debug_roundtrip) { + TRY(perform_debug_roundtrip(*profile)); + return 0; + } + if (measure) { if (profile->data_color_space() != Gfx::ICC::ColorSpace::RGB) { warnln("--measure only works for RGB ICC profiles");