Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(174)

Side by Side Diff: src/images/SkImageDecoder_libjpeg.cpp

Issue 24449003: Make Jpeg decoding more fault resistant. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: final rebase Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « gyp/tools.gyp ('k') | src/images/SkImageDecoder_libpng.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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);
OLDNEW
« no previous file with comments | « gyp/tools.gyp ('k') | src/images/SkImageDecoder_libpng.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698