Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(591)

Side by Side Diff: src/images/SkImageDecoder_libjpeg.cpp

Issue 12438025: Upstream changes from Android for decoding jpeg images. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: addressing comments Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « include/images/SkJpegUtility.h ('k') | src/images/SkJpegUtility.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2007 The Android Open Source Project 3 * Copyright 2007 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #include "SkImageDecoder.h" 10 #include "SkImageDecoder.h"
11 #include "SkImageEncoder.h" 11 #include "SkImageEncoder.h"
12 #include "SkJpegUtility.h" 12 #include "SkJpegUtility.h"
13 #include "SkColorPriv.h" 13 #include "SkColorPriv.h"
14 #include "SkDither.h" 14 #include "SkDither.h"
15 #include "SkScaledBitmapSampler.h" 15 #include "SkScaledBitmapSampler.h"
16 #include "SkStream.h" 16 #include "SkStream.h"
17 #include "SkTemplates.h" 17 #include "SkTemplates.h"
18 #include "SkTime.h"
18 #include "SkUtils.h" 19 #include "SkUtils.h"
20 #include "SkRect.h"
21 #include "SkCanvas.h"
19 22
20 #include <stdio.h> 23 #include <stdio.h>
21 extern "C" { 24 extern "C" {
22 #include "jpeglib.h" 25 #include "jpeglib.h"
23 #include "jerror.h" 26 #include "jerror.h"
24 } 27 }
25 28
26 // this enables timing code to report milliseconds for an encode 29 // Uncomment to enable the code path used by the Android framework with their
30 // custom image decoders.
31 //#if defined(SK_BUILD_FOR_ANDROID) && defined(SK_DEBUG)
32 // #define SK_BUILD_FOR_ANDROID_FRAMEWORK
33 //#endif
34
35 // These enable timing code that report milliseconds for an encoding/decoding
27 //#define TIME_ENCODE 36 //#define TIME_ENCODE
28 //#define TIME_DECODE 37 //#define TIME_DECODE
29 38
30 // this enables our rgb->yuv code, which is faster than libjpeg on ARM 39 // this enables our rgb->yuv code, which is faster than libjpeg on ARM
31 // disable for the moment, as we have some glitches when width != multiple of 4 40 // disable for the moment, as we have some glitches when width != multiple of 4
32 #define WE_CONVERT_TO_YUV 41 #define WE_CONVERT_TO_YUV
33 42
43 // If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offer s
44 // support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565.
45
34 ////////////////////////////////////////////////////////////////////////// 46 //////////////////////////////////////////////////////////////////////////
35 ////////////////////////////////////////////////////////////////////////// 47 //////////////////////////////////////////////////////////////////////////
36 48
49 static void overwrite_mem_buffer_size(j_decompress_ptr cinfo) {
50 #ifdef SK_BUILD_FOR_ANDROID
51 /* Check if the device indicates that it has a large amount of system memory
52 * if so, increase the memory allocation to 30MB instead of the default 5MB.
53 */
54 #ifdef ANDROID_LARGE_MEMORY_DEVICE
55 cinfo->mem->max_memory_to_use = 30 * 1024 * 1024;
56 #else
57 cinfo->mem->max_memory_to_use = 5 * 1024 * 1024;
58 #endif
59 #endif // SK_BUILD_FOR_ANDROID
60 }
61
62 //////////////////////////////////////////////////////////////////////////
63 //////////////////////////////////////////////////////////////////////////
64
65 class SkJPEGImageIndex {
66 public:
67 SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder)
68 : fSrcMgr(stream, decoder, true) {}
69
70 ~SkJPEGImageIndex() {
71 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
72 jpeg_destroy_huffman_index(&fHuffmanIndex);
73 #endif
74 jpeg_finish_decompress(&fCInfo);
75 jpeg_destroy_decompress(&fCInfo);
76 }
77
78 /**
79 * Init the cinfo struct using libjpeg and apply any necessary
80 * customizations.
81 */
82 void initializeInfo() {
83 jpeg_create_decompress(&fCInfo);
84 overwrite_mem_buffer_size(&fCInfo);
85 fCInfo.src = &fSrcMgr;
86 }
87
88 jpeg_decompress_struct* cinfo() { return &fCInfo; }
89
90 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
91 huffman_index* huffmanIndex() { return &fHuffmanIndex; }
92 #endif
93
94 private:
95 skjpeg_source_mgr fSrcMgr;
96 jpeg_decompress_struct fCInfo;
97 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
98 huffman_index fHuffmanIndex;
99 #endif
100 };
101
37 class SkJPEGImageDecoder : public SkImageDecoder { 102 class SkJPEGImageDecoder : public SkImageDecoder {
38 public: 103 public:
104 SkJPEGImageDecoder() {
105 fImageIndex = NULL;
106 fImageWidth = 0;
107 fImageHeight = 0;
108 }
109
110 virtual ~SkJPEGImageDecoder() {
111 SkDELETE(fImageIndex);
112 }
113
39 virtual Format getFormat() const { 114 virtual Format getFormat() const {
40 return kJPEG_Format; 115 return kJPEG_Format;
41 } 116 }
42 117
43 protected: 118 protected:
44 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode); 119 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
120 virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_ OVERRIDE;
121 virtual bool onDecodeRegion(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRI DE;
122 #endif
123 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
124
125 private:
126 SkJPEGImageIndex* fImageIndex;
127 int fImageWidth;
128 int fImageHeight;
129
130 typedef SkImageDecoder INHERITED;
45 }; 131 };
46 132
47 ////////////////////////////////////////////////////////////////////////// 133 //////////////////////////////////////////////////////////////////////////
48 134
49 #include "SkTime.h"
50
51 class AutoTimeMillis {
52 public:
53 AutoTimeMillis(const char label[]) : fLabel(label) {
54 if (!fLabel) {
55 fLabel = "";
56 }
57 fNow = SkTime::GetMSecs();
58 }
59 ~AutoTimeMillis() {
60 SkDebugf("---- Time (ms): %s %d\n", fLabel, SkTime::GetMSecs() - fNow);
61 }
62 private:
63 const char* fLabel;
64 SkMSec fNow;
65 };
66
67 /* Automatically clean up after throwing an exception */ 135 /* Automatically clean up after throwing an exception */
68 class JPEGAutoClean { 136 class JPEGAutoClean {
69 public: 137 public:
70 JPEGAutoClean(): cinfo_ptr(NULL) {} 138 JPEGAutoClean(): cinfo_ptr(NULL) {}
71 ~JPEGAutoClean() { 139 ~JPEGAutoClean() {
72 if (cinfo_ptr) { 140 if (cinfo_ptr) {
73 jpeg_destroy_decompress(cinfo_ptr); 141 jpeg_destroy_decompress(cinfo_ptr);
74 } 142 }
75 } 143 }
76 void set(jpeg_decompress_struct* info) { 144 void set(jpeg_decompress_struct* info) {
77 cinfo_ptr = info; 145 cinfo_ptr = info;
78 } 146 }
79 private: 147 private:
80 jpeg_decompress_struct* cinfo_ptr; 148 jpeg_decompress_struct* cinfo_ptr;
81 }; 149 };
82 150
83 #ifdef SK_BUILD_FOR_ANDROID
84
85 /* For non-ndk builds we could look at the system's jpeg memory cap and use it
86 * if it is set. However, for now we will use the NDK compliant hardcoded values
87 */
88 //#include <cutils/properties.h>
89 //static const char KEY_MEM_CAP[] = "ro.media.dec.jpeg.memcap";
90
91 static void overwrite_mem_buffer_size(j_decompress_ptr cinfo) {
92 #ifdef ANDROID_LARGE_MEMORY_DEVICE
93 cinfo->mem->max_memory_to_use = 30 * 1024 * 1024;
94 #else
95 cinfo->mem->max_memory_to_use = 5 * 1024 * 1024;
96 #endif
97 }
98 #endif
99
100
101 /////////////////////////////////////////////////////////////////////////////// 151 ///////////////////////////////////////////////////////////////////////////////
102 152
103 /* If we need to better match the request, we might examine the image and 153 /* If we need to better match the request, we might examine the image and
104 output dimensions, and determine if the downsampling jpeg provided is 154 output dimensions, and determine if the downsampling jpeg provided is
105 not sufficient. If so, we can recompute a modified sampleSize value to 155 not sufficient. If so, we can recompute a modified sampleSize value to
106 make up the difference. 156 make up the difference.
107 157
108 To skip this additional scaling, just set sampleSize = 1; below. 158 To skip this additional scaling, just set sampleSize = 1; below.
109 */ 159 */
110 static int recompute_sampleSize(int sampleSize, 160 static int recompute_sampleSize(int sampleSize,
111 const jpeg_decompress_struct& cinfo) { 161 const jpeg_decompress_struct& cinfo) {
112 return sampleSize * cinfo.output_width / cinfo.image_width; 162 return sampleSize * cinfo.output_width / cinfo.image_width;
113 } 163 }
114 164
115 static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) { 165 static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) {
116 /* These are initialized to 0, so if they have non-zero values, we assume 166 /* These are initialized to 0, so if they have non-zero values, we assume
117 they are "valid" (i.e. have been computed by libjpeg) 167 they are "valid" (i.e. have been computed by libjpeg)
118 */ 168 */
119 return cinfo.output_width != 0 && cinfo.output_height != 0; 169 return 0 != cinfo.output_width && 0 != cinfo.output_height;
120 } 170 }
121 171
122 static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, 172 static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count ) {
123 int count) {
124 for (int i = 0; i < count; i++) { 173 for (int i = 0; i < count; i++) {
125 JSAMPLE* rowptr = (JSAMPLE*)buffer; 174 JSAMPLE* rowptr = (JSAMPLE*)buffer;
126 int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1); 175 int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1);
127 if (row_count != 1) { 176 if (1 != row_count) {
128 return false; 177 return false;
129 } 178 }
130 } 179 }
131 return true; 180 return true;
132 } 181 }
133 182
183 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
184 static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo,
185 huffman_index *index, void* buffer, int count) {
186 for (int i = 0; i < count; i++) {
187 JSAMPLE* rowptr = (JSAMPLE*)buffer;
188 int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr);
189 if (1 != row_count) {
190 return false;
191 }
192 }
193 return true;
194 }
195 #endif
196
134 // This guy exists just to aid in debugging, as it allows debuggers to just 197 // This guy exists just to aid in debugging, as it allows debuggers to just
135 // set a break-point in one place to see all error exists. 198 // set a break-point in one place to see all error exists.
136 static bool return_false(const jpeg_decompress_struct& cinfo, 199 static bool return_false(const jpeg_decompress_struct& cinfo,
137 const SkBitmap& bm, const char msg[]) { 200 const SkBitmap& bm, const char msg[]) {
138 #if 0 201 #ifdef SK_DEBUG
139 SkDebugf("libjpeg error %d <%s> from %s [%d %d]", cinfo.err->msg_code, 202 SkDebugf("libjpeg error %d <%s> from %s [%d %d]", cinfo.err->msg_code,
140 cinfo.err->jpeg_message_table[cinfo.err->msg_code], msg, 203 cinfo.err->jpeg_message_table[cinfo.err->msg_code], msg,
141 bm.width(), bm.height()); 204 bm.width(), bm.height());
142 #endif 205 #endif
143 return false; // must always return false 206 return false; // must always return false
144 } 207 }
145 208
146 // Convert a scanline of CMYK samples to RGBX in place. Note that this 209 // Convert a scanline of CMYK samples to RGBX in place. Note that this
147 // method moves the "scanline" pointer in its processing 210 // method moves the "scanline" pointer in its processing
148 static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) { 211 static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) {
(...skipping 12 matching lines...) Expand all
161 for (unsigned int x = 0; x < width; ++x, scanline += 4) { 224 for (unsigned int x = 0; x < width; ++x, scanline += 4) {
162 scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]); 225 scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]);
163 scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]); 226 scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]);
164 scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]); 227 scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]);
165 scanline[3] = 255; 228 scanline[3] = 255;
166 } 229 }
167 } 230 }
168 231
169 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 232 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
170 #ifdef TIME_DECODE 233 #ifdef TIME_DECODE
171 AutoTimeMillis atm("JPEG Decode"); 234 SkAutoTime atm("JPEG Decode");
172 #endif 235 #endif
173 236
174 SkAutoMalloc srcStorage;
175 JPEGAutoClean autoClean; 237 JPEGAutoClean autoClean;
176 238
177 jpeg_decompress_struct cinfo; 239 jpeg_decompress_struct cinfo;
178 skjpeg_error_mgr sk_err; 240 skjpeg_error_mgr errorManager;
179 skjpeg_source_mgr sk_stream(stream, this, false); 241 skjpeg_source_mgr srcManager(stream, this, false);
180 242
181 cinfo.err = jpeg_std_error(&sk_err); 243 cinfo.err = jpeg_std_error(&errorManager);
182 sk_err.error_exit = skjpeg_error_exit; 244 errorManager.error_exit = skjpeg_error_exit;
183 245
184 // All objects need to be instantiated before this setjmp call so that 246 // All objects need to be instantiated before this setjmp call so that
185 // they will be cleaned up properly if an error occurs. 247 // they will be cleaned up properly if an error occurs.
186 if (setjmp(sk_err.fJmpBuf)) { 248 if (setjmp(errorManager.fJmpBuf)) {
187 return return_false(cinfo, *bm, "setjmp"); 249 return return_false(cinfo, *bm, "setjmp");
188 } 250 }
189 251
190 jpeg_create_decompress(&cinfo); 252 jpeg_create_decompress(&cinfo);
191 autoClean.set(&cinfo); 253 autoClean.set(&cinfo);
192 254
193 #ifdef SK_BUILD_FOR_ANDROID
194 overwrite_mem_buffer_size(&cinfo); 255 overwrite_mem_buffer_size(&cinfo);
195 #endif
196 256
197 //jpeg_stdio_src(&cinfo, file); 257 //jpeg_stdio_src(&cinfo, file);
198 cinfo.src = &sk_stream; 258 cinfo.src = &srcManager;
199 259
200 int status = jpeg_read_header(&cinfo, true); 260 int status = jpeg_read_header(&cinfo, true);
201 if (status != JPEG_HEADER_OK) { 261 if (status != JPEG_HEADER_OK) {
202 return return_false(cinfo, *bm, "read_header"); 262 return return_false(cinfo, *bm, "read_header");
203 } 263 }
204 264
205 /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it 265 /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it
206 can) much faster that we, just use their num/denom api to approximate 266 can) much faster that we, just use their num/denom api to approximate
207 the size. 267 the size.
208 */ 268 */
209 int sampleSize = this->getSampleSize(); 269 int sampleSize = this->getSampleSize();
210 270
211 cinfo.dct_method = JDCT_IFAST; 271 if (this->getPreferQualityOverSpeed()) {
272 cinfo.dct_method = JDCT_ISLOW;
273 } else {
274 cinfo.dct_method = JDCT_IFAST;
275 }
276
212 cinfo.scale_num = 1; 277 cinfo.scale_num = 1;
213 cinfo.scale_denom = sampleSize; 278 cinfo.scale_denom = sampleSize;
214 279
215 /* this gives about 30% performance improvement. In theory it may 280 /* this gives about 30% performance improvement. In theory it may
216 reduce the visual quality, in practice I'm not seeing a difference 281 reduce the visual quality, in practice I'm not seeing a difference
217 */ 282 */
218 cinfo.do_fancy_upsampling = 0; 283 cinfo.do_fancy_upsampling = 0;
219 284
220 /* this gives another few percents */ 285 /* this gives another few percents */
221 cinfo.do_block_smoothing = 0; 286 cinfo.do_block_smoothing = 0;
(...skipping 21 matching lines...) Expand all
243 if (SkBitmap::kARGB_8888_Config == config && JCS_CMYK != cinfo.out_color_spa ce) { 308 if (SkBitmap::kARGB_8888_Config == config && JCS_CMYK != cinfo.out_color_spa ce) {
244 cinfo.out_color_space = JCS_RGBA_8888; 309 cinfo.out_color_space = JCS_RGBA_8888;
245 } else if (SkBitmap::kRGB_565_Config == config && JCS_CMYK != cinfo.out_colo r_space) { 310 } else if (SkBitmap::kRGB_565_Config == config && JCS_CMYK != cinfo.out_colo r_space) {
246 cinfo.out_color_space = JCS_RGB_565; 311 cinfo.out_color_space = JCS_RGB_565;
247 if (this->getDitherImage()) { 312 if (this->getDitherImage()) {
248 cinfo.dither_mode = JDITHER_ORDERED; 313 cinfo.dither_mode = JDITHER_ORDERED;
249 } 314 }
250 } 315 }
251 #endif 316 #endif
252 317
253 if (sampleSize == 1 && mode == SkImageDecoder::kDecodeBounds_Mode) { 318 if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) {
254 bm->setConfig(config, cinfo.image_width, cinfo.image_height); 319 bm->setConfig(config, cinfo.image_width, cinfo.image_height);
255 bm->setIsOpaque(true); 320 bm->setIsOpaque(true);
256 return true; 321 return true;
257 } 322 }
258 323
259 /* image_width and image_height are the original dimensions, available 324 /* image_width and image_height are the original dimensions, available
260 after jpeg_read_header(). To see the scaled dimensions, we have to call 325 after jpeg_read_header(). To see the scaled dimensions, we have to call
261 jpeg_start_decompress(), and then read output_width and output_height. 326 jpeg_start_decompress(), and then read output_width and output_height.
262 */ 327 */
263 if (!jpeg_start_decompress(&cinfo)) { 328 if (!jpeg_start_decompress(&cinfo)) {
264 /* If we failed here, we may still have enough information to return 329 /* If we failed here, we may still have enough information to return
265 to the caller if they just wanted (subsampled bounds). If sampleSize 330 to the caller if they just wanted (subsampled bounds). If sampleSize
266 was 1, then we would have already returned. Thus we just check if 331 was 1, then we would have already returned. Thus we just check if
267 we're in kDecodeBounds_Mode, and that we have valid output sizes. 332 we're in kDecodeBounds_Mode, and that we have valid output sizes.
268 333
269 One reason to fail here is that we have insufficient stream data 334 One reason to fail here is that we have insufficient stream data
270 to complete the setup. However, output dimensions seem to get 335 to complete the setup. However, output dimensions seem to get
271 computed very early, which is why this special check can pay off. 336 computed very early, which is why this special check can pay off.
272 */ 337 */
273 if (SkImageDecoder::kDecodeBounds_Mode == mode && 338 if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimension s(cinfo)) {
274 valid_output_dimensions(cinfo)) {
275 SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height, 339 SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
276 recompute_sampleSize(sampleSize, cinfo)); 340 recompute_sampleSize(sampleSize, cinfo));
277 bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight()); 341 bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight());
278 bm->setIsOpaque(true); 342 bm->setIsOpaque(true);
279 return true; 343 return true;
280 } else { 344 } else {
281 return return_false(cinfo, *bm, "start_decompress"); 345 return return_false(cinfo, *bm, "start_decompress");
282 } 346 }
283 } 347 }
284 sampleSize = recompute_sampleSize(sampleSize, cinfo); 348 sampleSize = recompute_sampleSize(sampleSize, cinfo);
285 349
286 // should we allow the Chooser (if present) to pick a config for us??? 350 // should we allow the Chooser (if present) to pick a config for us???
287 if (!this->chooseFromOneChoice(config, cinfo.output_width, 351 if (!this->chooseFromOneChoice(config, cinfo.output_width, cinfo.output_heig ht)) {
288 cinfo.output_height)) {
289 return return_false(cinfo, *bm, "chooseFromOneChoice"); 352 return return_false(cinfo, *bm, "chooseFromOneChoice");
290 } 353 }
291 354
355 SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampl eSize);
356
357 bm->lockPixels();
358 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
359 bm->unlockPixels();
360 bool reuseBitmap = (rowptr != NULL);
361
362 if (reuseBitmap) {
363 if (sampler.scaledWidth() != bm->width() ||
364 sampler.scaledHeight() != bm->height()) {
365 // Dimensions must match
366 return false;
367 } else if (SkImageDecoder::kDecodeBounds_Mode == mode) {
368 return true;
369 }
370 } else {
371 bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
372 bm->setIsOpaque(true);
373 if (SkImageDecoder::kDecodeBounds_Mode == mode) {
374 return true;
375 }
376 if (!this->allocPixelRef(bm, NULL)) {
377 return return_false(cinfo, *bm, "allocPixelRef");
378 }
379 }
380
381 SkAutoLockPixels alp(*bm);
382
292 #ifdef ANDROID_RGB 383 #ifdef ANDROID_RGB
293 /* short-circuit the SkScaledBitmapSampler when possible, as this gives 384 /* short-circuit the SkScaledBitmapSampler when possible, as this gives
294 a significant performance boost. 385 a significant performance boost.
295 */ 386 */
296 if (sampleSize == 1 && 387 if (sampleSize == 1 &&
297 ((config == SkBitmap::kARGB_8888_Config && 388 ((config == SkBitmap::kARGB_8888_Config &&
298 cinfo.out_color_space == JCS_RGBA_8888) || 389 cinfo.out_color_space == JCS_RGBA_8888) ||
299 (config == SkBitmap::kRGB_565_Config && 390 (config == SkBitmap::kRGB_565_Config &&
300 cinfo.out_color_space == JCS_RGB_565))) 391 cinfo.out_color_space == JCS_RGB_565)))
301 { 392 {
302 bm->setConfig(config, cinfo.output_width, cinfo.output_height); 393 rowptr = (JSAMPLE*)bm->getPixels();
303 bm->setIsOpaque(true);
304 if (SkImageDecoder::kDecodeBounds_Mode == mode) {
305 return true;
306 }
307 if (!this->allocPixelRef(bm, NULL)) {
308 return return_false(cinfo, *bm, "allocPixelRef");
309 }
310 SkAutoLockPixels alp(*bm);
311 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
312 INT32 const bpr = bm->rowBytes(); 394 INT32 const bpr = bm->rowBytes();
313 395
314 while (cinfo.output_scanline < cinfo.output_height) { 396 while (cinfo.output_scanline < cinfo.output_height) {
315 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 397 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
316 // if row_count == 0, then we didn't get a scanline, so abort. 398 // if row_count == 0, then we didn't get a scanline, so abort.
317 // if we supported partial images, we might return true in this case 399 // if we supported partial images, we might return true in this case
318 if (0 == row_count) { 400 if (0 == row_count) {
319 return return_false(cinfo, *bm, "read_scanlines"); 401 return return_false(cinfo, *bm, "read_scanlines");
320 } 402 }
321 if (this->shouldCancelDecode()) { 403 if (this->shouldCancelDecode()) {
322 return return_false(cinfo, *bm, "shouldCancelDecode"); 404 return return_false(cinfo, *bm, "shouldCancelDecode");
323 } 405 }
324 rowptr += bpr; 406 rowptr += bpr;
325 } 407 }
408 if (reuseBitmap) {
409 bm->notifyPixelsChanged();
410 }
326 jpeg_finish_decompress(&cinfo); 411 jpeg_finish_decompress(&cinfo);
327 return true; 412 return true;
328 } 413 }
329 #endif 414 #endif
330 415
331 // check for supported formats 416 // check for supported formats
332 SkScaledBitmapSampler::SrcConfig sc; 417 SkScaledBitmapSampler::SrcConfig sc;
333 if (JCS_CMYK == cinfo.out_color_space) { 418 if (JCS_CMYK == cinfo.out_color_space) {
334 // In this case we will manually convert the CMYK values to RGB 419 // In this case we will manually convert the CMYK values to RGB
335 sc = SkScaledBitmapSampler::kRGBX; 420 sc = SkScaledBitmapSampler::kRGBX;
336 } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_spa ce) { 421 } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_spa ce) {
337 sc = SkScaledBitmapSampler::kRGB; 422 sc = SkScaledBitmapSampler::kRGB;
338 #ifdef ANDROID_RGB 423 #ifdef ANDROID_RGB
339 } else if (JCS_RGBA_8888 == cinfo.out_color_space) { 424 } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
340 sc = SkScaledBitmapSampler::kRGBX; 425 sc = SkScaledBitmapSampler::kRGBX;
341 } else if (JCS_RGB_565 == cinfo.out_color_space) { 426 } else if (JCS_RGB_565 == cinfo.out_color_space) {
342 sc = SkScaledBitmapSampler::kRGB_565; 427 sc = SkScaledBitmapSampler::kRGB_565;
343 #endif 428 #endif
344 } else if (1 == cinfo.out_color_components && 429 } else if (1 == cinfo.out_color_components &&
345 JCS_GRAYSCALE == cinfo.out_color_space) { 430 JCS_GRAYSCALE == cinfo.out_color_space) {
346 sc = SkScaledBitmapSampler::kGray; 431 sc = SkScaledBitmapSampler::kGray;
347 } else { 432 } else {
348 return return_false(cinfo, *bm, "jpeg colorspace"); 433 return return_false(cinfo, *bm, "jpeg colorspace");
349 } 434 }
350 435
351 SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height,
352 sampleSize);
353
354 bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
355 // jpegs are always opaque (i.e. have no per-pixel alpha)
356 bm->setIsOpaque(true);
357
358 if (SkImageDecoder::kDecodeBounds_Mode == mode) {
359 return true;
360 }
361 if (!this->allocPixelRef(bm, NULL)) {
362 return return_false(cinfo, *bm, "allocPixelRef");
363 }
364
365 SkAutoLockPixels alp(*bm);
366 if (!sampler.begin(bm, sc, this->getDitherImage())) { 436 if (!sampler.begin(bm, sc, this->getDitherImage())) {
367 return return_false(cinfo, *bm, "sampler.begin"); 437 return return_false(cinfo, *bm, "sampler.begin");
368 } 438 }
369 439
370 // The CMYK work-around relies on 4 components per pixel here 440 // The CMYK work-around relies on 4 components per pixel here
371 uint8_t* srcRow = (uint8_t*)srcStorage.reset(cinfo.output_width * 4); 441 SkAutoMalloc srcStorage(cinfo.output_width * 4);
442 uint8_t* srcRow = (uint8_t*)srcStorage.get();
372 443
373 // Possibly skip initial rows [sampler.srcY0] 444 // Possibly skip initial rows [sampler.srcY0]
374 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { 445 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
375 return return_false(cinfo, *bm, "skip rows"); 446 return return_false(cinfo, *bm, "skip rows");
376 } 447 }
377 448
378 // now loop through scanlines until y == bm->height() - 1 449 // now loop through scanlines until y == bm->height() - 1
379 for (int y = 0;; y++) { 450 for (int y = 0;; y++) {
380 JSAMPLE* rowptr = (JSAMPLE*)srcRow; 451 JSAMPLE* rowptr = (JSAMPLE*)srcRow;
381 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 452 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
(...skipping 17 matching lines...) Expand all
399 if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { 470 if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
400 return return_false(cinfo, *bm, "skip rows"); 471 return return_false(cinfo, *bm, "skip rows");
401 } 472 }
402 } 473 }
403 474
404 // we formally skip the rest, so we don't get a complaint from libjpeg 475 // we formally skip the rest, so we don't get a complaint from libjpeg
405 if (!skip_src_rows(&cinfo, srcRow, 476 if (!skip_src_rows(&cinfo, srcRow,
406 cinfo.output_height - cinfo.output_scanline)) { 477 cinfo.output_height - cinfo.output_scanline)) {
407 return return_false(cinfo, *bm, "skip rows"); 478 return return_false(cinfo, *bm, "skip rows");
408 } 479 }
480 if (reuseBitmap) {
481 bm->notifyPixelsChanged();
482 }
409 jpeg_finish_decompress(&cinfo); 483 jpeg_finish_decompress(&cinfo);
410 484
411 // SkDebugf("------------------- bm2 size %d [%d %d] %d\n", bm->getSize(), bm ->width(), bm->height(), bm->config());
412 return true; 485 return true;
413 } 486 }
414 487
488 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
489 bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *hei ght) {
490
491 SkJPEGImageIndex* imageIndex = SkNEW_ARGS(SkJPEGImageIndex, (stream, this));
492 jpeg_decompress_struct* cinfo = imageIndex->cinfo();
493 huffman_index* huffmanIndex = imageIndex->huffmanIndex();
494
495 skjpeg_error_mgr sk_err;
496 cinfo->err = jpeg_std_error(&sk_err);
497 sk_err.error_exit = skjpeg_error_exit;
498
499 // All objects need to be instantiated before this setjmp call so that
500 // they will be cleaned up properly if an error occurs.
501 if (setjmp(sk_err.fJmpBuf)) {
502 return false;
503 }
504
505 // create the cinfo used to create/build the huffmanIndex
506 imageIndex->initializeInfo();
507 cinfo->do_fancy_upsampling = 0;
508 cinfo->do_block_smoothing = 0;
509
510 int status = jpeg_read_header(cinfo, true);
511 if (JPEG_HEADER_OK != status) {
512 SkDELETE(imageIndex);
513 return false;
514 }
515
516 jpeg_create_huffman_index(cinfo, huffmanIndex);
517 cinfo->scale_num = 1;
518 cinfo->scale_denom = 1;
519 if (!jpeg_build_huffman_index(cinfo, huffmanIndex)) {
520 SkDELETE(imageIndex);
521 return false;
522 }
523
524 // destroy the cinfo used to create/build the huffman index
525 jpeg_destroy_decompress(cinfo);
526
527 // Init decoder to image decode mode
528 imageIndex->initializeInfo();
529
530 status = jpeg_read_header(cinfo, true);
531 if (JPEG_HEADER_OK != status) {
532 SkDELETE(imageIndex);
533 return false;
534 }
535
536 cinfo->out_color_space = JCS_RGBA_8888;
537 cinfo->do_fancy_upsampling = 0;
538 cinfo->do_block_smoothing = 0;
539
540 // instead of jpeg_start_decompress() we start a tiled decompress
541 jpeg_start_tile_decompress(cinfo);
542
543 cinfo->scale_num = 1;
544 *height = cinfo->output_height;
545 *width = cinfo->output_width;
546 fImageWidth = *width;
547 fImageHeight = *height;
548
549 SkDELETE(fImageIndex);
550 fImageIndex = imageIndex;
551
552 return true;
553 }
554
555 bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, const SkIRect& region) {
556 if (NULL == fImageIndex) {
557 return false;
558 }
559 jpeg_decompress_struct* cinfo = fImageIndex->cinfo();
560
561 SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight);
562 if (!rect.intersect(region)) {
563 // If the requested region is entirely outside the image return false
564 return false;
565 }
566
567
568 skjpeg_error_mgr errorManager;
569 cinfo->err = jpeg_std_error(&errorManager);
570 errorManager.error_exit = skjpeg_error_exit;
571 if (setjmp(errorManager.fJmpBuf)) {
572 return false;
573 }
574
575 int requestedSampleSize = this->getSampleSize();
576 cinfo->scale_denom = requestedSampleSize;
577
578 if (this->getPreferQualityOverSpeed()) {
579 cinfo->dct_method = JDCT_ISLOW;
580 } else {
581 cinfo->dct_method = JDCT_IFAST;
582 }
583
584 SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
585 if (config != SkBitmap::kARGB_8888_Config &&
586 config != SkBitmap::kARGB_4444_Config &&
587 config != SkBitmap::kRGB_565_Config) {
588 config = SkBitmap::kARGB_8888_Config;
589 }
590
591 /* default format is RGB */
592 cinfo->out_color_space = JCS_RGB;
593
594 #ifdef ANDROID_RGB
595 cinfo->dither_mode = JDITHER_NONE;
596 if (SkBitmap::kARGB_8888_Config == config) {
597 cinfo->out_color_space = JCS_RGBA_8888;
598 } else if (SkBitmap::kRGB_565_Config == config) {
599 cinfo->out_color_space = JCS_RGB_565;
600 if (this->getDitherImage()) {
601 cinfo->dither_mode = JDITHER_ORDERED;
602 }
603 }
604 #endif
605
606 int startX = rect.fLeft;
607 int startY = rect.fTop;
608 int width = rect.width();
609 int height = rect.height();
610
611 jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(),
612 &startX, &startY, &width, &height);
613 int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
614 int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_siz e);
615
616 SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
617
618 SkBitmap bitmap;
619 bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
620 bitmap.setIsOpaque(true);
621
622 // Check ahead of time if the swap(dest, src) is possible or not.
623 // If yes, then we will stick to AllocPixelRef since it's cheaper with the
624 // swap happening. If no, then we will use alloc to allocate pixels to
625 // prevent garbage collection.
626 int w = rect.width() / actualSampleSize;
627 int h = rect.height() / actualSampleSize;
628 bool swapOnly = (rect == region) && bm->isNull() &&
629 (w == bitmap.width()) && (h == bitmap.height()) &&
630 ((startX - rect.x()) / actualSampleSize == 0) &&
631 ((startY - rect.y()) / actualSampleSize == 0);
632 if (swapOnly) {
633 if (!this->allocPixelRef(&bitmap, NULL)) {
634 return return_false(*cinfo, bitmap, "allocPixelRef");
635 }
636 } else {
637 if (!bitmap.allocPixels()) {
638 return return_false(*cinfo, bitmap, "allocPixels");
639 }
640 }
641
642 SkAutoLockPixels alp(bitmap);
643
644 #ifdef ANDROID_RGB
645 /* short-circuit the SkScaledBitmapSampler when possible, as this gives
646 a significant performance boost.
647 */
648 if (skiaSampleSize == 1 &&
649 ((config == SkBitmap::kARGB_8888_Config &&
650 cinfo->out_color_space == JCS_RGBA_8888) ||
651 (config == SkBitmap::kRGB_565_Config &&
652 cinfo->out_color_space == JCS_RGB_565)))
653 {
654 JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels();
655 INT32 const bpr = bitmap.rowBytes();
656 int rowTotalCount = 0;
657
658 while (rowTotalCount < height) {
659 int rowCount = jpeg_read_tile_scanline(cinfo,
660 fImageIndex->huffmanIndex(),
661 &rowptr);
662 // if row_count == 0, then we didn't get a scanline, so abort.
663 // if we supported partial images, we might return true in this case
664 if (0 == rowCount) {
665 return return_false(*cinfo, bitmap, "read_scanlines");
666 }
667 if (this->shouldCancelDecode()) {
668 return return_false(*cinfo, bitmap, "shouldCancelDecode");
669 }
670 rowTotalCount += rowCount;
671 rowptr += bpr;
672 }
673
674 if (swapOnly) {
675 bm->swap(bitmap);
676 } else {
677 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
678 region.width(), region.height(), startX, startY);
679 }
680 return true;
681 }
682 #endif
683
684 // check for supported formats
685 SkScaledBitmapSampler::SrcConfig sc;
686 if (JCS_CMYK == cinfo->out_color_space) {
687 // In this case we will manually convert the CMYK values to RGB
688 sc = SkScaledBitmapSampler::kRGBX;
689 } else if (3 == cinfo->out_color_components && JCS_RGB == cinfo->out_color_s pace) {
690 sc = SkScaledBitmapSampler::kRGB;
691 #ifdef ANDROID_RGB
692 } else if (JCS_RGBA_8888 == cinfo->out_color_space) {
693 sc = SkScaledBitmapSampler::kRGBX;
694 } else if (JCS_RGB_565 == cinfo->out_color_space) {
695 sc = SkScaledBitmapSampler::kRGB_565;
696 #endif
697 } else if (1 == cinfo->out_color_components &&
698 JCS_GRAYSCALE == cinfo->out_color_space) {
699 sc = SkScaledBitmapSampler::kGray;
700 } else {
701 return return_false(*cinfo, *bm, "jpeg colorspace");
702 }
703
704 if (!sampler.begin(&bitmap, sc, this->getDitherImage())) {
705 return return_false(*cinfo, bitmap, "sampler.begin");
706 }
707
708 // The CMYK work-around relies on 4 components per pixel here
709 SkAutoMalloc srcStorage(width * 4);
710 uint8_t* srcRow = (uint8_t*)srcStorage.get();
711
712 // Possibly skip initial rows [sampler.srcY0]
713 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler. srcY0())) {
714 return return_false(*cinfo, bitmap, "skip rows");
715 }
716
717 // now loop through scanlines until y == bitmap->height() - 1
718 for (int y = 0;; y++) {
719 JSAMPLE* rowptr = (JSAMPLE*)srcRow;
720 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex (), &rowptr);
721 if (0 == row_count) {
722 return return_false(*cinfo, bitmap, "read_scanlines");
723 }
724 if (this->shouldCancelDecode()) {
725 return return_false(*cinfo, bitmap, "shouldCancelDecode");
726 }
727
728 if (JCS_CMYK == cinfo->out_color_space) {
729 convert_CMYK_to_RGB(srcRow, width);
730 }
731
732 sampler.next(srcRow);
733 if (bitmap.height() - 1 == y) {
734 // we're done
735 break;
736 }
737
738 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow,
739 sampler.srcDY() - 1)) {
740 return return_false(*cinfo, bitmap, "skip rows");
741 }
742 }
743 if (swapOnly) {
744 bm->swap(bitmap);
745 } else {
746 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
747 region.width(), region.height(), startX, startY);
748 }
749 return true;
750 }
751 #endif
752
415 /////////////////////////////////////////////////////////////////////////////// 753 ///////////////////////////////////////////////////////////////////////////////
416 754
417 #include "SkColorPriv.h" 755 #include "SkColorPriv.h"
418 756
419 // taken from jcolor.c in libjpeg 757 // taken from jcolor.c in libjpeg
420 #if 0 // 16bit - precise but slow 758 #if 0 // 16bit - precise but slow
421 #define CYR 19595 // 0.299 759 #define CYR 19595 // 0.299
422 #define CYG 38470 // 0.587 760 #define CYG 38470 // 0.587
423 #define CYB 7471 // 0.114 761 #define CYB 7471 // 0.114
424 762
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
575 return Write_Index_YUV; 913 return Write_Index_YUV;
576 default: 914 default:
577 return NULL; 915 return NULL;
578 } 916 }
579 } 917 }
580 918
581 class SkJPEGImageEncoder : public SkImageEncoder { 919 class SkJPEGImageEncoder : public SkImageEncoder {
582 protected: 920 protected:
583 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { 921 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
584 #ifdef TIME_ENCODE 922 #ifdef TIME_ENCODE
585 AutoTimeMillis atm("JPEG Encode"); 923 SkAutoTime atm("JPEG Encode");
586 #endif 924 #endif
587 925
588 const WriteScanline writer = ChooseWriter(bm); 926 const WriteScanline writer = ChooseWriter(bm);
589 if (NULL == writer) { 927 if (NULL == writer) {
590 return false; 928 return false;
591 } 929 }
592 930
593 SkAutoLockPixels alp(bm); 931 SkAutoLockPixels alp(bm);
594 if (NULL == bm.getPixels()) { 932 if (NULL == bm.getPixels()) {
595 return false; 933 return false;
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
672 return SkNEW(SkJPEGImageDecoder); 1010 return SkNEW(SkJPEGImageDecoder);
673 } 1011 }
674 1012
675 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { 1013 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
676 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; 1014 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
677 } 1015 }
678 1016
679 1017
680 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory); 1018 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory);
681 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efact ory); 1019 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efact ory);
OLDNEW
« no previous file with comments | « include/images/SkJpegUtility.h ('k') | src/images/SkJpegUtility.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698