1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/images/SkImageDecoder_libjpeg.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1249 @@ 1.4 +/* 1.5 + * Copyright 2007 The Android Open Source Project 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 + 1.12 +#include "SkImageDecoder.h" 1.13 +#include "SkImageEncoder.h" 1.14 +#include "SkJpegUtility.h" 1.15 +#include "SkColorPriv.h" 1.16 +#include "SkDither.h" 1.17 +#include "SkScaledBitmapSampler.h" 1.18 +#include "SkStream.h" 1.19 +#include "SkTemplates.h" 1.20 +#include "SkTime.h" 1.21 +#include "SkUtils.h" 1.22 +#include "SkRTConf.h" 1.23 +#include "SkRect.h" 1.24 +#include "SkCanvas.h" 1.25 + 1.26 + 1.27 +#include <stdio.h> 1.28 +extern "C" { 1.29 + #include "jpeglib.h" 1.30 + #include "jerror.h" 1.31 +} 1.32 + 1.33 +// These enable timing code that report milliseconds for an encoding/decoding 1.34 +//#define TIME_ENCODE 1.35 +//#define TIME_DECODE 1.36 + 1.37 +// this enables our rgb->yuv code, which is faster than libjpeg on ARM 1.38 +#define WE_CONVERT_TO_YUV 1.39 + 1.40 +// If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offers 1.41 +// support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565. 1.42 + 1.43 +#if defined(SK_DEBUG) 1.44 +#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS false 1.45 +#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS false 1.46 +#else // !defined(SK_DEBUG) 1.47 +#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS true 1.48 +#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS true 1.49 +#endif // defined(SK_DEBUG) 1.50 +SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderWarnings, 1.51 + "images.jpeg.suppressDecoderWarnings", 1.52 + DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS, 1.53 + "Suppress most JPG warnings when calling decode functions."); 1.54 +SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderErrors, 1.55 + "images.jpeg.suppressDecoderErrors", 1.56 + DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS, 1.57 + "Suppress most JPG error messages when decode " 1.58 + "function fails."); 1.59 + 1.60 +////////////////////////////////////////////////////////////////////////// 1.61 +////////////////////////////////////////////////////////////////////////// 1.62 + 1.63 +static void overwrite_mem_buffer_size(jpeg_decompress_struct* cinfo) { 1.64 +#ifdef SK_BUILD_FOR_ANDROID 1.65 + /* Check if the device indicates that it has a large amount of system memory 1.66 + * if so, increase the memory allocation to 30MB instead of the default 5MB. 1.67 + */ 1.68 +#ifdef ANDROID_LARGE_MEMORY_DEVICE 1.69 + cinfo->mem->max_memory_to_use = 30 * 1024 * 1024; 1.70 +#else 1.71 + cinfo->mem->max_memory_to_use = 5 * 1024 * 1024; 1.72 +#endif 1.73 +#endif // SK_BUILD_FOR_ANDROID 1.74 +} 1.75 + 1.76 +////////////////////////////////////////////////////////////////////////// 1.77 +////////////////////////////////////////////////////////////////////////// 1.78 + 1.79 +static void do_nothing_emit_message(jpeg_common_struct*, int) { 1.80 + /* do nothing */ 1.81 +} 1.82 +static void do_nothing_output_message(j_common_ptr) { 1.83 + /* do nothing */ 1.84 +} 1.85 + 1.86 +static void initialize_info(jpeg_decompress_struct* cinfo, skjpeg_source_mgr* src_mgr) { 1.87 + SkASSERT(cinfo != NULL); 1.88 + SkASSERT(src_mgr != NULL); 1.89 + jpeg_create_decompress(cinfo); 1.90 + overwrite_mem_buffer_size(cinfo); 1.91 + cinfo->src = src_mgr; 1.92 + /* To suppress warnings with a SK_DEBUG binary, set the 1.93 + * environment variable "skia_images_jpeg_suppressDecoderWarnings" 1.94 + * to "true". Inside a program that links to skia: 1.95 + * SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true); */ 1.96 + if (c_suppressJPEGImageDecoderWarnings) { 1.97 + cinfo->err->emit_message = &do_nothing_emit_message; 1.98 + } 1.99 + /* To suppress error messages with a SK_DEBUG binary, set the 1.100 + * environment variable "skia_images_jpeg_suppressDecoderErrors" 1.101 + * to "true". Inside a program that links to skia: 1.102 + * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */ 1.103 + if (c_suppressJPEGImageDecoderErrors) { 1.104 + cinfo->err->output_message = &do_nothing_output_message; 1.105 + } 1.106 +} 1.107 + 1.108 +#ifdef SK_BUILD_FOR_ANDROID 1.109 +class SkJPEGImageIndex { 1.110 +public: 1.111 + SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder) 1.112 + : fSrcMgr(stream, decoder) 1.113 + , fInfoInitialized(false) 1.114 + , fHuffmanCreated(false) 1.115 + , fDecompressStarted(false) 1.116 + { 1.117 + SkDEBUGCODE(fReadHeaderSucceeded = false;) 1.118 + } 1.119 + 1.120 + ~SkJPEGImageIndex() { 1.121 + if (fHuffmanCreated) { 1.122 + // Set to false before calling the libjpeg function, in case 1.123 + // the libjpeg function calls longjmp. Our setjmp handler may 1.124 + // attempt to delete this SkJPEGImageIndex, thus entering this 1.125 + // destructor again. Setting fHuffmanCreated to false first 1.126 + // prevents an infinite loop. 1.127 + fHuffmanCreated = false; 1.128 + jpeg_destroy_huffman_index(&fHuffmanIndex); 1.129 + } 1.130 + if (fDecompressStarted) { 1.131 + // Like fHuffmanCreated, set to false before calling libjpeg 1.132 + // function to prevent potential infinite loop. 1.133 + fDecompressStarted = false; 1.134 + jpeg_finish_decompress(&fCInfo); 1.135 + } 1.136 + if (fInfoInitialized) { 1.137 + this->destroyInfo(); 1.138 + } 1.139 + } 1.140 + 1.141 + /** 1.142 + * Destroy the cinfo struct. 1.143 + * After this call, if a huffman index was already built, it 1.144 + * can be used after calling initializeInfoAndReadHeader 1.145 + * again. Must not be called after startTileDecompress except 1.146 + * in the destructor. 1.147 + */ 1.148 + void destroyInfo() { 1.149 + SkASSERT(fInfoInitialized); 1.150 + SkASSERT(!fDecompressStarted); 1.151 + // Like fHuffmanCreated, set to false before calling libjpeg 1.152 + // function to prevent potential infinite loop. 1.153 + fInfoInitialized = false; 1.154 + jpeg_destroy_decompress(&fCInfo); 1.155 + SkDEBUGCODE(fReadHeaderSucceeded = false;) 1.156 + } 1.157 + 1.158 + /** 1.159 + * Initialize the cinfo struct. 1.160 + * Calls jpeg_create_decompress, makes customizations, and 1.161 + * finally calls jpeg_read_header. Returns true if jpeg_read_header 1.162 + * returns JPEG_HEADER_OK. 1.163 + * If cinfo was already initialized, destroyInfo must be called to 1.164 + * destroy the old one. Must not be called after startTileDecompress. 1.165 + */ 1.166 + bool initializeInfoAndReadHeader() { 1.167 + SkASSERT(!fInfoInitialized && !fDecompressStarted); 1.168 + initialize_info(&fCInfo, &fSrcMgr); 1.169 + fInfoInitialized = true; 1.170 + const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true)); 1.171 + SkDEBUGCODE(fReadHeaderSucceeded = success;) 1.172 + return success; 1.173 + } 1.174 + 1.175 + jpeg_decompress_struct* cinfo() { return &fCInfo; } 1.176 + 1.177 + huffman_index* huffmanIndex() { return &fHuffmanIndex; } 1.178 + 1.179 + /** 1.180 + * Build the index to be used for tile based decoding. 1.181 + * Must only be called after a successful call to 1.182 + * initializeInfoAndReadHeader and must not be called more 1.183 + * than once. 1.184 + */ 1.185 + bool buildHuffmanIndex() { 1.186 + SkASSERT(fReadHeaderSucceeded); 1.187 + SkASSERT(!fHuffmanCreated); 1.188 + jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex); 1.189 + SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom); 1.190 + fHuffmanCreated = jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex); 1.191 + return fHuffmanCreated; 1.192 + } 1.193 + 1.194 + /** 1.195 + * Start tile based decoding. Must only be called after a 1.196 + * successful call to buildHuffmanIndex, and must only be 1.197 + * called once. 1.198 + */ 1.199 + bool startTileDecompress() { 1.200 + SkASSERT(fHuffmanCreated); 1.201 + SkASSERT(fReadHeaderSucceeded); 1.202 + SkASSERT(!fDecompressStarted); 1.203 + if (jpeg_start_tile_decompress(&fCInfo)) { 1.204 + fDecompressStarted = true; 1.205 + return true; 1.206 + } 1.207 + return false; 1.208 + } 1.209 + 1.210 +private: 1.211 + skjpeg_source_mgr fSrcMgr; 1.212 + jpeg_decompress_struct fCInfo; 1.213 + huffman_index fHuffmanIndex; 1.214 + bool fInfoInitialized; 1.215 + bool fHuffmanCreated; 1.216 + bool fDecompressStarted; 1.217 + SkDEBUGCODE(bool fReadHeaderSucceeded;) 1.218 +}; 1.219 +#endif 1.220 + 1.221 +class SkJPEGImageDecoder : public SkImageDecoder { 1.222 +public: 1.223 +#ifdef SK_BUILD_FOR_ANDROID 1.224 + SkJPEGImageDecoder() { 1.225 + fImageIndex = NULL; 1.226 + fImageWidth = 0; 1.227 + fImageHeight = 0; 1.228 + } 1.229 + 1.230 + virtual ~SkJPEGImageDecoder() { 1.231 + SkDELETE(fImageIndex); 1.232 + } 1.233 +#endif 1.234 + 1.235 + virtual Format getFormat() const { 1.236 + return kJPEG_Format; 1.237 + } 1.238 + 1.239 +protected: 1.240 +#ifdef SK_BUILD_FOR_ANDROID 1.241 + virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) SK_OVERRIDE; 1.242 + virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE; 1.243 +#endif 1.244 + virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; 1.245 + 1.246 +private: 1.247 +#ifdef SK_BUILD_FOR_ANDROID 1.248 + SkJPEGImageIndex* fImageIndex; 1.249 + int fImageWidth; 1.250 + int fImageHeight; 1.251 +#endif 1.252 + 1.253 + /** 1.254 + * Determine the appropriate bitmap config and out_color_space based on 1.255 + * both the preference of the caller and the jpeg_color_space on the 1.256 + * jpeg_decompress_struct passed in. 1.257 + * Must be called after jpeg_read_header. 1.258 + */ 1.259 + SkBitmap::Config getBitmapConfig(jpeg_decompress_struct*); 1.260 + 1.261 + typedef SkImageDecoder INHERITED; 1.262 +}; 1.263 + 1.264 +////////////////////////////////////////////////////////////////////////// 1.265 + 1.266 +/* Automatically clean up after throwing an exception */ 1.267 +class JPEGAutoClean { 1.268 +public: 1.269 + JPEGAutoClean(): cinfo_ptr(NULL) {} 1.270 + ~JPEGAutoClean() { 1.271 + if (cinfo_ptr) { 1.272 + jpeg_destroy_decompress(cinfo_ptr); 1.273 + } 1.274 + } 1.275 + void set(jpeg_decompress_struct* info) { 1.276 + cinfo_ptr = info; 1.277 + } 1.278 +private: 1.279 + jpeg_decompress_struct* cinfo_ptr; 1.280 +}; 1.281 + 1.282 +/////////////////////////////////////////////////////////////////////////////// 1.283 + 1.284 +/* If we need to better match the request, we might examine the image and 1.285 + output dimensions, and determine if the downsampling jpeg provided is 1.286 + not sufficient. If so, we can recompute a modified sampleSize value to 1.287 + make up the difference. 1.288 + 1.289 + To skip this additional scaling, just set sampleSize = 1; below. 1.290 + */ 1.291 +static int recompute_sampleSize(int sampleSize, 1.292 + const jpeg_decompress_struct& cinfo) { 1.293 + return sampleSize * cinfo.output_width / cinfo.image_width; 1.294 +} 1.295 + 1.296 +static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) { 1.297 + /* These are initialized to 0, so if they have non-zero values, we assume 1.298 + they are "valid" (i.e. have been computed by libjpeg) 1.299 + */ 1.300 + return 0 != cinfo.output_width && 0 != cinfo.output_height; 1.301 +} 1.302 + 1.303 +static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) { 1.304 + for (int i = 0; i < count; i++) { 1.305 + JSAMPLE* rowptr = (JSAMPLE*)buffer; 1.306 + int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1); 1.307 + if (1 != row_count) { 1.308 + return false; 1.309 + } 1.310 + } 1.311 + return true; 1.312 +} 1.313 + 1.314 +#ifdef SK_BUILD_FOR_ANDROID 1.315 +static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo, 1.316 + huffman_index *index, void* buffer, int count) { 1.317 + for (int i = 0; i < count; i++) { 1.318 + JSAMPLE* rowptr = (JSAMPLE*)buffer; 1.319 + int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr); 1.320 + if (1 != row_count) { 1.321 + return false; 1.322 + } 1.323 + } 1.324 + return true; 1.325 +} 1.326 +#endif 1.327 + 1.328 +// This guy exists just to aid in debugging, as it allows debuggers to just 1.329 +// set a break-point in one place to see all error exists. 1.330 +static bool return_false(const jpeg_decompress_struct& cinfo, 1.331 + const SkBitmap& bm, const char caller[]) { 1.332 + if (!(c_suppressJPEGImageDecoderErrors)) { 1.333 + char buffer[JMSG_LENGTH_MAX]; 1.334 + cinfo.err->format_message((const j_common_ptr)&cinfo, buffer); 1.335 + SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", 1.336 + cinfo.err->msg_code, buffer, caller, bm.width(), bm.height()); 1.337 + } 1.338 + return false; // must always return false 1.339 +} 1.340 + 1.341 +// Convert a scanline of CMYK samples to RGBX in place. Note that this 1.342 +// method moves the "scanline" pointer in its processing 1.343 +static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) { 1.344 + // At this point we've received CMYK pixels from libjpeg. We 1.345 + // perform a crude conversion to RGB (based on the formulae 1.346 + // from easyrgb.com): 1.347 + // CMYK -> CMY 1.348 + // C = ( C * (1 - K) + K ) // for each CMY component 1.349 + // CMY -> RGB 1.350 + // R = ( 1 - C ) * 255 // for each RGB component 1.351 + // Unfortunately we are seeing inverted CMYK so all the original terms 1.352 + // are 1-. This yields: 1.353 + // CMYK -> CMY 1.354 + // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K 1.355 + // The conversion from CMY->RGB remains the same 1.356 + for (unsigned int x = 0; x < width; ++x, scanline += 4) { 1.357 + scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]); 1.358 + scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]); 1.359 + scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]); 1.360 + scanline[3] = 255; 1.361 + } 1.362 +} 1.363 + 1.364 +/** 1.365 + * Common code for setting the error manager. 1.366 + */ 1.367 +static void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* errorManager) { 1.368 + SkASSERT(cinfo != NULL); 1.369 + SkASSERT(errorManager != NULL); 1.370 + cinfo->err = jpeg_std_error(errorManager); 1.371 + errorManager->error_exit = skjpeg_error_exit; 1.372 +} 1.373 + 1.374 +/** 1.375 + * Common code for turning off upsampling and smoothing. Turning these 1.376 + * off helps performance without showing noticable differences in the 1.377 + * resulting bitmap. 1.378 + */ 1.379 +static void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) { 1.380 + SkASSERT(cinfo != NULL); 1.381 + /* this gives about 30% performance improvement. In theory it may 1.382 + reduce the visual quality, in practice I'm not seeing a difference 1.383 + */ 1.384 + cinfo->do_fancy_upsampling = 0; 1.385 + 1.386 + /* this gives another few percents */ 1.387 + cinfo->do_block_smoothing = 0; 1.388 +} 1.389 + 1.390 +/** 1.391 + * Common code for setting the dct method. 1.392 + */ 1.393 +static void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct* cinfo) { 1.394 + SkASSERT(cinfo != NULL); 1.395 +#ifdef DCT_IFAST_SUPPORTED 1.396 + if (decoder.getPreferQualityOverSpeed()) { 1.397 + cinfo->dct_method = JDCT_ISLOW; 1.398 + } else { 1.399 + cinfo->dct_method = JDCT_IFAST; 1.400 + } 1.401 +#else 1.402 + cinfo->dct_method = JDCT_ISLOW; 1.403 +#endif 1.404 +} 1.405 + 1.406 +SkBitmap::Config SkJPEGImageDecoder::getBitmapConfig(jpeg_decompress_struct* cinfo) { 1.407 + SkASSERT(cinfo != NULL); 1.408 + 1.409 + SrcDepth srcDepth = k32Bit_SrcDepth; 1.410 + if (JCS_GRAYSCALE == cinfo->jpeg_color_space) { 1.411 + srcDepth = k8BitGray_SrcDepth; 1.412 + } 1.413 + 1.414 + SkBitmap::Config config = this->getPrefConfig(srcDepth, /*hasAlpha*/ false); 1.415 + switch (config) { 1.416 + case SkBitmap::kA8_Config: 1.417 + // Only respect A8 config if the original is grayscale, 1.418 + // in which case we will treat the grayscale as alpha 1.419 + // values. 1.420 + if (cinfo->jpeg_color_space != JCS_GRAYSCALE) { 1.421 + config = SkBitmap::kARGB_8888_Config; 1.422 + } 1.423 + break; 1.424 + case SkBitmap::kARGB_8888_Config: 1.425 + // Fall through. 1.426 + case SkBitmap::kARGB_4444_Config: 1.427 + // Fall through. 1.428 + case SkBitmap::kRGB_565_Config: 1.429 + // These are acceptable destination configs. 1.430 + break; 1.431 + default: 1.432 + // Force all other configs to 8888. 1.433 + config = SkBitmap::kARGB_8888_Config; 1.434 + break; 1.435 + } 1.436 + 1.437 + switch (cinfo->jpeg_color_space) { 1.438 + case JCS_CMYK: 1.439 + // Fall through. 1.440 + case JCS_YCCK: 1.441 + // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up 1.442 + // so libjpeg will give us CMYK samples back and we will later 1.443 + // manually convert them to RGB 1.444 + cinfo->out_color_space = JCS_CMYK; 1.445 + break; 1.446 + case JCS_GRAYSCALE: 1.447 + if (SkBitmap::kA8_Config == config) { 1.448 + cinfo->out_color_space = JCS_GRAYSCALE; 1.449 + break; 1.450 + } 1.451 + // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB 1.452 + // config. Fall through to set to the default. 1.453 + default: 1.454 + cinfo->out_color_space = JCS_RGB; 1.455 + break; 1.456 + } 1.457 + return config; 1.458 +} 1.459 + 1.460 +#ifdef ANDROID_RGB 1.461 +/** 1.462 + * Based on the config and dither mode, adjust out_color_space and 1.463 + * dither_mode of cinfo. 1.464 + */ 1.465 +static void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo, 1.466 + SkBitmap::Config config, 1.467 + const SkImageDecoder& decoder) { 1.468 + SkASSERT(cinfo != NULL); 1.469 + cinfo->dither_mode = JDITHER_NONE; 1.470 + if (JCS_CMYK == cinfo->out_color_space) { 1.471 + return; 1.472 + } 1.473 + switch(config) { 1.474 + case SkBitmap::kARGB_8888_Config: 1.475 + cinfo->out_color_space = JCS_RGBA_8888; 1.476 + break; 1.477 + case SkBitmap::kRGB_565_Config: 1.478 + cinfo->out_color_space = JCS_RGB_565; 1.479 + if (decoder.getDitherImage()) { 1.480 + cinfo->dither_mode = JDITHER_ORDERED; 1.481 + } 1.482 + break; 1.483 + default: 1.484 + break; 1.485 + } 1.486 +} 1.487 +#endif 1.488 + 1.489 + 1.490 +/** 1.491 + Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y. 1.492 + Used when decoding fails partway through reading scanlines to fill 1.493 + remaining lines. */ 1.494 +static void fill_below_level(int y, SkBitmap* bitmap) { 1.495 + SkIRect rect = SkIRect::MakeLTRB(0, y, bitmap->width(), bitmap->height()); 1.496 + SkCanvas canvas(*bitmap); 1.497 + canvas.clipRect(SkRect::Make(rect)); 1.498 + canvas.drawColor(SK_ColorWHITE); 1.499 +} 1.500 + 1.501 +/** 1.502 + * Get the config and bytes per pixel of the source data. Return 1.503 + * whether the data is supported. 1.504 + */ 1.505 +static bool get_src_config(const jpeg_decompress_struct& cinfo, 1.506 + SkScaledBitmapSampler::SrcConfig* sc, 1.507 + int* srcBytesPerPixel) { 1.508 + SkASSERT(sc != NULL && srcBytesPerPixel != NULL); 1.509 + if (JCS_CMYK == cinfo.out_color_space) { 1.510 + // In this case we will manually convert the CMYK values to RGB 1.511 + *sc = SkScaledBitmapSampler::kRGBX; 1.512 + // The CMYK work-around relies on 4 components per pixel here 1.513 + *srcBytesPerPixel = 4; 1.514 + } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) { 1.515 + *sc = SkScaledBitmapSampler::kRGB; 1.516 + *srcBytesPerPixel = 3; 1.517 +#ifdef ANDROID_RGB 1.518 + } else if (JCS_RGBA_8888 == cinfo.out_color_space) { 1.519 + *sc = SkScaledBitmapSampler::kRGBX; 1.520 + *srcBytesPerPixel = 4; 1.521 + } else if (JCS_RGB_565 == cinfo.out_color_space) { 1.522 + *sc = SkScaledBitmapSampler::kRGB_565; 1.523 + *srcBytesPerPixel = 2; 1.524 +#endif 1.525 + } else if (1 == cinfo.out_color_components && 1.526 + JCS_GRAYSCALE == cinfo.out_color_space) { 1.527 + *sc = SkScaledBitmapSampler::kGray; 1.528 + *srcBytesPerPixel = 1; 1.529 + } else { 1.530 + return false; 1.531 + } 1.532 + return true; 1.533 +} 1.534 + 1.535 +bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 1.536 +#ifdef TIME_DECODE 1.537 + SkAutoTime atm("JPEG Decode"); 1.538 +#endif 1.539 + 1.540 + JPEGAutoClean autoClean; 1.541 + 1.542 + jpeg_decompress_struct cinfo; 1.543 + skjpeg_source_mgr srcManager(stream, this); 1.544 + 1.545 + skjpeg_error_mgr errorManager; 1.546 + set_error_mgr(&cinfo, &errorManager); 1.547 + 1.548 + // All objects need to be instantiated before this setjmp call so that 1.549 + // they will be cleaned up properly if an error occurs. 1.550 + if (setjmp(errorManager.fJmpBuf)) { 1.551 + return return_false(cinfo, *bm, "setjmp"); 1.552 + } 1.553 + 1.554 + initialize_info(&cinfo, &srcManager); 1.555 + autoClean.set(&cinfo); 1.556 + 1.557 + int status = jpeg_read_header(&cinfo, true); 1.558 + if (status != JPEG_HEADER_OK) { 1.559 + return return_false(cinfo, *bm, "read_header"); 1.560 + } 1.561 + 1.562 + /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it 1.563 + can) much faster that we, just use their num/denom api to approximate 1.564 + the size. 1.565 + */ 1.566 + int sampleSize = this->getSampleSize(); 1.567 + 1.568 + set_dct_method(*this, &cinfo); 1.569 + 1.570 + SkASSERT(1 == cinfo.scale_num); 1.571 + cinfo.scale_denom = sampleSize; 1.572 + 1.573 + turn_off_visual_optimizations(&cinfo); 1.574 + 1.575 + const SkBitmap::Config config = this->getBitmapConfig(&cinfo); 1.576 + 1.577 +#ifdef ANDROID_RGB 1.578 + adjust_out_color_space_and_dither(&cinfo, config, *this); 1.579 +#endif 1.580 + 1.581 + if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) { 1.582 + // Assume an A8 bitmap is not opaque to avoid the check of each 1.583 + // individual pixel. It is very unlikely to be opaque, since 1.584 + // an opaque A8 bitmap would not be very interesting. 1.585 + // Otherwise, a jpeg image is opaque. 1.586 + return bm->setConfig(config, cinfo.image_width, cinfo.image_height, 0, 1.587 + SkBitmap::kA8_Config == config ? 1.588 + kPremul_SkAlphaType : kOpaque_SkAlphaType); 1.589 + } 1.590 + 1.591 + /* image_width and image_height are the original dimensions, available 1.592 + after jpeg_read_header(). To see the scaled dimensions, we have to call 1.593 + jpeg_start_decompress(), and then read output_width and output_height. 1.594 + */ 1.595 + if (!jpeg_start_decompress(&cinfo)) { 1.596 + /* If we failed here, we may still have enough information to return 1.597 + to the caller if they just wanted (subsampled bounds). If sampleSize 1.598 + was 1, then we would have already returned. Thus we just check if 1.599 + we're in kDecodeBounds_Mode, and that we have valid output sizes. 1.600 + 1.601 + One reason to fail here is that we have insufficient stream data 1.602 + to complete the setup. However, output dimensions seem to get 1.603 + computed very early, which is why this special check can pay off. 1.604 + */ 1.605 + if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) { 1.606 + SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height, 1.607 + recompute_sampleSize(sampleSize, cinfo)); 1.608 + // Assume an A8 bitmap is not opaque to avoid the check of each 1.609 + // individual pixel. It is very unlikely to be opaque, since 1.610 + // an opaque A8 bitmap would not be very interesting. 1.611 + // Otherwise, a jpeg image is opaque. 1.612 + return bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight(), 1.613 + 0, SkBitmap::kA8_Config == config ? 1.614 + kPremul_SkAlphaType : kOpaque_SkAlphaType); 1.615 + } else { 1.616 + return return_false(cinfo, *bm, "start_decompress"); 1.617 + } 1.618 + } 1.619 + sampleSize = recompute_sampleSize(sampleSize, cinfo); 1.620 + 1.621 + // should we allow the Chooser (if present) to pick a config for us??? 1.622 + if (!this->chooseFromOneChoice(config, cinfo.output_width, cinfo.output_height)) { 1.623 + return return_false(cinfo, *bm, "chooseFromOneChoice"); 1.624 + } 1.625 + 1.626 + SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize); 1.627 + // Assume an A8 bitmap is not opaque to avoid the check of each 1.628 + // individual pixel. It is very unlikely to be opaque, since 1.629 + // an opaque A8 bitmap would not be very interesting. 1.630 + // Otherwise, a jpeg image is opaque. 1.631 + bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0, 1.632 + SkBitmap::kA8_Config != config ? kOpaque_SkAlphaType : kPremul_SkAlphaType); 1.633 + if (SkImageDecoder::kDecodeBounds_Mode == mode) { 1.634 + return true; 1.635 + } 1.636 + if (!this->allocPixelRef(bm, NULL)) { 1.637 + return return_false(cinfo, *bm, "allocPixelRef"); 1.638 + } 1.639 + 1.640 + SkAutoLockPixels alp(*bm); 1.641 + 1.642 +#ifdef ANDROID_RGB 1.643 + /* short-circuit the SkScaledBitmapSampler when possible, as this gives 1.644 + a significant performance boost. 1.645 + */ 1.646 + if (sampleSize == 1 && 1.647 + ((config == SkBitmap::kARGB_8888_Config && 1.648 + cinfo.out_color_space == JCS_RGBA_8888) || 1.649 + (config == SkBitmap::kRGB_565_Config && 1.650 + cinfo.out_color_space == JCS_RGB_565))) 1.651 + { 1.652 + JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); 1.653 + INT32 const bpr = bm->rowBytes(); 1.654 + 1.655 + while (cinfo.output_scanline < cinfo.output_height) { 1.656 + int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 1.657 + if (0 == row_count) { 1.658 + // if row_count == 0, then we didn't get a scanline, 1.659 + // so return early. We will return a partial image. 1.660 + fill_below_level(cinfo.output_scanline, bm); 1.661 + cinfo.output_scanline = cinfo.output_height; 1.662 + break; // Skip to jpeg_finish_decompress() 1.663 + } 1.664 + if (this->shouldCancelDecode()) { 1.665 + return return_false(cinfo, *bm, "shouldCancelDecode"); 1.666 + } 1.667 + rowptr += bpr; 1.668 + } 1.669 + jpeg_finish_decompress(&cinfo); 1.670 + return true; 1.671 + } 1.672 +#endif 1.673 + 1.674 + // check for supported formats 1.675 + SkScaledBitmapSampler::SrcConfig sc; 1.676 + int srcBytesPerPixel; 1.677 + 1.678 + if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) { 1.679 + return return_false(cinfo, *bm, "jpeg colorspace"); 1.680 + } 1.681 + 1.682 + if (!sampler.begin(bm, sc, *this)) { 1.683 + return return_false(cinfo, *bm, "sampler.begin"); 1.684 + } 1.685 + 1.686 + SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel); 1.687 + uint8_t* srcRow = (uint8_t*)srcStorage.get(); 1.688 + 1.689 + // Possibly skip initial rows [sampler.srcY0] 1.690 + if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { 1.691 + return return_false(cinfo, *bm, "skip rows"); 1.692 + } 1.693 + 1.694 + // now loop through scanlines until y == bm->height() - 1 1.695 + for (int y = 0;; y++) { 1.696 + JSAMPLE* rowptr = (JSAMPLE*)srcRow; 1.697 + int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 1.698 + if (0 == row_count) { 1.699 + // if row_count == 0, then we didn't get a scanline, 1.700 + // so return early. We will return a partial image. 1.701 + fill_below_level(y, bm); 1.702 + cinfo.output_scanline = cinfo.output_height; 1.703 + break; // Skip to jpeg_finish_decompress() 1.704 + } 1.705 + if (this->shouldCancelDecode()) { 1.706 + return return_false(cinfo, *bm, "shouldCancelDecode"); 1.707 + } 1.708 + 1.709 + if (JCS_CMYK == cinfo.out_color_space) { 1.710 + convert_CMYK_to_RGB(srcRow, cinfo.output_width); 1.711 + } 1.712 + 1.713 + sampler.next(srcRow); 1.714 + if (bm->height() - 1 == y) { 1.715 + // we're done 1.716 + break; 1.717 + } 1.718 + 1.719 + if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { 1.720 + return return_false(cinfo, *bm, "skip rows"); 1.721 + } 1.722 + } 1.723 + 1.724 + // we formally skip the rest, so we don't get a complaint from libjpeg 1.725 + if (!skip_src_rows(&cinfo, srcRow, 1.726 + cinfo.output_height - cinfo.output_scanline)) { 1.727 + return return_false(cinfo, *bm, "skip rows"); 1.728 + } 1.729 + jpeg_finish_decompress(&cinfo); 1.730 + 1.731 + return true; 1.732 +} 1.733 + 1.734 +#ifdef SK_BUILD_FOR_ANDROID 1.735 +bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) { 1.736 + 1.737 + SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (stream, this))); 1.738 + jpeg_decompress_struct* cinfo = imageIndex->cinfo(); 1.739 + 1.740 + skjpeg_error_mgr sk_err; 1.741 + set_error_mgr(cinfo, &sk_err); 1.742 + 1.743 + // All objects need to be instantiated before this setjmp call so that 1.744 + // they will be cleaned up properly if an error occurs. 1.745 + if (setjmp(sk_err.fJmpBuf)) { 1.746 + return false; 1.747 + } 1.748 + 1.749 + // create the cinfo used to create/build the huffmanIndex 1.750 + if (!imageIndex->initializeInfoAndReadHeader()) { 1.751 + return false; 1.752 + } 1.753 + 1.754 + if (!imageIndex->buildHuffmanIndex()) { 1.755 + return false; 1.756 + } 1.757 + 1.758 + // destroy the cinfo used to create/build the huffman index 1.759 + imageIndex->destroyInfo(); 1.760 + 1.761 + // Init decoder to image decode mode 1.762 + if (!imageIndex->initializeInfoAndReadHeader()) { 1.763 + return false; 1.764 + } 1.765 + 1.766 + // FIXME: This sets cinfo->out_color_space, which we may change later 1.767 + // based on the config in onDecodeSubset. This should be fine, since 1.768 + // jpeg_init_read_tile_scanline will check out_color_space again after 1.769 + // that change (when it calls jinit_color_deconverter). 1.770 + (void) this->getBitmapConfig(cinfo); 1.771 + 1.772 + turn_off_visual_optimizations(cinfo); 1.773 + 1.774 + // instead of jpeg_start_decompress() we start a tiled decompress 1.775 + if (!imageIndex->startTileDecompress()) { 1.776 + return false; 1.777 + } 1.778 + 1.779 + SkASSERT(1 == cinfo->scale_num); 1.780 + fImageWidth = cinfo->output_width; 1.781 + fImageHeight = cinfo->output_height; 1.782 + 1.783 + if (width) { 1.784 + *width = fImageWidth; 1.785 + } 1.786 + if (height) { 1.787 + *height = fImageHeight; 1.788 + } 1.789 + 1.790 + SkDELETE(fImageIndex); 1.791 + fImageIndex = imageIndex.detach(); 1.792 + 1.793 + return true; 1.794 +} 1.795 + 1.796 +bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { 1.797 + if (NULL == fImageIndex) { 1.798 + return false; 1.799 + } 1.800 + jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); 1.801 + 1.802 + SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); 1.803 + if (!rect.intersect(region)) { 1.804 + // If the requested region is entirely outside the image return false 1.805 + return false; 1.806 + } 1.807 + 1.808 + 1.809 + skjpeg_error_mgr errorManager; 1.810 + set_error_mgr(cinfo, &errorManager); 1.811 + 1.812 + if (setjmp(errorManager.fJmpBuf)) { 1.813 + return false; 1.814 + } 1.815 + 1.816 + int requestedSampleSize = this->getSampleSize(); 1.817 + cinfo->scale_denom = requestedSampleSize; 1.818 + 1.819 + set_dct_method(*this, cinfo); 1.820 + 1.821 + const SkBitmap::Config config = this->getBitmapConfig(cinfo); 1.822 +#ifdef ANDROID_RGB 1.823 + adjust_out_color_space_and_dither(cinfo, config, *this); 1.824 +#endif 1.825 + 1.826 + int startX = rect.fLeft; 1.827 + int startY = rect.fTop; 1.828 + int width = rect.width(); 1.829 + int height = rect.height(); 1.830 + 1.831 + jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), 1.832 + &startX, &startY, &width, &height); 1.833 + int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); 1.834 + int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size); 1.835 + 1.836 + SkScaledBitmapSampler sampler(width, height, skiaSampleSize); 1.837 + 1.838 + SkBitmap bitmap; 1.839 + bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight()); 1.840 + // Assume an A8 bitmap is not opaque to avoid the check of each 1.841 + // individual pixel. It is very unlikely to be opaque, since 1.842 + // an opaque A8 bitmap would not be very interesting. 1.843 + // Otherwise, a jpeg image is opaque. 1.844 + bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0, 1.845 + config == SkBitmap::kA8_Config ? kPremul_SkAlphaType : 1.846 + kOpaque_SkAlphaType); 1.847 + 1.848 + // Check ahead of time if the swap(dest, src) is possible or not. 1.849 + // If yes, then we will stick to AllocPixelRef since it's cheaper with the 1.850 + // swap happening. If no, then we will use alloc to allocate pixels to 1.851 + // prevent garbage collection. 1.852 + int w = rect.width() / actualSampleSize; 1.853 + int h = rect.height() / actualSampleSize; 1.854 + bool swapOnly = (rect == region) && bm->isNull() && 1.855 + (w == bitmap.width()) && (h == bitmap.height()) && 1.856 + ((startX - rect.x()) / actualSampleSize == 0) && 1.857 + ((startY - rect.y()) / actualSampleSize == 0); 1.858 + if (swapOnly) { 1.859 + if (!this->allocPixelRef(&bitmap, NULL)) { 1.860 + return return_false(*cinfo, bitmap, "allocPixelRef"); 1.861 + } 1.862 + } else { 1.863 + if (!bitmap.allocPixels()) { 1.864 + return return_false(*cinfo, bitmap, "allocPixels"); 1.865 + } 1.866 + } 1.867 + 1.868 + SkAutoLockPixels alp(bitmap); 1.869 + 1.870 +#ifdef ANDROID_RGB 1.871 + /* short-circuit the SkScaledBitmapSampler when possible, as this gives 1.872 + a significant performance boost. 1.873 + */ 1.874 + if (skiaSampleSize == 1 && 1.875 + ((config == SkBitmap::kARGB_8888_Config && 1.876 + cinfo->out_color_space == JCS_RGBA_8888) || 1.877 + (config == SkBitmap::kRGB_565_Config && 1.878 + cinfo->out_color_space == JCS_RGB_565))) 1.879 + { 1.880 + JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); 1.881 + INT32 const bpr = bitmap.rowBytes(); 1.882 + int rowTotalCount = 0; 1.883 + 1.884 + while (rowTotalCount < height) { 1.885 + int rowCount = jpeg_read_tile_scanline(cinfo, 1.886 + fImageIndex->huffmanIndex(), 1.887 + &rowptr); 1.888 + // if rowCount == 0, then we didn't get a scanline, so abort. 1.889 + // onDecodeSubset() relies on onBuildTileIndex(), which 1.890 + // needs a complete image to succeed. 1.891 + if (0 == rowCount) { 1.892 + return return_false(*cinfo, bitmap, "read_scanlines"); 1.893 + } 1.894 + if (this->shouldCancelDecode()) { 1.895 + return return_false(*cinfo, bitmap, "shouldCancelDecode"); 1.896 + } 1.897 + rowTotalCount += rowCount; 1.898 + rowptr += bpr; 1.899 + } 1.900 + 1.901 + if (swapOnly) { 1.902 + bm->swap(bitmap); 1.903 + } else { 1.904 + cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 1.905 + region.width(), region.height(), startX, startY); 1.906 + } 1.907 + return true; 1.908 + } 1.909 +#endif 1.910 + 1.911 + // check for supported formats 1.912 + SkScaledBitmapSampler::SrcConfig sc; 1.913 + int srcBytesPerPixel; 1.914 + 1.915 + if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) { 1.916 + return return_false(*cinfo, *bm, "jpeg colorspace"); 1.917 + } 1.918 + 1.919 + if (!sampler.begin(&bitmap, sc, *this)) { 1.920 + return return_false(*cinfo, bitmap, "sampler.begin"); 1.921 + } 1.922 + 1.923 + SkAutoMalloc srcStorage(width * srcBytesPerPixel); 1.924 + uint8_t* srcRow = (uint8_t*)srcStorage.get(); 1.925 + 1.926 + // Possibly skip initial rows [sampler.srcY0] 1.927 + if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) { 1.928 + return return_false(*cinfo, bitmap, "skip rows"); 1.929 + } 1.930 + 1.931 + // now loop through scanlines until y == bitmap->height() - 1 1.932 + for (int y = 0;; y++) { 1.933 + JSAMPLE* rowptr = (JSAMPLE*)srcRow; 1.934 + int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr); 1.935 + // if row_count == 0, then we didn't get a scanline, so abort. 1.936 + // onDecodeSubset() relies on onBuildTileIndex(), which 1.937 + // needs a complete image to succeed. 1.938 + if (0 == row_count) { 1.939 + return return_false(*cinfo, bitmap, "read_scanlines"); 1.940 + } 1.941 + if (this->shouldCancelDecode()) { 1.942 + return return_false(*cinfo, bitmap, "shouldCancelDecode"); 1.943 + } 1.944 + 1.945 + if (JCS_CMYK == cinfo->out_color_space) { 1.946 + convert_CMYK_to_RGB(srcRow, width); 1.947 + } 1.948 + 1.949 + sampler.next(srcRow); 1.950 + if (bitmap.height() - 1 == y) { 1.951 + // we're done 1.952 + break; 1.953 + } 1.954 + 1.955 + if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, 1.956 + sampler.srcDY() - 1)) { 1.957 + return return_false(*cinfo, bitmap, "skip rows"); 1.958 + } 1.959 + } 1.960 + if (swapOnly) { 1.961 + bm->swap(bitmap); 1.962 + } else { 1.963 + cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 1.964 + region.width(), region.height(), startX, startY); 1.965 + } 1.966 + return true; 1.967 +} 1.968 +#endif 1.969 + 1.970 +/////////////////////////////////////////////////////////////////////////////// 1.971 + 1.972 +#include "SkColorPriv.h" 1.973 + 1.974 +// taken from jcolor.c in libjpeg 1.975 +#if 0 // 16bit - precise but slow 1.976 + #define CYR 19595 // 0.299 1.977 + #define CYG 38470 // 0.587 1.978 + #define CYB 7471 // 0.114 1.979 + 1.980 + #define CUR -11059 // -0.16874 1.981 + #define CUG -21709 // -0.33126 1.982 + #define CUB 32768 // 0.5 1.983 + 1.984 + #define CVR 32768 // 0.5 1.985 + #define CVG -27439 // -0.41869 1.986 + #define CVB -5329 // -0.08131 1.987 + 1.988 + #define CSHIFT 16 1.989 +#else // 8bit - fast, slightly less precise 1.990 + #define CYR 77 // 0.299 1.991 + #define CYG 150 // 0.587 1.992 + #define CYB 29 // 0.114 1.993 + 1.994 + #define CUR -43 // -0.16874 1.995 + #define CUG -85 // -0.33126 1.996 + #define CUB 128 // 0.5 1.997 + 1.998 + #define CVR 128 // 0.5 1.999 + #define CVG -107 // -0.41869 1.1000 + #define CVB -21 // -0.08131 1.1001 + 1.1002 + #define CSHIFT 8 1.1003 +#endif 1.1004 + 1.1005 +static void rgb2yuv_32(uint8_t dst[], SkPMColor c) { 1.1006 + int r = SkGetPackedR32(c); 1.1007 + int g = SkGetPackedG32(c); 1.1008 + int b = SkGetPackedB32(c); 1.1009 + 1.1010 + int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT; 1.1011 + int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT; 1.1012 + int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT; 1.1013 + 1.1014 + dst[0] = SkToU8(y); 1.1015 + dst[1] = SkToU8(u + 128); 1.1016 + dst[2] = SkToU8(v + 128); 1.1017 +} 1.1018 + 1.1019 +static void rgb2yuv_4444(uint8_t dst[], U16CPU c) { 1.1020 + int r = SkGetPackedR4444(c); 1.1021 + int g = SkGetPackedG4444(c); 1.1022 + int b = SkGetPackedB4444(c); 1.1023 + 1.1024 + int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4); 1.1025 + int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4); 1.1026 + int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4); 1.1027 + 1.1028 + dst[0] = SkToU8(y); 1.1029 + dst[1] = SkToU8(u + 128); 1.1030 + dst[2] = SkToU8(v + 128); 1.1031 +} 1.1032 + 1.1033 +static void rgb2yuv_16(uint8_t dst[], U16CPU c) { 1.1034 + int r = SkGetPackedR16(c); 1.1035 + int g = SkGetPackedG16(c); 1.1036 + int b = SkGetPackedB16(c); 1.1037 + 1.1038 + int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2); 1.1039 + int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2); 1.1040 + int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2); 1.1041 + 1.1042 + dst[0] = SkToU8(y); 1.1043 + dst[1] = SkToU8(u + 128); 1.1044 + dst[2] = SkToU8(v + 128); 1.1045 +} 1.1046 + 1.1047 +/////////////////////////////////////////////////////////////////////////////// 1.1048 + 1.1049 +typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, 1.1050 + const void* SK_RESTRICT src, int width, 1.1051 + const SkPMColor* SK_RESTRICT ctable); 1.1052 + 1.1053 +static void Write_32_YUV(uint8_t* SK_RESTRICT dst, 1.1054 + const void* SK_RESTRICT srcRow, int width, 1.1055 + const SkPMColor*) { 1.1056 + const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; 1.1057 + while (--width >= 0) { 1.1058 +#ifdef WE_CONVERT_TO_YUV 1.1059 + rgb2yuv_32(dst, *src++); 1.1060 +#else 1.1061 + uint32_t c = *src++; 1.1062 + dst[0] = SkGetPackedR32(c); 1.1063 + dst[1] = SkGetPackedG32(c); 1.1064 + dst[2] = SkGetPackedB32(c); 1.1065 +#endif 1.1066 + dst += 3; 1.1067 + } 1.1068 +} 1.1069 + 1.1070 +static void Write_4444_YUV(uint8_t* SK_RESTRICT dst, 1.1071 + const void* SK_RESTRICT srcRow, int width, 1.1072 + const SkPMColor*) { 1.1073 + const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; 1.1074 + while (--width >= 0) { 1.1075 +#ifdef WE_CONVERT_TO_YUV 1.1076 + rgb2yuv_4444(dst, *src++); 1.1077 +#else 1.1078 + SkPMColor16 c = *src++; 1.1079 + dst[0] = SkPacked4444ToR32(c); 1.1080 + dst[1] = SkPacked4444ToG32(c); 1.1081 + dst[2] = SkPacked4444ToB32(c); 1.1082 +#endif 1.1083 + dst += 3; 1.1084 + } 1.1085 +} 1.1086 + 1.1087 +static void Write_16_YUV(uint8_t* SK_RESTRICT dst, 1.1088 + const void* SK_RESTRICT srcRow, int width, 1.1089 + const SkPMColor*) { 1.1090 + const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; 1.1091 + while (--width >= 0) { 1.1092 +#ifdef WE_CONVERT_TO_YUV 1.1093 + rgb2yuv_16(dst, *src++); 1.1094 +#else 1.1095 + uint16_t c = *src++; 1.1096 + dst[0] = SkPacked16ToR32(c); 1.1097 + dst[1] = SkPacked16ToG32(c); 1.1098 + dst[2] = SkPacked16ToB32(c); 1.1099 +#endif 1.1100 + dst += 3; 1.1101 + } 1.1102 +} 1.1103 + 1.1104 +static void Write_Index_YUV(uint8_t* SK_RESTRICT dst, 1.1105 + const void* SK_RESTRICT srcRow, int width, 1.1106 + const SkPMColor* SK_RESTRICT ctable) { 1.1107 + const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; 1.1108 + while (--width >= 0) { 1.1109 +#ifdef WE_CONVERT_TO_YUV 1.1110 + rgb2yuv_32(dst, ctable[*src++]); 1.1111 +#else 1.1112 + uint32_t c = ctable[*src++]; 1.1113 + dst[0] = SkGetPackedR32(c); 1.1114 + dst[1] = SkGetPackedG32(c); 1.1115 + dst[2] = SkGetPackedB32(c); 1.1116 +#endif 1.1117 + dst += 3; 1.1118 + } 1.1119 +} 1.1120 + 1.1121 +static WriteScanline ChooseWriter(const SkBitmap& bm) { 1.1122 + switch (bm.config()) { 1.1123 + case SkBitmap::kARGB_8888_Config: 1.1124 + return Write_32_YUV; 1.1125 + case SkBitmap::kRGB_565_Config: 1.1126 + return Write_16_YUV; 1.1127 + case SkBitmap::kARGB_4444_Config: 1.1128 + return Write_4444_YUV; 1.1129 + case SkBitmap::kIndex8_Config: 1.1130 + return Write_Index_YUV; 1.1131 + default: 1.1132 + return NULL; 1.1133 + } 1.1134 +} 1.1135 + 1.1136 +class SkJPEGImageEncoder : public SkImageEncoder { 1.1137 +protected: 1.1138 + virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { 1.1139 +#ifdef TIME_ENCODE 1.1140 + SkAutoTime atm("JPEG Encode"); 1.1141 +#endif 1.1142 + 1.1143 + SkAutoLockPixels alp(bm); 1.1144 + if (NULL == bm.getPixels()) { 1.1145 + return false; 1.1146 + } 1.1147 + 1.1148 + jpeg_compress_struct cinfo; 1.1149 + skjpeg_error_mgr sk_err; 1.1150 + skjpeg_destination_mgr sk_wstream(stream); 1.1151 + 1.1152 + // allocate these before set call setjmp 1.1153 + SkAutoMalloc oneRow; 1.1154 + SkAutoLockColors ctLocker; 1.1155 + 1.1156 + cinfo.err = jpeg_std_error(&sk_err); 1.1157 + sk_err.error_exit = skjpeg_error_exit; 1.1158 + if (setjmp(sk_err.fJmpBuf)) { 1.1159 + return false; 1.1160 + } 1.1161 + 1.1162 + // Keep after setjmp or mark volatile. 1.1163 + const WriteScanline writer = ChooseWriter(bm); 1.1164 + if (NULL == writer) { 1.1165 + return false; 1.1166 + } 1.1167 + 1.1168 + jpeg_create_compress(&cinfo); 1.1169 + cinfo.dest = &sk_wstream; 1.1170 + cinfo.image_width = bm.width(); 1.1171 + cinfo.image_height = bm.height(); 1.1172 + cinfo.input_components = 3; 1.1173 +#ifdef WE_CONVERT_TO_YUV 1.1174 + cinfo.in_color_space = JCS_YCbCr; 1.1175 +#else 1.1176 + cinfo.in_color_space = JCS_RGB; 1.1177 +#endif 1.1178 + cinfo.input_gamma = 1; 1.1179 + 1.1180 + jpeg_set_defaults(&cinfo); 1.1181 + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); 1.1182 +#ifdef DCT_IFAST_SUPPORTED 1.1183 + cinfo.dct_method = JDCT_IFAST; 1.1184 +#endif 1.1185 + 1.1186 + jpeg_start_compress(&cinfo, TRUE); 1.1187 + 1.1188 + const int width = bm.width(); 1.1189 + uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3); 1.1190 + 1.1191 + const SkPMColor* colors = ctLocker.lockColors(bm); 1.1192 + const void* srcRow = bm.getPixels(); 1.1193 + 1.1194 + while (cinfo.next_scanline < cinfo.image_height) { 1.1195 + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ 1.1196 + 1.1197 + writer(oneRowP, srcRow, width, colors); 1.1198 + row_pointer[0] = oneRowP; 1.1199 + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); 1.1200 + srcRow = (const void*)((const char*)srcRow + bm.rowBytes()); 1.1201 + } 1.1202 + 1.1203 + jpeg_finish_compress(&cinfo); 1.1204 + jpeg_destroy_compress(&cinfo); 1.1205 + 1.1206 + return true; 1.1207 + } 1.1208 +}; 1.1209 + 1.1210 +/////////////////////////////////////////////////////////////////////////////// 1.1211 +DEFINE_DECODER_CREATOR(JPEGImageDecoder); 1.1212 +DEFINE_ENCODER_CREATOR(JPEGImageEncoder); 1.1213 +/////////////////////////////////////////////////////////////////////////////// 1.1214 + 1.1215 +static bool is_jpeg(SkStreamRewindable* stream) { 1.1216 + static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF }; 1.1217 + static const size_t HEADER_SIZE = sizeof(gHeader); 1.1218 + 1.1219 + char buffer[HEADER_SIZE]; 1.1220 + size_t len = stream->read(buffer, HEADER_SIZE); 1.1221 + 1.1222 + if (len != HEADER_SIZE) { 1.1223 + return false; // can't read enough 1.1224 + } 1.1225 + if (memcmp(buffer, gHeader, HEADER_SIZE)) { 1.1226 + return false; 1.1227 + } 1.1228 + return true; 1.1229 +} 1.1230 + 1.1231 + 1.1232 +static SkImageDecoder* sk_libjpeg_dfactory(SkStreamRewindable* stream) { 1.1233 + if (is_jpeg(stream)) { 1.1234 + return SkNEW(SkJPEGImageDecoder); 1.1235 + } 1.1236 + return NULL; 1.1237 +} 1.1238 + 1.1239 +static SkImageDecoder::Format get_format_jpeg(SkStreamRewindable* stream) { 1.1240 + if (is_jpeg(stream)) { 1.1241 + return SkImageDecoder::kJPEG_Format; 1.1242 + } 1.1243 + return SkImageDecoder::kUnknown_Format; 1.1244 +} 1.1245 + 1.1246 +static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { 1.1247 + return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; 1.1248 +} 1.1249 + 1.1250 +static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); 1.1251 +static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); 1.1252 +static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory);