Home | History | Annotate | Download | only in images
      1 
      2 /*
      3  * Copyright 2007 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #include "SkImageDecoder.h"
     11 #include "SkImageEncoder.h"
     12 #include "SkJpegUtility.h"
     13 #include "SkColorPriv.h"
     14 #include "SkDither.h"
     15 #include "SkScaledBitmapSampler.h"
     16 #include "SkStream.h"
     17 #include "SkTemplates.h"
     18 #include "SkUtils.h"
     19 #include "SkRect.h"
     20 #include "SkCanvas.h"
     21 
     22 #include <stdio.h>
     23 extern "C" {
     24     #include "jpeglib.h"
     25     #include "jerror.h"
     26 }
     27 
     28 #ifdef SK_BUILD_FOR_ANDROID
     29 #include <cutils/properties.h>
     30 
     31 // Key to lookup the size of memory buffer set in system property
     32 static const char KEY_MEM_CAP[] = "ro.media.dec.jpeg.memcap";
     33 #endif
     34 
     35 // this enables timing code to report milliseconds for an encode
     36 //#define TIME_ENCODE
     37 //#define TIME_DECODE
     38 
     39 // this enables our rgb->yuv code, which is faster than libjpeg on ARM
     40 // disable for the moment, as we have some glitches when width != multiple of 4
     41 #define WE_CONVERT_TO_YUV
     42 
     43 //////////////////////////////////////////////////////////////////////////
     44 //////////////////////////////////////////////////////////////////////////
     45 
     46 class SkJPEGImageIndex {
     47 public:
     48     SkJPEGImageIndex() {}
     49     virtual ~SkJPEGImageIndex() {
     50         jpeg_destroy_huffman_index(index);
     51         jpeg_finish_decompress(cinfo);
     52         jpeg_destroy_decompress(cinfo);
     53         delete cinfo->src;
     54         free(cinfo);
     55     }
     56     jpeg_decompress_struct *cinfo;
     57     huffman_index *index;
     58 };
     59 
     60 
     61 class SkJPEGImageDecoder : public SkImageDecoder {
     62 public:
     63     SkJPEGImageDecoder() {
     64         index = NULL;
     65     }
     66     ~SkJPEGImageDecoder() {
     67         if (index)
     68             delete index;
     69     }
     70     virtual Format getFormat() const {
     71         return kJPEG_Format;
     72     }
     73 protected:
     74     virtual bool onBuildTileIndex(SkStream *stream,
     75                                 int *width, int *height);
     76     virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect rect);
     77     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
     78 private:
     79     SkJPEGImageIndex *index;
     80     int imageWidth;
     81     int imageHeight;
     82 };
     83 
     84 //////////////////////////////////////////////////////////////////////////
     85 
     86 #include "SkTime.h"
     87 
     88 class AutoTimeMillis {
     89 public:
     90     AutoTimeMillis(const char label[]) : fLabel(label) {
     91         if (!fLabel) {
     92             fLabel = "";
     93         }
     94         fNow = SkTime::GetMSecs();
     95     }
     96     ~AutoTimeMillis() {
     97         SkDebugf("---- Time (ms): %s %d\n", fLabel, SkTime::GetMSecs() - fNow);
     98     }
     99 private:
    100     const char* fLabel;
    101     SkMSec      fNow;
    102 };
    103 
    104 /* Automatically clean up after throwing an exception */
    105 class JPEGAutoClean {
    106 public:
    107     JPEGAutoClean(): cinfo_ptr(NULL) {}
    108     ~JPEGAutoClean() {
    109         if (cinfo_ptr) {
    110             jpeg_destroy_decompress(cinfo_ptr);
    111         }
    112     }
    113     void set(jpeg_decompress_struct* info) {
    114         cinfo_ptr = info;
    115     }
    116 private:
    117     jpeg_decompress_struct* cinfo_ptr;
    118 };
    119 
    120 #ifdef SK_BUILD_FOR_ANDROID
    121 /* Check if the memory cap property is set.
    122    If so, use the memory size for jpeg decode.
    123 */
    124 static void overwrite_mem_buffer_size(j_decompress_ptr cinfo) {
    125 #ifdef ANDROID_LARGE_MEMORY_DEVICE
    126     cinfo->mem->max_memory_to_use = 30 * 1024 * 1024;
    127 #else
    128     cinfo->mem->max_memory_to_use = 5 * 1024 * 1024;
    129 #endif
    130 }
    131 #endif
    132 
    133 
    134 ///////////////////////////////////////////////////////////////////////////////
    135 
    136 /*  If we need to better match the request, we might examine the image and
    137      output dimensions, and determine if the downsampling jpeg provided is
    138      not sufficient. If so, we can recompute a modified sampleSize value to
    139      make up the difference.
    140 
    141      To skip this additional scaling, just set sampleSize = 1; below.
    142  */
    143 static int recompute_sampleSize(int sampleSize,
    144                                 const jpeg_decompress_struct& cinfo) {
    145     return sampleSize * cinfo.output_width / cinfo.image_width;
    146 }
    147 
    148 static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) {
    149     /* These are initialized to 0, so if they have non-zero values, we assume
    150        they are "valid" (i.e. have been computed by libjpeg)
    151      */
    152     return cinfo.output_width != 0 && cinfo.output_height != 0;
    153 }
    154 
    155 static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer,
    156                           int count) {
    157     for (int i = 0; i < count; i++) {
    158         JSAMPLE* rowptr = (JSAMPLE*)buffer;
    159         int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1);
    160         if (row_count != 1) {
    161             return false;
    162         }
    163     }
    164     return true;
    165 }
    166 
    167 static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo,
    168                           huffman_index *index, void* buffer,
    169                           int count) {
    170     for (int i = 0; i < count; i++) {
    171         JSAMPLE* rowptr = (JSAMPLE*)buffer;
    172         int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr);
    173         if (row_count != 1) {
    174             return false;
    175         }
    176     }
    177     return true;
    178 }
    179 
    180 // This guy exists just to aid in debugging, as it allows debuggers to just
    181 // set a break-point in one place to see all error exists.
    182 static bool return_false(const jpeg_decompress_struct& cinfo,
    183                          const SkBitmap& bm, const char msg[]) {
    184 #ifdef SK_DEBUG
    185     SkDebugf("libjpeg error %d <%s> from %s [%d %d]", cinfo.err->msg_code,
    186              cinfo.err->jpeg_message_table[cinfo.err->msg_code], msg,
    187              bm.width(), bm.height());
    188 #endif
    189     return false;   // must always return false
    190 }
    191 
    192 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
    193 #ifdef TIME_DECODE
    194     AutoTimeMillis atm("JPEG Decode");
    195 #endif
    196 
    197     SkAutoMalloc  srcStorage;
    198     JPEGAutoClean autoClean;
    199 
    200     jpeg_decompress_struct  cinfo;
    201     skjpeg_error_mgr        sk_err;
    202     skjpeg_source_mgr       sk_stream(stream, this, false);
    203 
    204     cinfo.err = jpeg_std_error(&sk_err);
    205     sk_err.error_exit = skjpeg_error_exit;
    206 
    207     // All objects need to be instantiated before this setjmp call so that
    208     // they will be cleaned up properly if an error occurs.
    209     if (setjmp(sk_err.fJmpBuf)) {
    210         return return_false(cinfo, *bm, "setjmp");
    211     }
    212 
    213     jpeg_create_decompress(&cinfo);
    214     autoClean.set(&cinfo);
    215 
    216 #ifdef SK_BUILD_FOR_ANDROID
    217     overwrite_mem_buffer_size(&cinfo);
    218 #endif
    219 
    220     //jpeg_stdio_src(&cinfo, file);
    221     cinfo.src = &sk_stream;
    222 
    223     int status = jpeg_read_header(&cinfo, true);
    224     if (status != JPEG_HEADER_OK) {
    225         return return_false(cinfo, *bm, "read_header");
    226     }
    227 
    228     /*  Try to fulfill the requested sampleSize. Since jpeg can do it (when it
    229         can) much faster that we, just use their num/denom api to approximate
    230         the size.
    231     */
    232     int sampleSize = this->getSampleSize();
    233 
    234     if (this->getPreferQualityOverSpeed()) {
    235         cinfo.dct_method = JDCT_ISLOW;
    236     } else {
    237         cinfo.dct_method = JDCT_IFAST;
    238     }
    239 
    240     cinfo.scale_num = 1;
    241     cinfo.scale_denom = sampleSize;
    242 
    243     /* this gives about 30% performance improvement. In theory it may
    244        reduce the visual quality, in practice I'm not seeing a difference
    245      */
    246     cinfo.do_fancy_upsampling = 0;
    247 
    248     /* this gives another few percents */
    249     cinfo.do_block_smoothing = 0;
    250 
    251     /* default format is RGB */
    252     cinfo.out_color_space = JCS_RGB;
    253 
    254     SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
    255     // only these make sense for jpegs
    256     if (config != SkBitmap::kARGB_8888_Config &&
    257         config != SkBitmap::kARGB_4444_Config &&
    258         config != SkBitmap::kRGB_565_Config) {
    259         config = SkBitmap::kARGB_8888_Config;
    260     }
    261 
    262 #ifdef ANDROID_RGB
    263     cinfo.dither_mode = JDITHER_NONE;
    264     if (config == SkBitmap::kARGB_8888_Config) {
    265         cinfo.out_color_space = JCS_RGBA_8888;
    266     } else if (config == SkBitmap::kRGB_565_Config) {
    267         cinfo.out_color_space = JCS_RGB_565;
    268         if (this->getDitherImage()) {
    269             cinfo.dither_mode = JDITHER_ORDERED;
    270         }
    271     }
    272 #endif
    273 
    274     if (sampleSize == 1 && mode == SkImageDecoder::kDecodeBounds_Mode) {
    275         bm->setConfig(config, cinfo.image_width, cinfo.image_height);
    276         bm->setIsOpaque(true);
    277         return true;
    278     }
    279 
    280     /*  image_width and image_height are the original dimensions, available
    281         after jpeg_read_header(). To see the scaled dimensions, we have to call
    282         jpeg_start_decompress(), and then read output_width and output_height.
    283     */
    284     if (!jpeg_start_decompress(&cinfo)) {
    285         /*  If we failed here, we may still have enough information to return
    286             to the caller if they just wanted (subsampled bounds). If sampleSize
    287             was 1, then we would have already returned. Thus we just check if
    288             we're in kDecodeBounds_Mode, and that we have valid output sizes.
    289 
    290             One reason to fail here is that we have insufficient stream data
    291             to complete the setup. However, output dimensions seem to get
    292             computed very early, which is why this special check can pay off.
    293          */
    294         if (SkImageDecoder::kDecodeBounds_Mode == mode &&
    295                 valid_output_dimensions(cinfo)) {
    296             SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
    297                                        recompute_sampleSize(sampleSize, cinfo));
    298             bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight());
    299             bm->setIsOpaque(true);
    300             return true;
    301         } else {
    302             return return_false(cinfo, *bm, "start_decompress");
    303         }
    304     }
    305     sampleSize = recompute_sampleSize(sampleSize, cinfo);
    306 
    307     // should we allow the Chooser (if present) to pick a config for us???
    308     if (!this->chooseFromOneChoice(config, cinfo.output_width,
    309                                    cinfo.output_height)) {
    310         return return_false(cinfo, *bm, "chooseFromOneChoice");
    311     }
    312 
    313 #ifdef ANDROID_RGB
    314     /* short-circuit the SkScaledBitmapSampler when possible, as this gives
    315        a significant performance boost.
    316     */
    317     if (sampleSize == 1 &&
    318         ((config == SkBitmap::kARGB_8888_Config &&
    319                 cinfo.out_color_space == JCS_RGBA_8888) ||
    320         (config == SkBitmap::kRGB_565_Config &&
    321                 cinfo.out_color_space == JCS_RGB_565)))
    322     {
    323         bm->lockPixels();
    324         JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
    325         bm->unlockPixels();
    326         bool reuseBitmap = (rowptr != NULL);
    327         if (reuseBitmap && ((int) cinfo.output_width != bm->width() ||
    328                 (int) cinfo.output_height != bm->height())) {
    329             // Dimensions must match
    330             return false;
    331         }
    332 
    333         if (!reuseBitmap) {
    334             bm->setConfig(config, cinfo.output_width, cinfo.output_height);
    335             bm->setIsOpaque(true);
    336             if (SkImageDecoder::kDecodeBounds_Mode == mode) {
    337                 return true;
    338             }
    339             if (!this->allocPixelRef(bm, NULL)) {
    340                 return return_false(cinfo, *bm, "allocPixelRef");
    341             }
    342         } else if (SkImageDecoder::kDecodeBounds_Mode == mode) {
    343             return true;
    344         }
    345         SkAutoLockPixels alp(*bm);
    346         rowptr = (JSAMPLE*)bm->getPixels();
    347         INT32 const bpr =  bm->rowBytes();
    348 
    349         while (cinfo.output_scanline < cinfo.output_height) {
    350             int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
    351             // if row_count == 0, then we didn't get a scanline, so abort.
    352             // if we supported partial images, we might return true in this case
    353             if (0 == row_count) {
    354                 return return_false(cinfo, *bm, "read_scanlines");
    355             }
    356             if (this->shouldCancelDecode()) {
    357                 return return_false(cinfo, *bm, "shouldCancelDecode");
    358             }
    359             rowptr += bpr;
    360         }
    361         if (reuseBitmap) {
    362             bm->notifyPixelsChanged();
    363         }
    364         jpeg_finish_decompress(&cinfo);
    365         return true;
    366     }
    367 #endif
    368 
    369     // check for supported formats
    370     SkScaledBitmapSampler::SrcConfig sc;
    371     if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
    372         sc = SkScaledBitmapSampler::kRGB;
    373 #ifdef ANDROID_RGB
    374     } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
    375         sc = SkScaledBitmapSampler::kRGBX;
    376     } else if (JCS_RGB_565 == cinfo.out_color_space) {
    377         sc = SkScaledBitmapSampler::kRGB_565;
    378 #endif
    379     } else if (1 == cinfo.out_color_components &&
    380                JCS_GRAYSCALE == cinfo.out_color_space) {
    381         sc = SkScaledBitmapSampler::kGray;
    382     } else {
    383         return return_false(cinfo, *bm, "jpeg colorspace");
    384     }
    385 
    386     SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height,
    387                                   sampleSize);
    388 
    389     bm->lockPixels();
    390     JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
    391     bool reuseBitmap = (rowptr != NULL);
    392     bm->unlockPixels();
    393     if (reuseBitmap && (sampler.scaledWidth() != bm->width() ||
    394             sampler.scaledHeight() != bm->height())) {
    395         // Dimensions must match
    396         return false;
    397     }
    398 
    399     if (!reuseBitmap) {
    400         bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
    401         // jpegs are always opaque (i.e. have no per-pixel alpha)
    402         bm->setIsOpaque(true);
    403 
    404         if (SkImageDecoder::kDecodeBounds_Mode == mode) {
    405             return true;
    406         }
    407         if (!this->allocPixelRef(bm, NULL)) {
    408             return return_false(cinfo, *bm, "allocPixelRef");
    409         }
    410     } else if (SkImageDecoder::kDecodeBounds_Mode == mode) {
    411         return true;
    412     }
    413 
    414     SkAutoLockPixels alp(*bm);
    415     if (!sampler.begin(bm, sc, this->getDitherImage())) {
    416         return return_false(cinfo, *bm, "sampler.begin");
    417     }
    418 
    419     uint8_t* srcRow = (uint8_t*)srcStorage.reset(cinfo.output_width * 4);
    420 
    421     //  Possibly skip initial rows [sampler.srcY0]
    422     if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
    423         return return_false(cinfo, *bm, "skip rows");
    424     }
    425 
    426     // now loop through scanlines until y == bm->height() - 1
    427     for (int y = 0;; y++) {
    428         JSAMPLE* rowptr = (JSAMPLE*)srcRow;
    429         int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
    430         if (0 == row_count) {
    431             return return_false(cinfo, *bm, "read_scanlines");
    432         }
    433         if (this->shouldCancelDecode()) {
    434             return return_false(cinfo, *bm, "shouldCancelDecode");
    435         }
    436 
    437         sampler.next(srcRow);
    438         if (bm->height() - 1 == y) {
    439             // we're done
    440             break;
    441         }
    442 
    443         if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
    444             return return_false(cinfo, *bm, "skip rows");
    445         }
    446     }
    447 
    448     // we formally skip the rest, so we don't get a complaint from libjpeg
    449     if (!skip_src_rows(&cinfo, srcRow,
    450                        cinfo.output_height - cinfo.output_scanline)) {
    451         return return_false(cinfo, *bm, "skip rows");
    452     }
    453     if (reuseBitmap) {
    454         bm->notifyPixelsChanged();
    455     }
    456     jpeg_finish_decompress(&cinfo);
    457 
    458 //    SkDebugf("------------------- bm2 size %d [%d %d] %d\n", bm->getSize(), bm->width(), bm->height(), bm->config());
    459     return true;
    460 }
    461 
    462 bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream,
    463                                         int *width, int *height) {
    464     SkAutoMalloc  srcStorage;
    465     SkJPEGImageIndex *index = new SkJPEGImageIndex;
    466 
    467     jpeg_decompress_struct  *cinfo = (jpeg_decompress_struct*)
    468                                         malloc(sizeof(jpeg_decompress_struct));
    469     skjpeg_error_mgr        sk_err;
    470     skjpeg_source_mgr       *sk_stream =
    471         new skjpeg_source_mgr(stream, this, true);
    472     if (cinfo == NULL || sk_stream == NULL) {
    473         return false;
    474     }
    475 
    476     cinfo->err = jpeg_std_error(&sk_err);
    477     sk_err.error_exit = skjpeg_error_exit;
    478 
    479     // All objects need to be instantiated before this setjmp call so that
    480     // they will be cleaned up properly if an error occurs.
    481     if (setjmp(sk_err.fJmpBuf)) {
    482         return false;
    483     }
    484 
    485     jpeg_create_decompress(cinfo);
    486     cinfo->do_fancy_upsampling = 0;
    487     cinfo->do_block_smoothing = 0;
    488 
    489 #ifdef SK_BUILD_FOR_ANDROID
    490     overwrite_mem_buffer_size(cinfo);
    491 #endif
    492 
    493     cinfo->src = sk_stream;
    494     int status = jpeg_read_header(cinfo, true);
    495     if (status != JPEG_HEADER_OK) {
    496         return false;
    497     }
    498     index->index = (huffman_index*)malloc(sizeof(huffman_index));
    499     jpeg_create_huffman_index(cinfo, index->index);
    500 
    501     cinfo->scale_num = 1;
    502     cinfo->scale_denom = 1;
    503     if (!jpeg_build_huffman_index(cinfo, index->index)) {
    504         return false;
    505     }
    506     if (fReporter)
    507         fReporter->reportMemory(index->index->mem_used);
    508     jpeg_destroy_decompress(cinfo);
    509 
    510 
    511     // Init decoder to image decode mode
    512     jpeg_create_decompress(cinfo);
    513 
    514 #ifdef SK_BUILD_FOR_ANDROID
    515     overwrite_mem_buffer_size(cinfo);
    516 #endif
    517 
    518     cinfo->src = sk_stream;
    519     status = jpeg_read_header(cinfo,true);
    520     if (status != JPEG_HEADER_OK) {
    521         return false;
    522     }
    523     cinfo->out_color_space = JCS_RGBA_8888;
    524     cinfo->do_fancy_upsampling = 0;
    525     cinfo->do_block_smoothing = 0;
    526     //jpeg_start_decompress(cinfo);
    527     jpeg_start_tile_decompress(cinfo);
    528 
    529     cinfo->scale_num = 1;
    530     index->cinfo = cinfo;
    531     *height = cinfo->output_height;
    532     *width = cinfo->output_width;
    533     this->imageWidth = *width;
    534     this->imageHeight = *height;
    535     this->index = index;
    536     return true;
    537 }
    538 
    539 bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) {
    540     if (index == NULL) {
    541         return false;
    542     }
    543     jpeg_decompress_struct *cinfo = index->cinfo;
    544 
    545     SkIRect rect = SkIRect::MakeWH(this->imageWidth, this->imageHeight);
    546     if (!rect.intersect(region)) {
    547         // If the requested region is entirely outsides the image, just
    548         // returns false
    549         return false;
    550     }
    551     SkAutoMalloc  srcStorage;
    552     skjpeg_error_mgr        sk_err;
    553     cinfo->err = jpeg_std_error(&sk_err);
    554     sk_err.error_exit = skjpeg_error_exit;
    555     if (setjmp(sk_err.fJmpBuf)) {
    556         return false;
    557     }
    558     int requestedSampleSize = this->getSampleSize();
    559     cinfo->scale_denom = requestedSampleSize;
    560 
    561     if (this->getPreferQualityOverSpeed()) {
    562         cinfo->dct_method = JDCT_ISLOW;
    563     } else {
    564         cinfo->dct_method = JDCT_IFAST;
    565     }
    566 
    567     SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
    568     if (config != SkBitmap::kARGB_8888_Config &&
    569         config != SkBitmap::kARGB_4444_Config &&
    570         config != SkBitmap::kRGB_565_Config) {
    571         config = SkBitmap::kARGB_8888_Config;
    572     }
    573 
    574     /* default format is RGB */
    575     cinfo->out_color_space = JCS_RGB;
    576 
    577 #ifdef ANDROID_RGB
    578     cinfo->dither_mode = JDITHER_NONE;
    579     if (config == SkBitmap::kARGB_8888_Config) {
    580         cinfo->out_color_space = JCS_RGBA_8888;
    581     } else if (config == SkBitmap::kRGB_565_Config) {
    582         cinfo->out_color_space = JCS_RGB_565;
    583         if (this->getDitherImage()) {
    584             cinfo->dither_mode = JDITHER_ORDERED;
    585         }
    586     }
    587 #endif
    588     int startX = rect.fLeft;
    589     int startY = rect.fTop;
    590     int width = rect.width();
    591     int height = rect.height();
    592 
    593     jpeg_init_read_tile_scanline(cinfo, index->index,
    594                                  &startX, &startY, &width, &height);
    595     int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
    596     int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size);
    597 
    598     SkBitmap *bitmap = new SkBitmap;
    599     SkAutoTDelete<SkBitmap> adb(bitmap);
    600 
    601 #ifdef ANDROID_RGB
    602     /* short-circuit the SkScaledBitmapSampler when possible, as this gives
    603        a significant performance boost.
    604     */
    605     if (skiaSampleSize == 1 &&
    606         ((config == SkBitmap::kARGB_8888_Config &&
    607                 cinfo->out_color_space == JCS_RGBA_8888) ||
    608         (config == SkBitmap::kRGB_565_Config &&
    609                 cinfo->out_color_space == JCS_RGB_565)))
    610     {
    611         bitmap->setConfig(config, cinfo->output_width, height);
    612         bitmap->setIsOpaque(true);
    613 
    614         // Check ahead of time if the swap(dest, src) is possible or not.
    615         // If yes, then we will stick to AllocPixelRef since it's cheaper
    616         // with the swap happening. If no, then we will use alloc to allocate
    617         // pixels to prevent garbage collection.
    618         //
    619         // Not using a recycled-bitmap and the output rect is same as the
    620         // decoded region.
    621         int w = rect.width() / actualSampleSize;
    622         int h = rect.height() / actualSampleSize;
    623         bool swapOnly = (rect == region) && bm->isNull() &&
    624                         (w == bitmap->width()) && (h == bitmap->height()) &&
    625                         ((startX - rect.x()) / actualSampleSize == 0) &&
    626                         ((startY - rect.y()) / actualSampleSize == 0);
    627         if (swapOnly) {
    628             if (!this->allocPixelRef(bitmap, NULL)) {
    629                 return return_false(*cinfo, *bitmap, "allocPixelRef");
    630             }
    631         } else {
    632             if (!bitmap->allocPixels()) {
    633                 return return_false(*cinfo, *bitmap, "allocPixels");
    634             }
    635         }
    636 
    637         SkAutoLockPixels alp(*bitmap);
    638         JSAMPLE* rowptr = (JSAMPLE*)bitmap->getPixels();
    639         INT32 const bpr = bitmap->rowBytes();
    640         int row_total_count = 0;
    641 
    642         while (row_total_count < height) {
    643             int row_count = jpeg_read_tile_scanline(cinfo,
    644                     index->index, &rowptr);
    645             // if row_count == 0, then we didn't get a scanline, so abort.
    646             // if we supported partial images, we might return true in this case
    647             if (0 == row_count) {
    648                 return return_false(*cinfo, *bitmap, "read_scanlines");
    649             }
    650             if (this->shouldCancelDecode()) {
    651                 return return_false(*cinfo, *bitmap, "shouldCancelDecode");
    652             }
    653             row_total_count += row_count;
    654             rowptr += bpr;
    655         }
    656 
    657         if (swapOnly) {
    658             bm->swap(*bitmap);
    659         } else {
    660             cropBitmap(bm, bitmap, actualSampleSize, region.x(), region.y(),
    661                        region.width(), region.height(), startX, startY);
    662         }
    663         return true;
    664     }
    665 #endif
    666     // check for supported formats
    667     SkScaledBitmapSampler::SrcConfig sc;
    668     if (3 == cinfo->out_color_components && JCS_RGB == cinfo->out_color_space) {
    669         sc = SkScaledBitmapSampler::kRGB;
    670 #ifdef ANDROID_RGB
    671     } else if (JCS_RGBA_8888 == cinfo->out_color_space) {
    672         sc = SkScaledBitmapSampler::kRGBX;
    673     } else if (JCS_RGB_565 == cinfo->out_color_space) {
    674         sc = SkScaledBitmapSampler::kRGB_565;
    675 #endif
    676     } else if (1 == cinfo->out_color_components &&
    677                JCS_GRAYSCALE == cinfo->out_color_space) {
    678         sc = SkScaledBitmapSampler::kGray;
    679     } else {
    680         return return_false(*cinfo, *bm, "jpeg colorspace");
    681     }
    682 
    683     SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
    684 
    685     bitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
    686     bitmap->setIsOpaque(true);
    687 
    688     // Check ahead of time if the swap(dest, src) is possible or not.
    689     // If yes, then we will stick to AllocPixelRef since it's cheaper with the
    690     // swap happening. If no, then we will use alloc to allocate pixels to
    691     // prevent garbage collection.
    692     int w = rect.width() / actualSampleSize;
    693     int h = rect.height() / actualSampleSize;
    694     bool swapOnly = (rect == region) && bm->isNull() &&
    695                     (w == bitmap->width()) && (h == bitmap->height()) &&
    696                     ((startX - rect.x()) / actualSampleSize == 0) &&
    697                     ((startY - rect.y()) / actualSampleSize == 0);
    698     if (swapOnly) {
    699         if (!this->allocPixelRef(bitmap, NULL)) {
    700             return return_false(*cinfo, *bitmap, "allocPixelRef");
    701         }
    702     } else {
    703         if (!bitmap->allocPixels()) {
    704             return return_false(*cinfo, *bitmap, "allocPixels");
    705         }
    706     }
    707 
    708     SkAutoLockPixels alp(*bitmap);
    709     if (!sampler.begin(bitmap, sc, this->getDitherImage())) {
    710         return return_false(*cinfo, *bitmap, "sampler.begin");
    711     }
    712 
    713     uint8_t* srcRow = (uint8_t*)srcStorage.reset(width * 4);
    714 
    715     //  Possibly skip initial rows [sampler.srcY0]
    716     if (!skip_src_rows_tile(cinfo, index->index, srcRow, sampler.srcY0())) {
    717         return return_false(*cinfo, *bitmap, "skip rows");
    718     }
    719 
    720     // now loop through scanlines until y == bitmap->height() - 1
    721     for (int y = 0;; y++) {
    722         JSAMPLE* rowptr = (JSAMPLE*)srcRow;
    723         int row_count = jpeg_read_tile_scanline(cinfo, index->index, &rowptr);
    724         if (0 == row_count) {
    725             return return_false(*cinfo, *bitmap, "read_scanlines");
    726         }
    727         if (this->shouldCancelDecode()) {
    728             return return_false(*cinfo, *bitmap, "shouldCancelDecode");
    729         }
    730 
    731         sampler.next(srcRow);
    732         if (bitmap->height() - 1 == y) {
    733             // we're done
    734             break;
    735         }
    736 
    737         if (!skip_src_rows_tile(cinfo, index->index, srcRow,
    738                                 sampler.srcDY() - 1)) {
    739             return return_false(*cinfo, *bitmap, "skip rows");
    740         }
    741     }
    742     if (swapOnly) {
    743         bm->swap(*bitmap);
    744     } else {
    745         cropBitmap(bm, bitmap, actualSampleSize, region.x(), region.y(),
    746                    region.width(), region.height(), startX, startY);
    747     }
    748     return true;
    749 }
    750 
    751 ///////////////////////////////////////////////////////////////////////////////
    752 
    753 #include "SkColorPriv.h"
    754 
    755 // taken from jcolor.c in libjpeg
    756 #if 0   // 16bit - precise but slow
    757     #define CYR     19595   // 0.299
    758     #define CYG     38470   // 0.587
    759     #define CYB      7471   // 0.114
    760 
    761     #define CUR    -11059   // -0.16874
    762     #define CUG    -21709   // -0.33126
    763     #define CUB     32768   // 0.5
    764 
    765     #define CVR     32768   // 0.5
    766     #define CVG    -27439   // -0.41869
    767     #define CVB     -5329   // -0.08131
    768 
    769     #define CSHIFT  16
    770 #else      // 8bit - fast, slightly less precise
    771     #define CYR     77    // 0.299
    772     #define CYG     150    // 0.587
    773     #define CYB      29    // 0.114
    774 
    775     #define CUR     -43    // -0.16874
    776     #define CUG    -85    // -0.33126
    777     #define CUB     128    // 0.5
    778 
    779     #define CVR      128   // 0.5
    780     #define CVG     -107   // -0.41869
    781     #define CVB      -21   // -0.08131
    782 
    783     #define CSHIFT  8
    784 #endif
    785 
    786 static void rgb2yuv_32(uint8_t dst[], SkPMColor c) {
    787     int r = SkGetPackedR32(c);
    788     int g = SkGetPackedG32(c);
    789     int b = SkGetPackedB32(c);
    790 
    791     int  y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT;
    792     int  u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT;
    793     int  v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT;
    794 
    795     dst[0] = SkToU8(y);
    796     dst[1] = SkToU8(u + 128);
    797     dst[2] = SkToU8(v + 128);
    798 }
    799 
    800 static void rgb2yuv_4444(uint8_t dst[], U16CPU c) {
    801     int r = SkGetPackedR4444(c);
    802     int g = SkGetPackedG4444(c);
    803     int b = SkGetPackedB4444(c);
    804 
    805     int  y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4);
    806     int  u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4);
    807     int  v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4);
    808 
    809     dst[0] = SkToU8(y);
    810     dst[1] = SkToU8(u + 128);
    811     dst[2] = SkToU8(v + 128);
    812 }
    813 
    814 static void rgb2yuv_16(uint8_t dst[], U16CPU c) {
    815     int r = SkGetPackedR16(c);
    816     int g = SkGetPackedG16(c);
    817     int b = SkGetPackedB16(c);
    818 
    819     int  y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2);
    820     int  u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2);
    821     int  v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2);
    822 
    823     dst[0] = SkToU8(y);
    824     dst[1] = SkToU8(u + 128);
    825     dst[2] = SkToU8(v + 128);
    826 }
    827 
    828 ///////////////////////////////////////////////////////////////////////////////
    829 
    830 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
    831                               const void* SK_RESTRICT src, int width,
    832                               const SkPMColor* SK_RESTRICT ctable);
    833 
    834 static void Write_32_YUV(uint8_t* SK_RESTRICT dst,
    835                          const void* SK_RESTRICT srcRow, int width,
    836                          const SkPMColor*) {
    837     const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
    838     while (--width >= 0) {
    839 #ifdef WE_CONVERT_TO_YUV
    840         rgb2yuv_32(dst, *src++);
    841 #else
    842         uint32_t c = *src++;
    843         dst[0] = SkGetPackedR32(c);
    844         dst[1] = SkGetPackedG32(c);
    845         dst[2] = SkGetPackedB32(c);
    846 #endif
    847         dst += 3;
    848     }
    849 }
    850 
    851 static void Write_4444_YUV(uint8_t* SK_RESTRICT dst,
    852                            const void* SK_RESTRICT srcRow, int width,
    853                            const SkPMColor*) {
    854     const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
    855     while (--width >= 0) {
    856 #ifdef WE_CONVERT_TO_YUV
    857         rgb2yuv_4444(dst, *src++);
    858 #else
    859         SkPMColor16 c = *src++;
    860         dst[0] = SkPacked4444ToR32(c);
    861         dst[1] = SkPacked4444ToG32(c);
    862         dst[2] = SkPacked4444ToB32(c);
    863 #endif
    864         dst += 3;
    865     }
    866 }
    867 
    868 static void Write_16_YUV(uint8_t* SK_RESTRICT dst,
    869                          const void* SK_RESTRICT srcRow, int width,
    870                          const SkPMColor*) {
    871     const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
    872     while (--width >= 0) {
    873 #ifdef WE_CONVERT_TO_YUV
    874         rgb2yuv_16(dst, *src++);
    875 #else
    876         uint16_t c = *src++;
    877         dst[0] = SkPacked16ToR32(c);
    878         dst[1] = SkPacked16ToG32(c);
    879         dst[2] = SkPacked16ToB32(c);
    880 #endif
    881         dst += 3;
    882     }
    883 }
    884 
    885 static void Write_Index_YUV(uint8_t* SK_RESTRICT dst,
    886                             const void* SK_RESTRICT srcRow, int width,
    887                             const SkPMColor* SK_RESTRICT ctable) {
    888     const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
    889     while (--width >= 0) {
    890 #ifdef WE_CONVERT_TO_YUV
    891         rgb2yuv_32(dst, ctable[*src++]);
    892 #else
    893         uint32_t c = ctable[*src++];
    894         dst[0] = SkGetPackedR32(c);
    895         dst[1] = SkGetPackedG32(c);
    896         dst[2] = SkGetPackedB32(c);
    897 #endif
    898         dst += 3;
    899     }
    900 }
    901 
    902 static WriteScanline ChooseWriter(const SkBitmap& bm) {
    903     switch (bm.config()) {
    904         case SkBitmap::kARGB_8888_Config:
    905             return Write_32_YUV;
    906         case SkBitmap::kRGB_565_Config:
    907             return Write_16_YUV;
    908         case SkBitmap::kARGB_4444_Config:
    909             return Write_4444_YUV;
    910         case SkBitmap::kIndex8_Config:
    911             return Write_Index_YUV;
    912         default:
    913             return NULL;
    914     }
    915 }
    916 
    917 class SkJPEGImageEncoder : public SkImageEncoder {
    918 protected:
    919     virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
    920 #ifdef TIME_ENCODE
    921         AutoTimeMillis atm("JPEG Encode");
    922 #endif
    923 
    924         const WriteScanline writer = ChooseWriter(bm);
    925         if (NULL == writer) {
    926             return false;
    927         }
    928 
    929         SkAutoLockPixels alp(bm);
    930         if (NULL == bm.getPixels()) {
    931             return false;
    932         }
    933 
    934         jpeg_compress_struct    cinfo;
    935         skjpeg_error_mgr        sk_err;
    936         skjpeg_destination_mgr  sk_wstream(stream);
    937 
    938         // allocate these before set call setjmp
    939         SkAutoMalloc    oneRow;
    940         SkAutoLockColors ctLocker;
    941 
    942         cinfo.err = jpeg_std_error(&sk_err);
    943         sk_err.error_exit = skjpeg_error_exit;
    944         if (setjmp(sk_err.fJmpBuf)) {
    945             return false;
    946         }
    947         jpeg_create_compress(&cinfo);
    948 
    949         cinfo.dest = &sk_wstream;
    950         cinfo.image_width = bm.width();
    951         cinfo.image_height = bm.height();
    952         cinfo.input_components = 3;
    953 #ifdef WE_CONVERT_TO_YUV
    954         cinfo.in_color_space = JCS_YCbCr;
    955 #else
    956         cinfo.in_color_space = JCS_RGB;
    957 #endif
    958         cinfo.input_gamma = 1;
    959 
    960         jpeg_set_defaults(&cinfo);
    961         jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
    962         cinfo.dct_method = JDCT_IFAST;
    963 
    964         jpeg_start_compress(&cinfo, TRUE);
    965 
    966         const int       width = bm.width();
    967         uint8_t*        oneRowP = (uint8_t*)oneRow.reset(width * 3);
    968 
    969         const SkPMColor* colors = ctLocker.lockColors(bm);
    970         const void*      srcRow = bm.getPixels();
    971 
    972         while (cinfo.next_scanline < cinfo.image_height) {
    973             JSAMPROW row_pointer[1];    /* pointer to JSAMPLE row[s] */
    974 
    975             writer(oneRowP, srcRow, width, colors);
    976             row_pointer[0] = oneRowP;
    977             (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
    978             srcRow = (const void*)((const char*)srcRow + bm.rowBytes());
    979         }
    980 
    981         jpeg_finish_compress(&cinfo);
    982         jpeg_destroy_compress(&cinfo);
    983 
    984         return true;
    985     }
    986 };
    987 
    988 ///////////////////////////////////////////////////////////////////////////////
    989 
    990 #include "SkTRegistry.h"
    991 
    992 static SkImageDecoder* DFactory(SkStream* stream) {
    993     static const char gHeader[] = { 0xFF, 0xD8, 0xFF };
    994     static const size_t HEADER_SIZE = sizeof(gHeader);
    995 
    996     char buffer[HEADER_SIZE];
    997     size_t len = stream->read(buffer, HEADER_SIZE);
    998 
    999     if (len != HEADER_SIZE) {
   1000         return NULL;   // can't read enough
   1001     }
   1002     if (memcmp(buffer, gHeader, HEADER_SIZE)) {
   1003         return NULL;
   1004     }
   1005     return SkNEW(SkJPEGImageDecoder);
   1006 }
   1007 
   1008 static SkImageEncoder* EFactory(SkImageEncoder::Type t) {
   1009     return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
   1010 }
   1011 
   1012 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory);
   1013 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory);
   1014