SkImageDecoder_libjpeg.cpp revision 8d725b25a6287e49e2b0cb2965871186e716eded
1d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
2d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/*
3d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * Copyright 2007 The Android Open Source Project
4d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com *
5d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * Use of this source code is governed by a BSD-style license that can be
6d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * found in the LICENSE file.
7d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */
8d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
9d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
10d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkImageDecoder.h"
11d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkImageEncoder.h"
12d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkJpegUtility.h"
13d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkColorPriv.h"
14d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkDither.h"
15d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkScaledBitmapSampler.h"
16d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkStream.h"
17d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkTemplates.h"
18113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#include "SkTime.h"
19d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkUtils.h"
20113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#include "SkRect.h"
21113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#include "SkCanvas.h"
22d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
23d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include <stdio.h>
24d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comextern "C" {
25d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #include "jpeglib.h"
26d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #include "jerror.h"
27d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
28d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
29113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// Uncomment to enable the code path used by the Android framework with their
30113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// custom image decoders.
31113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com//#if defined(SK_BUILD_FOR_ANDROID) && defined(SK_DEBUG)
32113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com//  #define SK_BUILD_FOR_ANDROID_FRAMEWORK
33113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com//#endif
34113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
35113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// These enable timing code that report milliseconds for an encoding/decoding
36d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com//#define TIME_ENCODE
37d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com//#define TIME_DECODE
38d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
39d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// this enables our rgb->yuv code, which is faster than libjpeg on ARM
40d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// disable for the moment, as we have some glitches when width != multiple of 4
41d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#define WE_CONVERT_TO_YUV
42d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
43113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offers
44113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565.
45113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
46d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com//////////////////////////////////////////////////////////////////////////
47d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com//////////////////////////////////////////////////////////////////////////
48d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
49113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic void overwrite_mem_buffer_size(j_decompress_ptr cinfo) {
50113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID
51113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    /* Check if the device indicates that it has a large amount of system memory
52113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com     * if so, increase the memory allocation to 30MB instead of the default 5MB.
53113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com     */
54113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_LARGE_MEMORY_DEVICE
55113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->mem->max_memory_to_use = 30 * 1024 * 1024;
56113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#else
57113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->mem->max_memory_to_use = 5 * 1024 * 1024;
58113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
59113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif // SK_BUILD_FOR_ANDROID
60113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}
61113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
62113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com//////////////////////////////////////////////////////////////////////////
63113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com//////////////////////////////////////////////////////////////////////////
64113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
65113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comclass SkJPEGImageIndex {
66d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic:
67113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder)
68113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        : fSrcMgr(stream, decoder, true) {}
69113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
70113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    ~SkJPEGImageIndex() {
71113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
72113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        jpeg_destroy_huffman_index(&fHuffmanIndex);
73113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
74113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        jpeg_finish_decompress(&fCInfo);
75113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        jpeg_destroy_decompress(&fCInfo);
76d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
77d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
78113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    /**
79113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com     * Init the cinfo struct using libjpeg and apply any necessary
80113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com     * customizations.
81113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com     */
82113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    void initializeInfo() {
83113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        jpeg_create_decompress(&fCInfo);
84113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        overwrite_mem_buffer_size(&fCInfo);
85113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        fCInfo.src = &fSrcMgr;
86113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
87d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
88113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_decompress_struct* cinfo() { return &fCInfo; }
89d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
90113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
91113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    huffman_index* huffmanIndex() { return &fHuffmanIndex; }
92113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
93113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
94113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comprivate:
95113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    skjpeg_source_mgr  fSrcMgr;
96113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_decompress_struct fCInfo;
97113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
98113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    huffman_index fHuffmanIndex;
99113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
100113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com};
101d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
102113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comclass SkJPEGImageDecoder : public SkImageDecoder {
103d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic:
104113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkJPEGImageDecoder() {
105113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        fImageIndex = NULL;
106113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        fImageWidth = 0;
107113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        fImageHeight = 0;
108d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
109113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
110113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    virtual ~SkJPEGImageDecoder() {
111113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        SkDELETE(fImageIndex);
112d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
113113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
114113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    virtual Format getFormat() const {
115113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return kJPEG_Format;
116113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
117113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
118113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comprotected:
119113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
120113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_OVERRIDE;
1217e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com    virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE;
122113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
123113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
124113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
125d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprivate:
126113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkJPEGImageIndex* fImageIndex;
127113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int fImageWidth;
128113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int fImageHeight;
129113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
130113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    typedef SkImageDecoder INHERITED;
131d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com};
132d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
133113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com//////////////////////////////////////////////////////////////////////////
134113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
135d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/* Automatically clean up after throwing an exception */
136d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comclass JPEGAutoClean {
137d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic:
138d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    JPEGAutoClean(): cinfo_ptr(NULL) {}
139d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    ~JPEGAutoClean() {
140d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (cinfo_ptr) {
141d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            jpeg_destroy_decompress(cinfo_ptr);
142d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
143d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
144d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    void set(jpeg_decompress_struct* info) {
145d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo_ptr = info;
146d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
147d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprivate:
148d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    jpeg_decompress_struct* cinfo_ptr;
149d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com};
150d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
151d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com///////////////////////////////////////////////////////////////////////////////
152d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
153d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/*  If we need to better match the request, we might examine the image and
154d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     output dimensions, and determine if the downsampling jpeg provided is
155d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     not sufficient. If so, we can recompute a modified sampleSize value to
156d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     make up the difference.
157d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
158d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     To skip this additional scaling, just set sampleSize = 1; below.
159d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */
160d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic int recompute_sampleSize(int sampleSize,
161d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                                const jpeg_decompress_struct& cinfo) {
162d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    return sampleSize * cinfo.output_width / cinfo.image_width;
163d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
164d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
165d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) {
166d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /* These are initialized to 0, so if they have non-zero values, we assume
167d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com       they are "valid" (i.e. have been computed by libjpeg)
168d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     */
169113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    return 0 != cinfo.output_width && 0 != cinfo.output_height;
170d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
171d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
172113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) {
173d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    for (int i = 0; i < count; i++) {
174d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        JSAMPLE* rowptr = (JSAMPLE*)buffer;
175d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1);
176113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (1 != row_count) {
177d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return false;
178d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
179d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
180d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    return true;
181d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
182d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
183113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
184113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic bool skip_src_rows_tile(jpeg_decompress_struct* cinfo,
185113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                               huffman_index *index, void* buffer, int count) {
186113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    for (int i = 0; i < count; i++) {
187113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        JSAMPLE* rowptr = (JSAMPLE*)buffer;
188113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr);
189113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (1 != row_count) {
190113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return false;
191113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
192113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
193113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    return true;
194113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}
195113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
196113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
197d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// This guy exists just to aid in debugging, as it allows debuggers to just
198d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// set a break-point in one place to see all error exists.
199d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic bool return_false(const jpeg_decompress_struct& cinfo,
200d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                         const SkBitmap& bm, const char msg[]) {
201113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_DEBUG
202e8f3471f94d7532484537c32d5b92e68018897c6scroggo@google.com    SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", cinfo.err->msg_code,
203d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com             cinfo.err->jpeg_message_table[cinfo.err->msg_code], msg,
204d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com             bm.width(), bm.height());
205d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
206d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    return false;   // must always return false
207d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
208d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
2098570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com// Convert a scanline of CMYK samples to RGBX in place. Note that this
2108570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com// method moves the "scanline" pointer in its processing
2118570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) {
2128570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // At this point we've received CMYK pixels from libjpeg. We
213d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    // perform a crude conversion to RGB (based on the formulae
2148570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // from easyrgb.com):
2158570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //  CMYK -> CMY
2168570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //    C = ( C * (1 - K) + K )      // for each CMY component
2178570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //  CMY -> RGB
2188570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //    R = ( 1 - C ) * 255          // for each RGB component
2198570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // Unfortunately we are seeing inverted CMYK so all the original terms
2208570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // are 1-. This yields:
2218570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //  CMYK -> CMY
2228570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //    C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K
2238570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // The conversion from CMY->RGB remains the same
2248570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    for (unsigned int x = 0; x < width; ++x, scanline += 4) {
2258570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]);
2268570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]);
2278570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]);
2288570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        scanline[3] = 255;
2298570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    }
2308570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com}
2318570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com
232d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.combool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
233d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef TIME_DECODE
234113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkAutoTime atm("JPEG Decode");
235d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
236d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
237d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    JPEGAutoClean autoClean;
238d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
239d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    jpeg_decompress_struct  cinfo;
240113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    skjpeg_error_mgr        errorManager;
241113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    skjpeg_source_mgr       srcManager(stream, this, false);
242d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
243113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo.err = jpeg_std_error(&errorManager);
244113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    errorManager.error_exit = skjpeg_error_exit;
245d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
246d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // All objects need to be instantiated before this setjmp call so that
247d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // they will be cleaned up properly if an error occurs.
248113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (setjmp(errorManager.fJmpBuf)) {
249d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "setjmp");
250d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
251d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
252d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    jpeg_create_decompress(&cinfo);
253d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    autoClean.set(&cinfo);
254d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
255d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    overwrite_mem_buffer_size(&cinfo);
256d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
257d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    //jpeg_stdio_src(&cinfo, file);
258113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo.src = &srcManager;
259d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
260d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int status = jpeg_read_header(&cinfo, true);
261d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (status != JPEG_HEADER_OK) {
262d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "read_header");
263d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
264d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
265d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /*  Try to fulfill the requested sampleSize. Since jpeg can do it (when it
266d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        can) much faster that we, just use their num/denom api to approximate
267d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        the size.
268d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    */
269d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int sampleSize = this->getSampleSize();
270d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
2713acd3fcfad2d3f7fa3379ea8d26c9b870298b6d0scroggo@google.com#ifdef DCT_IFAST_SUPPORTED
272113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (this->getPreferQualityOverSpeed()) {
273113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        cinfo.dct_method = JDCT_ISLOW;
274113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else {
275113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        cinfo.dct_method = JDCT_IFAST;
276113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
2773acd3fcfad2d3f7fa3379ea8d26c9b870298b6d0scroggo@google.com#else
2783acd3fcfad2d3f7fa3379ea8d26c9b870298b6d0scroggo@google.com    cinfo.dct_method = JDCT_ISLOW;
2793acd3fcfad2d3f7fa3379ea8d26c9b870298b6d0scroggo@google.com#endif
280113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
281d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    cinfo.scale_num = 1;
282d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    cinfo.scale_denom = sampleSize;
283d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
284d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /* this gives about 30% performance improvement. In theory it may
285d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com       reduce the visual quality, in practice I'm not seeing a difference
286d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     */
287d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    cinfo.do_fancy_upsampling = 0;
288d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
289d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /* this gives another few percents */
290d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    cinfo.do_block_smoothing = 0;
291d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
292f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com    SrcDepth srcDepth = k32Bit_SrcDepth;
293d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /* default format is RGB */
2948570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    if (cinfo.jpeg_color_space == JCS_CMYK) {
2958570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        // libjpeg cannot convert from CMYK to RGB - here we set up
2968570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        // so libjpeg will give us CMYK samples back and we will
2978570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        // later manually convert them to RGB
2988570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        cinfo.out_color_space = JCS_CMYK;
299f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com    } else if (cinfo.jpeg_color_space == JCS_GRAYSCALE) {
300f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com        cinfo.out_color_space = JCS_GRAYSCALE;
301f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com        srcDepth = k8BitGray_SrcDepth;
3028570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    } else {
3038570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        cinfo.out_color_space = JCS_RGB;
3048570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    }
305d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
306f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com    SkBitmap::Config config = this->getPrefConfig(srcDepth, false);
307d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // only these make sense for jpegs
308f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com    if (SkBitmap::kA8_Config == config) {
309f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com        if (cinfo.jpeg_color_space != JCS_GRAYSCALE) {
310f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com            // Converting from a non grayscale image to A8 is
311f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com            // not currently supported.
312f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com            config = SkBitmap::kARGB_8888_Config;
313f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com            // Change the output from jpeg back to RGB.
314f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com            cinfo.out_color_space = JCS_RGB;
315f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com        }
316f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com    } else if (config != SkBitmap::kARGB_8888_Config &&
317f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com               config != SkBitmap::kARGB_4444_Config &&
318f698c8262df397a7015662e91b1a727e1134c418scroggo@google.com               config != SkBitmap::kRGB_565_Config) {
319d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        config = SkBitmap::kARGB_8888_Config;
320d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
321d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
322d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef ANDROID_RGB
323d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    cinfo.dither_mode = JDITHER_NONE;
3248570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    if (SkBitmap::kARGB_8888_Config == config && JCS_CMYK != cinfo.out_color_space) {
325d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.out_color_space = JCS_RGBA_8888;
3268570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    } else if (SkBitmap::kRGB_565_Config == config && JCS_CMYK != cinfo.out_color_space) {
327d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.out_color_space = JCS_RGB_565;
328d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (this->getDitherImage()) {
329d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            cinfo.dither_mode = JDITHER_ORDERED;
330d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
331d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
332d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
333d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
334113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) {
335d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        bm->setConfig(config, cinfo.image_width, cinfo.image_height);
3361f6b995fab80a2a258df87d9e6bf953976f37e68scroggo@google.com        bm->setIsOpaque(config != SkBitmap::kA8_Config);
337d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return true;
338d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
339d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
340d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /*  image_width and image_height are the original dimensions, available
341d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        after jpeg_read_header(). To see the scaled dimensions, we have to call
342d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_start_decompress(), and then read output_width and output_height.
343d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    */
344d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (!jpeg_start_decompress(&cinfo)) {
345d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        /*  If we failed here, we may still have enough information to return
346d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            to the caller if they just wanted (subsampled bounds). If sampleSize
347d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            was 1, then we would have already returned. Thus we just check if
348d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            we're in kDecodeBounds_Mode, and that we have valid output sizes.
349d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
350d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            One reason to fail here is that we have insufficient stream data
351d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            to complete the setup. However, output dimensions seem to get
352d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            computed very early, which is why this special check can pay off.
353d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com         */
354113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) {
355d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
356d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                                       recompute_sampleSize(sampleSize, cinfo));
357d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight());
3581f6b995fab80a2a258df87d9e6bf953976f37e68scroggo@google.com            bm->setIsOpaque(config != SkBitmap::kA8_Config);
359d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return true;
360d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        } else {
361d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return return_false(cinfo, *bm, "start_decompress");
362d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
363d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
364d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    sampleSize = recompute_sampleSize(sampleSize, cinfo);
365d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
366d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // should we allow the Chooser (if present) to pick a config for us???
367113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (!this->chooseFromOneChoice(config, cinfo.output_width, cinfo.output_height)) {
368d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "chooseFromOneChoice");
369d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
370d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
371113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize);
372bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com    bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
3731f6b995fab80a2a258df87d9e6bf953976f37e68scroggo@google.com    bm->setIsOpaque(config != SkBitmap::kA8_Config);
374bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
375bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com        return true;
376bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com    }
377bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com    if (!this->allocPixelRef(bm, NULL)) {
378bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com        return return_false(cinfo, *bm, "allocPixelRef");
379113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
380113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
381113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkAutoLockPixels alp(*bm);
382113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
383d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef ANDROID_RGB
384d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /* short-circuit the SkScaledBitmapSampler when possible, as this gives
385d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com       a significant performance boost.
386d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    */
387d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (sampleSize == 1 &&
388d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        ((config == SkBitmap::kARGB_8888_Config &&
389d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                cinfo.out_color_space == JCS_RGBA_8888) ||
390d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        (config == SkBitmap::kRGB_565_Config &&
391d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                cinfo.out_color_space == JCS_RGB_565)))
392d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    {
393bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com        JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
394d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        INT32 const bpr =  bm->rowBytes();
395d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
396d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        while (cinfo.output_scanline < cinfo.output_height) {
397d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
398d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            // if row_count == 0, then we didn't get a scanline, so abort.
399d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            // if we supported partial images, we might return true in this case
400d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            if (0 == row_count) {
401d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                return return_false(cinfo, *bm, "read_scanlines");
402d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            }
403d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            if (this->shouldCancelDecode()) {
404d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                return return_false(cinfo, *bm, "shouldCancelDecode");
405d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            }
406d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            rowptr += bpr;
407d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
408d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_finish_decompress(&cinfo);
409d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return true;
410d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
411d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
4128570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com
413d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // check for supported formats
414d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    SkScaledBitmapSampler::SrcConfig sc;
4158570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    if (JCS_CMYK == cinfo.out_color_space) {
4168570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        // In this case we will manually convert the CMYK values to RGB
4178570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        sc = SkScaledBitmapSampler::kRGBX;
4188570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
419d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        sc = SkScaledBitmapSampler::kRGB;
420d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef ANDROID_RGB
421d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
422d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        sc = SkScaledBitmapSampler::kRGBX;
423d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    } else if (JCS_RGB_565 == cinfo.out_color_space) {
424d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        sc = SkScaledBitmapSampler::kRGB_565;
425d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
426d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    } else if (1 == cinfo.out_color_components &&
427d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com               JCS_GRAYSCALE == cinfo.out_color_space) {
428d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        sc = SkScaledBitmapSampler::kGray;
429d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    } else {
430d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "jpeg colorspace");
431d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
432d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
433d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (!sampler.begin(bm, sc, this->getDitherImage())) {
434d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "sampler.begin");
435d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
436d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
4378570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // The CMYK work-around relies on 4 components per pixel here
438113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkAutoMalloc srcStorage(cinfo.output_width * 4);
439113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    uint8_t* srcRow = (uint8_t*)srcStorage.get();
440d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
441d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    //  Possibly skip initial rows [sampler.srcY0]
442d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
443d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "skip rows");
444d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
445d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
446d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // now loop through scanlines until y == bm->height() - 1
447d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    for (int y = 0;; y++) {
448d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        JSAMPLE* rowptr = (JSAMPLE*)srcRow;
449d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
450d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (0 == row_count) {
451d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return return_false(cinfo, *bm, "read_scanlines");
452d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
453d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (this->shouldCancelDecode()) {
454d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return return_false(cinfo, *bm, "shouldCancelDecode");
455d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
4568570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com
4578570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        if (JCS_CMYK == cinfo.out_color_space) {
4588570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com            convert_CMYK_to_RGB(srcRow, cinfo.output_width);
4598570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        }
4608570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com
461d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        sampler.next(srcRow);
462d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (bm->height() - 1 == y) {
463d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            // we're done
464d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            break;
465d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
466d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
467d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
468d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return return_false(cinfo, *bm, "skip rows");
469d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
470d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
471d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
472d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // we formally skip the rest, so we don't get a complaint from libjpeg
473d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (!skip_src_rows(&cinfo, srcRow,
474d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                       cinfo.output_height - cinfo.output_scanline)) {
475d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "skip rows");
476d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
477d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    jpeg_finish_decompress(&cinfo);
478d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
479d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    return true;
480d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
481d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
482113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
483113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.combool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *height) {
484113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
485113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkJPEGImageIndex* imageIndex = SkNEW_ARGS(SkJPEGImageIndex, (stream, this));
486113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_decompress_struct* cinfo = imageIndex->cinfo();
487113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    huffman_index* huffmanIndex = imageIndex->huffmanIndex();
488113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
489113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    skjpeg_error_mgr sk_err;
490113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->err = jpeg_std_error(&sk_err);
491113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    sk_err.error_exit = skjpeg_error_exit;
492113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
493113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // All objects need to be instantiated before this setjmp call so that
494113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // they will be cleaned up properly if an error occurs.
495113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (setjmp(sk_err.fJmpBuf)) {
496113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
497113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
498113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
499113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // create the cinfo used to create/build the huffmanIndex
500113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    imageIndex->initializeInfo();
501113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->do_fancy_upsampling = 0;
502113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->do_block_smoothing = 0;
503113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
504113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int status = jpeg_read_header(cinfo, true);
505113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (JPEG_HEADER_OK != status) {
506113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        SkDELETE(imageIndex);
507113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
508113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
509113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
510113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_create_huffman_index(cinfo, huffmanIndex);
511113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->scale_num = 1;
512113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->scale_denom = 1;
513113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (!jpeg_build_huffman_index(cinfo, huffmanIndex)) {
514113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        SkDELETE(imageIndex);
515113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
516113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
517113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
518113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // destroy the cinfo used to create/build the huffman index
519113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_destroy_decompress(cinfo);
520113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
521113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // Init decoder to image decode mode
522113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    imageIndex->initializeInfo();
523113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
524113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    status = jpeg_read_header(cinfo, true);
525113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (JPEG_HEADER_OK != status) {
526113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        SkDELETE(imageIndex);
527113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
528113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
529113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
530113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->out_color_space = JCS_RGBA_8888;
531113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->do_fancy_upsampling = 0;
532113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->do_block_smoothing = 0;
533113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
534113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // instead of jpeg_start_decompress() we start a tiled decompress
535113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_start_tile_decompress(cinfo);
536113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
537113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->scale_num = 1;
538113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    *height = cinfo->output_height;
539113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    *width = cinfo->output_width;
540113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    fImageWidth = *width;
541113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    fImageHeight = *height;
542113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
543113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkDELETE(fImageIndex);
544113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    fImageIndex = imageIndex;
545113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
546113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    return true;
547113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}
548113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
5497e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.combool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
550113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (NULL == fImageIndex) {
551113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
552113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
553113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_decompress_struct* cinfo = fImageIndex->cinfo();
554113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
555113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight);
556113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (!rect.intersect(region)) {
557113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        // If the requested region is entirely outside the image return false
558113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
559113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
560113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
561113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
562113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    skjpeg_error_mgr errorManager;
563113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->err = jpeg_std_error(&errorManager);
564113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    errorManager.error_exit = skjpeg_error_exit;
565113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (setjmp(errorManager.fJmpBuf)) {
566113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
567113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
568113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
569113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int requestedSampleSize = this->getSampleSize();
570113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->scale_denom = requestedSampleSize;
571113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
572113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (this->getPreferQualityOverSpeed()) {
573113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        cinfo->dct_method = JDCT_ISLOW;
574113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else {
575113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        cinfo->dct_method = JDCT_IFAST;
576113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
577113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
578113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
579113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (config != SkBitmap::kARGB_8888_Config &&
580113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        config != SkBitmap::kARGB_4444_Config &&
581113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        config != SkBitmap::kRGB_565_Config) {
582113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        config = SkBitmap::kARGB_8888_Config;
583113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
584113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
585113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    /* default format is RGB */
586113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->out_color_space = JCS_RGB;
587113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
588113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_RGB
589113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->dither_mode = JDITHER_NONE;
590113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (SkBitmap::kARGB_8888_Config == config) {
591113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        cinfo->out_color_space = JCS_RGBA_8888;
592113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else if (SkBitmap::kRGB_565_Config == config) {
593113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        cinfo->out_color_space = JCS_RGB_565;
594113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (this->getDitherImage()) {
595113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            cinfo->dither_mode = JDITHER_ORDERED;
596113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
597113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
598113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
599113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
600113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int startX = rect.fLeft;
601113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int startY = rect.fTop;
602113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int width = rect.width();
603113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int height = rect.height();
604113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
605113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(),
606113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                                 &startX, &startY, &width, &height);
607113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
608113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size);
609113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
610113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
611113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
612113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkBitmap bitmap;
613113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
614113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    bitmap.setIsOpaque(true);
615113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
616113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // Check ahead of time if the swap(dest, src) is possible or not.
617113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // If yes, then we will stick to AllocPixelRef since it's cheaper with the
618113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // swap happening. If no, then we will use alloc to allocate pixels to
619113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // prevent garbage collection.
620113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int w = rect.width() / actualSampleSize;
621113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int h = rect.height() / actualSampleSize;
622113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    bool swapOnly = (rect == region) && bm->isNull() &&
623113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                    (w == bitmap.width()) && (h == bitmap.height()) &&
624113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                    ((startX - rect.x()) / actualSampleSize == 0) &&
625113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                    ((startY - rect.y()) / actualSampleSize == 0);
626113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (swapOnly) {
627113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (!this->allocPixelRef(&bitmap, NULL)) {
628113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "allocPixelRef");
629113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
630113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else {
631113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (!bitmap.allocPixels()) {
632113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "allocPixels");
633113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
634113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
635113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
636113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkAutoLockPixels alp(bitmap);
637113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
638113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_RGB
639113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    /* short-circuit the SkScaledBitmapSampler when possible, as this gives
640113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com       a significant performance boost.
641113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    */
642113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (skiaSampleSize == 1 &&
643113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        ((config == SkBitmap::kARGB_8888_Config &&
644113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                cinfo->out_color_space == JCS_RGBA_8888) ||
645113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        (config == SkBitmap::kRGB_565_Config &&
646113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                cinfo->out_color_space == JCS_RGB_565)))
647113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    {
648113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels();
649113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        INT32 const bpr = bitmap.rowBytes();
650113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        int rowTotalCount = 0;
651113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
652113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        while (rowTotalCount < height) {
653113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            int rowCount = jpeg_read_tile_scanline(cinfo,
654113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                                                   fImageIndex->huffmanIndex(),
655113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                                                   &rowptr);
656113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            // if row_count == 0, then we didn't get a scanline, so abort.
657113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            // if we supported partial images, we might return true in this case
658113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            if (0 == rowCount) {
659113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                return return_false(*cinfo, bitmap, "read_scanlines");
660113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            }
661113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            if (this->shouldCancelDecode()) {
662113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                return return_false(*cinfo, bitmap, "shouldCancelDecode");
663113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            }
664113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            rowTotalCount += rowCount;
665113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            rowptr += bpr;
666113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
667113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
668113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (swapOnly) {
669113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            bm->swap(bitmap);
670113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        } else {
671113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
672113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                       region.width(), region.height(), startX, startY);
673113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
674113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return true;
675113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
676113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
677113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
678113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // check for supported formats
679113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkScaledBitmapSampler::SrcConfig sc;
680113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (JCS_CMYK == cinfo->out_color_space) {
681113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        // In this case we will manually convert the CMYK values to RGB
682113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        sc = SkScaledBitmapSampler::kRGBX;
683113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else if (3 == cinfo->out_color_components && JCS_RGB == cinfo->out_color_space) {
684113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        sc = SkScaledBitmapSampler::kRGB;
685113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_RGB
686113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else if (JCS_RGBA_8888 == cinfo->out_color_space) {
687113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        sc = SkScaledBitmapSampler::kRGBX;
688113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else if (JCS_RGB_565 == cinfo->out_color_space) {
689113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        sc = SkScaledBitmapSampler::kRGB_565;
690113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
691113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else if (1 == cinfo->out_color_components &&
692113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com               JCS_GRAYSCALE == cinfo->out_color_space) {
693113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        sc = SkScaledBitmapSampler::kGray;
694113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else {
695113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return return_false(*cinfo, *bm, "jpeg colorspace");
696113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
697113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
698113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (!sampler.begin(&bitmap, sc, this->getDitherImage())) {
699113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return return_false(*cinfo, bitmap, "sampler.begin");
700113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
701113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
702113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // The CMYK work-around relies on 4 components per pixel here
703113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkAutoMalloc  srcStorage(width * 4);
704113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    uint8_t* srcRow = (uint8_t*)srcStorage.get();
705113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
706113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    //  Possibly skip initial rows [sampler.srcY0]
707113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) {
708113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return return_false(*cinfo, bitmap, "skip rows");
709113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
710113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
711113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // now loop through scanlines until y == bitmap->height() - 1
712113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    for (int y = 0;; y++) {
713113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        JSAMPLE* rowptr = (JSAMPLE*)srcRow;
714113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr);
715113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (0 == row_count) {
716113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "read_scanlines");
717113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
718113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (this->shouldCancelDecode()) {
719113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "shouldCancelDecode");
720113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
721113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
722113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (JCS_CMYK == cinfo->out_color_space) {
723113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            convert_CMYK_to_RGB(srcRow, width);
724113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
725113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
726113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        sampler.next(srcRow);
727113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (bitmap.height() - 1 == y) {
728113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            // we're done
729113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            break;
730113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
731113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
732113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow,
733113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                                sampler.srcDY() - 1)) {
734113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "skip rows");
735113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
736113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
737113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (swapOnly) {
738113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        bm->swap(bitmap);
739113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else {
740113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
741113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                   region.width(), region.height(), startX, startY);
742113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
743113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    return true;
744113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}
745113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
746113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
747d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com///////////////////////////////////////////////////////////////////////////////
748d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
749d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkColorPriv.h"
750d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
751d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// taken from jcolor.c in libjpeg
752d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#if 0   // 16bit - precise but slow
753d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYR     19595   // 0.299
754d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYG     38470   // 0.587
755d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYB      7471   // 0.114
756d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
757d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUR    -11059   // -0.16874
758d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUG    -21709   // -0.33126
759d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUB     32768   // 0.5
760d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
761d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVR     32768   // 0.5
762d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVG    -27439   // -0.41869
763d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVB     -5329   // -0.08131
764d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
765d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CSHIFT  16
766d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else      // 8bit - fast, slightly less precise
767d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYR     77    // 0.299
768d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYG     150    // 0.587
769d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYB      29    // 0.114
770d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
771d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUR     -43    // -0.16874
772d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUG    -85    // -0.33126
773d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUB     128    // 0.5
774d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
775d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVR      128   // 0.5
776d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVG     -107   // -0.41869
777d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVB      -21   // -0.08131
778d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
779d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CSHIFT  8
780d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
781d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
782d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_32(uint8_t dst[], SkPMColor c) {
783d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int r = SkGetPackedR32(c);
784d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int g = SkGetPackedG32(c);
785d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int b = SkGetPackedB32(c);
786d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
787d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT;
788d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT;
789d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT;
790d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
791d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[0] = SkToU8(y);
792d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[1] = SkToU8(u + 128);
793d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[2] = SkToU8(v + 128);
794d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
795d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
796d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_4444(uint8_t dst[], U16CPU c) {
797d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int r = SkGetPackedR4444(c);
798d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int g = SkGetPackedG4444(c);
799d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int b = SkGetPackedB4444(c);
800d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
801d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4);
802d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4);
803d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4);
804d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
805d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[0] = SkToU8(y);
806d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[1] = SkToU8(u + 128);
807d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[2] = SkToU8(v + 128);
808d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
809d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
810d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_16(uint8_t dst[], U16CPU c) {
811d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int r = SkGetPackedR16(c);
812d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int g = SkGetPackedG16(c);
813d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int b = SkGetPackedB16(c);
814d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
815d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2);
816d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2);
817d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2);
818d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
819d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[0] = SkToU8(y);
820d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[1] = SkToU8(u + 128);
821d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[2] = SkToU8(v + 128);
822d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
823d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
824d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com///////////////////////////////////////////////////////////////////////////////
825d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
826d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comtypedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
827d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                              const void* SK_RESTRICT src, int width,
828d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                              const SkPMColor* SK_RESTRICT ctable);
829d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
830d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_32_YUV(uint8_t* SK_RESTRICT dst,
831d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                         const void* SK_RESTRICT srcRow, int width,
832d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                         const SkPMColor*) {
833d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
834d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    while (--width >= 0) {
835d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
836d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        rgb2yuv_32(dst, *src++);
837d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
838d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        uint32_t c = *src++;
839d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[0] = SkGetPackedR32(c);
840d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[1] = SkGetPackedG32(c);
841d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[2] = SkGetPackedB32(c);
842d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
843d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst += 3;
844d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
845d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
846d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
847d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_4444_YUV(uint8_t* SK_RESTRICT dst,
848d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                           const void* SK_RESTRICT srcRow, int width,
849d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                           const SkPMColor*) {
850d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
851d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    while (--width >= 0) {
852d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
853d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        rgb2yuv_4444(dst, *src++);
854d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
855d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        SkPMColor16 c = *src++;
856d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[0] = SkPacked4444ToR32(c);
857d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[1] = SkPacked4444ToG32(c);
858d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[2] = SkPacked4444ToB32(c);
859d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
860d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst += 3;
861d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
862d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
863d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
864d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_16_YUV(uint8_t* SK_RESTRICT dst,
865d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                         const void* SK_RESTRICT srcRow, int width,
866d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                         const SkPMColor*) {
867d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
868d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    while (--width >= 0) {
869d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
870d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        rgb2yuv_16(dst, *src++);
871d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
872d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        uint16_t c = *src++;
873d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[0] = SkPacked16ToR32(c);
874d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[1] = SkPacked16ToG32(c);
875d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[2] = SkPacked16ToB32(c);
876d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
877d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst += 3;
878d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
879d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
880d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
881d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_Index_YUV(uint8_t* SK_RESTRICT dst,
882d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                            const void* SK_RESTRICT srcRow, int width,
883d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                            const SkPMColor* SK_RESTRICT ctable) {
884d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
885d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    while (--width >= 0) {
886d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
887d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        rgb2yuv_32(dst, ctable[*src++]);
888d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
889d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        uint32_t c = ctable[*src++];
890d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[0] = SkGetPackedR32(c);
891d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[1] = SkGetPackedG32(c);
892d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[2] = SkGetPackedB32(c);
893d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
894d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst += 3;
895d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
896d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
897d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
898d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic WriteScanline ChooseWriter(const SkBitmap& bm) {
899d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    switch (bm.config()) {
900d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        case SkBitmap::kARGB_8888_Config:
901d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return Write_32_YUV;
902d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        case SkBitmap::kRGB_565_Config:
903d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return Write_16_YUV;
904d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        case SkBitmap::kARGB_4444_Config:
905d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return Write_4444_YUV;
906d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        case SkBitmap::kIndex8_Config:
907d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return Write_Index_YUV;
908d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        default:
909d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return NULL;
910d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
911d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
912d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
913d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comclass SkJPEGImageEncoder : public SkImageEncoder {
914d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprotected:
915d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
916d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef TIME_ENCODE
917113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        SkAutoTime atm("JPEG Encode");
918d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
919d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
920d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        SkAutoLockPixels alp(bm);
921d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (NULL == bm.getPixels()) {
922d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return false;
923d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
924d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
925d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_compress_struct    cinfo;
926d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        skjpeg_error_mgr        sk_err;
927d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        skjpeg_destination_mgr  sk_wstream(stream);
928d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
929d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        // allocate these before set call setjmp
930d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        SkAutoMalloc    oneRow;
931d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        SkAutoLockColors ctLocker;
932d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
933d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.err = jpeg_std_error(&sk_err);
934d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        sk_err.error_exit = skjpeg_error_exit;
935d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (setjmp(sk_err.fJmpBuf)) {
936d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return false;
937d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
938d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
9398d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        // Keep after setjmp or mark volatile.
9408d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        const WriteScanline writer = ChooseWriter(bm);
9418d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        if (NULL == writer) {
9428d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com            return false;
9438d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        }
9448d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com
9458d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        jpeg_create_compress(&cinfo);
946d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.dest = &sk_wstream;
947d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.image_width = bm.width();
948d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.image_height = bm.height();
949d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.input_components = 3;
950d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
951d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.in_color_space = JCS_YCbCr;
952d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
953d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.in_color_space = JCS_RGB;
954d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
955d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.input_gamma = 1;
956d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
957d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_set_defaults(&cinfo);
958d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
959b7decc539887069f3fb0f9fc80d543b437bdd624scroggo@google.com#ifdef DCT_IFAST_SUPPORTED
960d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.dct_method = JDCT_IFAST;
961b7decc539887069f3fb0f9fc80d543b437bdd624scroggo@google.com#endif
962d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
963d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_start_compress(&cinfo, TRUE);
964d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
965d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        const int       width = bm.width();
9668570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        uint8_t*        oneRowP = (uint8_t*)oneRow.reset(width * 3);
967d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
968d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        const SkPMColor* colors = ctLocker.lockColors(bm);
969d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        const void*      srcRow = bm.getPixels();
970d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
971d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        while (cinfo.next_scanline < cinfo.image_height) {
972d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            JSAMPROW row_pointer[1];    /* pointer to JSAMPLE row[s] */
973d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
974d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            writer(oneRowP, srcRow, width, colors);
975d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            row_pointer[0] = oneRowP;
976d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
977d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            srcRow = (const void*)((const char*)srcRow + bm.rowBytes());
978d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
979d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
980d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_finish_compress(&cinfo);
981d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_destroy_compress(&cinfo);
982d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
983d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return true;
984d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
985d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com};
986d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
987d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com///////////////////////////////////////////////////////////////////////////////
988ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.comDEFINE_DECODER_CREATOR(JPEGImageDecoder);
989ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.comDEFINE_ENCODER_CREATOR(JPEGImageEncoder);
990ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.com///////////////////////////////////////////////////////////////////////////////
991d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
99239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic bool is_jpeg(SkStream* stream) {
993ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.com    static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF };
994d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    static const size_t HEADER_SIZE = sizeof(gHeader);
995d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
996d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    char buffer[HEADER_SIZE];
997d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    size_t len = stream->read(buffer, HEADER_SIZE);
998d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
999d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (len != HEADER_SIZE) {
100039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com        return false;   // can't read enough
1001d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1002d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (memcmp(buffer, gHeader, HEADER_SIZE)) {
100339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com        return false;
100439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    }
100539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    return true;
100639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com}
100739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com
100839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com#include "SkTRegistry.h"
100939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com
101039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic SkImageDecoder* sk_libjpeg_dfactory(SkStream* stream) {
101139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    if (is_jpeg(stream)) {
101239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com        return SkNEW(SkJPEGImageDecoder);
101339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    }
101439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    return NULL;
101539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com}
101639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com
101739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic SkImageDecoder::Format get_format_jpeg(SkStream* stream) {
101839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    if (is_jpeg(stream)) {
101939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com        return SkImageDecoder::kJPEG_Format;
1020d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
102139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    return SkImageDecoder::kUnknown_Format;
1022d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1023d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
10248570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
1025d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
1026d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1027d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
10288570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com
10298570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory);
103039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_jpeg);
10318570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efactory);
1032