Change sRGB and XYZD50 profiles to functions
By only exporting functions, shared-library building on Windows is
significantly simpler (no need to dllimport).
See also: https://skia-review.googlesource.com/c/skia/+/124983
Change-Id: I916b77b8cb4f54d2e087e3e8c78ad4459c7ee927
Reviewed-on: https://skia-review.googlesource.com/124982
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@chromium.org>
diff --git a/skcms.h b/skcms.h
index 94dfe03..2053fe6 100644
--- a/skcms.h
+++ b/skcms.h
@@ -113,9 +113,9 @@
} skcms_ICCProfile;
// The sRGB color profile is so commonly used that we offer a canonical skcms_ICCProfile for it.
-SKCMS_API extern const skcms_ICCProfile skcms_sRGB_profile;
+SKCMS_API const skcms_ICCProfile* skcms_sRGB_profile(void);
// Ditto for XYZD50, the most common profile connection space.
-SKCMS_API extern const skcms_ICCProfile skcms_XYZD50_profile;
+SKCMS_API const skcms_ICCProfile* skcms_XYZD50_profile(void);
// Practical equality test for two skcms_ICCProfiles.
// The implementation is subject to change, but it will always try to answer
diff --git a/src/ICCProfile.c b/src/ICCProfile.c
index 90ce6fc..322e097 100644
--- a/src/ICCProfile.c
+++ b/src/ICCProfile.c
@@ -781,63 +781,71 @@
return usable_as_src(profile);
}
-const skcms_ICCProfile skcms_sRGB_profile = {
- // These fields are moot when not a skcms_Parse()'d profile.
- .buffer = NULL,
- .size = 0,
- .tag_count = 0,
- // We choose to represent sRGB with its canonical transfer function,
- // and with its canonical XYZD50 gamut matrix.
- .data_color_space = make_signature('R', 'G', 'B', ' '),
- .pcs = make_signature('X', 'Y', 'Z', ' '),
- .has_trc = true,
- .has_toXYZD50 = true,
- .has_A2B = false,
+const skcms_ICCProfile* skcms_sRGB_profile() {
+ static const skcms_ICCProfile sRGB_profile = {
+ // These fields are moot when not a skcms_Parse()'d profile.
+ .buffer = NULL,
+ .size = 0,
+ .tag_count = 0,
- .trc = {
- {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0 }}},
- {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0 }}},
- {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0 }}},
- },
+ // We choose to represent sRGB with its canonical transfer function,
+ // and with its canonical XYZD50 gamut matrix.
+ .data_color_space = make_signature('R', 'G', 'B', ' '),
+ .pcs = make_signature('X', 'Y', 'Z', ' '),
+ .has_trc = true,
+ .has_toXYZD50 = true,
+ .has_A2B = false,
- .toXYZD50 = {{
- { 0.436065674f, 0.385147095f, 0.143066406f },
- { 0.222488403f, 0.716873169f, 0.060607910f },
- { 0.013916016f, 0.097076416f, 0.714096069f },
- }},
+ .trc = {
+ {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0 }}},
+ {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0 }}},
+ {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0 }}},
+ },
- .has_poly_tf = { true, true, true },
- .poly_tf = {
- {0.293833881617f, 0.704207003117f, (float)(1/12.92), 0.04045f},
- {0.293833881617f, 0.704207003117f, (float)(1/12.92), 0.04045f},
- {0.293833881617f, 0.704207003117f, (float)(1/12.92), 0.04045f},
- },
-};
+ .toXYZD50 = {{
+ { 0.436065674f, 0.385147095f, 0.143066406f },
+ { 0.222488403f, 0.716873169f, 0.060607910f },
+ { 0.013916016f, 0.097076416f, 0.714096069f },
+ }},
-const skcms_ICCProfile skcms_XYZD50_profile = {
- .buffer = NULL,
- .size = 0,
- .tag_count = 0,
+ .has_poly_tf = { true, true, true },
+ .poly_tf = {
+ {0.293833881617f, 0.704207003117f, (float)(1/12.92), 0.04045f},
+ {0.293833881617f, 0.704207003117f, (float)(1/12.92), 0.04045f},
+ {0.293833881617f, 0.704207003117f, (float)(1/12.92), 0.04045f},
+ },
+ };
+ return &sRGB_profile;
+}
- .data_color_space = make_signature('R', 'G', 'B', ' '),
- .pcs = make_signature('X', 'Y', 'Z', ' '),
- .has_trc = true,
- .has_toXYZD50 = true,
- .has_A2B = false,
+const skcms_ICCProfile* skcms_XYZD50_profile() {
+ static const skcms_ICCProfile XYZD50_profile = {
+ .buffer = NULL,
+ .size = 0,
+ .tag_count = 0,
- .trc = {
- {{0, {1,1,0,0,0,0,0}}},
- {{0, {1,1,0,0,0,0,0}}},
- {{0, {1,1,0,0,0,0,0}}},
- },
+ .data_color_space = make_signature('R', 'G', 'B', ' '),
+ .pcs = make_signature('X', 'Y', 'Z', ' '),
+ .has_trc = true,
+ .has_toXYZD50 = true,
+ .has_A2B = false,
- .toXYZD50 = {{
- {1,0,0},
- {0,1,0},
- {0,0,1},
- }},
-};
+ .trc = {
+ {{0, {1,1,0,0,0,0,0}}},
+ {{0, {1,1,0,0,0,0,0}}},
+ {{0, {1,1,0,0,0,0,0}}},
+ },
+
+ .toXYZD50 = {{
+ {1,0,0},
+ {0,1,0},
+ {0,0,1},
+ }},
+ };
+
+ return &XYZD50_profile;
+}
const uint8_t skcms_252_random_bytes[] = {
8, 179, 128, 204, 253, 38, 134, 184, 68, 102, 32, 138, 99, 39, 169, 215,
@@ -885,13 +893,13 @@
dstB[252];
if (!skcms_Transform(
skcms_252_random_bytes, fmt, skcms_AlphaFormat_Unpremul, A,
- dstA, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, &skcms_XYZD50_profile,
+ dstA, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, skcms_XYZD50_profile(),
npixels)) {
return false;
}
if (!skcms_Transform(
skcms_252_random_bytes, fmt, skcms_AlphaFormat_Unpremul, B,
- dstB, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, &skcms_XYZD50_profile,
+ dstB, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, skcms_XYZD50_profile(),
npixels)) {
return false;
}
diff --git a/test_only.c b/test_only.c
index 2acb466..7a37dd3 100644
--- a/test_only.c
+++ b/test_only.c
@@ -32,7 +32,7 @@
if (!skcms_Transform(
skcms_252_random_bytes, fmt, skcms_AlphaFormat_Unpremul, profile,
- dst, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, &skcms_XYZD50_profile,
+ dst, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, skcms_XYZD50_profile(),
npixels)) {
fprintf(fp, "We can parse this profile, but not transform it XYZD50!\n");
return;
@@ -61,7 +61,7 @@
uint8_t opt[252];
if (!skcms_Transform(
skcms_252_random_bytes, fmt, skcms_AlphaFormat_Unpremul, optimized,
- opt, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, &skcms_XYZD50_profile,
+ opt, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, skcms_XYZD50_profile(),
npixels)) {
fprintf(fp, "We cannot transform the optimized profile! THIS IS REALLY BAD.\n");
return;
@@ -184,7 +184,7 @@
}
skcms_ICCProfile best_single_curve = *profile;
- skcms_EnsureUsableAsDestinationWithSingleCurve(&best_single_curve, &skcms_sRGB_profile);
+ skcms_EnsureUsableAsDestinationWithSingleCurve(&best_single_curve, skcms_sRGB_profile());
dump_transfer_function(fp, "Best", &best_single_curve.trc[0].parametric, 0.0f);
if (profile->has_toXYZD50) {
@@ -251,7 +251,7 @@
}
}
- if (skcms_ApproximatelyEqualProfiles(profile, &skcms_sRGB_profile)) {
+ if (skcms_ApproximatelyEqualProfiles(profile, skcms_sRGB_profile())) {
fprintf(fp, "This profile ≈ sRGB.\n");
}
}
diff --git a/tests.c b/tests.c
index 3f6f961..9d88f33 100644
--- a/tests.c
+++ b/tests.c
@@ -1006,16 +1006,16 @@
// We can't transform to table-based profiles (yet?).
expect(!skcms_Transform(
- &src, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, &skcms_sRGB_profile,
+ &src, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, skcms_sRGB_profile(),
&dst, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, &profile,
1));
// We take care to use a fallback profile that is not sRGB. :)
- skcms_EnsureUsableAsDestination(&profile, &skcms_XYZD50_profile);
+ skcms_EnsureUsableAsDestination(&profile, skcms_XYZD50_profile());
// Now the transform should work.
expect(skcms_Transform(
- &src, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, &skcms_sRGB_profile,
+ &src, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, skcms_sRGB_profile(),
&dst, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, &profile,
1));
@@ -1034,7 +1034,7 @@
expect(skcms_Parse(ptr, len, &profile));
skcms_ICCProfile usable_as_dst = profile;
- skcms_EnsureUsableAsDestination(&usable_as_dst, &skcms_sRGB_profile);
+ skcms_EnsureUsableAsDestination(&usable_as_dst, skcms_sRGB_profile());
// These profiles should behave nearly (or exactly) identical.
// If we let any part of sRGB (eg PolyTF) leak into usable_as_dst, this will fail.
@@ -1042,7 +1042,7 @@
// Same sequence as above, using the more aggressive SingleCurve version.
skcms_ICCProfile single_curve = profile;
- skcms_EnsureUsableAsDestinationWithSingleCurve(&single_curve, &skcms_sRGB_profile);
+ skcms_EnsureUsableAsDestinationWithSingleCurve(&single_curve, skcms_sRGB_profile());
expect(skcms_ApproximatelyEqualProfiles(&profile, &single_curve));
free(ptr);
@@ -1050,7 +1050,7 @@
static void test_sRGB_profile_has_poly_tf() {
// If we can find an skcms_PolyTF for anything, it'd better be sRGB.
- skcms_ICCProfile srgb = skcms_sRGB_profile;
+ skcms_ICCProfile srgb = *skcms_sRGB_profile();
// First, test skcms_OptimizeForSpeed() is a no-op if the has_poly_tf bits are already set.
for (int i = 0; i < 3; i++) {
@@ -1080,7 +1080,7 @@
}
// Mostly a reminder to update skcms_sRGB_profile when skcms_OptimizeForSpeed() changes.
- expect(0 == memcmp(&srgb, &skcms_sRGB_profile, sizeof(srgb)));
+ expect(0 == memcmp(&srgb, skcms_sRGB_profile(), sizeof(srgb)));
}
static void test_AlmostLinear2() {
@@ -1089,7 +1089,7 @@
// This table will fit with a b+e offset that's non-zero, and cannot be fit with a PolyTF.
uint8_t table_16[] = { 0x50, 0x50, 0x50, 0x63 };
- skcms_ICCProfile p = skcms_sRGB_profile;
+ skcms_ICCProfile p = *skcms_sRGB_profile();
p.trc[0].table_entries = 2;
p.trc[0].table_8 = NULL;
p.trc[0].table_16 = table_16;
@@ -1103,7 +1103,7 @@
static void test_AlmostLinear3() {
uint8_t table_8[] = { 0x00, 0x50, 0xff };
- skcms_ICCProfile p = skcms_sRGB_profile;
+ skcms_ICCProfile p = *skcms_sRGB_profile();
p.trc[0].table_entries = 3;
p.trc[0].table_8 = table_8;
p.trc[0].table_16 = NULL;