gfx/skia/trunk/src/images/SkImageDecoder_libjpeg.cpp

changeset 0
6474c204b198
     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);

mercurial