OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2007 The Android Open Source Project | 2 * Copyright 2007 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 | 8 |
9 #include "SkImageDecoder.h" | 9 #include "SkImageDecoder.h" |
10 #include "SkImageEncoder.h" | 10 #include "SkImageEncoder.h" |
(...skipping 12 matching lines...) Expand all Loading... |
23 extern "C" { | 23 extern "C" { |
24 #include "jpeglib.h" | 24 #include "jpeglib.h" |
25 #include "jerror.h" | 25 #include "jerror.h" |
26 } | 26 } |
27 | 27 |
28 // These enable timing code that report milliseconds for an encoding/decoding | 28 // These enable timing code that report milliseconds for an encoding/decoding |
29 //#define TIME_ENCODE | 29 //#define TIME_ENCODE |
30 //#define TIME_DECODE | 30 //#define TIME_DECODE |
31 | 31 |
32 // this enables our rgb->yuv code, which is faster than libjpeg on ARM | 32 // this enables our rgb->yuv code, which is faster than libjpeg on ARM |
33 // disable for the moment, as we have some glitches when width != multiple of 4 | |
34 #define WE_CONVERT_TO_YUV | 33 #define WE_CONVERT_TO_YUV |
35 | 34 |
36 // If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offer
s | 35 // If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offer
s |
37 // support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565. | 36 // support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565. |
38 | 37 |
39 ////////////////////////////////////////////////////////////////////////// | 38 ////////////////////////////////////////////////////////////////////////// |
40 ////////////////////////////////////////////////////////////////////////// | 39 ////////////////////////////////////////////////////////////////////////// |
41 | 40 |
42 static void overwrite_mem_buffer_size(j_decompress_ptr cinfo) { | 41 static void overwrite_mem_buffer_size(jpeg_decompress_struct* cinfo) { |
43 #ifdef SK_BUILD_FOR_ANDROID | 42 #ifdef SK_BUILD_FOR_ANDROID |
44 /* Check if the device indicates that it has a large amount of system memory | 43 /* Check if the device indicates that it has a large amount of system memory |
45 * if so, increase the memory allocation to 30MB instead of the default 5MB. | 44 * if so, increase the memory allocation to 30MB instead of the default 5MB. |
46 */ | 45 */ |
47 #ifdef ANDROID_LARGE_MEMORY_DEVICE | 46 #ifdef ANDROID_LARGE_MEMORY_DEVICE |
48 cinfo->mem->max_memory_to_use = 30 * 1024 * 1024; | 47 cinfo->mem->max_memory_to_use = 30 * 1024 * 1024; |
49 #else | 48 #else |
50 cinfo->mem->max_memory_to_use = 5 * 1024 * 1024; | 49 cinfo->mem->max_memory_to_use = 5 * 1024 * 1024; |
51 #endif | 50 #endif |
52 #endif // SK_BUILD_FOR_ANDROID | 51 #endif // SK_BUILD_FOR_ANDROID |
53 } | 52 } |
54 | 53 |
55 ////////////////////////////////////////////////////////////////////////// | 54 ////////////////////////////////////////////////////////////////////////// |
56 ////////////////////////////////////////////////////////////////////////// | 55 ////////////////////////////////////////////////////////////////////////// |
57 | 56 |
| 57 static void initialize_info(jpeg_decompress_struct* cinfo, skjpeg_source_mgr* sr
c_mgr) { |
| 58 SkASSERT(cinfo != NULL); |
| 59 SkASSERT(src_mgr != NULL); |
| 60 jpeg_create_decompress(cinfo); |
| 61 overwrite_mem_buffer_size(cinfo); |
| 62 cinfo->src = src_mgr; |
| 63 } |
| 64 |
58 #ifdef SK_BUILD_FOR_ANDROID | 65 #ifdef SK_BUILD_FOR_ANDROID |
59 class SkJPEGImageIndex { | 66 class SkJPEGImageIndex { |
60 public: | 67 public: |
61 SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder) | 68 SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder) |
62 : fSrcMgr(stream, decoder) | 69 : fSrcMgr(stream, decoder) |
63 , fInfoInitialized(false) | 70 , fInfoInitialized(false) |
64 , fHuffmanCreated(false) | 71 , fHuffmanCreated(false) |
65 , fDecompressStarted(false) | 72 , fDecompressStarted(false) |
66 { | 73 { |
67 SkDEBUGCODE(fReadHeaderSucceeded = false;) | 74 SkDEBUGCODE(fReadHeaderSucceeded = false;) |
68 } | 75 } |
69 | 76 |
70 ~SkJPEGImageIndex() { | 77 ~SkJPEGImageIndex() { |
71 if (fHuffmanCreated) { | 78 if (fHuffmanCreated) { |
| 79 // Set to false before calling the libjpeg function, in case |
| 80 // the libjpeg function calls longjmp. Our setjmp handler may |
| 81 // attempt to delete this SkJPEGImageIndex, thus entering this |
| 82 // destructor again. Setting fHuffmanCreated to false first |
| 83 // prevents an infinite loop. |
72 fHuffmanCreated = false; | 84 fHuffmanCreated = false; |
73 jpeg_destroy_huffman_index(&fHuffmanIndex); | 85 jpeg_destroy_huffman_index(&fHuffmanIndex); |
74 } | 86 } |
75 if (fDecompressStarted) { | 87 if (fDecompressStarted) { |
| 88 // Like fHuffmanCreated, set to false before calling libjpeg |
| 89 // function to prevent potential infinite loop. |
76 fDecompressStarted = false; | 90 fDecompressStarted = false; |
77 jpeg_finish_decompress(&fCInfo); | 91 jpeg_finish_decompress(&fCInfo); |
78 } | 92 } |
79 if (fInfoInitialized) { | 93 if (fInfoInitialized) { |
80 this->destroyInfo(); | 94 this->destroyInfo(); |
81 } | 95 } |
82 } | 96 } |
83 | 97 |
84 /** | 98 /** |
85 * Destroy the cinfo struct. | 99 * Destroy the cinfo struct. |
86 * After this call, if a huffman index was already built, it | 100 * After this call, if a huffman index was already built, it |
87 * can be used after calling initializeInfoAndReadHeader | 101 * can be used after calling initializeInfoAndReadHeader |
88 * again. Must not be called after startTileDecompress except | 102 * again. Must not be called after startTileDecompress except |
89 * in the destructor. | 103 * in the destructor. |
90 */ | 104 */ |
91 void destroyInfo() { | 105 void destroyInfo() { |
92 SkASSERT(fInfoInitialized); | 106 SkASSERT(fInfoInitialized); |
93 SkASSERT(!fDecompressStarted); | 107 SkASSERT(!fDecompressStarted); |
| 108 // Like fHuffmanCreated, set to false before calling libjpeg |
| 109 // function to prevent potential infinite loop. |
94 fInfoInitialized = false; | 110 fInfoInitialized = false; |
95 jpeg_destroy_decompress(&fCInfo); | 111 jpeg_destroy_decompress(&fCInfo); |
96 SkDEBUGCODE(fReadHeaderSucceeded = false;) | 112 SkDEBUGCODE(fReadHeaderSucceeded = false;) |
97 } | 113 } |
98 | 114 |
99 /** | 115 /** |
100 * Initialize the cinfo struct. | 116 * Initialize the cinfo struct. |
101 * Calls jpeg_create_decompress, makes customizations, and | 117 * Calls jpeg_create_decompress, makes customizations, and |
102 * finally calls jpeg_read_header. Returns true if jpeg_read_header | 118 * finally calls jpeg_read_header. Returns true if jpeg_read_header |
103 * returns JPEG_HEADER_OK. | 119 * returns JPEG_HEADER_OK. |
104 * If cinfo was already initialized, destroyInfo must be called to | 120 * If cinfo was already initialized, destroyInfo must be called to |
105 * destroy the old one. Must not be called after startTileDecompress. | 121 * destroy the old one. Must not be called after startTileDecompress. |
106 */ | 122 */ |
107 bool initializeInfoAndReadHeader() { | 123 bool initializeInfoAndReadHeader() { |
108 SkASSERT(!fInfoInitialized && !fDecompressStarted); | 124 SkASSERT(!fInfoInitialized && !fDecompressStarted); |
109 jpeg_create_decompress(&fCInfo); | 125 initialize_info(&fCInfo, &fSrcMgr); |
110 overwrite_mem_buffer_size(&fCInfo); | |
111 fCInfo.src = &fSrcMgr; | |
112 fInfoInitialized = true; | 126 fInfoInitialized = true; |
113 const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true))
; | 127 const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true))
; |
114 SkDEBUGCODE(fReadHeaderSucceeded = success;) | 128 SkDEBUGCODE(fReadHeaderSucceeded = success;) |
115 return success; | 129 return success; |
116 } | 130 } |
117 | 131 |
118 jpeg_decompress_struct* cinfo() { return &fCInfo; } | 132 jpeg_decompress_struct* cinfo() { return &fCInfo; } |
119 | 133 |
120 huffman_index* huffmanIndex() { return &fHuffmanIndex; } | 134 huffman_index* huffmanIndex() { return &fHuffmanIndex; } |
121 | 135 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 #endif | 200 #endif |
187 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; | 201 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; |
188 | 202 |
189 private: | 203 private: |
190 #ifdef SK_BUILD_FOR_ANDROID | 204 #ifdef SK_BUILD_FOR_ANDROID |
191 SkJPEGImageIndex* fImageIndex; | 205 SkJPEGImageIndex* fImageIndex; |
192 int fImageWidth; | 206 int fImageWidth; |
193 int fImageHeight; | 207 int fImageHeight; |
194 #endif | 208 #endif |
195 | 209 |
| 210 /** |
| 211 * Determine the appropriate bitmap config and out_color_space based on |
| 212 * both the preference of the caller and the jpeg_color_space on the |
| 213 * jpeg_decompress_struct passed in. |
| 214 * Must be called after jpeg_read_header. |
| 215 */ |
| 216 SkBitmap::Config getBitmapConfig(jpeg_decompress_struct*); |
| 217 |
196 typedef SkImageDecoder INHERITED; | 218 typedef SkImageDecoder INHERITED; |
197 }; | 219 }; |
198 | 220 |
199 ////////////////////////////////////////////////////////////////////////// | 221 ////////////////////////////////////////////////////////////////////////// |
200 | 222 |
201 /* Automatically clean up after throwing an exception */ | 223 /* Automatically clean up after throwing an exception */ |
202 class JPEGAutoClean { | 224 class JPEGAutoClean { |
203 public: | 225 public: |
204 JPEGAutoClean(): cinfo_ptr(NULL) {} | 226 JPEGAutoClean(): cinfo_ptr(NULL) {} |
205 ~JPEGAutoClean() { | 227 ~JPEGAutoClean() { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K | 310 // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K |
289 // The conversion from CMY->RGB remains the same | 311 // The conversion from CMY->RGB remains the same |
290 for (unsigned int x = 0; x < width; ++x, scanline += 4) { | 312 for (unsigned int x = 0; x < width; ++x, scanline += 4) { |
291 scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]); | 313 scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]); |
292 scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]); | 314 scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]); |
293 scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]); | 315 scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]); |
294 scanline[3] = 255; | 316 scanline[3] = 255; |
295 } | 317 } |
296 } | 318 } |
297 | 319 |
| 320 /** |
| 321 * Common code for setting the error manager. |
| 322 */ |
| 323 static void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* error
Manager) { |
| 324 SkASSERT(cinfo != NULL); |
| 325 SkASSERT(errorManager != NULL); |
| 326 cinfo->err = jpeg_std_error(errorManager); |
| 327 errorManager->error_exit = skjpeg_error_exit; |
| 328 } |
| 329 |
| 330 /** |
| 331 * Common code for turning off upsampling and smoothing. Turning these |
| 332 * off helps performance without showing noticable differences in the |
| 333 * resulting bitmap. |
| 334 */ |
| 335 static void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) { |
| 336 SkASSERT(cinfo != NULL); |
| 337 /* this gives about 30% performance improvement. In theory it may |
| 338 reduce the visual quality, in practice I'm not seeing a difference |
| 339 */ |
| 340 cinfo->do_fancy_upsampling = 0; |
| 341 |
| 342 /* this gives another few percents */ |
| 343 cinfo->do_block_smoothing = 0; |
| 344 } |
| 345 |
| 346 /** |
| 347 * Common code for setting the dct method. |
| 348 */ |
| 349 static void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct
* cinfo) { |
| 350 SkASSERT(cinfo != NULL); |
| 351 #ifdef DCT_IFAST_SUPPORTED |
| 352 if (decoder.getPreferQualityOverSpeed()) { |
| 353 cinfo->dct_method = JDCT_ISLOW; |
| 354 } else { |
| 355 cinfo->dct_method = JDCT_IFAST; |
| 356 } |
| 357 #else |
| 358 cinfo->dct_method = JDCT_ISLOW; |
| 359 #endif |
| 360 } |
| 361 |
| 362 SkBitmap::Config SkJPEGImageDecoder::getBitmapConfig(jpeg_decompress_struct* cin
fo) { |
| 363 SkASSERT(cinfo != NULL); |
| 364 |
| 365 SrcDepth srcDepth = k32Bit_SrcDepth; |
| 366 if (JCS_GRAYSCALE == cinfo->jpeg_color_space) { |
| 367 srcDepth = k8BitGray_SrcDepth; |
| 368 } |
| 369 |
| 370 SkBitmap::Config config = this->getPrefConfig(srcDepth, /*hasAlpha*/ false); |
| 371 switch (config) { |
| 372 case SkBitmap::kA8_Config: |
| 373 // Only respect A8 config if the original is grayscale, |
| 374 // in which case we will treat the grayscale as alpha |
| 375 // values. |
| 376 if (cinfo->jpeg_color_space != JCS_GRAYSCALE) { |
| 377 config = SkBitmap::kARGB_8888_Config; |
| 378 } |
| 379 break; |
| 380 case SkBitmap::kARGB_8888_Config: |
| 381 // Fall through. |
| 382 case SkBitmap::kARGB_4444_Config: |
| 383 // Fall through. |
| 384 case SkBitmap::kRGB_565_Config: |
| 385 // These are acceptable destination configs. |
| 386 break; |
| 387 default: |
| 388 // Force all other configs to 8888. |
| 389 config = SkBitmap::kARGB_8888_Config; |
| 390 break; |
| 391 } |
| 392 |
| 393 switch (cinfo->jpeg_color_space) { |
| 394 case JCS_CMYK: |
| 395 // Fall through. |
| 396 case JCS_YCCK: |
| 397 // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up |
| 398 // so libjpeg will give us CMYK samples back and we will later |
| 399 // manually convert them to RGB |
| 400 cinfo->out_color_space = JCS_CMYK; |
| 401 break; |
| 402 case JCS_GRAYSCALE: |
| 403 if (SkBitmap::kA8_Config == config) { |
| 404 cinfo->out_color_space = JCS_GRAYSCALE; |
| 405 break; |
| 406 } |
| 407 // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB |
| 408 // config. Fall through to set to the default. |
| 409 default: |
| 410 cinfo->out_color_space = JCS_RGB; |
| 411 break; |
| 412 } |
| 413 return config; |
| 414 } |
| 415 |
| 416 #ifdef ANDROID_RGB |
| 417 /** |
| 418 * Based on the config and dither mode, adjust out_color_space and |
| 419 * dither_mode of cinfo. |
| 420 */ |
| 421 static void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo, |
| 422 SkBitmap::Config config, |
| 423 const SkImageDecoder& decoder) { |
| 424 SkASSERT(cinfo != NULL); |
| 425 cinfo->dither_mode = JDITHER_NONE; |
| 426 if (JCS_CMYK == cinfo->out_color_space) { |
| 427 return; |
| 428 } |
| 429 switch(config) { |
| 430 case SkBitmap::kARGB_8888_Config: |
| 431 cinfo->out_color_space = JCS_RGBA_8888; |
| 432 break; |
| 433 case SkBitmap::kRGB_565_Config: |
| 434 cinfo->out_color_space = JCS_RGB_565; |
| 435 if (decoder.getDitherImage()) { |
| 436 cinfo->dither_mode = JDITHER_ORDERED; |
| 437 } |
| 438 break; |
| 439 default: |
| 440 break; |
| 441 } |
| 442 } |
| 443 #endif |
| 444 |
298 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { | 445 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
299 #ifdef TIME_DECODE | 446 #ifdef TIME_DECODE |
300 SkAutoTime atm("JPEG Decode"); | 447 SkAutoTime atm("JPEG Decode"); |
301 #endif | 448 #endif |
302 | 449 |
303 JPEGAutoClean autoClean; | 450 JPEGAutoClean autoClean; |
304 | 451 |
305 jpeg_decompress_struct cinfo; | 452 jpeg_decompress_struct cinfo; |
306 skjpeg_error_mgr errorManager; | |
307 skjpeg_source_mgr srcManager(stream, this); | 453 skjpeg_source_mgr srcManager(stream, this); |
308 | 454 |
309 cinfo.err = jpeg_std_error(&errorManager); | 455 skjpeg_error_mgr errorManager; |
310 errorManager.error_exit = skjpeg_error_exit; | 456 set_error_mgr(&cinfo, &errorManager); |
311 | 457 |
312 // All objects need to be instantiated before this setjmp call so that | 458 // All objects need to be instantiated before this setjmp call so that |
313 // they will be cleaned up properly if an error occurs. | 459 // they will be cleaned up properly if an error occurs. |
314 if (setjmp(errorManager.fJmpBuf)) { | 460 if (setjmp(errorManager.fJmpBuf)) { |
315 return return_false(cinfo, *bm, "setjmp"); | 461 return return_false(cinfo, *bm, "setjmp"); |
316 } | 462 } |
317 | 463 |
318 jpeg_create_decompress(&cinfo); | 464 initialize_info(&cinfo, &srcManager); |
319 autoClean.set(&cinfo); | 465 autoClean.set(&cinfo); |
320 | 466 |
321 overwrite_mem_buffer_size(&cinfo); | |
322 | |
323 //jpeg_stdio_src(&cinfo, file); | |
324 cinfo.src = &srcManager; | |
325 | |
326 int status = jpeg_read_header(&cinfo, true); | 467 int status = jpeg_read_header(&cinfo, true); |
327 if (status != JPEG_HEADER_OK) { | 468 if (status != JPEG_HEADER_OK) { |
328 return return_false(cinfo, *bm, "read_header"); | 469 return return_false(cinfo, *bm, "read_header"); |
329 } | 470 } |
330 | 471 |
331 /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it | 472 /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it |
332 can) much faster that we, just use their num/denom api to approximate | 473 can) much faster that we, just use their num/denom api to approximate |
333 the size. | 474 the size. |
334 */ | 475 */ |
335 int sampleSize = this->getSampleSize(); | 476 int sampleSize = this->getSampleSize(); |
336 | 477 |
337 #ifdef DCT_IFAST_SUPPORTED | 478 set_dct_method(*this, &cinfo); |
338 if (this->getPreferQualityOverSpeed()) { | |
339 cinfo.dct_method = JDCT_ISLOW; | |
340 } else { | |
341 cinfo.dct_method = JDCT_IFAST; | |
342 } | |
343 #else | |
344 cinfo.dct_method = JDCT_ISLOW; | |
345 #endif | |
346 | 479 |
347 cinfo.scale_num = 1; | 480 SkASSERT(1 == cinfo.scale_num); |
348 cinfo.scale_denom = sampleSize; | 481 cinfo.scale_denom = sampleSize; |
349 | 482 |
350 /* this gives about 30% performance improvement. In theory it may | 483 turn_off_visual_optimizations(&cinfo); |
351 reduce the visual quality, in practice I'm not seeing a difference | |
352 */ | |
353 cinfo.do_fancy_upsampling = 0; | |
354 | 484 |
355 /* this gives another few percents */ | 485 const SkBitmap::Config config = this->getBitmapConfig(&cinfo); |
356 cinfo.do_block_smoothing = 0; | |
357 | |
358 SrcDepth srcDepth = k32Bit_SrcDepth; | |
359 /* default format is RGB */ | |
360 if (cinfo.jpeg_color_space == JCS_CMYK) { | |
361 // libjpeg cannot convert from CMYK to RGB - here we set up | |
362 // so libjpeg will give us CMYK samples back and we will | |
363 // later manually convert them to RGB | |
364 cinfo.out_color_space = JCS_CMYK; | |
365 } else if (cinfo.jpeg_color_space == JCS_GRAYSCALE) { | |
366 cinfo.out_color_space = JCS_GRAYSCALE; | |
367 srcDepth = k8BitGray_SrcDepth; | |
368 } else { | |
369 cinfo.out_color_space = JCS_RGB; | |
370 } | |
371 | |
372 SkBitmap::Config config = this->getPrefConfig(srcDepth, false); | |
373 // only these make sense for jpegs | |
374 if (SkBitmap::kA8_Config == config) { | |
375 if (cinfo.jpeg_color_space != JCS_GRAYSCALE) { | |
376 // Converting from a non grayscale image to A8 is | |
377 // not currently supported. | |
378 config = SkBitmap::kARGB_8888_Config; | |
379 // Change the output from jpeg back to RGB. | |
380 cinfo.out_color_space = JCS_RGB; | |
381 } | |
382 } else if (config != SkBitmap::kARGB_8888_Config && | |
383 config != SkBitmap::kARGB_4444_Config && | |
384 config != SkBitmap::kRGB_565_Config) { | |
385 config = SkBitmap::kARGB_8888_Config; | |
386 } | |
387 | 486 |
388 #ifdef ANDROID_RGB | 487 #ifdef ANDROID_RGB |
389 cinfo.dither_mode = JDITHER_NONE; | 488 adjust_out_color_space_and_dither(&cinfo, config, *this); |
390 if (SkBitmap::kARGB_8888_Config == config && JCS_CMYK != cinfo.out_color_spa
ce) { | |
391 cinfo.out_color_space = JCS_RGBA_8888; | |
392 } else if (SkBitmap::kRGB_565_Config == config && JCS_CMYK != cinfo.out_colo
r_space) { | |
393 cinfo.out_color_space = JCS_RGB_565; | |
394 if (this->getDitherImage()) { | |
395 cinfo.dither_mode = JDITHER_ORDERED; | |
396 } | |
397 } | |
398 #endif | 489 #endif |
399 | 490 |
400 if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) { | 491 if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) { |
401 bm->setConfig(config, cinfo.image_width, cinfo.image_height); | 492 bm->setConfig(config, cinfo.image_width, cinfo.image_height); |
402 bm->setIsOpaque(config != SkBitmap::kA8_Config); | 493 bm->setIsOpaque(config != SkBitmap::kA8_Config); |
403 return true; | 494 return true; |
404 } | 495 } |
405 | 496 |
406 /* image_width and image_height are the original dimensions, available | 497 /* image_width and image_height are the original dimensions, available |
407 after jpeg_read_header(). To see the scaled dimensions, we have to call | 498 after jpeg_read_header(). To see the scaled dimensions, we have to call |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
545 return true; | 636 return true; |
546 } | 637 } |
547 | 638 |
548 #ifdef SK_BUILD_FOR_ANDROID | 639 #ifdef SK_BUILD_FOR_ANDROID |
549 bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *hei
ght) { | 640 bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *hei
ght) { |
550 | 641 |
551 SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (str
eam, this))); | 642 SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (str
eam, this))); |
552 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); | 643 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); |
553 | 644 |
554 skjpeg_error_mgr sk_err; | 645 skjpeg_error_mgr sk_err; |
555 cinfo->err = jpeg_std_error(&sk_err); | 646 set_error_mgr(cinfo, &sk_err); |
556 sk_err.error_exit = skjpeg_error_exit; | |
557 | 647 |
558 // All objects need to be instantiated before this setjmp call so that | 648 // All objects need to be instantiated before this setjmp call so that |
559 // they will be cleaned up properly if an error occurs. | 649 // they will be cleaned up properly if an error occurs. |
560 if (setjmp(sk_err.fJmpBuf)) { | 650 if (setjmp(sk_err.fJmpBuf)) { |
561 return false; | 651 return false; |
562 } | 652 } |
563 | 653 |
564 // create the cinfo used to create/build the huffmanIndex | 654 // create the cinfo used to create/build the huffmanIndex |
565 if (!imageIndex->initializeInfoAndReadHeader()) { | 655 if (!imageIndex->initializeInfoAndReadHeader()) { |
566 return false; | 656 return false; |
567 } | 657 } |
568 | 658 |
569 if (!imageIndex->buildHuffmanIndex()) { | 659 if (!imageIndex->buildHuffmanIndex()) { |
570 return false; | 660 return false; |
571 } | 661 } |
572 | 662 |
573 // destroy the cinfo used to create/build the huffman index | 663 // destroy the cinfo used to create/build the huffman index |
574 imageIndex->destroyInfo(); | 664 imageIndex->destroyInfo(); |
575 | 665 |
576 // Init decoder to image decode mode | 666 // Init decoder to image decode mode |
577 if (!imageIndex->initializeInfoAndReadHeader()) { | 667 if (!imageIndex->initializeInfoAndReadHeader()) { |
578 return false; | 668 return false; |
579 } | 669 } |
580 | 670 |
581 cinfo->out_color_space = JCS_RGBA_8888; | 671 // FIXME: This sets cinfo->out_color_space, which we may change later |
582 cinfo->do_fancy_upsampling = 0; | 672 // based on the config in onDecodeSubset. This should be fine, since |
583 cinfo->do_block_smoothing = 0; | 673 // jpeg_init_read_tile_scanline will check out_color_space again after |
| 674 // that change (when it calls jinit_color_deconverter). |
| 675 (void) this->getBitmapConfig(cinfo); |
| 676 |
| 677 turn_off_visual_optimizations(cinfo); |
584 | 678 |
585 // instead of jpeg_start_decompress() we start a tiled decompress | 679 // instead of jpeg_start_decompress() we start a tiled decompress |
586 if (!imageIndex->startTileDecompress()) { | 680 if (!imageIndex->startTileDecompress()) { |
587 return false; | 681 return false; |
588 } | 682 } |
589 | 683 |
590 SkASSERT(1 == cinfo->scale_num); | 684 SkASSERT(1 == cinfo->scale_num); |
591 *height = cinfo->output_height; | 685 fImageWidth = cinfo->output_width; |
592 *width = cinfo->output_width; | 686 fImageHeight = cinfo->output_height; |
593 fImageWidth = *width; | 687 |
594 fImageHeight = *height; | 688 if (width) { |
| 689 *width = fImageWidth; |
| 690 } |
| 691 if (height) { |
| 692 *height = fImageHeight; |
| 693 } |
595 | 694 |
596 SkDELETE(fImageIndex); | 695 SkDELETE(fImageIndex); |
597 fImageIndex = imageIndex.detach(); | 696 fImageIndex = imageIndex.detach(); |
598 | 697 |
599 return true; | 698 return true; |
600 } | 699 } |
601 | 700 |
602 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { | 701 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { |
603 if (NULL == fImageIndex) { | 702 if (NULL == fImageIndex) { |
604 return false; | 703 return false; |
605 } | 704 } |
606 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); | 705 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); |
607 | 706 |
608 SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); | 707 SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); |
609 if (!rect.intersect(region)) { | 708 if (!rect.intersect(region)) { |
610 // If the requested region is entirely outside the image return false | 709 // If the requested region is entirely outside the image return false |
611 return false; | 710 return false; |
612 } | 711 } |
613 | 712 |
614 | 713 |
615 skjpeg_error_mgr errorManager; | 714 skjpeg_error_mgr errorManager; |
616 cinfo->err = jpeg_std_error(&errorManager); | 715 set_error_mgr(cinfo, &errorManager); |
617 errorManager.error_exit = skjpeg_error_exit; | 716 |
618 if (setjmp(errorManager.fJmpBuf)) { | 717 if (setjmp(errorManager.fJmpBuf)) { |
619 return false; | 718 return false; |
620 } | 719 } |
621 | 720 |
622 int requestedSampleSize = this->getSampleSize(); | 721 int requestedSampleSize = this->getSampleSize(); |
623 cinfo->scale_denom = requestedSampleSize; | 722 cinfo->scale_denom = requestedSampleSize; |
624 | 723 |
625 if (this->getPreferQualityOverSpeed()) { | 724 set_dct_method(*this, cinfo); |
626 cinfo->dct_method = JDCT_ISLOW; | |
627 } else { | |
628 cinfo->dct_method = JDCT_IFAST; | |
629 } | |
630 | 725 |
631 SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false); | 726 const SkBitmap::Config config = this->getBitmapConfig(cinfo); |
632 if (config != SkBitmap::kARGB_8888_Config && | |
633 config != SkBitmap::kARGB_4444_Config && | |
634 config != SkBitmap::kRGB_565_Config) { | |
635 config = SkBitmap::kARGB_8888_Config; | |
636 } | |
637 | |
638 /* default format is RGB */ | |
639 cinfo->out_color_space = JCS_RGB; | |
640 | |
641 #ifdef ANDROID_RGB | 727 #ifdef ANDROID_RGB |
642 cinfo->dither_mode = JDITHER_NONE; | 728 adjust_out_color_space_and_dither(cinfo, config, *this); |
643 if (SkBitmap::kARGB_8888_Config == config) { | |
644 cinfo->out_color_space = JCS_RGBA_8888; | |
645 } else if (SkBitmap::kRGB_565_Config == config) { | |
646 cinfo->out_color_space = JCS_RGB_565; | |
647 if (this->getDitherImage()) { | |
648 cinfo->dither_mode = JDITHER_ORDERED; | |
649 } | |
650 } | |
651 #endif | 729 #endif |
652 | 730 |
653 int startX = rect.fLeft; | 731 int startX = rect.fLeft; |
654 int startY = rect.fTop; | 732 int startY = rect.fTop; |
655 int width = rect.width(); | 733 int width = rect.width(); |
656 int height = rect.height(); | 734 int height = rect.height(); |
657 | 735 |
658 jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), | 736 jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), |
659 &startX, &startY, &width, &height); | 737 &startX, &startY, &width, &height); |
660 int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); | 738 int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); |
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1075 } | 1153 } |
1076 | 1154 |
1077 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 1155 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { |
1078 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; | 1156 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; |
1079 } | 1157 } |
1080 | 1158 |
1081 | 1159 |
1082 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory); | 1160 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory); |
1083 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_jpeg
); | 1161 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_jpeg
); |
1084 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efact
ory); | 1162 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efact
ory); |
OLD | NEW |