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" |
| 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 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 549 cinfo.out_color_space == JCS_RGB_565))) | 574 cinfo.out_color_space == JCS_RGB_565))) |
| 550 { | 575 { |
| 551 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); | 576 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); |
| 552 INT32 const bpr = bm->rowBytes(); | 577 INT32 const bpr = bm->rowBytes(); |
| 553 | 578 |
| 554 while (cinfo.output_scanline < cinfo.output_height) { | 579 while (cinfo.output_scanline < cinfo.output_height) { |
| 555 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); | 580 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); |
| 556 // if row_count == 0, then we didn't get a scanline, so abort. | 581 // 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 | 582 // if we supported partial images, we might return true in this case |
| 558 if (0 == row_count) { | 583 if (0 == row_count) { |
| 559 return return_false(cinfo, *bm, "read_scanlines"); | 584 return true; |
|
scroggo
2013/10/02 17:05:04
The remaining rows will still be uninitialized.
| |
| 560 } | 585 } |
| 561 if (this->shouldCancelDecode()) { | 586 if (this->shouldCancelDecode()) { |
| 562 return return_false(cinfo, *bm, "shouldCancelDecode"); | 587 return return_false(cinfo, *bm, "shouldCancelDecode"); |
| 563 } | 588 } |
| 564 rowptr += bpr; | 589 rowptr += bpr; |
| 565 } | 590 } |
| 566 jpeg_finish_decompress(&cinfo); | 591 jpeg_finish_decompress(&cinfo); |
| 567 return true; | 592 return true; |
| 568 } | 593 } |
| 569 #endif | 594 #endif |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 599 // Possibly skip initial rows [sampler.srcY0] | 624 // Possibly skip initial rows [sampler.srcY0] |
| 600 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { | 625 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { |
| 601 return return_false(cinfo, *bm, "skip rows"); | 626 return return_false(cinfo, *bm, "skip rows"); |
| 602 } | 627 } |
| 603 | 628 |
| 604 // now loop through scanlines until y == bm->height() - 1 | 629 // now loop through scanlines until y == bm->height() - 1 |
| 605 for (int y = 0;; y++) { | 630 for (int y = 0;; y++) { |
| 606 JSAMPLE* rowptr = (JSAMPLE*)srcRow; | 631 JSAMPLE* rowptr = (JSAMPLE*)srcRow; |
| 607 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); | 632 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); |
| 608 if (0 == row_count) { | 633 if (0 == row_count) { |
| 609 return return_false(cinfo, *bm, "read_scanlines"); | 634 return true; |
|
scroggo
2013/10/02 17:05:04
Ditto
| |
| 610 } | 635 } |
| 611 if (this->shouldCancelDecode()) { | 636 if (this->shouldCancelDecode()) { |
| 612 return return_false(cinfo, *bm, "shouldCancelDecode"); | 637 return return_false(cinfo, *bm, "shouldCancelDecode"); |
| 613 } | 638 } |
| 614 | 639 |
| 615 if (JCS_CMYK == cinfo.out_color_space) { | 640 if (JCS_CMYK == cinfo.out_color_space) { |
| 616 convert_CMYK_to_RGB(srcRow, cinfo.output_width); | 641 convert_CMYK_to_RGB(srcRow, cinfo.output_width); |
| 617 } | 642 } |
| 618 | 643 |
| 619 sampler.next(srcRow); | 644 sampler.next(srcRow); |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 781 INT32 const bpr = bitmap.rowBytes(); | 806 INT32 const bpr = bitmap.rowBytes(); |
| 782 int rowTotalCount = 0; | 807 int rowTotalCount = 0; |
| 783 | 808 |
| 784 while (rowTotalCount < height) { | 809 while (rowTotalCount < height) { |
| 785 int rowCount = jpeg_read_tile_scanline(cinfo, | 810 int rowCount = jpeg_read_tile_scanline(cinfo, |
| 786 fImageIndex->huffmanIndex(), | 811 fImageIndex->huffmanIndex(), |
| 787 &rowptr); | 812 &rowptr); |
| 788 // if row_count == 0, then we didn't get a scanline, so abort. | 813 // if row_count == 0, then we didn't get a scanline, so abort. |
| 789 // if we supported partial images, we might return true in this case | 814 // if we supported partial images, we might return true in this case |
| 790 if (0 == rowCount) { | 815 if (0 == rowCount) { |
| 791 return return_false(*cinfo, bitmap, "read_scanlines"); | 816 return true; |
|
scroggo
2013/10/02 17:05:04
Ditto
| |
| 792 } | 817 } |
| 793 if (this->shouldCancelDecode()) { | 818 if (this->shouldCancelDecode()) { |
| 794 return return_false(*cinfo, bitmap, "shouldCancelDecode"); | 819 return return_false(*cinfo, bitmap, "shouldCancelDecode"); |
| 795 } | 820 } |
| 796 rowTotalCount += rowCount; | 821 rowTotalCount += rowCount; |
| 797 rowptr += bpr; | 822 rowptr += bpr; |
| 798 } | 823 } |
| 799 | 824 |
| 800 if (swapOnly) { | 825 if (swapOnly) { |
| 801 bm->swap(bitmap); | 826 bm->swap(bitmap); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 838 // Possibly skip initial rows [sampler.srcY0] | 863 // Possibly skip initial rows [sampler.srcY0] |
| 839 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler. srcY0())) { | 864 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler. srcY0())) { |
| 840 return return_false(*cinfo, bitmap, "skip rows"); | 865 return return_false(*cinfo, bitmap, "skip rows"); |
| 841 } | 866 } |
| 842 | 867 |
| 843 // now loop through scanlines until y == bitmap->height() - 1 | 868 // now loop through scanlines until y == bitmap->height() - 1 |
| 844 for (int y = 0;; y++) { | 869 for (int y = 0;; y++) { |
| 845 JSAMPLE* rowptr = (JSAMPLE*)srcRow; | 870 JSAMPLE* rowptr = (JSAMPLE*)srcRow; |
| 846 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex (), &rowptr); | 871 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex (), &rowptr); |
| 847 if (0 == row_count) { | 872 if (0 == row_count) { |
| 848 return return_false(*cinfo, bitmap, "read_scanlines"); | 873 return true; |
|
scroggo
2013/10/02 17:05:04
Ditto
| |
| 849 } | 874 } |
| 850 if (this->shouldCancelDecode()) { | 875 if (this->shouldCancelDecode()) { |
| 851 return return_false(*cinfo, bitmap, "shouldCancelDecode"); | 876 return return_false(*cinfo, bitmap, "shouldCancelDecode"); |
| 852 } | 877 } |
| 853 | 878 |
| 854 if (JCS_CMYK == cinfo->out_color_space) { | 879 if (JCS_CMYK == cinfo->out_color_space) { |
| 855 convert_CMYK_to_RGB(srcRow, width); | 880 convert_CMYK_to_RGB(srcRow, width); |
| 856 } | 881 } |
| 857 | 882 |
| 858 sampler.next(srcRow); | 883 sampler.next(srcRow); |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1152 return SkImageDecoder::kUnknown_Format; | 1177 return SkImageDecoder::kUnknown_Format; |
| 1153 } | 1178 } |
| 1154 | 1179 |
| 1155 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 1180 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { |
| 1156 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; | 1181 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; |
| 1157 } | 1182 } |
| 1158 | 1183 |
| 1159 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); | 1184 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); |
| 1160 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); | 1185 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); |
| 1161 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); | 1186 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); |
| OLD | NEW |