Index: src/codec/SkSwizzler.cpp |
diff --git a/src/codec/SkSwizzler.cpp b/src/codec/SkSwizzler.cpp |
index 4eea8799c55a5b69641e600b465967cfc61c045c..242866db441da201e2827d8d106b2960beab8b21 100644 |
--- a/src/codec/SkSwizzler.cpp |
+++ b/src/codec/SkSwizzler.cpp |
@@ -480,6 +480,89 @@ static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_premul_skipZ( |
return COMPUTE_RESULT_ALPHA; |
} |
+// kCMYK |
+// |
+// CMYK is stored as four bytes per pixel. |
+// |
+// We will implement a crude conversion from CMYK -> RGB using formulas |
+// from easyrgb.com. |
+// |
+// CMYK -> CMY |
+// C = C * (1 - K) + K |
+// M = M * (1 - K) + K |
+// Y = Y * (1 - K) + K |
+// |
+// libjpeg actually gives us inverted CMYK, so we must subtract the |
+// original terms from 1. |
+// CMYK -> CMY |
+// C = (1 - C) * (1 - (1 - K)) + (1 - K) |
+// M = (1 - M) * (1 - (1 - K)) + (1 - K) |
+// Y = (1 - Y) * (1 - (1 - K)) + (1 - K) |
+// |
+// Simplifying the above expression. |
+// CMYK -> CMY |
+// C = 1 - CK |
+// M = 1 - MK |
+// Y = 1 - YK |
+// |
+// CMY -> RGB |
+// R = (1 - C) * 255 |
+// G = (1 - M) * 255 |
+// B = (1 - Y) * 255 |
+// |
+// Therefore the full conversion is below. This can be verified at |
+// www.rapidtables.com (assuming inverted CMYK). |
+// CMYK -> RGB |
+// R = C * K * 255 |
+// G = M * K * 255 |
+// B = Y * K * 255 |
+// |
+// As a final note, we have treated the CMYK values as if they were on |
+// a scale from 0-1, when in fact they are 8-bit ints scaling from 0-255. |
+// We must divide each CMYK component by 255 to obtain the true conversion |
+// we should perform. |
+// CMYK -> RGB |
+// R = C * K / 255 |
+// G = M * K / 255 |
+// B = Y * K / 255 |
+static SkSwizzler::ResultAlpha swizzle_cmyk_to_n32( |
+ void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, |
+ int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { |
+ |
+ src += offset; |
+ SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; |
+ for (int x = 0; x < dstWidth; x++) { |
+ const uint8_t r = SkMulDiv255Round(src[0], src[3]); |
+ const uint8_t g = SkMulDiv255Round(src[1], src[3]); |
+ const uint8_t b = SkMulDiv255Round(src[2], src[3]); |
+ |
+ dst[x] = SkPackARGB32NoCheck(0xFF, r, g, b); |
+ src += deltaSrc; |
+ } |
+ |
+ // CMYK is always opaque |
+ return SkSwizzler::kOpaque_ResultAlpha; |
+} |
+ |
+static SkSwizzler::ResultAlpha swizzle_cmyk_to_565( |
+ void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, |
+ int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { |
+ |
+ src += offset; |
+ uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; |
+ for (int x = 0; x < dstWidth; x++) { |
+ const uint8_t r = SkMulDiv255Round(src[0], src[3]); |
+ const uint8_t g = SkMulDiv255Round(src[1], src[3]); |
+ const uint8_t b = SkMulDiv255Round(src[2], src[3]); |
+ |
+ dst[x] = SkPack888ToRGB16(r, g, b); |
+ src += deltaSrc; |
+ } |
+ |
+ // CMYK is always opaque |
+ return SkSwizzler::kOpaque_ResultAlpha; |
+} |
+ |
/** |
FIXME: This was my idea to cheat in order to continue taking advantage of skipping zeroes. |
This would be fine for drawing normally, but not for drawing with transfer modes. Being |
@@ -672,6 +755,19 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, |
default: |
break; |
} |
+ break; |
+ case kCMYK: |
+ switch (dstInfo.colorType()) { |
+ case kN32_SkColorType: |
+ proc = &swizzle_cmyk_to_n32; |
+ break; |
+ case kRGB_565_SkColorType: |
+ proc = &swizzle_cmyk_to_565; |
+ break; |
+ default: |
+ break; |
+ } |
+ break; |
default: |
break; |
} |