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 |