Transform improvements
- special case x == 1 in approx_powf()
- skip gamut transforms when src gamut == dst gamut
- add test of sRGB byte to linear sRGB float
Change-Id: Ib7a41d80afa456fc69924efb4ca4e230e15a6a01
Reviewed-on: https://skia-review.googlesource.com/113718
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/Transform.c b/src/Transform.c
index df7fe8d..94e39d7 100644
--- a/src/Transform.c
+++ b/src/Transform.c
@@ -272,8 +272,7 @@
// TODO: The rest of this could perhaps be specialized further knowing 0 <= y < 1.
assert (0 <= y && y < 1);
- return r * (F)if_then_else(x == F0, F0
- , approx_pow2(approx_log2(x) * y));
+ return (F)if_then_else((x == F0) | (x == F1), x, r * approx_pow2(approx_log2(x) * y));
}
// Return tf(x).
@@ -929,7 +928,8 @@
if (dstProfile != srcProfile ||
srcAlpha == skcms_AlphaFormat_PremulLinear ||
dstAlpha == skcms_AlphaFormat_PremulLinear) {
- // Linearize using TRC curves, either parametric or 16-bit tables.
+
+ // Linearize source using TRC curves, either parametric or 16-bit tables.
if (srcProfile->has_trc && srcProfile->has_toXYZD50) {
void* tf_stages[] = { (void*) tf_r, (void*) tf_g, (void*) tf_b };
void* table_16_stages[] = { (void*)table_16_r, (void*)table_16_g, (void*)table_16_b };
@@ -950,24 +950,43 @@
if (srcAlpha == skcms_AlphaFormat_PremulLinear) {
*ip++ = (void*)unpremul;
}
-
- *ip++ = (void*)matrix_3x3;
- *args++ = &srcProfile->toXYZD50;
} else {
// TODO: A2B
}
- // Back to dst RGB. (TODO: support tables here?)
+ // We only support destination gamuts that can be transformed from XYZD50.
+ if (!dstProfile->has_toXYZD50) {
+ return false;
+ }
+
+ // Sources with a toXYZD50 matrix still need to be transformed.
+ // Others (A2B) should already be in XYZD50 at this point.
+ static const skcms_Matrix3x3 I = {{
+ { 1.0f, 0.0f, 0.0f },
+ { 0.0f, 1.0f, 0.0f },
+ { 0.0f, 0.0f, 1.0f },
+ }};
+ const skcms_Matrix3x3* to_xyz = srcProfile->has_toXYZD50 ? &srcProfile->toXYZD50 : &I;
+
+ // There's a chance the source and destination gamuts are identical,
+ // in which case we can skip the gamut transform.
+ if (0 != memcmp(&dstProfile->toXYZD50, to_xyz, sizeof(skcms_Matrix3x3))) {
+ if (!skcms_Matrix3x3_invert(&dstProfile->toXYZD50, &from_xyz)) {
+ return false;
+ }
+ // TODO: concat these here and only append one matrix_3x3 stage.
+ *ip++ = (void*)matrix_3x3; *args++ = to_xyz;
+ *ip++ = (void*)matrix_3x3; *args++ = &from_xyz;
+ }
+
+ // Encode back to dst RGB using its parametric transfer functions.
if (dstProfile->has_trc &&
dstProfile->trc[0].table_entries == 0 &&
dstProfile->trc[1].table_entries == 0 &&
dstProfile->trc[2].table_entries == 0 &&
skcms_TransferFunction_invert(&dstProfile->trc[0].parametric, &inv_dst_tf_r) &&
skcms_TransferFunction_invert(&dstProfile->trc[1].parametric, &inv_dst_tf_g) &&
- skcms_TransferFunction_invert(&dstProfile->trc[2].parametric, &inv_dst_tf_b) &&
- dstProfile->has_toXYZD50 &&
- skcms_Matrix3x3_invert(&dstProfile->toXYZD50, &from_xyz)) {
- *ip++ = (void*)matrix_3x3; *args++ = &from_xyz;
+ skcms_TransferFunction_invert(&dstProfile->trc[2].parametric, &inv_dst_tf_b)) {
if (dstAlpha == skcms_AlphaFormat_PremulLinear) {
*ip++ = (void*)premul;
diff --git a/tests.c b/tests.c
index 33fa6a5..aada0c7 100644
--- a/tests.c
+++ b/tests.c
@@ -1028,6 +1028,38 @@
free(ptr);
}
+static void test_ByteToLinearFloat() {
+ uint32_t src[1] = { 0xFFFFFFFF };
+ float dst[4];
+
+ void* srgb_ptr;
+ size_t srgb_len;
+ expect(load_file("profiles/mobile/sRGB_parametric.icc", &srgb_ptr, &srgb_len));
+
+ skcms_ICCProfile srgb, srgb_linear;
+ expect(skcms_Parse(srgb_ptr, srgb_len, &srgb));
+ srgb_linear = srgb;
+ for (int i = 0; i < 3; ++i) {
+ srgb_linear.trc[i].parametric.g = 1.0f;
+ srgb_linear.trc[i].parametric.a = 1.0f;
+ srgb_linear.trc[i].parametric.b = 0.0f;
+ srgb_linear.trc[i].parametric.c = 0.0f;
+ srgb_linear.trc[i].parametric.d = 0.0f;
+ srgb_linear.trc[i].parametric.e = 0.0f;
+ srgb_linear.trc[i].parametric.f = 0.0f;
+ }
+
+ skcms_Transform(src, skcms_PixelFormat_BGRA_8888, skcms_AlphaFormat_Unpremul, &srgb,
+ dst, skcms_PixelFormat_RGBA_ffff, skcms_AlphaFormat_Unpremul, &srgb_linear, 1);
+
+ expect(dst[0] == 1.0f);
+ expect(dst[1] == 1.0f);
+ expect(dst[2] == 1.0f);
+ expect(dst[3] == 1.0f);
+
+ free(srgb_ptr);
+}
+
int main(int argc, char** argv) {
bool regenTestData = false;
for (int i = 1; i < argc; ++i) {
@@ -1052,6 +1084,7 @@
test_SimpleRoundTrip();
test_FloatRoundTrips();
test_sRGB_AllBytes();
+ test_ByteToLinearFloat();
test_TRC_Table16();
test_Premul();