SkImageDecoder_libjpeg.cpp revision 58190644c30e1c4aa8e527f3503c58f841e0fcf3
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 onDecodeSubset(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]\n", 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    SrcDepth srcDepth = k32Bit_SrcDepth;
293    /* default format is RGB */
294    if (cinfo.jpeg_color_space == JCS_CMYK) {
295        // libjpeg cannot convert from CMYK to RGB - here we set up
296        // so libjpeg will give us CMYK samples back and we will
297        // later manually convert them to RGB
298        cinfo.out_color_space = JCS_CMYK;
299    } else if (cinfo.jpeg_color_space == JCS_GRAYSCALE) {
300        cinfo.out_color_space = JCS_GRAYSCALE;
301        srcDepth = k8BitGray_SrcDepth;
302    } else {
303        cinfo.out_color_space = JCS_RGB;
304    }
305
306    SkBitmap::Config config = this->getPrefConfig(srcDepth, false);
307    // only these make sense for jpegs
308    if (SkBitmap::kA8_Config == config) {
309        if (cinfo.jpeg_color_space != JCS_GRAYSCALE) {
310            // Converting from a non grayscale image to A8 is
311            // not currently supported.
312            config = SkBitmap::kARGB_8888_Config;
313            // Change the output from jpeg back to RGB.
314            cinfo.out_color_space = JCS_RGB;
315        }
316    } else if (config != SkBitmap::kARGB_8888_Config &&
317               config != SkBitmap::kARGB_4444_Config &&
318               config != SkBitmap::kRGB_565_Config) {
319        config = SkBitmap::kARGB_8888_Config;
320    }
321
322#ifdef ANDROID_RGB
323    cinfo.dither_mode = JDITHER_NONE;
324    if (SkBitmap::kARGB_8888_Config == config && JCS_CMYK != cinfo.out_color_space) {
325        cinfo.out_color_space = JCS_RGBA_8888;
326    } else if (SkBitmap::kRGB_565_Config == config && JCS_CMYK != cinfo.out_color_space) {
327        cinfo.out_color_space = JCS_RGB_565;
328        if (this->getDitherImage()) {
329            cinfo.dither_mode = JDITHER_ORDERED;
330        }
331    }
332#endif
333
334    if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) {
335        bm->setConfig(config, cinfo.image_width, cinfo.image_height);
336        bm->setIsOpaque(config != SkBitmap::kA8_Config);
337        return true;
338    }
339
340    /*  image_width and image_height are the original dimensions, available
341        after jpeg_read_header(). To see the scaled dimensions, we have to call
342        jpeg_start_decompress(), and then read output_width and output_height.
343    */
344    if (!jpeg_start_decompress(&cinfo)) {
345        /*  If we failed here, we may still have enough information to return
346            to the caller if they just wanted (subsampled bounds). If sampleSize
347            was 1, then we would have already returned. Thus we just check if
348            we're in kDecodeBounds_Mode, and that we have valid output sizes.
349
350            One reason to fail here is that we have insufficient stream data
351            to complete the setup. However, output dimensions seem to get
352            computed very early, which is why this special check can pay off.
353         */
354        if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) {
355            SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
356                                       recompute_sampleSize(sampleSize, cinfo));
357            bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight());
358            bm->setIsOpaque(config != SkBitmap::kA8_Config);
359            return true;
360        } else {
361            return return_false(cinfo, *bm, "start_decompress");
362        }
363    }
364    sampleSize = recompute_sampleSize(sampleSize, cinfo);
365
366    // should we allow the Chooser (if present) to pick a config for us???
367    if (!this->chooseFromOneChoice(config, cinfo.output_width, cinfo.output_height)) {
368        return return_false(cinfo, *bm, "chooseFromOneChoice");
369    }
370
371    SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize);
372    bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
373    bm->setIsOpaque(config != SkBitmap::kA8_Config);
374    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
375        return true;
376    }
377    if (!this->allocPixelRef(bm, NULL)) {
378        return return_false(cinfo, *bm, "allocPixelRef");
379    }
380
381    SkAutoLockPixels alp(*bm);
382
383#ifdef ANDROID_RGB
384    /* short-circuit the SkScaledBitmapSampler when possible, as this gives
385       a significant performance boost.
386    */
387    if (sampleSize == 1 &&
388        ((config == SkBitmap::kARGB_8888_Config &&
389                cinfo.out_color_space == JCS_RGBA_8888) ||
390        (config == SkBitmap::kRGB_565_Config &&
391                cinfo.out_color_space == JCS_RGB_565)))
392    {
393        JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
394        INT32 const bpr =  bm->rowBytes();
395
396        while (cinfo.output_scanline < cinfo.output_height) {
397            int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
398            // if row_count == 0, then we didn't get a scanline, so abort.
399            // if we supported partial images, we might return true in this case
400            if (0 == row_count) {
401                return return_false(cinfo, *bm, "read_scanlines");
402            }
403            if (this->shouldCancelDecode()) {
404                return return_false(cinfo, *bm, "shouldCancelDecode");
405            }
406            rowptr += bpr;
407        }
408        jpeg_finish_decompress(&cinfo);
409        return true;
410    }
411#endif
412
413    // check for supported formats
414    SkScaledBitmapSampler::SrcConfig sc;
415    if (JCS_CMYK == cinfo.out_color_space) {
416        // In this case we will manually convert the CMYK values to RGB
417        sc = SkScaledBitmapSampler::kRGBX;
418    } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
419        sc = SkScaledBitmapSampler::kRGB;
420#ifdef ANDROID_RGB
421    } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
422        sc = SkScaledBitmapSampler::kRGBX;
423    } else if (JCS_RGB_565 == cinfo.out_color_space) {
424        sc = SkScaledBitmapSampler::kRGB_565;
425#endif
426    } else if (1 == cinfo.out_color_components &&
427               JCS_GRAYSCALE == cinfo.out_color_space) {
428        sc = SkScaledBitmapSampler::kGray;
429    } else {
430        return return_false(cinfo, *bm, "jpeg colorspace");
431    }
432
433    if (!sampler.begin(bm, sc, this->getDitherImage())) {
434        return return_false(cinfo, *bm, "sampler.begin");
435    }
436
437    // The CMYK work-around relies on 4 components per pixel here
438    SkAutoMalloc srcStorage(cinfo.output_width * 4);
439    uint8_t* srcRow = (uint8_t*)srcStorage.get();
440
441    //  Possibly skip initial rows [sampler.srcY0]
442    if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
443        return return_false(cinfo, *bm, "skip rows");
444    }
445
446    // now loop through scanlines until y == bm->height() - 1
447    for (int y = 0;; y++) {
448        JSAMPLE* rowptr = (JSAMPLE*)srcRow;
449        int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
450        if (0 == row_count) {
451            return return_false(cinfo, *bm, "read_scanlines");
452        }
453        if (this->shouldCancelDecode()) {
454            return return_false(cinfo, *bm, "shouldCancelDecode");
455        }
456
457        if (JCS_CMYK == cinfo.out_color_space) {
458            convert_CMYK_to_RGB(srcRow, cinfo.output_width);
459        }
460
461        sampler.next(srcRow);
462        if (bm->height() - 1 == y) {
463            // we're done
464            break;
465        }
466
467        if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
468            return return_false(cinfo, *bm, "skip rows");
469        }
470    }
471
472    // we formally skip the rest, so we don't get a complaint from libjpeg
473    if (!skip_src_rows(&cinfo, srcRow,
474                       cinfo.output_height - cinfo.output_scanline)) {
475        return return_false(cinfo, *bm, "skip rows");
476    }
477    jpeg_finish_decompress(&cinfo);
478
479    return true;
480}
481
482#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
483bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *height) {
484
485    SkJPEGImageIndex* imageIndex = SkNEW_ARGS(SkJPEGImageIndex, (stream, this));
486    jpeg_decompress_struct* cinfo = imageIndex->cinfo();
487    huffman_index* huffmanIndex = imageIndex->huffmanIndex();
488
489    skjpeg_error_mgr sk_err;
490    cinfo->err = jpeg_std_error(&sk_err);
491    sk_err.error_exit = skjpeg_error_exit;
492
493    // All objects need to be instantiated before this setjmp call so that
494    // they will be cleaned up properly if an error occurs.
495    if (setjmp(sk_err.fJmpBuf)) {
496        return false;
497    }
498
499    // create the cinfo used to create/build the huffmanIndex
500    imageIndex->initializeInfo();
501    cinfo->do_fancy_upsampling = 0;
502    cinfo->do_block_smoothing = 0;
503
504    int status = jpeg_read_header(cinfo, true);
505    if (JPEG_HEADER_OK != status) {
506        SkDELETE(imageIndex);
507        return false;
508    }
509
510    jpeg_create_huffman_index(cinfo, huffmanIndex);
511    cinfo->scale_num = 1;
512    cinfo->scale_denom = 1;
513    if (!jpeg_build_huffman_index(cinfo, huffmanIndex)) {
514        SkDELETE(imageIndex);
515        return false;
516    }
517
518    // destroy the cinfo used to create/build the huffman index
519    jpeg_destroy_decompress(cinfo);
520
521    // Init decoder to image decode mode
522    imageIndex->initializeInfo();
523
524    status = jpeg_read_header(cinfo, true);
525    if (JPEG_HEADER_OK != status) {
526        SkDELETE(imageIndex);
527        return false;
528    }
529
530    cinfo->out_color_space = JCS_RGBA_8888;
531    cinfo->do_fancy_upsampling = 0;
532    cinfo->do_block_smoothing = 0;
533
534    // instead of jpeg_start_decompress() we start a tiled decompress
535    jpeg_start_tile_decompress(cinfo);
536
537    cinfo->scale_num = 1;
538    *height = cinfo->output_height;
539    *width = cinfo->output_width;
540    fImageWidth = *width;
541    fImageHeight = *height;
542
543    SkDELETE(fImageIndex);
544    fImageIndex = imageIndex;
545
546    return true;
547}
548
549bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
550    if (NULL == fImageIndex) {
551        return false;
552    }
553    jpeg_decompress_struct* cinfo = fImageIndex->cinfo();
554
555    SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight);
556    if (!rect.intersect(region)) {
557        // If the requested region is entirely outside the image return false
558        return false;
559    }
560
561
562    skjpeg_error_mgr errorManager;
563    cinfo->err = jpeg_std_error(&errorManager);
564    errorManager.error_exit = skjpeg_error_exit;
565    if (setjmp(errorManager.fJmpBuf)) {
566        return false;
567    }
568
569    int requestedSampleSize = this->getSampleSize();
570    cinfo->scale_denom = requestedSampleSize;
571
572    if (this->getPreferQualityOverSpeed()) {
573        cinfo->dct_method = JDCT_ISLOW;
574    } else {
575        cinfo->dct_method = JDCT_IFAST;
576    }
577
578    SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
579    if (config != SkBitmap::kARGB_8888_Config &&
580        config != SkBitmap::kARGB_4444_Config &&
581        config != SkBitmap::kRGB_565_Config) {
582        config = SkBitmap::kARGB_8888_Config;
583    }
584
585    /* default format is RGB */
586    cinfo->out_color_space = JCS_RGB;
587
588#ifdef ANDROID_RGB
589    cinfo->dither_mode = JDITHER_NONE;
590    if (SkBitmap::kARGB_8888_Config == config) {
591        cinfo->out_color_space = JCS_RGBA_8888;
592    } else if (SkBitmap::kRGB_565_Config == config) {
593        cinfo->out_color_space = JCS_RGB_565;
594        if (this->getDitherImage()) {
595            cinfo->dither_mode = JDITHER_ORDERED;
596        }
597    }
598#endif
599
600    int startX = rect.fLeft;
601    int startY = rect.fTop;
602    int width = rect.width();
603    int height = rect.height();
604
605    jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(),
606                                 &startX, &startY, &width, &height);
607    int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
608    int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size);
609
610    SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
611
612    SkBitmap bitmap;
613    bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
614    bitmap.setIsOpaque(true);
615
616    // Check ahead of time if the swap(dest, src) is possible or not.
617    // If yes, then we will stick to AllocPixelRef since it's cheaper with the
618    // swap happening. If no, then we will use alloc to allocate pixels to
619    // prevent garbage collection.
620    int w = rect.width() / actualSampleSize;
621    int h = rect.height() / actualSampleSize;
622    bool swapOnly = (rect == region) && bm->isNull() &&
623                    (w == bitmap.width()) && (h == bitmap.height()) &&
624                    ((startX - rect.x()) / actualSampleSize == 0) &&
625                    ((startY - rect.y()) / actualSampleSize == 0);
626    if (swapOnly) {
627        if (!this->allocPixelRef(&bitmap, NULL)) {
628            return return_false(*cinfo, bitmap, "allocPixelRef");
629        }
630    } else {
631        if (!bitmap.allocPixels()) {
632            return return_false(*cinfo, bitmap, "allocPixels");
633        }
634    }
635
636    SkAutoLockPixels alp(bitmap);
637
638#ifdef ANDROID_RGB
639    /* short-circuit the SkScaledBitmapSampler when possible, as this gives
640       a significant performance boost.
641    */
642    if (skiaSampleSize == 1 &&
643        ((config == SkBitmap::kARGB_8888_Config &&
644                cinfo->out_color_space == JCS_RGBA_8888) ||
645        (config == SkBitmap::kRGB_565_Config &&
646                cinfo->out_color_space == JCS_RGB_565)))
647    {
648        JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels();
649        INT32 const bpr = bitmap.rowBytes();
650        int rowTotalCount = 0;
651
652        while (rowTotalCount < height) {
653            int rowCount = jpeg_read_tile_scanline(cinfo,
654                                                   fImageIndex->huffmanIndex(),
655                                                   &rowptr);
656            // if row_count == 0, then we didn't get a scanline, so abort.
657            // if we supported partial images, we might return true in this case
658            if (0 == rowCount) {
659                return return_false(*cinfo, bitmap, "read_scanlines");
660            }
661            if (this->shouldCancelDecode()) {
662                return return_false(*cinfo, bitmap, "shouldCancelDecode");
663            }
664            rowTotalCount += rowCount;
665            rowptr += bpr;
666        }
667
668        if (swapOnly) {
669            bm->swap(bitmap);
670        } else {
671            cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
672                       region.width(), region.height(), startX, startY);
673        }
674        return true;
675    }
676#endif
677
678    // check for supported formats
679    SkScaledBitmapSampler::SrcConfig sc;
680    if (JCS_CMYK == cinfo->out_color_space) {
681        // In this case we will manually convert the CMYK values to RGB
682        sc = SkScaledBitmapSampler::kRGBX;
683    } else if (3 == cinfo->out_color_components && JCS_RGB == cinfo->out_color_space) {
684        sc = SkScaledBitmapSampler::kRGB;
685#ifdef ANDROID_RGB
686    } else if (JCS_RGBA_8888 == cinfo->out_color_space) {
687        sc = SkScaledBitmapSampler::kRGBX;
688    } else if (JCS_RGB_565 == cinfo->out_color_space) {
689        sc = SkScaledBitmapSampler::kRGB_565;
690#endif
691    } else if (1 == cinfo->out_color_components &&
692               JCS_GRAYSCALE == cinfo->out_color_space) {
693        sc = SkScaledBitmapSampler::kGray;
694    } else {
695        return return_false(*cinfo, *bm, "jpeg colorspace");
696    }
697
698    if (!sampler.begin(&bitmap, sc, this->getDitherImage())) {
699        return return_false(*cinfo, bitmap, "sampler.begin");
700    }
701
702    // The CMYK work-around relies on 4 components per pixel here
703    SkAutoMalloc  srcStorage(width * 4);
704    uint8_t* srcRow = (uint8_t*)srcStorage.get();
705
706    //  Possibly skip initial rows [sampler.srcY0]
707    if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) {
708        return return_false(*cinfo, bitmap, "skip rows");
709    }
710
711    // now loop through scanlines until y == bitmap->height() - 1
712    for (int y = 0;; y++) {
713        JSAMPLE* rowptr = (JSAMPLE*)srcRow;
714        int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr);
715        if (0 == row_count) {
716            return return_false(*cinfo, bitmap, "read_scanlines");
717        }
718        if (this->shouldCancelDecode()) {
719            return return_false(*cinfo, bitmap, "shouldCancelDecode");
720        }
721
722        if (JCS_CMYK == cinfo->out_color_space) {
723            convert_CMYK_to_RGB(srcRow, width);
724        }
725
726        sampler.next(srcRow);
727        if (bitmap.height() - 1 == y) {
728            // we're done
729            break;
730        }
731
732        if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow,
733                                sampler.srcDY() - 1)) {
734            return return_false(*cinfo, bitmap, "skip rows");
735        }
736    }
737    if (swapOnly) {
738        bm->swap(bitmap);
739    } else {
740        cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
741                   region.width(), region.height(), startX, startY);
742    }
743    return true;
744}
745#endif
746
747///////////////////////////////////////////////////////////////////////////////
748
749#include "SkColorPriv.h"
750
751// taken from jcolor.c in libjpeg
752#if 0   // 16bit - precise but slow
753    #define CYR     19595   // 0.299
754    #define CYG     38470   // 0.587
755    #define CYB      7471   // 0.114
756
757    #define CUR    -11059   // -0.16874
758    #define CUG    -21709   // -0.33126
759    #define CUB     32768   // 0.5
760
761    #define CVR     32768   // 0.5
762    #define CVG    -27439   // -0.41869
763    #define CVB     -5329   // -0.08131
764
765    #define CSHIFT  16
766#else      // 8bit - fast, slightly less precise
767    #define CYR     77    // 0.299
768    #define CYG     150    // 0.587
769    #define CYB      29    // 0.114
770
771    #define CUR     -43    // -0.16874
772    #define CUG    -85    // -0.33126
773    #define CUB     128    // 0.5
774
775    #define CVR      128   // 0.5
776    #define CVG     -107   // -0.41869
777    #define CVB      -21   // -0.08131
778
779    #define CSHIFT  8
780#endif
781
782static void rgb2yuv_32(uint8_t dst[], SkPMColor c) {
783    int r = SkGetPackedR32(c);
784    int g = SkGetPackedG32(c);
785    int b = SkGetPackedB32(c);
786
787    int  y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT;
788    int  u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT;
789    int  v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT;
790
791    dst[0] = SkToU8(y);
792    dst[1] = SkToU8(u + 128);
793    dst[2] = SkToU8(v + 128);
794}
795
796static void rgb2yuv_4444(uint8_t dst[], U16CPU c) {
797    int r = SkGetPackedR4444(c);
798    int g = SkGetPackedG4444(c);
799    int b = SkGetPackedB4444(c);
800
801    int  y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4);
802    int  u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4);
803    int  v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4);
804
805    dst[0] = SkToU8(y);
806    dst[1] = SkToU8(u + 128);
807    dst[2] = SkToU8(v + 128);
808}
809
810static void rgb2yuv_16(uint8_t dst[], U16CPU c) {
811    int r = SkGetPackedR16(c);
812    int g = SkGetPackedG16(c);
813    int b = SkGetPackedB16(c);
814
815    int  y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2);
816    int  u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2);
817    int  v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2);
818
819    dst[0] = SkToU8(y);
820    dst[1] = SkToU8(u + 128);
821    dst[2] = SkToU8(v + 128);
822}
823
824///////////////////////////////////////////////////////////////////////////////
825
826typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
827                              const void* SK_RESTRICT src, int width,
828                              const SkPMColor* SK_RESTRICT ctable);
829
830static void Write_32_YUV(uint8_t* SK_RESTRICT dst,
831                         const void* SK_RESTRICT srcRow, int width,
832                         const SkPMColor*) {
833    const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
834    while (--width >= 0) {
835#ifdef WE_CONVERT_TO_YUV
836        rgb2yuv_32(dst, *src++);
837#else
838        uint32_t c = *src++;
839        dst[0] = SkGetPackedR32(c);
840        dst[1] = SkGetPackedG32(c);
841        dst[2] = SkGetPackedB32(c);
842#endif
843        dst += 3;
844    }
845}
846
847static void Write_4444_YUV(uint8_t* SK_RESTRICT dst,
848                           const void* SK_RESTRICT srcRow, int width,
849                           const SkPMColor*) {
850    const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
851    while (--width >= 0) {
852#ifdef WE_CONVERT_TO_YUV
853        rgb2yuv_4444(dst, *src++);
854#else
855        SkPMColor16 c = *src++;
856        dst[0] = SkPacked4444ToR32(c);
857        dst[1] = SkPacked4444ToG32(c);
858        dst[2] = SkPacked4444ToB32(c);
859#endif
860        dst += 3;
861    }
862}
863
864static void Write_16_YUV(uint8_t* SK_RESTRICT dst,
865                         const void* SK_RESTRICT srcRow, int width,
866                         const SkPMColor*) {
867    const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
868    while (--width >= 0) {
869#ifdef WE_CONVERT_TO_YUV
870        rgb2yuv_16(dst, *src++);
871#else
872        uint16_t c = *src++;
873        dst[0] = SkPacked16ToR32(c);
874        dst[1] = SkPacked16ToG32(c);
875        dst[2] = SkPacked16ToB32(c);
876#endif
877        dst += 3;
878    }
879}
880
881static void Write_Index_YUV(uint8_t* SK_RESTRICT dst,
882                            const void* SK_RESTRICT srcRow, int width,
883                            const SkPMColor* SK_RESTRICT ctable) {
884    const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
885    while (--width >= 0) {
886#ifdef WE_CONVERT_TO_YUV
887        rgb2yuv_32(dst, ctable[*src++]);
888#else
889        uint32_t c = ctable[*src++];
890        dst[0] = SkGetPackedR32(c);
891        dst[1] = SkGetPackedG32(c);
892        dst[2] = SkGetPackedB32(c);
893#endif
894        dst += 3;
895    }
896}
897
898static WriteScanline ChooseWriter(const SkBitmap& bm) {
899    switch (bm.config()) {
900        case SkBitmap::kARGB_8888_Config:
901            return Write_32_YUV;
902        case SkBitmap::kRGB_565_Config:
903            return Write_16_YUV;
904        case SkBitmap::kARGB_4444_Config:
905            return Write_4444_YUV;
906        case SkBitmap::kIndex8_Config:
907            return Write_Index_YUV;
908        default:
909            return NULL;
910    }
911}
912
913class SkJPEGImageEncoder : public SkImageEncoder {
914protected:
915    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
916#ifdef TIME_ENCODE
917        SkAutoTime atm("JPEG Encode");
918#endif
919
920        SkAutoLockPixels alp(bm);
921        if (NULL == bm.getPixels()) {
922            return false;
923        }
924
925        jpeg_compress_struct    cinfo;
926        skjpeg_error_mgr        sk_err;
927        skjpeg_destination_mgr  sk_wstream(stream);
928
929        // allocate these before set call setjmp
930        SkAutoMalloc    oneRow;
931        SkAutoLockColors ctLocker;
932
933        cinfo.err = jpeg_std_error(&sk_err);
934        sk_err.error_exit = skjpeg_error_exit;
935        if (setjmp(sk_err.fJmpBuf)) {
936            return false;
937        }
938
939        // Keep after setjmp or mark volatile.
940        const WriteScanline writer = ChooseWriter(bm);
941        if (NULL == writer) {
942            return false;
943        }
944
945        jpeg_create_compress(&cinfo);
946        cinfo.dest = &sk_wstream;
947        cinfo.image_width = bm.width();
948        cinfo.image_height = bm.height();
949        cinfo.input_components = 3;
950#ifdef WE_CONVERT_TO_YUV
951        cinfo.in_color_space = JCS_YCbCr;
952#else
953        cinfo.in_color_space = JCS_RGB;
954#endif
955        cinfo.input_gamma = 1;
956
957        jpeg_set_defaults(&cinfo);
958        jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
959#ifdef DCT_IFAST_SUPPORTED
960        cinfo.dct_method = JDCT_IFAST;
961#endif
962
963        jpeg_start_compress(&cinfo, TRUE);
964
965        const int       width = bm.width();
966        uint8_t*        oneRowP = (uint8_t*)oneRow.reset(width * 3);
967
968        const SkPMColor* colors = ctLocker.lockColors(bm);
969        const void*      srcRow = bm.getPixels();
970
971        while (cinfo.next_scanline < cinfo.image_height) {
972            JSAMPROW row_pointer[1];    /* pointer to JSAMPLE row[s] */
973
974            writer(oneRowP, srcRow, width, colors);
975            row_pointer[0] = oneRowP;
976            (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
977            srcRow = (const void*)((const char*)srcRow + bm.rowBytes());
978        }
979
980        jpeg_finish_compress(&cinfo);
981        jpeg_destroy_compress(&cinfo);
982
983        return true;
984    }
985};
986
987///////////////////////////////////////////////////////////////////////////////
988DEFINE_DECODER_CREATOR(JPEGImageDecoder);
989DEFINE_ENCODER_CREATOR(JPEGImageEncoder);
990///////////////////////////////////////////////////////////////////////////////
991
992static bool is_jpeg(SkStream* stream) {
993    static const unsigned 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 false;   // can't read enough
1001    }
1002    if (memcmp(buffer, gHeader, HEADER_SIZE)) {
1003        return false;
1004    }
1005    return true;
1006}
1007
1008#include "SkTRegistry.h"
1009
1010static SkImageDecoder* sk_libjpeg_dfactory(SkStream* stream) {
1011    if (is_jpeg(stream)) {
1012        return SkNEW(SkJPEGImageDecoder);
1013    }
1014    return NULL;
1015}
1016
1017static SkImageDecoder::Format get_format_jpeg(SkStream* stream) {
1018    if (is_jpeg(stream)) {
1019        return SkImageDecoder::kJPEG_Format;
1020    }
1021    return SkImageDecoder::kUnknown_Format;
1022}
1023
1024static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
1025    return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
1026}
1027
1028
1029static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory);
1030static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_jpeg);
1031static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efactory);
1032