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