Adding CMYK jpeg changes w/o .gyp alterations
http://codereview.appspot.com/5785054/
git-svn-id: http://skia.googlecode.com/svn/trunk@3442 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index 77d383a..5cb45a2 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -146,6 +146,29 @@
return false; // must always return false
}
+// Convert a scanline of CMYK samples to RGBX in place. Note that this
+// method moves the "scanline" pointer in its processing
+static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) {
+ // At this point we've received CMYK pixels from libjpeg. We
+ // perform a crude conversion to RGB (based on the formulae
+ // from easyrgb.com):
+ // CMYK -> CMY
+ // C = ( C * (1 - K) + K ) // for each CMY component
+ // CMY -> RGB
+ // R = ( 1 - C ) * 255 // for each RGB component
+ // Unfortunately we are seeing inverted CMYK so all the original terms
+ // are 1-. This yields:
+ // CMYK -> CMY
+ // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K
+ // The conversion from CMY->RGB remains the same
+ for (unsigned int x = 0; x < width; ++x, scanline += 4) {
+ scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]);
+ scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]);
+ scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]);
+ scanline[3] = 255;
+ }
+}
+
bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
#ifdef TIME_DECODE
AutoTimeMillis atm("JPEG Decode");
@@ -156,7 +179,7 @@
jpeg_decompress_struct cinfo;
skjpeg_error_mgr sk_err;
- skjpeg_source_mgr sk_stream(stream, this);
+ skjpeg_source_mgr sk_stream(stream, this, false);
cinfo.err = jpeg_std_error(&sk_err);
sk_err.error_exit = skjpeg_error_exit;
@@ -201,7 +224,14 @@
cinfo.do_block_smoothing = 0;
/* default format is RGB */
- cinfo.out_color_space = JCS_RGB;
+ if (cinfo.jpeg_color_space == JCS_CMYK) {
+ // libjpeg cannot convert from CMYK to RGB - here we set up
+ // so libjpeg will give us CMYK samples back and we will
+ // later manually convert them to RGB
+ cinfo.out_color_space = JCS_CMYK;
+ } else {
+ cinfo.out_color_space = JCS_RGB;
+ }
SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
// only these make sense for jpegs
@@ -213,9 +243,9 @@
#ifdef ANDROID_RGB
cinfo.dither_mode = JDITHER_NONE;
- if (config == SkBitmap::kARGB_8888_Config) {
+ if (SkBitmap::kARGB_8888_Config == config && JCS_CMYK != cinfo.out_color_space) {
cinfo.out_color_space = JCS_RGBA_8888;
- } else if (config == SkBitmap::kRGB_565_Config) {
+ } else if (SkBitmap::kRGB_565_Config == config && JCS_CMYK != cinfo.out_color_space) {
cinfo.out_color_space = JCS_RGB_565;
if (this->getDitherImage()) {
cinfo.dither_mode = JDITHER_ORDERED;
@@ -300,10 +330,13 @@
return true;
}
#endif
-
+
// check for supported formats
SkScaledBitmapSampler::SrcConfig sc;
- if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
+ if (JCS_CMYK == cinfo.out_color_space) {
+ // In this case we will manually convert the CMYK values to RGB
+ sc = SkScaledBitmapSampler::kRGBX;
+ } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
sc = SkScaledBitmapSampler::kRGB;
#ifdef ANDROID_RGB
} else if (JCS_RGBA_8888 == cinfo.out_color_space) {
@@ -322,7 +355,7 @@
sampleSize);
bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
- // jpegs are always opauqe (i.e. have no per-pixel alpha)
+ // jpegs are always opaque (i.e. have no per-pixel alpha)
bm->setIsOpaque(true);
if (SkImageDecoder::kDecodeBounds_Mode == mode) {
@@ -332,12 +365,13 @@
return return_false(cinfo, *bm, "allocPixelRef");
}
- SkAutoLockPixels alp(*bm);
+ SkAutoLockPixels alp(*bm);
if (!sampler.begin(bm, sc, this->getDitherImage())) {
return return_false(cinfo, *bm, "sampler.begin");
}
- uint8_t* srcRow = (uint8_t*)srcStorage.alloc(cinfo.output_width * 4);
+ // The CMYK work-around relies on 4 components per pixel here
+ uint8_t* srcRow = (uint8_t*)srcStorage.reset(cinfo.output_width * 4);
// Possibly skip initial rows [sampler.srcY0]
if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
@@ -354,7 +388,11 @@
if (this->shouldCancelDecode()) {
return return_false(cinfo, *bm, "shouldCancelDecode");
}
-
+
+ if (JCS_CMYK == cinfo.out_color_space) {
+ convert_CMYK_to_RGB(srcRow, cinfo.output_width);
+ }
+
sampler.next(srcRow);
if (bm->height() - 1 == y) {
// we're done
@@ -593,7 +631,7 @@
jpeg_start_compress(&cinfo, TRUE);
const int width = bm.width();
- uint8_t* oneRowP = (uint8_t*)oneRow.alloc(width * 3);
+ uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3);
const SkPMColor* colors = ctLocker.lockColors(bm);
const void* srcRow = bm.getPixels();
@@ -618,7 +656,7 @@
#include "SkTRegistry.h"
-static SkImageDecoder* DFactory(SkStream* stream) {
+SkImageDecoder* sk_libjpeg_dfactory(SkStream* stream) {
static const char gHeader[] = { 0xFF, 0xD8, 0xFF };
static const size_t HEADER_SIZE = sizeof(gHeader);
@@ -634,9 +672,11 @@
return SkNEW(SkJPEGImageDecoder);
}
-static SkImageEncoder* EFactory(SkImageEncoder::Type t) {
+static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
}
-static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory);
-static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory);
+
+static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory);
+static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efactory);
+