#include "jpeglib.h"
}
-/*
- * Convert a row of CMYK samples to RGBA in place.
- * Note that this method moves the row pointer.
- * @param width the number of pixels in the row that is being converted
- * CMYK is stored as four bytes per pixel
- */
-static void convert_CMYK_to_RGBA(uint8_t* row, uint32_t width) {
- // 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
- for (uint32_t x = 0; x < width; x++, row += 4) {
-#if defined(SK_PMCOLOR_IS_RGBA)
- row[0] = SkMulDiv255Round(row[0], row[3]);
- row[1] = SkMulDiv255Round(row[1], row[3]);
- row[2] = SkMulDiv255Round(row[2], row[3]);
-#else
- uint8_t tmp = row[0];
- row[0] = SkMulDiv255Round(row[2], row[3]);
- row[1] = SkMulDiv255Round(row[1], row[3]);
- row[2] = SkMulDiv255Round(tmp, row[3]);
-#endif
- row[3] = 0xFF;
- }
-}
-
bool SkJpegCodec::IsJpeg(SkStream* stream) {
static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF };
char buffer[sizeof(jpegSig)];
return true;
case kRGB_565_SkColorType:
if (isCMYK) {
- // FIXME (msarett): We need to support 565 here. It's not hard to do, considering
- // we already convert CMYK to RGBA, I just need to do it. I think it might be
- // best to do this in SkSwizzler and also move convert_CMYK_to_RGBA into SkSwizzler.
- return false;
+ fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
} else {
#if defined(GOOGLE3)
return false;
// If it's not, we want to know because it means our strategy is not optimal.
SkASSERT(1 == dinfo->rec_outbuf_height);
+ if (JCS_CMYK == dinfo->out_color_space) {
+ this->initializeSwizzler(dstInfo, options);
+ }
+
// Perform the decode a single row at a time
uint32_t dstHeight = dstInfo.height();
- JSAMPLE* dstRow = (JSAMPLE*) dst;
+
+ JSAMPLE* dstRow;
+ if (fSwizzler) {
+ // write data to storage row, then sample using swizzler
+ dstRow = fSrcRow;
+ } else {
+ // write data directly to dst
+ dstRow = (JSAMPLE*) dst;
+ }
+
for (uint32_t y = 0; y < dstHeight; y++) {
// Read rows of the image
uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1);
return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput);
}
- // Convert to RGBA if necessary
- if (JCS_CMYK == dinfo->out_color_space) {
- convert_CMYK_to_RGBA(dstRow, dstInfo.width());
+ if (fSwizzler) {
+ // use swizzler to sample row
+ fSwizzler->swizzle(dst, dstRow);
+ dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes);
+ } else {
+ dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
}
-
- // Move to the next row
- dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
}
return kSuccess;
void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
SkSwizzler::SrcConfig srcConfig = SkSwizzler::kUnknown;
- switch (dstInfo.colorType()) {
- case kGray_8_SkColorType:
- srcConfig = SkSwizzler::kGray;
- break;
- case kRGBA_8888_SkColorType:
- srcConfig = SkSwizzler::kRGBX;
- break;
- case kBGRA_8888_SkColorType:
- srcConfig = SkSwizzler::kBGRX;
- break;
- case kRGB_565_SkColorType:
- srcConfig = SkSwizzler::kRGB_565;
- break;
- default:
- // This function should only be called if the colorType is supported by jpeg
+ if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
+ srcConfig = SkSwizzler::kCMYK;
+ } else {
+ switch (dstInfo.colorType()) {
+ case kGray_8_SkColorType:
+ srcConfig = SkSwizzler::kGray;
+ break;
+ case kRGBA_8888_SkColorType:
+ srcConfig = SkSwizzler::kRGBX;
+ break;
+ case kBGRA_8888_SkColorType:
+ srcConfig = SkSwizzler::kBGRX;
+ break;
+ case kRGB_565_SkColorType:
+ srcConfig = SkSwizzler::kRGB_565;
+ break;
+ default:
+ // This function should only be called if the colorType is supported by jpeg
#if defined(GOOGLE3)
- SK_CRASH();
+ SK_CRASH();
#else
- SkASSERT(false);
+ SkASSERT(false);
#endif
+ }
}
fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, options));
return kInvalidInput;
}
- // We will need a swizzler if we are performing a subset decode
- if (options.fSubset) {
+ // We will need a swizzler if we are performing a subset decode or
+ // converting from CMYK.
+ if (options.fSubset || JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
this->initializeSwizzler(dstInfo, options);
}
return y;
}
- // Convert to RGBA if necessary
- if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
- convert_CMYK_to_RGBA(dstRow, fDecoderMgr->dinfo()->output_width);
- }
-
- if(fSwizzler) {
+ if (fSwizzler) {
// use swizzler to sample row
fSwizzler->swizzle(dst, dstRow);
dst = SkTAddOffset<JSAMPLE>(dst, rowBytes);
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
default:
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;
}