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