Add support for Alpha8, Gray8, and 4444 pixel formats
Gray 8 is particularly special: It's always computed as luminance (Y),
transformed by the destination transfer function. When invoked with no
color profiles, src and dst are assumed to be sRGB.
Change-Id: I2218924d2f43e1e81b3aa48db55398acea4a7a41
Reviewed-on: https://skia-review.googlesource.com/136604
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
diff --git a/skcms.h b/skcms.h
index 97728c4..abc604b 100644
--- a/skcms.h
+++ b/skcms.h
@@ -166,9 +166,17 @@
};
typedef enum skcms_PixelFormat {
+ skcms_PixelFormat_A_8,
+ skcms_PixelFormat_A_8_,
+ skcms_PixelFormat_G_8,
+ skcms_PixelFormat_G_8_,
+
skcms_PixelFormat_RGB_565,
skcms_PixelFormat_BGR_565,
+ skcms_PixelFormat_ABGR_4444,
+ skcms_PixelFormat_ARGB_4444,
+
skcms_PixelFormat_RGB_888,
skcms_PixelFormat_BGR_888,
skcms_PixelFormat_RGBA_8888,
diff --git a/src/Transform.c b/src/Transform.c
index f07c5e7..ebfd0ce 100644
--- a/src/Transform.c
+++ b/src/Transform.c
@@ -354,6 +354,9 @@
static size_t bytes_per_pixel(skcms_PixelFormat fmt) {
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_ABGR_4444 >> 1: return 2;
case skcms_PixelFormat_RGB_565 >> 1: return 2;
case skcms_PixelFormat_RGB_888 >> 1: return 3;
case skcms_PixelFormat_RGBA_8888 >> 1: return 4;
@@ -430,6 +433,9 @@
switch (srcFmt >> 1) {
default: return false;
+ case skcms_PixelFormat_A_8 >> 1: *ops++ = Op_load_a8; break;
+ case skcms_PixelFormat_G_8 >> 1: *ops++ = Op_load_g8; break;
+ case skcms_PixelFormat_ABGR_4444 >> 1: *ops++ = Op_load_4444; break;
case skcms_PixelFormat_RGB_565 >> 1: *ops++ = Op_load_565; break;
case skcms_PixelFormat_RGB_888 >> 1: *ops++ = Op_load_888; break;
case skcms_PixelFormat_RGBA_8888 >> 1: *ops++ = Op_load_8888; break;
@@ -444,6 +450,14 @@
if (srcFmt & 1) {
*ops++ = 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;
+ }
if (srcProfile->data_color_space == skcms_Signature_CMYK) {
// Photoshop creates CMYK images as inverse CMYK.
@@ -585,6 +599,9 @@
}
switch (dstFmt >> 1) {
default: return false;
+ case skcms_PixelFormat_A_8 >> 1: *ops++ = Op_store_a8; break;
+ case skcms_PixelFormat_G_8 >> 1: *ops++ = Op_store_g8; break;
+ case skcms_PixelFormat_ABGR_4444 >> 1: *ops++ = Op_store_4444; break;
case skcms_PixelFormat_RGB_565 >> 1: *ops++ = Op_store_565; break;
case skcms_PixelFormat_RGB_888 >> 1: *ops++ = Op_store_888; break;
case skcms_PixelFormat_RGBA_8888 >> 1: *ops++ = Op_store_8888; break;
diff --git a/src/Transform.h b/src/Transform.h
index 1c4c15b..6eda899 100644
--- a/src/Transform.h
+++ b/src/Transform.h
@@ -11,6 +11,9 @@
#define FOREACH_Op(M) \
M(noop) \
+ M(load_a8) \
+ M(load_g8) \
+ M(load_4444) \
M(load_565) \
M(load_888) \
M(load_8888) \
@@ -46,6 +49,9 @@
M(clut_3D_16) \
M(clut_4D_8) \
M(clut_4D_16) \
+ M(store_a8) \
+ M(store_g8) \
+ M(store_4444) \
M(store_565) \
M(store_888) \
M(store_8888) \
diff --git a/src/Transform_inl.h b/src/Transform_inl.h
index 224412b..fd3100a 100644
--- a/src/Transform_inl.h
+++ b/src/Transform_inl.h
@@ -576,6 +576,28 @@
switch (profile_next_op(*ops++)) {
case Op_noop: break;
+ case Op_load_a8:{
+ U8 alpha;
+ small_memcpy(&alpha, src + i, N);
+ a = F_from_U8(alpha);
+ } break;
+
+ case Op_load_g8:{
+ U8 gray;
+ small_memcpy(&gray, src + i, N);
+ r = g = b = F_from_U8(gray);
+ } break;
+
+ case Op_load_4444:{
+ U16 abgr;
+ small_memcpy(&abgr, src + 2*i, 2*N);
+
+ r = CAST(F, (abgr >> 12) & 0xf) * (1/15.0f);
+ g = CAST(F, (abgr >> 8) & 0xf) * (1/15.0f);
+ b = CAST(F, (abgr >> 4) & 0xf) * (1/15.0f);
+ a = CAST(F, (abgr >> 0) & 0xf) * (1/15.0f);
+ } break;
+
case Op_load_565:{
U16 rgb;
small_memcpy(&rgb, src + 2*i, 2*N);
@@ -879,6 +901,25 @@
// Notice, from here on down the store_ ops all return, ending the loop.
+ case Op_store_a8: {
+ U8 alpha = CAST(U8, to_fixed(a * 255));
+ small_memcpy(dst + i, &alpha, N);
+ } return;
+
+ case Op_store_g8: {
+ // g should be holding luminance (Y) (r,g,b ~~~> X,Y,Z)
+ U8 gray = CAST(U8, to_fixed(g * 255));
+ small_memcpy(dst + i, &gray, N);
+ } return;
+
+ case Op_store_4444: {
+ U16 abgr = CAST(U16, to_fixed(r * 15) << 12)
+ | CAST(U16, to_fixed(g * 15) << 8)
+ | CAST(U16, to_fixed(b * 15) << 4)
+ | CAST(U16, to_fixed(a * 15) << 0);
+ small_memcpy(dst + 2*i, &abgr, 2*N);
+ } return;
+
case Op_store_565: {
U16 rgb = CAST(U16, to_fixed(r * 31) << 0 )
| CAST(U16, to_fixed(g * 63) << 5 )