| 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" |
| 11 #include "SkJpegUtility.h" | 11 #include "SkJpegUtility.h" |
| 12 #include "SkColorPriv.h" | 12 #include "SkColorPriv.h" |
| 13 #include "SkDither.h" | 13 #include "SkDither.h" |
| 14 #include "SkScaledBitmapSampler.h" | 14 #include "SkScaledBitmapSampler.h" |
| 15 #include "SkStream.h" | 15 #include "SkStream.h" |
| 16 #include "SkTemplates.h" | 16 #include "SkTemplates.h" |
| 17 #include "SkTime.h" | 17 #include "SkTime.h" |
| 18 #include "SkUtils.h" | 18 #include "SkUtils.h" |
| 19 #include "SkRect.h" | 19 #include "SkRect.h" |
| 20 #include "SkCanvas.h" | 20 #include "SkCanvas.h" |
| 21 | 21 |
| 22 #if defined(SK_DEBUG) |
| 23 #include "SkRTConf.h" // SK_CONF_DECLARE |
| 24 #endif // defined(SK_DEBUG) |
| 25 |
| 22 #include <stdio.h> | 26 #include <stdio.h> |
| 23 extern "C" { | 27 extern "C" { |
| 24 #include "jpeglib.h" | 28 #include "jpeglib.h" |
| 25 #include "jerror.h" | 29 #include "jerror.h" |
| 26 } | 30 } |
| 27 | 31 |
| 28 // These enable timing code that report milliseconds for an encoding/decoding | 32 // These enable timing code that report milliseconds for an encoding/decoding |
| 29 //#define TIME_ENCODE | 33 //#define TIME_ENCODE |
| 30 //#define TIME_DECODE | 34 //#define TIME_DECODE |
| 31 | 35 |
| 32 // this enables our rgb->yuv code, which is faster than libjpeg on ARM | 36 // this enables our rgb->yuv code, which is faster than libjpeg on ARM |
| 33 #define WE_CONVERT_TO_YUV | 37 #define WE_CONVERT_TO_YUV |
| 34 | 38 |
| 35 // If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offer
s | 39 // If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offer
s |
| 36 // support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565. | 40 // support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565. |
| 37 | 41 |
| 42 #if defined(SK_DEBUG) |
| 43 SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderWarnings, |
| 44 "images.jpeg.suppressDecoderWarnings", false, |
| 45 "Suppress most JPG warnings when calling decode functions."); |
| 46 #endif // defined(SK_DEBUG) |
| 47 |
| 38 ////////////////////////////////////////////////////////////////////////// | 48 ////////////////////////////////////////////////////////////////////////// |
| 39 ////////////////////////////////////////////////////////////////////////// | 49 ////////////////////////////////////////////////////////////////////////// |
| 40 | 50 |
| 41 static void overwrite_mem_buffer_size(jpeg_decompress_struct* cinfo) { | 51 static void overwrite_mem_buffer_size(jpeg_decompress_struct* cinfo) { |
| 42 #ifdef SK_BUILD_FOR_ANDROID | 52 #ifdef SK_BUILD_FOR_ANDROID |
| 43 /* Check if the device indicates that it has a large amount of system memory | 53 /* Check if the device indicates that it has a large amount of system memory |
| 44 * if so, increase the memory allocation to 30MB instead of the default 5MB. | 54 * if so, increase the memory allocation to 30MB instead of the default 5MB. |
| 45 */ | 55 */ |
| 46 #ifdef ANDROID_LARGE_MEMORY_DEVICE | 56 #ifdef ANDROID_LARGE_MEMORY_DEVICE |
| 47 cinfo->mem->max_memory_to_use = 30 * 1024 * 1024; | 57 cinfo->mem->max_memory_to_use = 30 * 1024 * 1024; |
| 48 #else | 58 #else |
| 49 cinfo->mem->max_memory_to_use = 5 * 1024 * 1024; | 59 cinfo->mem->max_memory_to_use = 5 * 1024 * 1024; |
| 50 #endif | 60 #endif |
| 51 #endif // SK_BUILD_FOR_ANDROID | 61 #endif // SK_BUILD_FOR_ANDROID |
| 52 } | 62 } |
| 53 | 63 |
| 54 ////////////////////////////////////////////////////////////////////////// | 64 ////////////////////////////////////////////////////////////////////////// |
| 55 ////////////////////////////////////////////////////////////////////////// | 65 ////////////////////////////////////////////////////////////////////////// |
| 56 | 66 |
| 67 static void do_nothing_emit_message(jpeg_common_struct*, int) { |
| 68 /* do nothing */ |
| 69 } |
| 70 |
| 57 static void initialize_info(jpeg_decompress_struct* cinfo, skjpeg_source_mgr* sr
c_mgr) { | 71 static void initialize_info(jpeg_decompress_struct* cinfo, skjpeg_source_mgr* sr
c_mgr) { |
| 58 SkASSERT(cinfo != NULL); | 72 SkASSERT(cinfo != NULL); |
| 59 SkASSERT(src_mgr != NULL); | 73 SkASSERT(src_mgr != NULL); |
| 60 jpeg_create_decompress(cinfo); | 74 jpeg_create_decompress(cinfo); |
| 61 overwrite_mem_buffer_size(cinfo); | 75 overwrite_mem_buffer_size(cinfo); |
| 62 cinfo->src = src_mgr; | 76 cinfo->src = src_mgr; |
| 77 #if defined(SK_DEBUG) |
| 78 /* To suppress warnings with a SK_DEBUG binary, set the |
| 79 * environment variable "skia_images_jpeg_suppressDecoderWarnings" |
| 80 * to "true". Inside a program that links to skia: |
| 81 * SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true); */ |
| 82 if (c_suppressJPEGImageDecoderWarnings) { |
| 83 cinfo->err->emit_message = &do_nothing_emit_message; |
| 84 } |
| 85 #else // Always suppress in release mode. |
| 86 cinfo->err->emit_message = &do_nothing_emit_message; |
| 87 #endif // defined(SK_DEBUG) |
| 63 } | 88 } |
| 64 | 89 |
| 65 #ifdef SK_BUILD_FOR_ANDROID | 90 #ifdef SK_BUILD_FOR_ANDROID |
| 66 class SkJPEGImageIndex { | 91 class SkJPEGImageIndex { |
| 67 public: | 92 public: |
| 68 SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder) | 93 SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder) |
| 69 : fSrcMgr(stream, decoder) | 94 : fSrcMgr(stream, decoder) |
| 70 , fInfoInitialized(false) | 95 , fInfoInitialized(false) |
| 71 , fHuffmanCreated(false) | 96 , fHuffmanCreated(false) |
| 72 , fDecompressStarted(false) | 97 , fDecompressStarted(false) |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 436 if (decoder.getDitherImage()) { | 461 if (decoder.getDitherImage()) { |
| 437 cinfo->dither_mode = JDITHER_ORDERED; | 462 cinfo->dither_mode = JDITHER_ORDERED; |
| 438 } | 463 } |
| 439 break; | 464 break; |
| 440 default: | 465 default: |
| 441 break; | 466 break; |
| 442 } | 467 } |
| 443 } | 468 } |
| 444 #endif | 469 #endif |
| 445 | 470 |
| 471 |
| 472 /** |
| 473 Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y. |
| 474 Used when decoding fails partway through reading scanlines to fill |
| 475 remaining lines. */ |
| 476 static void fill_below_level(int y, SkBitmap* bitmap) { |
| 477 SkRect rect = SkRect::MakeLTRB(0, y, bitmap->width(), bitmap->height()); |
| 478 SkCanvas canvas(*bitmap); |
| 479 canvas.clipRect(rect); |
| 480 canvas.drawColor(SK_ColorWHITE); |
| 481 } |
| 482 |
| 483 |
| 446 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { | 484 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
| 447 #ifdef TIME_DECODE | 485 #ifdef TIME_DECODE |
| 448 SkAutoTime atm("JPEG Decode"); | 486 SkAutoTime atm("JPEG Decode"); |
| 449 #endif | 487 #endif |
| 450 | 488 |
| 451 JPEGAutoClean autoClean; | 489 JPEGAutoClean autoClean; |
| 452 | 490 |
| 453 jpeg_decompress_struct cinfo; | 491 jpeg_decompress_struct cinfo; |
| 454 skjpeg_source_mgr srcManager(stream, this); | 492 skjpeg_source_mgr srcManager(stream, this); |
| 455 | 493 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 546 ((config == SkBitmap::kARGB_8888_Config && | 584 ((config == SkBitmap::kARGB_8888_Config && |
| 547 cinfo.out_color_space == JCS_RGBA_8888) || | 585 cinfo.out_color_space == JCS_RGBA_8888) || |
| 548 (config == SkBitmap::kRGB_565_Config && | 586 (config == SkBitmap::kRGB_565_Config && |
| 549 cinfo.out_color_space == JCS_RGB_565))) | 587 cinfo.out_color_space == JCS_RGB_565))) |
| 550 { | 588 { |
| 551 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); | 589 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); |
| 552 INT32 const bpr = bm->rowBytes(); | 590 INT32 const bpr = bm->rowBytes(); |
| 553 | 591 |
| 554 while (cinfo.output_scanline < cinfo.output_height) { | 592 while (cinfo.output_scanline < cinfo.output_height) { |
| 555 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); | 593 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); |
| 556 // if row_count == 0, then we didn't get a scanline, so abort. | |
| 557 // if we supported partial images, we might return true in this case | |
| 558 if (0 == row_count) { | 594 if (0 == row_count) { |
| 559 return return_false(cinfo, *bm, "read_scanlines"); | 595 // if row_count == 0, then we didn't get a scanline, |
| 596 // so return early. We will return a partial image. |
| 597 fill_below_level(cinfo.output_scanline, bm); |
| 598 cinfo.output_scanline = cinfo.output_height; |
| 599 break; // Skip to jpeg_finish_decompress() |
| 560 } | 600 } |
| 561 if (this->shouldCancelDecode()) { | 601 if (this->shouldCancelDecode()) { |
| 562 return return_false(cinfo, *bm, "shouldCancelDecode"); | 602 return return_false(cinfo, *bm, "shouldCancelDecode"); |
| 563 } | 603 } |
| 564 rowptr += bpr; | 604 rowptr += bpr; |
| 565 } | 605 } |
| 566 jpeg_finish_decompress(&cinfo); | 606 jpeg_finish_decompress(&cinfo); |
| 567 return true; | 607 return true; |
| 568 } | 608 } |
| 569 #endif | 609 #endif |
| (...skipping 29 matching lines...) Expand all Loading... |
| 599 // Possibly skip initial rows [sampler.srcY0] | 639 // Possibly skip initial rows [sampler.srcY0] |
| 600 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { | 640 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { |
| 601 return return_false(cinfo, *bm, "skip rows"); | 641 return return_false(cinfo, *bm, "skip rows"); |
| 602 } | 642 } |
| 603 | 643 |
| 604 // now loop through scanlines until y == bm->height() - 1 | 644 // now loop through scanlines until y == bm->height() - 1 |
| 605 for (int y = 0;; y++) { | 645 for (int y = 0;; y++) { |
| 606 JSAMPLE* rowptr = (JSAMPLE*)srcRow; | 646 JSAMPLE* rowptr = (JSAMPLE*)srcRow; |
| 607 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); | 647 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); |
| 608 if (0 == row_count) { | 648 if (0 == row_count) { |
| 609 return return_false(cinfo, *bm, "read_scanlines"); | 649 // if row_count == 0, then we didn't get a scanline, |
| 650 // so return early. We will return a partial image. |
| 651 fill_below_level(y, bm); |
| 652 cinfo.output_scanline = cinfo.output_height; |
| 653 break; // Skip to jpeg_finish_decompress() |
| 610 } | 654 } |
| 611 if (this->shouldCancelDecode()) { | 655 if (this->shouldCancelDecode()) { |
| 612 return return_false(cinfo, *bm, "shouldCancelDecode"); | 656 return return_false(cinfo, *bm, "shouldCancelDecode"); |
| 613 } | 657 } |
| 614 | 658 |
| 615 if (JCS_CMYK == cinfo.out_color_space) { | 659 if (JCS_CMYK == cinfo.out_color_space) { |
| 616 convert_CMYK_to_RGB(srcRow, cinfo.output_width); | 660 convert_CMYK_to_RGB(srcRow, cinfo.output_width); |
| 617 } | 661 } |
| 618 | 662 |
| 619 sampler.next(srcRow); | 663 sampler.next(srcRow); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 778 cinfo->out_color_space == JCS_RGB_565))) | 822 cinfo->out_color_space == JCS_RGB_565))) |
| 779 { | 823 { |
| 780 JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); | 824 JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); |
| 781 INT32 const bpr = bitmap.rowBytes(); | 825 INT32 const bpr = bitmap.rowBytes(); |
| 782 int rowTotalCount = 0; | 826 int rowTotalCount = 0; |
| 783 | 827 |
| 784 while (rowTotalCount < height) { | 828 while (rowTotalCount < height) { |
| 785 int rowCount = jpeg_read_tile_scanline(cinfo, | 829 int rowCount = jpeg_read_tile_scanline(cinfo, |
| 786 fImageIndex->huffmanIndex(), | 830 fImageIndex->huffmanIndex(), |
| 787 &rowptr); | 831 &rowptr); |
| 788 // if row_count == 0, then we didn't get a scanline, so abort. | 832 // if rowCount == 0, then we didn't get a scanline, so abort. |
| 789 // if we supported partial images, we might return true in this case | 833 // onDecodeSubset() relies on onBuildTileIndex(), which |
| 834 // needs a complete image to succeed. |
| 790 if (0 == rowCount) { | 835 if (0 == rowCount) { |
| 791 return return_false(*cinfo, bitmap, "read_scanlines"); | 836 return return_false(*cinfo, bitmap, "read_scanlines"); |
| 792 } | 837 } |
| 793 if (this->shouldCancelDecode()) { | 838 if (this->shouldCancelDecode()) { |
| 794 return return_false(*cinfo, bitmap, "shouldCancelDecode"); | 839 return return_false(*cinfo, bitmap, "shouldCancelDecode"); |
| 795 } | 840 } |
| 796 rowTotalCount += rowCount; | 841 rowTotalCount += rowCount; |
| 797 rowptr += bpr; | 842 rowptr += bpr; |
| 798 } | 843 } |
| 799 | 844 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 837 | 882 |
| 838 // Possibly skip initial rows [sampler.srcY0] | 883 // Possibly skip initial rows [sampler.srcY0] |
| 839 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.
srcY0())) { | 884 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.
srcY0())) { |
| 840 return return_false(*cinfo, bitmap, "skip rows"); | 885 return return_false(*cinfo, bitmap, "skip rows"); |
| 841 } | 886 } |
| 842 | 887 |
| 843 // now loop through scanlines until y == bitmap->height() - 1 | 888 // now loop through scanlines until y == bitmap->height() - 1 |
| 844 for (int y = 0;; y++) { | 889 for (int y = 0;; y++) { |
| 845 JSAMPLE* rowptr = (JSAMPLE*)srcRow; | 890 JSAMPLE* rowptr = (JSAMPLE*)srcRow; |
| 846 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex
(), &rowptr); | 891 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex
(), &rowptr); |
| 892 // if row_count == 0, then we didn't get a scanline, so abort. |
| 893 // onDecodeSubset() relies on onBuildTileIndex(), which |
| 894 // needs a complete image to succeed. |
| 847 if (0 == row_count) { | 895 if (0 == row_count) { |
| 848 return return_false(*cinfo, bitmap, "read_scanlines"); | 896 return return_false(*cinfo, bitmap, "read_scanlines"); |
| 849 } | 897 } |
| 850 if (this->shouldCancelDecode()) { | 898 if (this->shouldCancelDecode()) { |
| 851 return return_false(*cinfo, bitmap, "shouldCancelDecode"); | 899 return return_false(*cinfo, bitmap, "shouldCancelDecode"); |
| 852 } | 900 } |
| 853 | 901 |
| 854 if (JCS_CMYK == cinfo->out_color_space) { | 902 if (JCS_CMYK == cinfo->out_color_space) { |
| 855 convert_CMYK_to_RGB(srcRow, width); | 903 convert_CMYK_to_RGB(srcRow, width); |
| 856 } | 904 } |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1152 return SkImageDecoder::kUnknown_Format; | 1200 return SkImageDecoder::kUnknown_Format; |
| 1153 } | 1201 } |
| 1154 | 1202 |
| 1155 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 1203 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { |
| 1156 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; | 1204 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; |
| 1157 } | 1205 } |
| 1158 | 1206 |
| 1159 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); | 1207 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); |
| 1160 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); | 1208 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); |
| 1161 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); | 1209 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); |
| OLD | NEW |