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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 #ifdef SK_BUILD_FOR_ANDROID | |
58 class SkJPEGImageIndex { | 59 class SkJPEGImageIndex { |
59 public: | 60 public: |
60 SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder) | 61 SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder) |
61 : fSrcMgr(stream, decoder) {} | 62 : fSrcMgr(stream, decoder) |
63 , fInfoInitialized(false) | |
64 , fHuffmanCreated(false) | |
65 , fDecompressStarted(false) | |
66 { | |
67 SkDEBUGCODE(fReadHeaderSucceeded = false;) | |
68 } | |
62 | 69 |
63 ~SkJPEGImageIndex() { | 70 ~SkJPEGImageIndex() { |
64 #ifdef SK_BUILD_FOR_ANDROID | 71 if (fHuffmanCreated) { |
65 jpeg_destroy_huffman_index(&fHuffmanIndex); | 72 fHuffmanCreated = false; |
66 #endif | 73 jpeg_destroy_huffman_index(&fHuffmanIndex); |
67 jpeg_finish_decompress(&fCInfo); | 74 } |
68 jpeg_destroy_decompress(&fCInfo); | 75 if (fDecompressStarted) { |
76 fDecompressStarted = false; | |
scroggo
2013/08/05 15:18:41
As mtklein pointed out, in patch set 3, if jpeg_fi
| |
77 jpeg_finish_decompress(&fCInfo); | |
78 } | |
79 if (fInfoInitialized) { | |
80 this->destroyInfo(); | |
81 } | |
69 } | 82 } |
70 | 83 |
71 /** | 84 /** |
72 * Init the cinfo struct using libjpeg and apply any necessary | 85 * Destroy the cinfo struct. |
73 * customizations. | 86 * After this call, if a huffman index was already built, it |
87 * can be used after calling initializeInfoAndReadHeader | |
88 * again. Must not be called after startTileDecompress except | |
89 * in the destructor. | |
74 */ | 90 */ |
75 void initializeInfo() { | 91 void destroyInfo() { |
92 SkASSERT(fInfoInitialized); | |
93 SkASSERT(!fDecompressStarted); | |
94 fInfoInitialized = false; | |
95 jpeg_destroy_decompress(&fCInfo); | |
96 SkDEBUGCODE(fReadHeaderSucceeded = false;) | |
97 } | |
98 | |
99 /** | |
100 * Initialize the cinfo struct. | |
101 * Calls jpeg_create_decompress, makes customizations, and | |
102 * finally calls jpeg_read_header. Returns true if jpeg_read_header | |
103 * returns JPEG_HEADER_OK. | |
104 * If cinfo was already initialized, destroyInfo must be called to | |
105 * destroy the old one. Must not be called after startTileDecompress. | |
106 */ | |
107 bool initializeInfoAndReadHeader() { | |
108 SkASSERT(!fInfoInitialized && !fDecompressStarted); | |
76 jpeg_create_decompress(&fCInfo); | 109 jpeg_create_decompress(&fCInfo); |
77 overwrite_mem_buffer_size(&fCInfo); | 110 overwrite_mem_buffer_size(&fCInfo); |
78 fCInfo.src = &fSrcMgr; | 111 fCInfo.src = &fSrcMgr; |
112 fInfoInitialized = true; | |
113 const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true)) ; | |
114 SkDEBUGCODE(fReadHeaderSucceeded = success;) | |
115 return success; | |
79 } | 116 } |
80 | 117 |
81 jpeg_decompress_struct* cinfo() { return &fCInfo; } | 118 jpeg_decompress_struct* cinfo() { return &fCInfo; } |
82 | 119 |
83 #ifdef SK_BUILD_FOR_ANDROID | |
84 huffman_index* huffmanIndex() { return &fHuffmanIndex; } | 120 huffman_index* huffmanIndex() { return &fHuffmanIndex; } |
85 #endif | 121 |
122 /** | |
123 * Build the index to be used for tile based decoding. | |
124 * Must only be called after a successful call to | |
125 * initializeInfoAndReadHeader and must not be called more | |
126 * than once. | |
127 */ | |
128 bool buildHuffmanIndex() { | |
129 SkASSERT(fReadHeaderSucceeded); | |
130 SkASSERT(!fHuffmanCreated); | |
131 jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex); | |
132 fHuffmanCreated = true; | |
133 SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom); | |
134 return jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex); | |
135 } | |
136 | |
137 /** | |
138 * Start tile based decoding. Must only be called after a | |
139 * successful call to buildHuffmanIndex, and must only be | |
140 * called once. | |
141 */ | |
142 bool startTileDecompress() { | |
143 SkASSERT(fHuffmanCreated); | |
144 SkASSERT(fReadHeaderSucceeded); | |
145 SkASSERT(!fDecompressStarted); | |
146 if (jpeg_start_tile_decompress(&fCInfo)) { | |
147 fDecompressStarted = true; | |
148 return true; | |
149 } | |
150 return false; | |
151 } | |
86 | 152 |
87 private: | 153 private: |
88 skjpeg_source_mgr fSrcMgr; | 154 skjpeg_source_mgr fSrcMgr; |
89 jpeg_decompress_struct fCInfo; | 155 jpeg_decompress_struct fCInfo; |
90 #ifdef SK_BUILD_FOR_ANDROID | |
91 huffman_index fHuffmanIndex; | 156 huffman_index fHuffmanIndex; |
157 bool fInfoInitialized; | |
158 bool fHuffmanCreated; | |
159 bool fDecompressStarted; | |
160 SkDEBUGCODE(bool fReadHeaderSucceeded;) | |
161 }; | |
92 #endif | 162 #endif |
93 }; | |
94 | 163 |
95 class SkJPEGImageDecoder : public SkImageDecoder { | 164 class SkJPEGImageDecoder : public SkImageDecoder { |
96 public: | 165 public: |
166 #ifdef SK_BUILD_FOR_ANDROID | |
97 SkJPEGImageDecoder() { | 167 SkJPEGImageDecoder() { |
98 fImageIndex = NULL; | 168 fImageIndex = NULL; |
99 fImageWidth = 0; | 169 fImageWidth = 0; |
100 fImageHeight = 0; | 170 fImageHeight = 0; |
101 } | 171 } |
102 | 172 |
103 virtual ~SkJPEGImageDecoder() { | 173 virtual ~SkJPEGImageDecoder() { |
104 SkDELETE(fImageIndex); | 174 SkDELETE(fImageIndex); |
105 } | 175 } |
176 #endif | |
106 | 177 |
107 virtual Format getFormat() const { | 178 virtual Format getFormat() const { |
108 return kJPEG_Format; | 179 return kJPEG_Format; |
109 } | 180 } |
110 | 181 |
111 protected: | 182 protected: |
112 #ifdef SK_BUILD_FOR_ANDROID | 183 #ifdef SK_BUILD_FOR_ANDROID |
113 virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_ OVERRIDE; | 184 virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_ OVERRIDE; |
114 virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRI DE; | 185 virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRI DE; |
115 #endif | 186 #endif |
116 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; | 187 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; |
117 | 188 |
118 private: | 189 private: |
190 #ifdef SK_BUILD_FOR_ANDROID | |
119 SkJPEGImageIndex* fImageIndex; | 191 SkJPEGImageIndex* fImageIndex; |
120 int fImageWidth; | 192 int fImageWidth; |
121 int fImageHeight; | 193 int fImageHeight; |
194 #endif | |
122 | 195 |
123 typedef SkImageDecoder INHERITED; | 196 typedef SkImageDecoder INHERITED; |
124 }; | 197 }; |
125 | 198 |
126 ////////////////////////////////////////////////////////////////////////// | 199 ////////////////////////////////////////////////////////////////////////// |
127 | 200 |
128 /* Automatically clean up after throwing an exception */ | 201 /* Automatically clean up after throwing an exception */ |
129 class JPEGAutoClean { | 202 class JPEGAutoClean { |
130 public: | 203 public: |
131 JPEGAutoClean(): cinfo_ptr(NULL) {} | 204 JPEGAutoClean(): cinfo_ptr(NULL) {} |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
468 return return_false(cinfo, *bm, "skip rows"); | 541 return return_false(cinfo, *bm, "skip rows"); |
469 } | 542 } |
470 jpeg_finish_decompress(&cinfo); | 543 jpeg_finish_decompress(&cinfo); |
471 | 544 |
472 return true; | 545 return true; |
473 } | 546 } |
474 | 547 |
475 #ifdef SK_BUILD_FOR_ANDROID | 548 #ifdef SK_BUILD_FOR_ANDROID |
476 bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *hei ght) { | 549 bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *hei ght) { |
477 | 550 |
478 SkJPEGImageIndex* imageIndex = SkNEW_ARGS(SkJPEGImageIndex, (stream, this)); | 551 SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (str eam, this))); |
479 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); | 552 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); |
480 huffman_index* huffmanIndex = imageIndex->huffmanIndex(); | |
481 | 553 |
482 skjpeg_error_mgr sk_err; | 554 skjpeg_error_mgr sk_err; |
483 cinfo->err = jpeg_std_error(&sk_err); | 555 cinfo->err = jpeg_std_error(&sk_err); |
484 sk_err.error_exit = skjpeg_error_exit; | 556 sk_err.error_exit = skjpeg_error_exit; |
485 | 557 |
486 // All objects need to be instantiated before this setjmp call so that | 558 // All objects need to be instantiated before this setjmp call so that |
487 // they will be cleaned up properly if an error occurs. | 559 // they will be cleaned up properly if an error occurs. |
488 if (setjmp(sk_err.fJmpBuf)) { | 560 if (setjmp(sk_err.fJmpBuf)) { |
489 return false; | 561 return false; |
490 } | 562 } |
491 | 563 |
492 // create the cinfo used to create/build the huffmanIndex | 564 // create the cinfo used to create/build the huffmanIndex |
493 imageIndex->initializeInfo(); | 565 if (!imageIndex->initializeInfoAndReadHeader()) { |
494 cinfo->do_fancy_upsampling = 0; | |
495 cinfo->do_block_smoothing = 0; | |
496 | |
497 int status = jpeg_read_header(cinfo, true); | |
498 if (JPEG_HEADER_OK != status) { | |
499 SkDELETE(imageIndex); | |
500 return false; | 566 return false; |
501 } | 567 } |
502 | 568 |
503 jpeg_create_huffman_index(cinfo, huffmanIndex); | 569 if (!imageIndex->buildHuffmanIndex()) { |
504 cinfo->scale_num = 1; | |
505 cinfo->scale_denom = 1; | |
506 if (!jpeg_build_huffman_index(cinfo, huffmanIndex)) { | |
507 SkDELETE(imageIndex); | |
508 return false; | 570 return false; |
509 } | 571 } |
510 | 572 |
511 // destroy the cinfo used to create/build the huffman index | 573 // destroy the cinfo used to create/build the huffman index |
512 jpeg_destroy_decompress(cinfo); | 574 imageIndex->destroyInfo(); |
513 | 575 |
514 // Init decoder to image decode mode | 576 // Init decoder to image decode mode |
515 imageIndex->initializeInfo(); | 577 if (!imageIndex->initializeInfoAndReadHeader()) { |
516 | |
517 status = jpeg_read_header(cinfo, true); | |
518 if (JPEG_HEADER_OK != status) { | |
519 SkDELETE(imageIndex); | |
520 return false; | 578 return false; |
521 } | 579 } |
522 | 580 |
523 cinfo->out_color_space = JCS_RGBA_8888; | 581 cinfo->out_color_space = JCS_RGBA_8888; |
524 cinfo->do_fancy_upsampling = 0; | 582 cinfo->do_fancy_upsampling = 0; |
525 cinfo->do_block_smoothing = 0; | 583 cinfo->do_block_smoothing = 0; |
526 | 584 |
527 // instead of jpeg_start_decompress() we start a tiled decompress | 585 // instead of jpeg_start_decompress() we start a tiled decompress |
528 jpeg_start_tile_decompress(cinfo); | 586 if (!imageIndex->startTileDecompress()) { |
587 return false; | |
588 } | |
529 | 589 |
530 cinfo->scale_num = 1; | 590 SkASSERT(1 == cinfo->scale_num); |
531 *height = cinfo->output_height; | 591 *height = cinfo->output_height; |
532 *width = cinfo->output_width; | 592 *width = cinfo->output_width; |
533 fImageWidth = *width; | 593 fImageWidth = *width; |
534 fImageHeight = *height; | 594 fImageHeight = *height; |
535 | 595 |
536 SkDELETE(fImageIndex); | 596 SkDELETE(fImageIndex); |
537 fImageIndex = imageIndex; | 597 fImageIndex = imageIndex.detach(); |
538 | 598 |
539 return true; | 599 return true; |
540 } | 600 } |
541 | 601 |
542 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { | 602 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { |
543 if (NULL == fImageIndex) { | 603 if (NULL == fImageIndex) { |
544 return false; | 604 return false; |
545 } | 605 } |
546 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); | 606 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); |
547 | 607 |
(...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1015 } | 1075 } |
1016 | 1076 |
1017 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 1077 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { |
1018 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; | 1078 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; |
1019 } | 1079 } |
1020 | 1080 |
1021 | 1081 |
1022 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory); | 1082 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory); |
1023 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_jpeg ); | 1083 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_jpeg ); |
1024 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efact ory); | 1084 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efact ory); |
OLD | NEW |