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>
23extern "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
32static 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
46class SkJPEGImageIndex {
47public:
48    SkJPEGImageIndex() {}
49    virtual ~SkJPEGImageIndex() {
50        jpeg_destroy_huffman_index(index);
51        delete cinfo->src;
52        jpeg_finish_decompress(cinfo);
53        jpeg_destroy_decompress(cinfo);
54        free(cinfo);
55    }
56    jpeg_decompress_struct *cinfo;
57    huffman_index *index;
58};
59
60
61class SkJPEGImageDecoder : public SkImageDecoder {
62public:
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    }
73protected:
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);
78private:
79    SkJPEGImageIndex *index;
80    int imageWidth;
81    int imageHeight;
82};
83
84//////////////////////////////////////////////////////////////////////////
85
86#include "SkTime.h"
87
88class AutoTimeMillis {
89public:
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    }
99private:
100    const char* fLabel;
101    SkMSec      fNow;
102};
103
104/* Automatically clean up after throwing an exception */
105class JPEGAutoClean {
106public:
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    }
116private:
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*/
124static 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 */
143static int recompute_sampleSize(int sampleSize,
144                                const jpeg_decompress_struct& cinfo) {
145    return sampleSize * cinfo.output_width / cinfo.image_width;
146}
147
148static 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
155static 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
167static 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.
182static 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
192bool 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
462bool 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
539bool 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
786static 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
800static 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
814static 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
830typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
831                              const void* SK_RESTRICT src, int width,
832                              const SkPMColor* SK_RESTRICT ctable);
833
834static 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
851static 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
868static 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
885static 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
902static 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
917class SkJPEGImageEncoder : public SkImageEncoder {
918protected:
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
992static 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
1008static SkImageEncoder* EFactory(SkImageEncoder::Type t) {
1009    return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
1010}
1011
1012static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory);
1013static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory);
1014