Chromium Code Reviews| 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 | 33 // disable for the moment, as we have some glitches when width != multiple of 4 |
|
mtklein
2013/08/05 22:31:09
Off topic, but maybe we should delete this line, g
scroggo
2013/08/06 15:06:27
Done. This line has been here since we imported th
| |
| 34 #define WE_CONVERT_TO_YUV | 34 #define WE_CONVERT_TO_YUV |
| 35 | 35 |
| 36 // If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offer s | 36 // 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. | 37 // support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565. |
| 38 | 38 |
| 39 ////////////////////////////////////////////////////////////////////////// | 39 ////////////////////////////////////////////////////////////////////////// |
| 40 ////////////////////////////////////////////////////////////////////////// | 40 ////////////////////////////////////////////////////////////////////////// |
| 41 | 41 |
| 42 static void overwrite_mem_buffer_size(j_decompress_ptr cinfo) { | 42 static void overwrite_mem_buffer_size(j_decompress_ptr cinfo) { |
|
mtklein
2013/08/05 22:31:09
Is j_decompress_ptr == jpeg_decompress_struct* ?
scroggo
2013/08/06 15:06:27
Yes. This is the only instance of j_decompress_ptr
| |
| 43 #ifdef SK_BUILD_FOR_ANDROID | 43 #ifdef SK_BUILD_FOR_ANDROID |
| 44 /* Check if the device indicates that it has a large amount of system memory | 44 /* 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. | 45 * if so, increase the memory allocation to 30MB instead of the default 5MB. |
| 46 */ | 46 */ |
| 47 #ifdef ANDROID_LARGE_MEMORY_DEVICE | 47 #ifdef ANDROID_LARGE_MEMORY_DEVICE |
| 48 cinfo->mem->max_memory_to_use = 30 * 1024 * 1024; | 48 cinfo->mem->max_memory_to_use = 30 * 1024 * 1024; |
| 49 #else | 49 #else |
| 50 cinfo->mem->max_memory_to_use = 5 * 1024 * 1024; | 50 cinfo->mem->max_memory_to_use = 5 * 1024 * 1024; |
| 51 #endif | 51 #endif |
| 52 #endif // SK_BUILD_FOR_ANDROID | 52 #endif // SK_BUILD_FOR_ANDROID |
| 53 } | 53 } |
| 54 | 54 |
| 55 ////////////////////////////////////////////////////////////////////////// | 55 ////////////////////////////////////////////////////////////////////////// |
| 56 ////////////////////////////////////////////////////////////////////////// | 56 ////////////////////////////////////////////////////////////////////////// |
| 57 | 57 |
| 58 static void initialize_info(jpeg_decompress_struct* cinfo, skjpeg_source_mgr* sr c_mgr) { | |
|
mtklein
2013/08/05 22:31:09
cinfo is a pretty cryptic name. even just decompr
scroggo
2013/08/06 15:06:27
Agreed. Yes, the name is canonical.
| |
| 59 SkASSERT(cinfo != NULL); | |
| 60 SkASSERT(src_mgr != NULL); | |
| 61 jpeg_create_decompress(cinfo); | |
| 62 overwrite_mem_buffer_size(cinfo); | |
| 63 cinfo->src = src_mgr; | |
| 64 } | |
| 65 | |
| 58 #ifdef SK_BUILD_FOR_ANDROID | 66 #ifdef SK_BUILD_FOR_ANDROID |
| 59 class SkJPEGImageIndex { | 67 class SkJPEGImageIndex { |
| 60 public: | 68 public: |
| 61 SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder) | 69 SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder) |
| 62 : fSrcMgr(stream, decoder) | 70 : fSrcMgr(stream, decoder) |
| 63 , fInfoInitialized(false) | 71 , fInfoInitialized(false) |
| 64 , fHuffmanCreated(false) | 72 , fHuffmanCreated(false) |
| 65 , fDecompressStarted(false) | 73 , fDecompressStarted(false) |
| 66 { | 74 { |
| 67 SkDEBUGCODE(fReadHeaderSucceeded = false;) | 75 SkDEBUGCODE(fReadHeaderSucceeded = false;) |
| 68 } | 76 } |
| 69 | 77 |
| 70 ~SkJPEGImageIndex() { | 78 ~SkJPEGImageIndex() { |
|
mtklein
2013/08/05 22:31:09
Can you add a note in here about why we set the fl
scroggo
2013/08/06 15:06:27
Done.
| |
| 71 if (fHuffmanCreated) { | 79 if (fHuffmanCreated) { |
| 72 fHuffmanCreated = false; | 80 fHuffmanCreated = false; |
| 73 jpeg_destroy_huffman_index(&fHuffmanIndex); | 81 jpeg_destroy_huffman_index(&fHuffmanIndex); |
| 74 } | 82 } |
| 75 if (fDecompressStarted) { | 83 if (fDecompressStarted) { |
| 76 fDecompressStarted = false; | 84 fDecompressStarted = false; |
| 77 jpeg_finish_decompress(&fCInfo); | 85 jpeg_finish_decompress(&fCInfo); |
| 78 } | 86 } |
| 79 if (fInfoInitialized) { | 87 if (fInfoInitialized) { |
| 80 this->destroyInfo(); | 88 this->destroyInfo(); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 99 /** | 107 /** |
| 100 * Initialize the cinfo struct. | 108 * Initialize the cinfo struct. |
| 101 * Calls jpeg_create_decompress, makes customizations, and | 109 * Calls jpeg_create_decompress, makes customizations, and |
| 102 * finally calls jpeg_read_header. Returns true if jpeg_read_header | 110 * finally calls jpeg_read_header. Returns true if jpeg_read_header |
| 103 * returns JPEG_HEADER_OK. | 111 * returns JPEG_HEADER_OK. |
| 104 * If cinfo was already initialized, destroyInfo must be called to | 112 * If cinfo was already initialized, destroyInfo must be called to |
| 105 * destroy the old one. Must not be called after startTileDecompress. | 113 * destroy the old one. Must not be called after startTileDecompress. |
| 106 */ | 114 */ |
| 107 bool initializeInfoAndReadHeader() { | 115 bool initializeInfoAndReadHeader() { |
| 108 SkASSERT(!fInfoInitialized && !fDecompressStarted); | 116 SkASSERT(!fInfoInitialized && !fDecompressStarted); |
| 109 jpeg_create_decompress(&fCInfo); | 117 initialize_info(&fCInfo, &fSrcMgr); |
| 110 overwrite_mem_buffer_size(&fCInfo); | |
| 111 fCInfo.src = &fSrcMgr; | |
| 112 fInfoInitialized = true; | 118 fInfoInitialized = true; |
| 113 const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true)) ; | 119 const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true)) ; |
| 114 SkDEBUGCODE(fReadHeaderSucceeded = success;) | 120 SkDEBUGCODE(fReadHeaderSucceeded = success;) |
| 115 return success; | 121 return success; |
| 116 } | 122 } |
| 117 | 123 |
| 118 jpeg_decompress_struct* cinfo() { return &fCInfo; } | 124 jpeg_decompress_struct* cinfo() { return &fCInfo; } |
|
mtklein
2013/08/05 22:31:09
these two guys can be const methods?
scroggo
2013/08/06 15:06:27
No, these are modified and passed to functions tha
mtklein
2013/08/06 15:22:48
just meant
jpeg_decompress_struct* cinfo() const
scroggo
2013/08/06 15:29:46
That gives me the following error:
../../../src/i
| |
| 119 | 125 |
| 120 huffman_index* huffmanIndex() { return &fHuffmanIndex; } | 126 huffman_index* huffmanIndex() { return &fHuffmanIndex; } |
| 121 | 127 |
| 122 /** | 128 /** |
| 123 * Build the index to be used for tile based decoding. | 129 * Build the index to be used for tile based decoding. |
| 124 * Must only be called after a successful call to | 130 * Must only be called after a successful call to |
| 125 * initializeInfoAndReadHeader and must not be called more | 131 * initializeInfoAndReadHeader and must not be called more |
| 126 * than once. | 132 * than once. |
| 127 */ | 133 */ |
| 128 bool buildHuffmanIndex() { | 134 bool buildHuffmanIndex() { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 186 #endif | 192 #endif |
| 187 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; | 193 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; |
| 188 | 194 |
| 189 private: | 195 private: |
| 190 #ifdef SK_BUILD_FOR_ANDROID | 196 #ifdef SK_BUILD_FOR_ANDROID |
| 191 SkJPEGImageIndex* fImageIndex; | 197 SkJPEGImageIndex* fImageIndex; |
| 192 int fImageWidth; | 198 int fImageWidth; |
| 193 int fImageHeight; | 199 int fImageHeight; |
| 194 #endif | 200 #endif |
| 195 | 201 |
| 202 /** | |
| 203 * Determine the appropriate bitmap config and out_color_space based on | |
| 204 * both the preference of the caller and the jpeg_color_space on the | |
| 205 * jpeg_decompress_struct passed in. | |
| 206 * Must be called after jpeg_read_header. | |
| 207 */ | |
| 208 SkBitmap::Config getBitmapConfig(jpeg_decompress_struct*); | |
| 209 | |
| 196 typedef SkImageDecoder INHERITED; | 210 typedef SkImageDecoder INHERITED; |
| 197 }; | 211 }; |
| 198 | 212 |
| 199 ////////////////////////////////////////////////////////////////////////// | 213 ////////////////////////////////////////////////////////////////////////// |
| 200 | 214 |
| 201 /* Automatically clean up after throwing an exception */ | 215 /* Automatically clean up after throwing an exception */ |
| 202 class JPEGAutoClean { | 216 class JPEGAutoClean { |
| 203 public: | 217 public: |
| 204 JPEGAutoClean(): cinfo_ptr(NULL) {} | 218 JPEGAutoClean(): cinfo_ptr(NULL) {} |
| 205 ~JPEGAutoClean() { | 219 ~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 | 302 // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K |
| 289 // The conversion from CMY->RGB remains the same | 303 // The conversion from CMY->RGB remains the same |
| 290 for (unsigned int x = 0; x < width; ++x, scanline += 4) { | 304 for (unsigned int x = 0; x < width; ++x, scanline += 4) { |
| 291 scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]); | 305 scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]); |
| 292 scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]); | 306 scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]); |
| 293 scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]); | 307 scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]); |
| 294 scanline[3] = 255; | 308 scanline[3] = 255; |
| 295 } | 309 } |
| 296 } | 310 } |
| 297 | 311 |
| 312 /** | |
| 313 * Common code for setting the error manager. | |
| 314 */ | |
| 315 static void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* error Manager) { | |
| 316 SkASSERT(cinfo != NULL); | |
| 317 SkASSERT(errorManager != NULL); | |
| 318 cinfo->err = jpeg_std_error(errorManager); | |
| 319 errorManager->error_exit = skjpeg_error_exit; | |
| 320 } | |
| 321 | |
| 322 /** | |
| 323 * Common code for turning off upsampling and smoothing. Turning these | |
| 324 * off helps performance without showing noticable differences in the | |
| 325 * resulting bitmap. | |
| 326 */ | |
| 327 static void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) { | |
| 328 SkASSERT(cinfo != NULL); | |
| 329 /* this gives about 30% performance improvement. In theory it may | |
| 330 reduce the visual quality, in practice I'm not seeing a difference | |
| 331 */ | |
| 332 cinfo->do_fancy_upsampling = 0; | |
| 333 | |
| 334 /* this gives another few percents */ | |
| 335 cinfo->do_block_smoothing = 0; | |
| 336 } | |
| 337 | |
| 338 /** | |
| 339 * Common code for setting the dct method. | |
| 340 */ | |
| 341 static void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct * cinfo) { | |
| 342 SkASSERT(cinfo != NULL); | |
| 343 #ifdef DCT_IFAST_SUPPORTED | |
| 344 if (decoder.getPreferQualityOverSpeed()) { | |
| 345 cinfo->dct_method = JDCT_ISLOW; | |
| 346 } else { | |
| 347 cinfo->dct_method = JDCT_IFAST; | |
| 348 } | |
| 349 #else | |
| 350 cinfo->dct_method = JDCT_ISLOW; | |
| 351 #endif | |
| 352 } | |
| 353 | |
| 354 SkBitmap::Config SkJPEGImageDecoder::getBitmapConfig(jpeg_decompress_struct* cin fo) { | |
|
mtklein
2013/08/05 22:31:09
can we make this guy take a const&?
scroggo
2013/08/06 15:06:27
The Skia style guide states to use a pointer when
mtklein
2013/08/06 15:22:48
Right. It looks to me like it's only being read h
scroggo
2013/08/06 15:29:46
No, the second switch statement will modify it.
| |
| 355 SkASSERT(cinfo != NULL); | |
| 356 | |
| 357 SrcDepth srcDepth = k32Bit_SrcDepth; | |
| 358 if (JCS_GRAYSCALE == cinfo->jpeg_color_space) { | |
| 359 srcDepth = k8BitGray_SrcDepth; | |
| 360 } | |
| 361 | |
| 362 SkBitmap::Config config = this->getPrefConfig(srcDepth, false); | |
|
mtklein
2013/08/05 22:31:09
Would help my reading to add a reminder what the f
scroggo
2013/08/06 15:06:27
Done.
| |
| 363 switch (config) { | |
| 364 case SkBitmap::kA8_Config: | |
| 365 // Only respect A8 config if the original is grayscale, | |
| 366 // in which case we will treat the grayscale as alpha | |
| 367 // values. | |
| 368 if (cinfo->jpeg_color_space != JCS_GRAYSCALE) { | |
| 369 config = SkBitmap::kARGB_8888_Config; | |
| 370 } | |
| 371 break; | |
| 372 case SkBitmap::kARGB_8888_Config: | |
| 373 // Fall through. | |
| 374 case SkBitmap::kARGB_4444_Config: | |
| 375 // Fall through. | |
| 376 case SkBitmap::kRGB_565_Config: | |
| 377 // These are acceptable destination configs. | |
| 378 break; | |
| 379 default: | |
| 380 // Force all other configs to 8888. | |
| 381 config = SkBitmap::kARGB_8888_Config; | |
| 382 } | |
| 383 | |
| 384 switch (cinfo->jpeg_color_space) { | |
| 385 case JCS_CMYK: | |
| 386 // Fall through. | |
| 387 case JCS_YCCK: | |
|
scroggo
2013/08/05 21:47:51
In the old code, JCS_YCCK results in a request for
| |
| 388 // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up | |
| 389 // so libjpeg will give us CMYK samples back and we will later | |
| 390 // manually convert them to RGB | |
| 391 cinfo->out_color_space = JCS_CMYK; | |
| 392 break; | |
| 393 case JCS_GRAYSCALE: | |
| 394 if (SkBitmap::kA8_Config == config) { | |
| 395 cinfo->out_color_space = JCS_GRAYSCALE; | |
| 396 break; | |
| 397 } | |
| 398 // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB | |
| 399 // config. Fall through to set to the default. | |
| 400 default: | |
| 401 cinfo->out_color_space = JCS_RGB; | |
| 402 break; | |
|
mtklein
2013/08/05 22:31:09
just for consistency i'd add a break above or remo
scroggo
2013/08/06 15:06:27
Done.
| |
| 403 } | |
| 404 return config; | |
| 405 } | |
| 406 | |
| 407 #ifdef ANDROID_RGB | |
| 408 /** | |
| 409 * FIXME: Improve this name. Here is what this function does: | |
|
scroggo
2013/08/05 21:47:51
Suggestions?
| |
| 410 * - Set cinfo->dither_mode | |
| 411 * - change the out color space custom color spaces. | |
| 412 */ | |
| 413 static void apply_dither_mode(jpeg_decompress_struct* cinfo, SkBitmap::Config co nfig, | |
|
mtklein
2013/08/05 22:31:09
funky arg indent?
mtklein
2013/08/05 22:31:09
maybe adjustOutColorSpaceForDither?
scroggo
2013/08/06 15:06:27
How about adjust_out_color_space_and_dither?
scroggo
2013/08/06 15:06:27
Done.
| |
| 414 const SkImageDecoder& decoder) { | |
| 415 SkASSERT(cinfo != NULL); | |
| 416 cinfo->dither_mode = JDITHER_NONE; | |
| 417 if (JCS_CMYK == cinfo->out_color_space) { | |
|
scroggo
2013/08/05 21:47:51
This check was not happening in tile based decode.
| |
| 418 return; | |
| 419 } | |
| 420 switch(config) { | |
| 421 case SkBitmap::kARGB_8888_Config: | |
| 422 cinfo->out_color_space = JCS_RGBA_8888; | |
| 423 break; | |
| 424 case SkBitmap::kRGB_565_Config: | |
| 425 cinfo->out_color_space = JCS_RGB_565; | |
| 426 if (decoder.getDitherImage()) { | |
| 427 cinfo->dither_mode = JDITHER_ORDERED; | |
| 428 } | |
| 429 break; | |
| 430 default: | |
| 431 break; | |
| 432 } | |
| 433 } | |
| 434 #endif | |
| 435 | |
| 298 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { | 436 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
| 299 #ifdef TIME_DECODE | 437 #ifdef TIME_DECODE |
| 300 SkAutoTime atm("JPEG Decode"); | 438 SkAutoTime atm("JPEG Decode"); |
| 301 #endif | 439 #endif |
| 302 | 440 |
| 303 JPEGAutoClean autoClean; | 441 JPEGAutoClean autoClean; |
| 304 | 442 |
| 305 jpeg_decompress_struct cinfo; | 443 jpeg_decompress_struct cinfo; |
| 306 skjpeg_error_mgr errorManager; | |
| 307 skjpeg_source_mgr srcManager(stream, this); | 444 skjpeg_source_mgr srcManager(stream, this); |
| 308 | 445 |
| 309 cinfo.err = jpeg_std_error(&errorManager); | 446 skjpeg_error_mgr errorManager; |
| 310 errorManager.error_exit = skjpeg_error_exit; | 447 set_error_mgr(&cinfo, &errorManager); |
| 311 | 448 |
| 312 // All objects need to be instantiated before this setjmp call so that | 449 // All objects need to be instantiated before this setjmp call so that |
| 313 // they will be cleaned up properly if an error occurs. | 450 // they will be cleaned up properly if an error occurs. |
| 314 if (setjmp(errorManager.fJmpBuf)) { | 451 if (setjmp(errorManager.fJmpBuf)) { |
| 315 return return_false(cinfo, *bm, "setjmp"); | 452 return return_false(cinfo, *bm, "setjmp"); |
| 316 } | 453 } |
| 317 | 454 |
| 318 jpeg_create_decompress(&cinfo); | 455 initialize_info(&cinfo, &srcManager); |
| 319 autoClean.set(&cinfo); | 456 autoClean.set(&cinfo); |
| 320 | 457 |
| 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); | 458 int status = jpeg_read_header(&cinfo, true); |
| 327 if (status != JPEG_HEADER_OK) { | 459 if (status != JPEG_HEADER_OK) { |
| 328 return return_false(cinfo, *bm, "read_header"); | 460 return return_false(cinfo, *bm, "read_header"); |
| 329 } | 461 } |
| 330 | 462 |
| 331 /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it | 463 /* 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 | 464 can) much faster that we, just use their num/denom api to approximate |
| 333 the size. | 465 the size. |
| 334 */ | 466 */ |
| 335 int sampleSize = this->getSampleSize(); | 467 int sampleSize = this->getSampleSize(); |
| 336 | 468 |
| 337 #ifdef DCT_IFAST_SUPPORTED | 469 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 | 470 |
| 347 cinfo.scale_num = 1; | |
|
scroggo
2013/08/05 21:47:51
scale_num defaults to 1, so this line is unnecessa
mtklein
2013/08/05 22:31:09
maybe add an assert like in the tiled code?
scroggo
2013/08/06 15:06:27
Done.
| |
| 348 cinfo.scale_denom = sampleSize; | 471 cinfo.scale_denom = sampleSize; |
| 349 | 472 |
| 350 /* this gives about 30% performance improvement. In theory it may | 473 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 | 474 |
| 355 /* this gives another few percents */ | 475 SkBitmap::Config config = this->getBitmapConfig(&cinfo); |
|
mtklein
2013/08/05 22:31:09
const?
scroggo
2013/08/06 15:06:27
Done.
| |
| 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; | |
|
scroggo
2013/08/05 21:47:51
This line would incorrectly change out_color_space
| |
| 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 | 476 |
| 388 #ifdef ANDROID_RGB | 477 #ifdef ANDROID_RGB |
| 389 cinfo.dither_mode = JDITHER_NONE; | 478 apply_dither_mode(&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 | 479 #endif |
| 399 | 480 |
| 400 if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) { | 481 if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) { |
| 401 bm->setConfig(config, cinfo.image_width, cinfo.image_height); | 482 bm->setConfig(config, cinfo.image_width, cinfo.image_height); |
| 402 bm->setIsOpaque(config != SkBitmap::kA8_Config); | 483 bm->setIsOpaque(config != SkBitmap::kA8_Config); |
| 403 return true; | 484 return true; |
| 404 } | 485 } |
| 405 | 486 |
| 406 /* image_width and image_height are the original dimensions, available | 487 /* image_width and image_height are the original dimensions, available |
| 407 after jpeg_read_header(). To see the scaled dimensions, we have to call | 488 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; | 626 return true; |
| 546 } | 627 } |
| 547 | 628 |
| 548 #ifdef SK_BUILD_FOR_ANDROID | 629 #ifdef SK_BUILD_FOR_ANDROID |
| 549 bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *hei ght) { | 630 bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *hei ght) { |
| 550 | 631 |
| 551 SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (str eam, this))); | 632 SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (str eam, this))); |
| 552 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); | 633 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); |
| 553 | 634 |
| 554 skjpeg_error_mgr sk_err; | 635 skjpeg_error_mgr sk_err; |
| 555 cinfo->err = jpeg_std_error(&sk_err); | 636 set_error_mgr(cinfo, &sk_err); |
| 556 sk_err.error_exit = skjpeg_error_exit; | |
| 557 | 637 |
| 558 // All objects need to be instantiated before this setjmp call so that | 638 // All objects need to be instantiated before this setjmp call so that |
| 559 // they will be cleaned up properly if an error occurs. | 639 // they will be cleaned up properly if an error occurs. |
| 560 if (setjmp(sk_err.fJmpBuf)) { | 640 if (setjmp(sk_err.fJmpBuf)) { |
| 561 return false; | 641 return false; |
| 562 } | 642 } |
| 563 | 643 |
| 564 // create the cinfo used to create/build the huffmanIndex | 644 // create the cinfo used to create/build the huffmanIndex |
| 565 if (!imageIndex->initializeInfoAndReadHeader()) { | 645 if (!imageIndex->initializeInfoAndReadHeader()) { |
| 566 return false; | 646 return false; |
| 567 } | 647 } |
| 568 | 648 |
| 569 if (!imageIndex->buildHuffmanIndex()) { | 649 if (!imageIndex->buildHuffmanIndex()) { |
| 570 return false; | 650 return false; |
| 571 } | 651 } |
| 572 | 652 |
| 573 // destroy the cinfo used to create/build the huffman index | 653 // destroy the cinfo used to create/build the huffman index |
| 574 imageIndex->destroyInfo(); | 654 imageIndex->destroyInfo(); |
| 575 | 655 |
| 576 // Init decoder to image decode mode | 656 // Init decoder to image decode mode |
| 577 if (!imageIndex->initializeInfoAndReadHeader()) { | 657 if (!imageIndex->initializeInfoAndReadHeader()) { |
| 578 return false; | 658 return false; |
| 579 } | 659 } |
| 580 | 660 |
| 581 cinfo->out_color_space = JCS_RGBA_8888; | 661 // FIXME: This sets cinfo->out_color_space, which we may change later |
| 582 cinfo->do_fancy_upsampling = 0; | 662 // based on the config in onDecodeSubset. This should be fine, since |
| 583 cinfo->do_block_smoothing = 0; | 663 // jpeg_init_read_tile_scanline will check out_color_space again after |
| 664 // that change (when it calls jinit_color_deconverter). | |
| 665 (void) this->getBitmapConfig(cinfo); | |
| 666 | |
| 667 turn_off_visual_optimizations(cinfo); | |
| 584 | 668 |
| 585 // instead of jpeg_start_decompress() we start a tiled decompress | 669 // instead of jpeg_start_decompress() we start a tiled decompress |
| 586 if (!imageIndex->startTileDecompress()) { | 670 if (!imageIndex->startTileDecompress()) { |
| 587 return false; | 671 return false; |
| 588 } | 672 } |
| 589 | 673 |
| 590 SkASSERT(1 == cinfo->scale_num); | 674 SkASSERT(1 == cinfo->scale_num); |
| 591 *height = cinfo->output_height; | 675 fImageWidth = cinfo->output_width; |
| 592 *width = cinfo->output_width; | 676 fImageHeight = cinfo->output_height; |
| 593 fImageWidth = *width; | 677 |
| 594 fImageHeight = *height; | 678 if (width) { |
| 679 *width = fImageWidth; | |
| 680 } | |
| 681 if (height) { | |
| 682 *height = fImageHeight; | |
| 683 } | |
| 595 | 684 |
| 596 SkDELETE(fImageIndex); | 685 SkDELETE(fImageIndex); |
| 597 fImageIndex = imageIndex.detach(); | 686 fImageIndex = imageIndex.detach(); |
| 598 | 687 |
| 599 return true; | 688 return true; |
| 600 } | 689 } |
| 601 | 690 |
| 602 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { | 691 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { |
| 603 if (NULL == fImageIndex) { | 692 if (NULL == fImageIndex) { |
| 604 return false; | 693 return false; |
| 605 } | 694 } |
| 606 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); | 695 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); |
| 607 | 696 |
| 608 SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); | 697 SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); |
| 609 if (!rect.intersect(region)) { | 698 if (!rect.intersect(region)) { |
| 610 // If the requested region is entirely outside the image return false | 699 // If the requested region is entirely outside the image return false |
| 611 return false; | 700 return false; |
| 612 } | 701 } |
| 613 | 702 |
| 614 | 703 |
| 615 skjpeg_error_mgr errorManager; | 704 skjpeg_error_mgr errorManager; |
| 616 cinfo->err = jpeg_std_error(&errorManager); | 705 set_error_mgr(cinfo, &errorManager); |
| 617 errorManager.error_exit = skjpeg_error_exit; | 706 |
| 618 if (setjmp(errorManager.fJmpBuf)) { | 707 if (setjmp(errorManager.fJmpBuf)) { |
| 619 return false; | 708 return false; |
| 620 } | 709 } |
| 621 | 710 |
| 622 int requestedSampleSize = this->getSampleSize(); | 711 int requestedSampleSize = this->getSampleSize(); |
| 623 cinfo->scale_denom = requestedSampleSize; | 712 cinfo->scale_denom = requestedSampleSize; |
| 624 | 713 |
| 625 if (this->getPreferQualityOverSpeed()) { | 714 set_dct_method(*this, cinfo); |
|
scroggo
2013/08/05 21:47:51
The new method checks #ifdef's where appropraiate.
| |
| 626 cinfo->dct_method = JDCT_ISLOW; | |
| 627 } else { | |
| 628 cinfo->dct_method = JDCT_IFAST; | |
| 629 } | |
| 630 | 715 |
| 631 SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false); | 716 SkBitmap::Config config = this->getBitmapConfig(cinfo); |
|
scroggo
2013/08/05 21:47:51
The new code has the behavior used in onDecode, so
|
mtklein
2013/08/05 22:31:09
const?
scroggo
2013/08/06 15:06:27
Done.
|
| 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; | |
|
scroggo
2013/08/05 21:47:51
Likewise, the new code uses a valid color space.
| |
| 640 | |
| 641 #ifdef ANDROID_RGB | 717 #ifdef ANDROID_RGB |
| 642 cinfo->dither_mode = JDITHER_NONE; | 718 apply_dither_mode(cinfo, config, *this); |
| 643 if (SkBitmap::kARGB_8888_Config == config) { | |
|
scroggo
2013/08/05 21:47:51
The factored out function checks for cmyk.
| |
| 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 | 719 #endif |
| 652 | 720 |
| 653 int startX = rect.fLeft; | 721 int startX = rect.fLeft; |
| 654 int startY = rect.fTop; | 722 int startY = rect.fTop; |
| 655 int width = rect.width(); | 723 int width = rect.width(); |
| 656 int height = rect.height(); | 724 int height = rect.height(); |
| 657 | 725 |
| 658 jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), | 726 jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), |
| 659 &startX, &startY, &width, &height); | 727 &startX, &startY, &width, &height); |
| 660 int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); | 728 int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); |
| (...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1075 } | 1143 } |
| 1076 | 1144 |
| 1077 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 1145 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { |
| 1078 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; | 1146 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; |
| 1079 } | 1147 } |
| 1080 | 1148 |
| 1081 | 1149 |
| 1082 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory); | 1150 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory); |
| 1083 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_jpeg ); | 1151 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_jpeg ); |
| 1084 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efact ory); | 1152 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efact ory); |
| OLD | NEW |