From d0e96b552c3721ca3702eec640948611cd3e5740 Mon Sep 17 00:00:00 2001 From: Bart Diricx Date: Sun, 22 Jun 2025 09:20:57 +0200 Subject: [PATCH 1/7] Add suport for multiple Output ICC profile types The default Output ICC profile is still "sRGB" (backwards compatibility). Additionally, a second wide-gamut Output ICC profile "Display-P3" has been added. This profile uses a D65 white point, a sRGB transfer function, the DCI-P3 primaries and is widely supported by modern browsers. --- CMakeLists.txt | 2 +- package.json | 2 +- src/dicomicc.c | 84 ++++++++++++++++++++++++++++++++++----- src/dicomicc.h | 13 ++++++ wasm/src/ColorManager.hpp | 14 ++++--- wasm/src/jslib.cpp | 2 +- 6 files changed, 99 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 485c9fe..3e2f6e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.16) project (dicomicc) set(DICOMICC_VERSION_MAJOR 0) -set(DICOMICC_VERSION_MINOR 1) +set(DICOMICC_VERSION_MINOR 2) set(DICOMICC_VERSION_PATCH 0) set(DICOMICC_VERSION "${DICOMICC_VERSION_MAJOR}.${DICOMICC_VERSION_MINOR}.${DICOMICC_VERSION_PATCH}") diff --git a/package.json b/package.json index 31f50b0..c9526ce 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dicomicc", - "version": "0.1.0", + "version": "0.2.0", "description": "WASM bindings and JavaScript API for the dicomicc C library", "main": "dist/dicomiccwasm.js", "publishConfig": { diff --git a/src/dicomicc.c b/src/dicomicc.c index deab91b..97f5817 100644 --- a/src/dicomicc.c +++ b/src/dicomicc.c @@ -16,23 +16,74 @@ const char *dcm_icc_get_version(void) { return DCMICC_VERSION; } -DmcIccTransform *dcm_icc_transform_create(const char *icc_profile, - uint32_t icc_profile_size, - uint8_t planar_configuration, - uint16_t columns, - uint16_t rows) { +DmcIccTransform *dcm_icc_transform_create_for_output(const char *icc_profile, + uint32_t icc_profile_size, + uint8_t planar_configuration, + uint16_t columns, + uint16_t rows, + DcmIccOutputType output_type) { cmsUInt32Number type; // Input ICC profile: obtained from DICOM data set - const cmsHPROFILE in_handle = cmsOpenProfileFromMem(icc_profile, - icc_profile_size); + const cmsHPROFILE in_handle = cmsOpenProfileFromMem(icc_profile, + icc_profile_size); + cmsHPROFILE out_handle = NULL; if (in_handle == NULL) { return NULL; } - // Output ICC profile: fixed to sRGB - const cmsHPROFILE out_handle = cmsCreate_sRGBProfile(); + // sRGB output ICC profile (use build-in littleCMS functionality) + if (output_type == DCM_ICC_OUTPUT_SRGB) { + // Output ICC profile: fixed to sRGB + out_handle = cmsCreate_sRGBProfile(); + + // Display-P3 output ICC profile: this is a wide-gamut RGB color space + } else if (output_type == DCM_ICC_OUTPUT_DISPLAY_P3) { + // D65 White Point + cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 }; + // Display-P3 primaries (same as DCI-P3) + cmsCIExyYTRIPLE DisplayP3Primaries = { + {0.6800, 0.3200, 1.0}, // Display P3 Red + {0.2650, 0.6900, 1.0}, // Display P3 Green + {0.1500, 0.0600, 1.0} // Display P3 Blue + }; + // sRGB transfer function + cmsToneCurve* sRGBTransferFunction[3]; + cmsFloat64Number Parameters[5]; + Parameters[0] = 2.4; + Parameters[1] = 1. / 1.055; + Parameters[2] = 0.055 / 1.055; + Parameters[3] = 1. / 12.92; + Parameters[4] = 0.04045; + + sRGBTransferFunction[0] = sRGBTransferFunction[1] = sRGBTransferFunction[2] = cmsBuildParametricToneCurve(NULL, 4, Parameters); + if (sRGBTransferFunction[0] == NULL) { + cmsCloseProfile(in_handle); + return NULL; + } + + // Combine the white point, primaries, and transfer functions into an RGB profile + out_handle = cmsCreateRGBProfileTHR(NULL, &D65, &DisplayP3Primaries, sRGBTransferFunction); + cmsFreeToneCurve(sRGBTransferFunction[0]); + + if (out_handle == NULL) { + cmsCloseProfile(in_handle); + return NULL; + } + + // Set the profile description + const wchar_t* description = L"Display-P3"; + cmsMLU* mlu = cmsMLUalloc(NULL, 1); + cmsMLUsetWide(mlu, "en", "US", description); + cmsWriteTag(out_handle, cmsSigProfileDescriptionTag, mlu); + cmsMLUfree(mlu); + + } else { + // Unknown or unsupported output_type + cmsCloseProfile(in_handle); + return NULL; + } if (out_handle == NULL) { cmsCloseProfile(in_handle); @@ -72,6 +123,21 @@ DmcIccTransform *dcm_icc_transform_create(const char *icc_profile, return icc_transform; } +// Backward-compatible wrapper function +DmcIccTransform *dcm_icc_transform_create(const char *icc_profile, + uint32_t icc_profile_size, + uint8_t planar_configuration, + uint16_t columns, + uint16_t rows) { + // Call the extended function with DCM_ICC_OUTPUT_SRGB as the default output type + return dcm_icc_transform_create_for_output(icc_profile, + icc_profile_size, + planar_configuration, + columns, + rows, + DCM_ICC_OUTPUT_SRGB); +} + void dcm_icc_transform_apply(const DmcIccTransform *icc_transform, const char *frame, uint32_t frame_size, diff --git a/src/dicomicc.h b/src/dicomicc.h index d2b4d6b..10bb0e6 100644 --- a/src/dicomicc.h +++ b/src/dicomicc.h @@ -5,8 +5,21 @@ typedef struct _DmcIccTransform DmcIccTransform; +// Enum to specify the desired output ICC profile type +typedef enum { + DCM_ICC_OUTPUT_SRGB = 0, // Standard sRGB profile + DCM_ICC_OUTPUT_DISPLAY_P3 = 1 // Display P3 profile +} DcmIccOutputType; + extern const char *dcm_icc_get_version(void); +extern DmcIccTransform *dcm_icc_transform_create_for_output(const char *icc_profile, + uint32_t icc_profile_size, + uint8_t planar_configuration, + uint16_t columns, + uint16_t rows, + DcmIccOutputType output_type); + extern DmcIccTransform *dcm_icc_transform_create(const char *icc_profile, uint32_t icc_profile_size, uint8_t planar_configuration, diff --git a/wasm/src/ColorManager.hpp b/wasm/src/ColorManager.hpp index 89e9a52..0f1942f 100644 --- a/wasm/src/ColorManager.hpp +++ b/wasm/src/ColorManager.hpp @@ -21,18 +21,20 @@ class ColorManager { /// Constructor /// ColorManager(FrameInfo frameInfo, - const val &iccProfile) { + const val &iccProfile, + int outputType = 0 /* 0: sRGB (default), 1: Display-P3 */) { this->frameInfo = frameInfo; const std::vector iccProfileVector = convertJSArrayToNumberVector(iccProfile); - this->icc_transform = dcm_icc_transform_create((const char *) iccProfileVector.data(), - (uint32_t) iccProfileVector.size(), - this->frameInfo.planarConfiguration, - this->frameInfo.columns, - this->frameInfo.rows); + this->icc_transform = dcm_icc_transform_create_for_output((const char *) iccProfileVector.data(), + (uint32_t) iccProfileVector.size(), + this->frameInfo.planarConfiguration, + this->frameInfo.columns, + this->frameInfo.rows, + static_cast(outputType)); } /// diff --git a/wasm/src/jslib.cpp b/wasm/src/jslib.cpp index 5c3770f..7396fc0 100644 --- a/wasm/src/jslib.cpp +++ b/wasm/src/jslib.cpp @@ -17,7 +17,7 @@ EMSCRIPTEN_BINDINGS(FrameInfo) { EMSCRIPTEN_BINDINGS(ColorManager) { class_("ColorManager") - .constructor() + .constructor() .function("getFrameInfo", &ColorManager::getFrameInfo) .function("transform", &ColorManager::transform) ; From 37790cd60005d6cb63318188d2426e8f6624f3b4 Mon Sep 17 00:00:00 2001 From: Andrey Fedorov Date: Thu, 10 Jul 2025 12:16:18 -0400 Subject: [PATCH 2/7] change install location install to a system dir does not work on mac --- .github/workflows/run_unit_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_unit_tests.yml b/.github/workflows/run_unit_tests.yml index 8501e69..4b8e1f1 100644 --- a/.github/workflows/run_unit_tests.yml +++ b/.github/workflows/run_unit_tests.yml @@ -98,7 +98,7 @@ jobs: run: | mkdir build cd build - cmake -DCMAKE_PREFIX_PATH='/usr/local' .. + cmake -DCMAKE_PREFIX_PATH=$PWD/install .. make make install From 3885fff542f3d9f45e12ac217c8a7193e29e4ced Mon Sep 17 00:00:00 2001 From: Bart Diricx Date: Wed, 30 Jul 2025 17:00:35 +0200 Subject: [PATCH 3/7] Attempt to fix unit test build failure on macos --- .github/workflows/run_unit_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_unit_tests.yml b/.github/workflows/run_unit_tests.yml index 4b8e1f1..19c3b3b 100644 --- a/.github/workflows/run_unit_tests.yml +++ b/.github/workflows/run_unit_tests.yml @@ -98,7 +98,7 @@ jobs: run: | mkdir build cd build - cmake -DCMAKE_PREFIX_PATH=$PWD/install .. + cmake -DCMAKE_PREFIX_PATH=$PWD/install -DCMAKE_INSTALL_PREFIX=$PWD/install .. make make install From db22f948bd1e600ff3f3cc05f4ed69aa8caaebef Mon Sep 17 00:00:00 2001 From: Bart Diricx Date: Thu, 7 Aug 2025 17:39:28 +0200 Subject: [PATCH 4/7] Handle PR feedback: use enum value instead of hardcoded integer value + Add support for Adobe RGB (1998) and ROMM RGB --- src/dicomicc.c | 280 +++++++++++++++++++++++++++++++------- src/dicomicc.h | 6 +- wasm/src/ColorManager.hpp | 2 +- wasm/src/jslib.cpp | 13 ++ 4 files changed, 250 insertions(+), 51 deletions(-) diff --git a/src/dicomicc.c b/src/dicomicc.c index 97f5817..e2c0a95 100644 --- a/src/dicomicc.c +++ b/src/dicomicc.c @@ -16,6 +16,224 @@ const char *dcm_icc_get_version(void) { return DCMICC_VERSION; } +/** + * Create an sRGB ICC profile + */ +cmsHPROFILE create_srgb_profile(void) { + // Use the built-in littleCMS sRGB profile creation function + cmsHPROFILE profile = cmsCreate_sRGBProfile(); + + if (profile == NULL) { + fprintf(stderr, "Error: Failed to create sRGB profile\n"); + return NULL; + } + + return profile; +} + +/** + * Create a Display-P3 ICC profile + * Based on https://www.color.org/chardata/rgb/DisplayP3.xalter + */ +cmsHPROFILE create_display_p3_profile(void) { + // D65 White Point + cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 }; + + // Display-P3 primaries (same as DCI-P3) + cmsCIExyYTRIPLE DisplayP3Primaries = { + {0.6800, 0.3200, 1.0}, // Display P3 Red + {0.2650, 0.6900, 1.0}, // Display P3 Green + {0.1500, 0.0600, 1.0} // Display P3 Blue + }; + + // sRGB transfer function parameters, parametric curve type 4: + // Y = (a * X + b) ^ gamma for X >= d + // Y = c * X for X < d + cmsToneCurve* sRGBTransferFunction[3]; + cmsFloat64Number Parameters[5]; + Parameters[0] = 2.4; // Gamma + Parameters[1] = 1. / 1.055; // a + Parameters[2] = 0.055 / 1.055; // b + Parameters[3] = 1. / 12.92; // c + Parameters[4] = 0.04045; // d + + // Create the tone curve + sRGBTransferFunction[0] = sRGBTransferFunction[1] = sRGBTransferFunction[2] = + cmsBuildParametricToneCurve(NULL, 4, Parameters); + + if (sRGBTransferFunction[0] == NULL) { + fprintf(stderr, "Error: Failed to create sRGB transfer function\n"); + return NULL; + } + + // Combine the white point, primaries, and transfer functions into an RGB profile + cmsHPROFILE profile = cmsCreateRGBProfileTHR(NULL, &D65, &DisplayP3Primaries, sRGBTransferFunction); + + // Free the tone curve (profile now owns a copy) + cmsFreeToneCurve(sRGBTransferFunction[0]); + + if (profile == NULL) { + fprintf(stderr, "Error: Failed to create Display-P3 profile\n"); + return NULL; + } + + // Set the profile description + const wchar_t* description = L"Display-P3"; + cmsMLU* mlu = cmsMLUalloc(NULL, 1); + if (mlu != NULL) { + cmsMLUsetWide(mlu, "en", "US", description); + cmsWriteTag(profile, cmsSigProfileDescriptionTag, mlu); + cmsMLUfree(mlu); + } + + // Set additional profile information + const wchar_t* copyright = L"Public Domain"; + cmsMLU* copyright_mlu = cmsMLUalloc(NULL, 1); + if (copyright_mlu != NULL) { + cmsMLUsetWide(copyright_mlu, "en", "US", copyright); + cmsWriteTag(profile, cmsSigCopyrightTag, copyright_mlu); + cmsMLUfree(copyright_mlu); + } + + return profile; +} + +/** + * Create an Adobe RGB ICC profile + * Based on https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf (incl. Annex C) + */ +cmsHPROFILE create_adobe_rgb_profile(void) { + // D65 White Point + cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 }; + + // AdobeRGB primaries + cmsCIExyYTRIPLE AdobeRGBPrimaries = { + {0.6400, 0.3300, 1.0}, // Adobe RGB Red + {0.2100, 0.7100, 1.0}, // Adobe RGB Green + {0.1500, 0.0600, 1.0} // Adobe RGB Blue + }; + + // Adobe RGB transfer function parameters, parametric curve type 4: + // Y = (a * X + b) ^ gamma for X >= d + // Y = c * X for X < d + cmsToneCurve* AdobeRGBTransferFunction[3]; + cmsFloat64Number Parameters[5]; + Parameters[0] = 2. + 13107. / 65536.; // Gamma + Parameters[1] = 1.; // a + Parameters[2] = 0; // b + Parameters[3] = 1. / 32; // c + Parameters[4] = 0.055680761; // d (= c ^ (1 / (gamma - 1)) + + // Create the tone curve + AdobeRGBTransferFunction[0] = AdobeRGBTransferFunction[1] = AdobeRGBTransferFunction[2] = + cmsBuildParametricToneCurve(NULL, 4, Parameters); + + if (AdobeRGBTransferFunction[0] == NULL) { + fprintf(stderr, "Error: Failed to create Adobe RGB transfer function\n"); + return NULL; + } + + // Combine the white point, primaries, and transfer functions into an RGB profile + cmsHPROFILE profile = cmsCreateRGBProfileTHR(NULL, &D65, &AdobeRGBPrimaries, AdobeRGBTransferFunction); + + // Free the tone curve (profile now owns a copy) + cmsFreeToneCurve(AdobeRGBTransferFunction[0]); + + if (profile == NULL) { + fprintf(stderr, "Error: Failed to create Adobe RGB profile\n"); + return NULL; + } + + // Set the profile description + const wchar_t* description = L"Adobe RGB (1998)"; + cmsMLU* mlu = cmsMLUalloc(NULL, 1); + if (mlu != NULL) { + cmsMLUsetWide(mlu, "en", "US", description); + cmsWriteTag(profile, cmsSigProfileDescriptionTag, mlu); + cmsMLUfree(mlu); + } + + // Set additional profile information + const wchar_t* copyright = L"Public Domain"; + cmsMLU* copyright_mlu = cmsMLUalloc(NULL, 1); + if (copyright_mlu != NULL) { + cmsMLUsetWide(copyright_mlu, "en", "US", copyright); + cmsWriteTag(profile, cmsSigCopyrightTag, copyright_mlu); + cmsMLUfree(copyright_mlu); + } + + return profile; +} + +/* + * Create a ROMM RGB ICC profile + * Based on https://www.color.org/chardata/rgb/ROMMRGB.pdf + */ +cmsHPROFILE create_romm_rgb_profile(void) { + // D50 White Point + cmsCIExyY D50 = { 0.3457, 0.3585, 1.0 }; + + // ROMM RGB primaries + cmsCIExyYTRIPLE RommRGBPrimaries = { + {0.7347, 0.2653, 1.0}, // ROMM RGB Red + {0.1596, 0.8404, 1.0}, // ROMM RGB Green + {0.0366, 0.0001, 1.0} // ROMM RGB Blue + }; + + // ROMM RGB transfer function parameters, parametric curve type 5: + // Y = (a * X + b) ^ gamma + e for X >= d + // Y = c * X + f for X < d + cmsToneCurve* RommRGBTransferFunction[3]; + cmsFloat64Number Parameters[7]; + Parameters[0] = 1.8; // Gamma + Parameters[1] = 0.996527; // a + Parameters[2] = 0.003473; // b + Parameters[3] = 0.0622829; // c + Parameters[4] = 0.03125; // d + Parameters[5] = 0.0; // e + Parameters[6] = 0.003473; // f + + // Create the tone curve + RommRGBTransferFunction[0] = RommRGBTransferFunction[1] = RommRGBTransferFunction[2] = + cmsBuildParametricToneCurve(NULL, 5, Parameters); + + if (RommRGBTransferFunction[0] == NULL) { + fprintf(stderr, "Error: Failed to create Romm RGB transfer function\n"); + return NULL; + } + + // Combine the white point, primaries, and transfer functions into an RGB profile + cmsHPROFILE profile = cmsCreateRGBProfileTHR(NULL, &D50, &RommRGBPrimaries, RommRGBTransferFunction); + + // Free the tone curve (profile now owns a copy) + cmsFreeToneCurve(RommRGBTransferFunction[0]); + + if (profile == NULL) { + fprintf(stderr, "Error: Failed to create Romm RGB profile\n"); + return NULL; + } + + // Set the profile description + const wchar_t* description = L"ROMM RGB"; + cmsMLU* mlu = cmsMLUalloc(NULL, 1); + if (mlu != NULL) { + cmsMLUsetWide(mlu, "en", "US", description); + cmsWriteTag(profile, cmsSigProfileDescriptionTag, mlu); + cmsMLUfree(mlu); + } + + // Set additional profile information + const wchar_t* copyright = L"Public Domain"; + cmsMLU* copyright_mlu = cmsMLUalloc(NULL, 1); + if (copyright_mlu != NULL) { + cmsMLUsetWide(copyright_mlu, "en", "US", copyright); + cmsWriteTag(profile, cmsSigCopyrightTag, copyright_mlu); + cmsMLUfree(copyright_mlu); + } + + return profile; +} + DmcIccTransform *dcm_icc_transform_create_for_output(const char *icc_profile, uint32_t icc_profile_size, uint8_t planar_configuration, @@ -33,56 +251,22 @@ DmcIccTransform *dcm_icc_transform_create_for_output(const char *icc_profile, return NULL; } - // sRGB output ICC profile (use build-in littleCMS functionality) - if (output_type == DCM_ICC_OUTPUT_SRGB) { - // Output ICC profile: fixed to sRGB - out_handle = cmsCreate_sRGBProfile(); - - // Display-P3 output ICC profile: this is a wide-gamut RGB color space - } else if (output_type == DCM_ICC_OUTPUT_DISPLAY_P3) { - // D65 White Point - cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 }; - // Display-P3 primaries (same as DCI-P3) - cmsCIExyYTRIPLE DisplayP3Primaries = { - {0.6800, 0.3200, 1.0}, // Display P3 Red - {0.2650, 0.6900, 1.0}, // Display P3 Green - {0.1500, 0.0600, 1.0} // Display P3 Blue - }; - // sRGB transfer function - cmsToneCurve* sRGBTransferFunction[3]; - cmsFloat64Number Parameters[5]; - Parameters[0] = 2.4; - Parameters[1] = 1. / 1.055; - Parameters[2] = 0.055 / 1.055; - Parameters[3] = 1. / 12.92; - Parameters[4] = 0.04045; - - sRGBTransferFunction[0] = sRGBTransferFunction[1] = sRGBTransferFunction[2] = cmsBuildParametricToneCurve(NULL, 4, Parameters); - if (sRGBTransferFunction[0] == NULL) { + switch (output_type) { + case DCM_ICC_OUTPUT_SRGB: + out_handle = create_srgb_profile(); + break; + case DCM_ICC_OUTPUT_DISPLAY_P3: + out_handle = create_display_p3_profile(); + break; + case DCM_ICC_OUTPUT_ADOBE_RGB: + out_handle = create_adobe_rgb_profile(); + break; + case DCM_ICC_OUTPUT_ROMM_RGB: + out_handle = create_romm_rgb_profile(); + break; + default: cmsCloseProfile(in_handle); return NULL; - } - - // Combine the white point, primaries, and transfer functions into an RGB profile - out_handle = cmsCreateRGBProfileTHR(NULL, &D65, &DisplayP3Primaries, sRGBTransferFunction); - cmsFreeToneCurve(sRGBTransferFunction[0]); - - if (out_handle == NULL) { - cmsCloseProfile(in_handle); - return NULL; - } - - // Set the profile description - const wchar_t* description = L"Display-P3"; - cmsMLU* mlu = cmsMLUalloc(NULL, 1); - cmsMLUsetWide(mlu, "en", "US", description); - cmsWriteTag(out_handle, cmsSigProfileDescriptionTag, mlu); - cmsMLUfree(mlu); - - } else { - // Unknown or unsupported output_type - cmsCloseProfile(in_handle); - return NULL; } if (out_handle == NULL) { diff --git a/src/dicomicc.h b/src/dicomicc.h index 10bb0e6..20d223a 100644 --- a/src/dicomicc.h +++ b/src/dicomicc.h @@ -7,8 +7,10 @@ typedef struct _DmcIccTransform DmcIccTransform; // Enum to specify the desired output ICC profile type typedef enum { - DCM_ICC_OUTPUT_SRGB = 0, // Standard sRGB profile - DCM_ICC_OUTPUT_DISPLAY_P3 = 1 // Display P3 profile + DCM_ICC_OUTPUT_SRGB = 0, // Standard sRGB profile + DCM_ICC_OUTPUT_DISPLAY_P3 = 1, // Display-P3 profile + DCM_ICC_OUTPUT_ADOBE_RGB = 2, // Adobe RGB (1998) profile + DCM_ICC_OUTPUT_ROMM_RGB = 3 // ROMM RGB profile } DcmIccOutputType; extern const char *dcm_icc_get_version(void); diff --git a/wasm/src/ColorManager.hpp b/wasm/src/ColorManager.hpp index 0f1942f..855fcfd 100644 --- a/wasm/src/ColorManager.hpp +++ b/wasm/src/ColorManager.hpp @@ -22,7 +22,7 @@ class ColorManager { /// ColorManager(FrameInfo frameInfo, const val &iccProfile, - int outputType = 0 /* 0: sRGB (default), 1: Display-P3 */) { + int outputType = DCM_ICC_OUTPUT_SRGB) { this->frameInfo = frameInfo; diff --git a/wasm/src/jslib.cpp b/wasm/src/jslib.cpp index 7396fc0..447fab8 100644 --- a/wasm/src/jslib.cpp +++ b/wasm/src/jslib.cpp @@ -3,8 +3,21 @@ #include #include +extern "C" { + #include +} + using namespace emscripten; +EMSCRIPTEN_BINDINGS(DcmIccOutputType) { + enum_("DcmIccOutputType") + .value("SRGB", DCM_ICC_OUTPUT_SRGB) + .value("DISPLAY_P3", DCM_ICC_OUTPUT_DISPLAY_P3) + .value("ADOBE_RGB", DCM_ICC_OUTPUT_ADOBE_RGB) + .value("ROMM_RGB", DCM_ICC_OUTPUT_ROMM_RGB) + ; +} + EMSCRIPTEN_BINDINGS(FrameInfo) { value_object("FrameInfo") .field("columns", &FrameInfo::columns) From d4e3e51ad384d4ffe032637ef4f60289aba1d7cc Mon Sep 17 00:00:00 2001 From: Bart Diricx Date: Fri, 8 Aug 2025 00:29:21 +0200 Subject: [PATCH 5/7] Use ROMM RGB without 'measurement correction', guaranteeing black and white remain unchanged by the transfer function. See https://github.com/saucecontrol/Compact-ICC-Profiles/issues/22#issuecomment-3165178003 for more info --- src/dicomicc.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/dicomicc.c b/src/dicomicc.c index e2c0a95..fc97889 100644 --- a/src/dicomicc.c +++ b/src/dicomicc.c @@ -180,22 +180,20 @@ cmsHPROFILE create_romm_rgb_profile(void) { {0.0366, 0.0001, 1.0} // ROMM RGB Blue }; - // ROMM RGB transfer function parameters, parametric curve type 5: - // Y = (a * X + b) ^ gamma + e for X >= d - // Y = c * X + f for X < d + // ROMM RGB transfer function parameters, parametric curve type 4: + // Y = (a * X + b) ^ gamma for X >= d + // Y = c * X for X < d cmsToneCurve* RommRGBTransferFunction[3]; - cmsFloat64Number Parameters[7]; - Parameters[0] = 1.8; // Gamma - Parameters[1] = 0.996527; // a - Parameters[2] = 0.003473; // b - Parameters[3] = 0.0622829; // c - Parameters[4] = 0.03125; // d - Parameters[5] = 0.0; // e - Parameters[6] = 0.003473; // f + cmsFloat64Number Parameters[5]; + Parameters[0] = 1.8; // Gamma + Parameters[1] = 1.0; // a + Parameters[2] = 0.0; // b + Parameters[3] = 0.0625; // c + Parameters[4] = 0.03125; // d // Create the tone curve RommRGBTransferFunction[0] = RommRGBTransferFunction[1] = RommRGBTransferFunction[2] = - cmsBuildParametricToneCurve(NULL, 5, Parameters); + cmsBuildParametricToneCurve(NULL, 4, Parameters); if (RommRGBTransferFunction[0] == NULL) { fprintf(stderr, "Error: Failed to create Romm RGB transfer function\n"); From 35dd17a1019c0a2af38eebf2ea057fdff4acff4f Mon Sep 17 00:00:00 2001 From: diricxbart <59538746+diricxbart@users.noreply.github.com> Date: Thu, 4 Sep 2025 23:29:10 +0200 Subject: [PATCH 6/7] Fix typo in comments based on copilot review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/dicomicc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dicomicc.c b/src/dicomicc.c index fc97889..90c13f3 100644 --- a/src/dicomicc.c +++ b/src/dicomicc.c @@ -122,7 +122,7 @@ cmsHPROFILE create_adobe_rgb_profile(void) { Parameters[1] = 1.; // a Parameters[2] = 0; // b Parameters[3] = 1. / 32; // c - Parameters[4] = 0.055680761; // d (= c ^ (1 / (gamma - 1)) + Parameters[4] = 0.055680761; // d (= c ^ (1 / (gamma - 1))) // Create the tone curve AdobeRGBTransferFunction[0] = AdobeRGBTransferFunction[1] = AdobeRGBTransferFunction[2] = From 6d9b6751d9e635d88e81686e35e3e4c8a4546bf1 Mon Sep 17 00:00:00 2001 From: Bart Diricx Date: Thu, 4 Sep 2025 23:45:19 +0200 Subject: [PATCH 7/7] macos-latest already has cmake installed, no need to install it again --- .github/workflows/run_unit_tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/run_unit_tests.yml b/.github/workflows/run_unit_tests.yml index 19c3b3b..28ae782 100644 --- a/.github/workflows/run_unit_tests.yml +++ b/.github/workflows/run_unit_tests.yml @@ -86,7 +86,6 @@ jobs: brew install \ autoconf \ automake \ - cmake \ emscripten \ libtool \ little-cms2 \