Add `skcms_PixelFormat_GA_88` support for `skcms_Transform`.
Bug: chromium:40278281
Change-Id: I5dec2c12fe09ae0d66365e901100430cce5e9e2a
Reviewed-on: https://skia-review.googlesource.com/c/skcms/+/880812
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Ćukasz Anforowicz <lukasza@google.com>
Reviewed-by: Leon Scroggins <scroggo@google.com>
diff --git a/ninja/clang b/ninja/clang
index 1a4b7e6..ed85687 100644
--- a/ninja/clang
+++ b/ninja/clang
@@ -1,6 +1,6 @@
cc = clang
cxx = clang++
-cflags = -fcolor-diagnostics -Weverything -ffp-contract=off
+cflags = -fcolor-diagnostics -Weverything -Wno-unsafe-buffer-usage -ffp-contract=off
out = out/clang$mode
include ninja/local
diff --git a/skcms.cc b/skcms.cc
index 047f21b..cc1b699 100644
--- a/skcms.cc
+++ b/skcms.cc
@@ -2450,6 +2450,7 @@
switch (fmt >> 1) { // ignore rgb/bgr
case skcms_PixelFormat_A_8 >> 1: return 1;
case skcms_PixelFormat_G_8 >> 1: return 1;
+ case skcms_PixelFormat_GA_88 >> 1: return 2;
case skcms_PixelFormat_ABGR_4444 >> 1: return 2;
case skcms_PixelFormat_RGB_565 >> 1: return 2;
case skcms_PixelFormat_RGB_888 >> 1: return 3;
@@ -2562,6 +2563,7 @@
default: return false;
case skcms_PixelFormat_A_8 >> 1: add_op(Op::load_a8); break;
case skcms_PixelFormat_G_8 >> 1: add_op(Op::load_g8); break;
+ case skcms_PixelFormat_GA_88 >> 1: add_op(Op::load_ga88); break;
case skcms_PixelFormat_ABGR_4444 >> 1: add_op(Op::load_4444); break;
case skcms_PixelFormat_RGB_565 >> 1: add_op(Op::load_565); break;
case skcms_PixelFormat_RGB_888 >> 1: add_op(Op::load_888); break;
@@ -2593,12 +2595,17 @@
add_op(Op::swap_rb);
}
skcms_ICCProfile gray_dst_profile;
- if ((dstFmt >> 1) == (skcms_PixelFormat_G_8 >> 1)) {
- // When transforming to gray, stop at XYZ (by setting toXYZ to identity), then transform
- // luminance (Y) by the destination transfer function.
- gray_dst_profile = *dstProfile;
- skcms_SetXYZD50(&gray_dst_profile, &skcms_XYZD50_profile()->toXYZD50);
- dstProfile = &gray_dst_profile;
+ switch (dstFmt >> 1) {
+ case skcms_PixelFormat_G_8:
+ case skcms_PixelFormat_GA_88:
+ // When transforming to gray, stop at XYZ (by setting toXYZ to identity), then transform
+ // luminance (Y) by the destination transfer function.
+ gray_dst_profile = *dstProfile;
+ skcms_SetXYZD50(&gray_dst_profile, &skcms_XYZD50_profile()->toXYZD50);
+ dstProfile = &gray_dst_profile;
+ break;
+ default:
+ break;
}
if (srcProfile->data_color_space == skcms_Signature_CMYK) {
@@ -2760,6 +2767,7 @@
default: return false;
case skcms_PixelFormat_A_8 >> 1: add_op(Op::store_a8); break;
case skcms_PixelFormat_G_8 >> 1: add_op(Op::store_g8); break;
+ case skcms_PixelFormat_GA_88 >> 1: add_op(Op::store_ga88); break;
case skcms_PixelFormat_ABGR_4444 >> 1: add_op(Op::store_4444); break;
case skcms_PixelFormat_RGB_565 >> 1: add_op(Op::store_565); break;
case skcms_PixelFormat_RGB_888 >> 1: add_op(Op::store_888); break;
diff --git a/src/Transform_inl.h b/src/Transform_inl.h
index ab9b94d..99bbbc5 100644
--- a/src/Transform_inl.h
+++ b/src/Transform_inl.h
@@ -837,6 +837,12 @@
r = g = b = F_from_U8(load<U8>(src + 1*i));
}
+STAGE(load_ga88, NoCtx) {
+ U16 u16 = load<U16>(src + 2 * i);
+ r = g = b = cast<F>((u16 >> 0) & 0xff) * (1 / 255.0f);
+ a = cast<F>((u16 >> 8) & 0xff) * (1 / 255.0f);
+}
+
STAGE(load_4444, NoCtx) {
U16 abgr = load<U16>(src + 2*i);
@@ -1255,6 +1261,12 @@
store(dst + 1*i, cast<U8>(to_fixed(g * 255)));
}
+FINAL_STAGE(store_ga88, NoCtx) {
+ // g should be holding luminance (Y) (r,g,b ~~~> X,Y,Z)
+ store<U16>(dst + 2*i, cast<U16>(to_fixed(g * 255) << 0 )
+ | cast<U16>(to_fixed(a * 255) << 8 ));
+}
+
FINAL_STAGE(store_4444, NoCtx) {
store<U16>(dst + 2*i, cast<U16>(to_fixed(r * 15) << 12)
| cast<U16>(to_fixed(g * 15) << 8)
diff --git a/src/skcms_Transform.h b/src/skcms_Transform.h
index 9f02e79..d5e542a 100644
--- a/src/skcms_Transform.h
+++ b/src/skcms_Transform.h
@@ -20,6 +20,7 @@
#define SKCMS_WORK_OPS(M) \
M(load_a8) \
M(load_g8) \
+ M(load_ga88) \
M(load_4444) \
M(load_565) \
M(load_888) \
@@ -89,6 +90,7 @@
#define SKCMS_STORE_OPS(M) \
M(store_a8) \
M(store_g8) \
+ M(store_ga88) \
M(store_4444) \
M(store_565) \
M(store_888) \
diff --git a/src/skcms_public.h b/src/skcms_public.h
index 3510f89..00c51c6 100644
--- a/src/skcms_public.h
+++ b/src/skcms_public.h
@@ -275,6 +275,8 @@
skcms_PixelFormat_A_8_,
skcms_PixelFormat_G_8,
skcms_PixelFormat_G_8_,
+ skcms_PixelFormat_GA_88, // Grayscale with alpha.
+ skcms_PixelFormat_GA_88_,
skcms_PixelFormat_RGB_565,
skcms_PixelFormat_BGR_565,
@@ -286,39 +288,39 @@
skcms_PixelFormat_BGR_888,
skcms_PixelFormat_RGBA_8888,
skcms_PixelFormat_BGRA_8888,
- skcms_PixelFormat_RGBA_8888_sRGB, // Automatic sRGB encoding / decoding.
- skcms_PixelFormat_BGRA_8888_sRGB, // (Generally used with linear transfer functions.)
+ skcms_PixelFormat_RGBA_8888_sRGB, // Automatic sRGB encoding / decoding.
+ skcms_PixelFormat_BGRA_8888_sRGB, // (Generally used with linear transfer functions.)
skcms_PixelFormat_RGBA_1010102,
skcms_PixelFormat_BGRA_1010102,
- skcms_PixelFormat_RGB_161616LE, // Little-endian. Pointers must be 16-bit aligned.
+ skcms_PixelFormat_RGB_161616LE, // Little-endian. Pointers must be 16-bit aligned.
skcms_PixelFormat_BGR_161616LE,
skcms_PixelFormat_RGBA_16161616LE,
skcms_PixelFormat_BGRA_16161616LE,
- skcms_PixelFormat_RGB_161616BE, // Big-endian. Pointers must be 16-bit aligned.
+ skcms_PixelFormat_RGB_161616BE, // Big-endian. Pointers must be 16-bit aligned.
skcms_PixelFormat_BGR_161616BE,
skcms_PixelFormat_RGBA_16161616BE,
skcms_PixelFormat_BGRA_16161616BE,
- skcms_PixelFormat_RGB_hhh_Norm, // 1-5-10 half-precision float in [0,1]
- skcms_PixelFormat_BGR_hhh_Norm, // Pointers must be 16-bit aligned.
+ skcms_PixelFormat_RGB_hhh_Norm, // 1-5-10 half-precision float in [0,1]
+ skcms_PixelFormat_BGR_hhh_Norm, // Pointers must be 16-bit aligned.
skcms_PixelFormat_RGBA_hhhh_Norm,
skcms_PixelFormat_BGRA_hhhh_Norm,
- skcms_PixelFormat_RGB_hhh, // 1-5-10 half-precision float.
- skcms_PixelFormat_BGR_hhh, // Pointers must be 16-bit aligned.
+ skcms_PixelFormat_RGB_hhh, // 1-5-10 half-precision float.
+ skcms_PixelFormat_BGR_hhh, // Pointers must be 16-bit aligned.
skcms_PixelFormat_RGBA_hhhh,
skcms_PixelFormat_BGRA_hhhh,
- skcms_PixelFormat_RGB_fff, // 1-8-23 single-precision float (the normal kind).
- skcms_PixelFormat_BGR_fff, // Pointers must be 32-bit aligned.
+ skcms_PixelFormat_RGB_fff, // 1-8-23 single-precision float (the normal kind).
+ skcms_PixelFormat_BGR_fff, // Pointers must be 32-bit aligned.
skcms_PixelFormat_RGBA_ffff,
skcms_PixelFormat_BGRA_ffff,
- skcms_PixelFormat_RGB_101010x_XR, // Note: This is located here to signal no clamping.
- skcms_PixelFormat_BGR_101010x_XR, // Compatible with MTLPixelFormatBGR10_XR.
+ skcms_PixelFormat_RGB_101010x_XR, // Note: This is located here to signal no clamping.
+ skcms_PixelFormat_BGR_101010x_XR, // Compatible with MTLPixelFormatBGR10_XR.
skcms_PixelFormat_RGBA_10101010_XR, // Note: This is located here to signal no clamping.
skcms_PixelFormat_BGRA_10101010_XR, // Compatible with MTLPixelFormatBGRA10_XR.
} skcms_PixelFormat;
diff --git a/tests.c b/tests.c
index 90bd9dd..2d36cc2 100644
--- a/tests.c
+++ b/tests.c
@@ -440,6 +440,64 @@
expect(((dst[1] >> 24) & 0xff) == 255);
}
+static void test_FormatConversions_G8(void) {
+ uint8_t src[1 * 256] = {0};
+ for (int i = 0; i < 256; i++) {
+ src[i] = (uint8_t)i;
+ }
+
+ uint8_t dst[4 * 256] = {0};
+ expect(skcms_Transform(src, skcms_PixelFormat_G_8 , skcms_AlphaFormat_Unpremul, NULL,
+ dst, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, NULL,
+ 256));
+ for (int i = 0; i < 256; i++) {
+ expect(dst[i * 4 + 0] == (uint8_t)i); // red = gray
+ expect(dst[i * 4 + 1] == (uint8_t)i); // green = gray
+ expect(dst[i * 4 + 2] == (uint8_t)i); // blue = gray
+ expect(dst[i * 4 + 3] == 0xFF); // opaque
+ }
+
+ // Let's convert back the other way.
+ uint8_t back[1 * 256] = {0};
+ expect(skcms_Transform(dst, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, NULL,
+ back, skcms_PixelFormat_G_8 , skcms_AlphaFormat_Unpremul, NULL,
+ 256));
+ for (int i = 0; i < 256; i++) {
+ expect(src[i] == back[i]);
+ }
+}
+
+static void test_FormatConversions_GA88(void) {
+ uint8_t src[2 * 256] = {0};
+ for (int i = 0; i < 256; i++) {
+ // Using a different "gray" and "alpha" value will hopefully catch most
+ // potential LE-vs-BE confusion bugs.
+ src[i * 2 + 0] = (uint8_t)i;
+ src[i * 2 + 1] = (uint8_t)((i * 7) % 256);
+ }
+
+ uint8_t dst[4 * 256] = {0};
+ expect(skcms_Transform(src, skcms_PixelFormat_GA_88 , skcms_AlphaFormat_Unpremul, NULL,
+ dst, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, NULL,
+ 256));
+ for (int i = 0; i < 256; i++) {
+ expect(dst[i * 4 + 0] == (uint8_t)i); // red = gray
+ expect(dst[i * 4 + 1] == (uint8_t)i); // green = gray
+ expect(dst[i * 4 + 2] == (uint8_t)i); // blue = gray
+ expect(dst[i * 4 + 3] == src[i * 2 + 1]);
+ }
+
+ // Let's convert back the other way.
+ uint8_t back[2 * 256] = {0};
+ expect(skcms_Transform(dst, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, NULL,
+ back, skcms_PixelFormat_GA_88 , skcms_AlphaFormat_Unpremul, NULL,
+ 256));
+ for (int i = 0; i < 256; i++) {
+ expect(src[i * 2 + 0] == back[i * 2 + 0]);
+ expect(src[i * 2 + 1] == back[i * 2 + 1]);
+ }
+}
+
static void test_FormatConversions_half(void) {
uint16_t src[] = {
0x3c00, // 1.0
@@ -1877,6 +1935,8 @@
test_FormatConversions_161616LE();
test_FormatConversions_16161616BE();
test_FormatConversions_161616BE();
+ test_FormatConversions_G8();
+ test_FormatConversions_GA88();
test_FormatConversions_half();
test_FormatConversions_half_norm();
test_FormatConversions_float();