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 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
95 } | 95 } |
96 /* To suppress error messages with a SK_DEBUG binary, set the | 96 /* To suppress error messages with a SK_DEBUG binary, set the |
97 * environment variable "skia_images_jpeg_suppressDecoderErrors" | 97 * environment variable "skia_images_jpeg_suppressDecoderErrors" |
98 * to "true". Inside a program that links to skia: | 98 * to "true". Inside a program that links to skia: |
99 * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */ | 99 * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */ |
100 if (c_suppressJPEGImageDecoderErrors) { | 100 if (c_suppressJPEGImageDecoderErrors) { |
101 cinfo->err->output_message = &do_nothing_output_message; | 101 cinfo->err->output_message = &do_nothing_output_message; |
102 } | 102 } |
103 } | 103 } |
104 | 104 |
105 static void compute_uv_size(const jpeg_decompress_struct& info, int& width, int& height) | |
106 { | |
107 int h = info.cur_comp_info[0]->h_samp_factor; | |
108 int v = info.cur_comp_info[0]->v_samp_factor; | |
109 width = (info.output_width + h - 1) / h; | |
110 height = (info.output_height + v - 1) / v; | |
111 } | |
112 | |
105 #ifdef SK_BUILD_FOR_ANDROID | 113 #ifdef SK_BUILD_FOR_ANDROID |
106 class SkJPEGImageIndex { | 114 class SkJPEGImageIndex { |
107 public: | 115 public: |
108 SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder) | 116 SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder) |
109 : fSrcMgr(stream, decoder) | 117 : fSrcMgr(stream, decoder) |
110 , fInfoInitialized(false) | 118 , fInfoInitialized(false) |
111 , fHuffmanCreated(false) | 119 , fHuffmanCreated(false) |
112 , fDecompressStarted(false) | 120 , fDecompressStarted(false) |
113 { | 121 { |
114 SkDEBUGCODE(fReadHeaderSucceeded = false;) | 122 SkDEBUGCODE(fReadHeaderSucceeded = false;) |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
210 huffman_index fHuffmanIndex; | 218 huffman_index fHuffmanIndex; |
211 bool fInfoInitialized; | 219 bool fInfoInitialized; |
212 bool fHuffmanCreated; | 220 bool fHuffmanCreated; |
213 bool fDecompressStarted; | 221 bool fDecompressStarted; |
214 SkDEBUGCODE(bool fReadHeaderSucceeded;) | 222 SkDEBUGCODE(bool fReadHeaderSucceeded;) |
215 }; | 223 }; |
216 #endif | 224 #endif |
217 | 225 |
218 class SkJPEGImageDecoder : public SkImageDecoder { | 226 class SkJPEGImageDecoder : public SkImageDecoder { |
219 public: | 227 public: |
228 SkJPEGImageDecoder() { | |
220 #ifdef SK_BUILD_FOR_ANDROID | 229 #ifdef SK_BUILD_FOR_ANDROID |
221 SkJPEGImageDecoder() { | |
222 fImageIndex = NULL; | 230 fImageIndex = NULL; |
223 fImageWidth = 0; | 231 fImageWidth = 0; |
224 fImageHeight = 0; | 232 fImageHeight = 0; |
233 #endif | |
234 fYUVBuffers[0] = fYUVBuffers[1] = fYUVBuffers[2] = NULL; | |
235 fRowBytes[0] = fRowBytes[1] = fRowBytes[2] = 0; | |
225 } | 236 } |
226 | 237 |
238 #ifdef SK_BUILD_FOR_ANDROID | |
227 virtual ~SkJPEGImageDecoder() { | 239 virtual ~SkJPEGImageDecoder() { |
228 SkDELETE(fImageIndex); | 240 SkDELETE(fImageIndex); |
229 } | 241 } |
230 #endif | 242 #endif |
231 | 243 |
232 virtual Format getFormat() const { | 244 virtual Format getFormat() const { |
233 return kJPEG_Format; | 245 return kJPEG_Format; |
234 } | 246 } |
235 | 247 |
248 virtual bool getImageFormat(SkStream* stream, SkISize sizes[3]) SK_OVERRIDE; | |
249 virtual void setYUVBuffers(void* yuv[3], size_t rowBytes[3]) SK_OVERRIDE; | |
250 | |
236 protected: | 251 protected: |
237 #ifdef SK_BUILD_FOR_ANDROID | 252 #ifdef SK_BUILD_FOR_ANDROID |
238 virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *h eight) SK_OVERRIDE; | 253 virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *h eight) SK_OVERRIDE; |
239 virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRI DE; | 254 virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRI DE; |
240 #endif | 255 #endif |
241 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; | 256 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; |
242 | 257 |
243 private: | 258 private: |
244 #ifdef SK_BUILD_FOR_ANDROID | 259 #ifdef SK_BUILD_FOR_ANDROID |
245 SkJPEGImageIndex* fImageIndex; | 260 SkJPEGImageIndex* fImageIndex; |
246 int fImageWidth; | 261 int fImageWidth; |
247 int fImageHeight; | 262 int fImageHeight; |
248 #endif | 263 #endif |
264 uint8_t* fYUVBuffers[3]; | |
265 size_t fRowBytes[3]; | |
266 | |
267 bool isSupportedYUVFormat(jpeg_decompress_struct& cinfo) const { | |
268 if ((cinfo.jpeg_color_space == JCS_YCbCr) && | |
269 (cinfo.num_components == 3) && | |
270 (cinfo.scale_denom <= 8) && | |
271 (cinfo.cur_comp_info[1]->h_samp_factor == 1) && | |
272 (cinfo.cur_comp_info[1]->v_samp_factor == 1) && | |
273 (cinfo.cur_comp_info[2]->h_samp_factor == 1) && | |
274 (cinfo.cur_comp_info[2]->v_samp_factor == 1)) { | |
275 int h = cinfo.cur_comp_info[0]->h_samp_factor; | |
276 int v = cinfo.cur_comp_info[0]->v_samp_factor; | |
277 if (((h == 1) || (h == 2) || (h == 4)) && | |
278 ((v == 1) || (v == 2))) { | |
279 cinfo.out_color_space = JCS_YCbCr; | |
280 cinfo.raw_data_out = TRUE; | |
281 | |
282 #ifdef SK_PRINT_YUV_FORMAT | |
283 printf("YUV 4:%d:%d\n", 4 / h, (v == 1) ? 4 / h : 0); | |
scroggo
2014/07/18 21:52:41
SkDebugf?
| |
284 #endif | |
285 return true; | |
286 } | |
287 } | |
288 return false; | |
289 } | |
290 | |
291 bool canDecodeToYUV(jpeg_decompress_struct& cinfo) const { | |
292 return ((NULL != fYUVBuffers[0]) && | |
293 (NULL != fYUVBuffers[1]) && | |
294 (NULL != fYUVBuffers[2]) && | |
295 (fRowBytes[0] > 0) && | |
296 (fRowBytes[1] > 0) && | |
297 (fRowBytes[2] > 0) && | |
298 isSupportedYUVFormat(cinfo)); | |
299 } | |
249 | 300 |
250 /** | 301 /** |
251 * Determine the appropriate bitmap colortype and out_color_space based on | 302 * Determine the appropriate bitmap colortype and out_color_space based on |
252 * both the preference of the caller and the jpeg_color_space on the | 303 * both the preference of the caller and the jpeg_color_space on the |
253 * jpeg_decompress_struct passed in. | 304 * jpeg_decompress_struct passed in. |
254 * Must be called after jpeg_read_header. | 305 * Must be called after jpeg_read_header. |
255 */ | 306 */ |
256 SkColorType getBitmapColorType(jpeg_decompress_struct*); | 307 SkColorType getBitmapColorType(jpeg_decompress_struct*); |
257 | 308 |
309 bool decodeToBitmap(SkBitmap* bm, | |
310 jpeg_decompress_struct& cinfo, | |
311 SkScaledBitmapSampler& sampler); | |
312 bool decodeToYUV(jpeg_decompress_struct& cinfo); | |
313 | |
258 typedef SkImageDecoder INHERITED; | 314 typedef SkImageDecoder INHERITED; |
259 }; | 315 }; |
260 | 316 |
261 ////////////////////////////////////////////////////////////////////////// | 317 ////////////////////////////////////////////////////////////////////////// |
262 | 318 |
263 /* Automatically clean up after throwing an exception */ | 319 /* Automatically clean up after throwing an exception */ |
264 class JPEGAutoClean { | 320 class JPEGAutoClean { |
265 public: | 321 public: |
266 JPEGAutoClean(): cinfo_ptr(NULL) {} | 322 JPEGAutoClean(): cinfo_ptr(NULL) {} |
267 ~JPEGAutoClean() { | 323 ~JPEGAutoClean() { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
318 return false; | 374 return false; |
319 } | 375 } |
320 } | 376 } |
321 return true; | 377 return true; |
322 } | 378 } |
323 #endif | 379 #endif |
324 | 380 |
325 // This guy exists just to aid in debugging, as it allows debuggers to just | 381 // This guy exists just to aid in debugging, as it allows debuggers to just |
326 // set a break-point in one place to see all error exists. | 382 // set a break-point in one place to see all error exists. |
327 static bool return_false(const jpeg_decompress_struct& cinfo, | 383 static bool return_false(const jpeg_decompress_struct& cinfo, |
328 const SkBitmap& bm, const char caller[]) { | 384 const SkBitmap* bm, const char caller[]) { |
329 if (!(c_suppressJPEGImageDecoderErrors)) { | 385 if (!(c_suppressJPEGImageDecoderErrors)) { |
330 char buffer[JMSG_LENGTH_MAX]; | 386 char buffer[JMSG_LENGTH_MAX]; |
331 cinfo.err->format_message((const j_common_ptr)&cinfo, buffer); | 387 cinfo.err->format_message((const j_common_ptr)&cinfo, buffer); |
332 SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", | 388 SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", |
333 cinfo.err->msg_code, buffer, caller, bm.width(), bm.height()); | 389 cinfo.err->msg_code, buffer, caller, |
390 (NULL == bm) ? bm->width() : 0, | |
scroggo
2014/07/18 21:52:41
This is backwards. If NULL == bm, you want to retu
| |
391 (NULL == bm) ? bm->height() : 0); | |
334 } | 392 } |
335 return false; // must always return false | 393 return false; // must always return false |
336 } | 394 } |
337 | 395 |
338 // Convert a scanline of CMYK samples to RGBX in place. Note that this | 396 // Convert a scanline of CMYK samples to RGBX in place. Note that this |
339 // method moves the "scanline" pointer in its processing | 397 // method moves the "scanline" pointer in its processing |
340 static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) { | 398 static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) { |
341 // At this point we've received CMYK pixels from libjpeg. We | 399 // At this point we've received CMYK pixels from libjpeg. We |
342 // perform a crude conversion to RGB (based on the formulae | 400 // perform a crude conversion to RGB (based on the formulae |
343 // from easyrgb.com): | 401 // from easyrgb.com): |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
538 | 596 |
539 jpeg_decompress_struct cinfo; | 597 jpeg_decompress_struct cinfo; |
540 skjpeg_source_mgr srcManager(stream, this); | 598 skjpeg_source_mgr srcManager(stream, this); |
541 | 599 |
542 skjpeg_error_mgr errorManager; | 600 skjpeg_error_mgr errorManager; |
543 set_error_mgr(&cinfo, &errorManager); | 601 set_error_mgr(&cinfo, &errorManager); |
544 | 602 |
545 // All objects need to be instantiated before this setjmp call so that | 603 // All objects need to be instantiated before this setjmp call so that |
546 // they will be cleaned up properly if an error occurs. | 604 // they will be cleaned up properly if an error occurs. |
547 if (setjmp(errorManager.fJmpBuf)) { | 605 if (setjmp(errorManager.fJmpBuf)) { |
548 return return_false(cinfo, *bm, "setjmp"); | 606 return return_false(cinfo, bm, "setjmp"); |
549 } | 607 } |
550 | 608 |
551 initialize_info(&cinfo, &srcManager); | 609 initialize_info(&cinfo, &srcManager); |
552 autoClean.set(&cinfo); | 610 autoClean.set(&cinfo); |
553 | 611 |
554 int status = jpeg_read_header(&cinfo, true); | 612 int status = jpeg_read_header(&cinfo, true); |
555 if (status != JPEG_HEADER_OK) { | 613 if (status != JPEG_HEADER_OK) { |
556 return return_false(cinfo, *bm, "read_header"); | 614 return return_false(cinfo, bm, "read_header"); |
557 } | 615 } |
558 | 616 |
559 /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it | 617 /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it |
560 can) much faster that we, just use their num/denom api to approximate | 618 can) much faster that we, just use their num/denom api to approximate |
561 the size. | 619 the size. |
562 */ | 620 */ |
563 int sampleSize = this->getSampleSize(); | 621 int sampleSize = this->getSampleSize(); |
564 | 622 |
565 set_dct_method(*this, &cinfo); | 623 set_dct_method(*this, &cinfo); |
566 | 624 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
601 if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimension s(cinfo)) { | 659 if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimension s(cinfo)) { |
602 SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height, | 660 SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height, |
603 recompute_sampleSize(sampleSize, cinfo)); | 661 recompute_sampleSize(sampleSize, cinfo)); |
604 // Assume an A8 bitmap is not opaque to avoid the check of each | 662 // Assume an A8 bitmap is not opaque to avoid the check of each |
605 // individual pixel. It is very unlikely to be opaque, since | 663 // individual pixel. It is very unlikely to be opaque, since |
606 // an opaque A8 bitmap would not be very interesting. | 664 // an opaque A8 bitmap would not be very interesting. |
607 // Otherwise, a jpeg image is opaque. | 665 // Otherwise, a jpeg image is opaque. |
608 return bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaled Height(), | 666 return bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaled Height(), |
609 colorType, alphaType)); | 667 colorType, alphaType)); |
610 } else { | 668 } else { |
611 return return_false(cinfo, *bm, "start_decompress"); | 669 return return_false(cinfo, bm, "start_decompress"); |
612 } | 670 } |
613 } | 671 } |
614 sampleSize = recompute_sampleSize(sampleSize, cinfo); | 672 sampleSize = recompute_sampleSize(sampleSize, cinfo); |
615 | 673 |
616 #ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER | 674 #ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER |
617 // should we allow the Chooser (if present) to pick a colortype for us??? | 675 // should we allow the Chooser (if present) to pick a colortype for us??? |
618 if (!this->chooseFromOneChoice(colorType, cinfo.output_width, cinfo.output_h eight)) { | 676 if (!this->chooseFromOneChoice(colorType, cinfo.output_width, cinfo.output_h eight)) { |
619 return return_false(cinfo, *bm, "chooseFromOneChoice"); | 677 return return_false(cinfo, bm, "chooseFromOneChoice"); |
620 } | 678 } |
621 #endif | 679 #endif |
622 | 680 |
623 SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampl eSize); | 681 SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampl eSize); |
624 // Assume an A8 bitmap is not opaque to avoid the check of each | 682 // Assume an A8 bitmap is not opaque to avoid the check of each |
625 // individual pixel. It is very unlikely to be opaque, since | 683 // individual pixel. It is very unlikely to be opaque, since |
626 // an opaque A8 bitmap would not be very interesting. | 684 // an opaque A8 bitmap would not be very interesting. |
627 // Otherwise, a jpeg image is opaque. | 685 // Otherwise, a jpeg image is opaque. |
628 bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), | 686 bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), |
629 colorType, alphaType)); | 687 colorType, alphaType)); |
630 if (SkImageDecoder::kDecodeBounds_Mode == mode) { | 688 if (SkImageDecoder::kDecodeBounds_Mode == mode) { |
631 return true; | 689 return true; |
632 } | 690 } |
691 | |
692 return canDecodeToYUV(cinfo) ? decodeToYUV(cinfo) : decodeToBitmap(bm, cinfo , sampler); | |
scroggo
2014/07/18 21:52:41
It seems awkward that if canDecodeToYUV is true we
| |
693 } | |
694 | |
695 bool SkJPEGImageDecoder::decodeToBitmap(SkBitmap* bm, | |
696 jpeg_decompress_struct& cinfo, | |
697 SkScaledBitmapSampler& sampler) { | |
633 if (!this->allocPixelRef(bm, NULL)) { | 698 if (!this->allocPixelRef(bm, NULL)) { |
634 return return_false(cinfo, *bm, "allocPixelRef"); | 699 return return_false(cinfo, bm, "allocPixelRef"); |
635 } | 700 } |
636 | 701 |
637 SkAutoLockPixels alp(*bm); | 702 SkAutoLockPixels alp(*bm); |
638 | 703 |
639 #ifdef ANDROID_RGB | 704 #ifdef ANDROID_RGB |
640 /* short-circuit the SkScaledBitmapSampler when possible, as this gives | 705 /* short-circuit the SkScaledBitmapSampler when possible, as this gives |
641 a significant performance boost. | 706 a significant performance boost. |
642 */ | 707 */ |
643 if (sampleSize == 1 && | 708 if (sampleSize == 1 && |
644 ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_888 8) || | 709 ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_888 8) || |
645 (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_ 565))) | 710 (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_ 565))) |
646 { | 711 { |
647 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); | 712 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); |
648 INT32 const bpr = bm->rowBytes(); | 713 INT32 const bpr = bm->rowBytes(); |
649 | 714 |
650 while (cinfo.output_scanline < cinfo.output_height) { | 715 while (cinfo.output_scanline < cinfo.output_height) { |
651 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); | 716 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); |
652 if (0 == row_count) { | 717 if (0 == row_count) { |
653 // if row_count == 0, then we didn't get a scanline, | 718 // if row_count == 0, then we didn't get a scanline, |
654 // so return early. We will return a partial image. | 719 // so return early. We will return a partial image. |
655 fill_below_level(cinfo.output_scanline, bm); | 720 fill_below_level(cinfo.output_scanline, bm); |
656 cinfo.output_scanline = cinfo.output_height; | 721 cinfo.output_scanline = cinfo.output_height; |
657 break; // Skip to jpeg_finish_decompress() | 722 break; // Skip to jpeg_finish_decompress() |
658 } | 723 } |
659 if (this->shouldCancelDecode()) { | 724 if (this->shouldCancelDecode()) { |
660 return return_false(cinfo, *bm, "shouldCancelDecode"); | 725 return return_false(cinfo, bm, "shouldCancelDecode"); |
661 } | 726 } |
662 rowptr += bpr; | 727 rowptr += bpr; |
663 } | 728 } |
664 jpeg_finish_decompress(&cinfo); | 729 jpeg_finish_decompress(&cinfo); |
665 return true; | 730 return true; |
666 } | 731 } |
667 #endif | 732 #endif |
668 | 733 |
669 // check for supported formats | 734 // check for supported formats |
670 SkScaledBitmapSampler::SrcConfig sc; | 735 SkScaledBitmapSampler::SrcConfig sc; |
671 int srcBytesPerPixel; | 736 int srcBytesPerPixel; |
672 | 737 |
673 if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) { | 738 if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) { |
674 return return_false(cinfo, *bm, "jpeg colorspace"); | 739 return return_false(cinfo, bm, "jpeg colorspace"); |
675 } | 740 } |
676 | 741 |
677 if (!sampler.begin(bm, sc, *this)) { | 742 if (!sampler.begin(bm, sc, *this)) { |
678 return return_false(cinfo, *bm, "sampler.begin"); | 743 return return_false(cinfo, bm, "sampler.begin"); |
679 } | 744 } |
680 | 745 |
681 SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel); | 746 SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel); |
682 uint8_t* srcRow = (uint8_t*)srcStorage.get(); | 747 uint8_t* srcRow = (uint8_t*)srcStorage.get(); |
683 | 748 |
684 // Possibly skip initial rows [sampler.srcY0] | 749 // Possibly skip initial rows [sampler.srcY0] |
685 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { | 750 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { |
686 return return_false(cinfo, *bm, "skip rows"); | 751 return return_false(cinfo, bm, "skip rows"); |
687 } | 752 } |
688 | 753 |
689 // now loop through scanlines until y == bm->height() - 1 | 754 // now loop through scanlines until y == bm->height() - 1 |
690 for (int y = 0;; y++) { | 755 for (int y = 0;; y++) { |
691 JSAMPLE* rowptr = (JSAMPLE*)srcRow; | 756 JSAMPLE* rowptr = (JSAMPLE*)srcRow; |
692 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); | 757 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); |
693 if (0 == row_count) { | 758 if (0 == row_count) { |
694 // if row_count == 0, then we didn't get a scanline, | 759 // if row_count == 0, then we didn't get a scanline, |
695 // so return early. We will return a partial image. | 760 // so return early. We will return a partial image. |
696 fill_below_level(y, bm); | 761 fill_below_level(y, bm); |
697 cinfo.output_scanline = cinfo.output_height; | 762 cinfo.output_scanline = cinfo.output_height; |
698 break; // Skip to jpeg_finish_decompress() | 763 break; // Skip to jpeg_finish_decompress() |
699 } | 764 } |
700 if (this->shouldCancelDecode()) { | 765 if (this->shouldCancelDecode()) { |
701 return return_false(cinfo, *bm, "shouldCancelDecode"); | 766 return return_false(cinfo, bm, "shouldCancelDecode"); |
702 } | 767 } |
703 | 768 |
704 if (JCS_CMYK == cinfo.out_color_space) { | 769 if (JCS_CMYK == cinfo.out_color_space) { |
705 convert_CMYK_to_RGB(srcRow, cinfo.output_width); | 770 convert_CMYK_to_RGB(srcRow, cinfo.output_width); |
706 } | 771 } |
707 | 772 |
708 sampler.next(srcRow); | 773 sampler.next(srcRow); |
709 if (bm->height() - 1 == y) { | 774 if (bm->height() - 1 == y) { |
710 // we're done | 775 // we're done |
711 break; | 776 break; |
712 } | 777 } |
713 | 778 |
714 if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { | 779 if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { |
715 return return_false(cinfo, *bm, "skip rows"); | 780 return return_false(cinfo, bm, "skip rows"); |
716 } | 781 } |
717 } | 782 } |
718 | 783 |
719 // we formally skip the rest, so we don't get a complaint from libjpeg | 784 // we formally skip the rest, so we don't get a complaint from libjpeg |
720 if (!skip_src_rows(&cinfo, srcRow, | 785 if (!skip_src_rows(&cinfo, srcRow, |
721 cinfo.output_height - cinfo.output_scanline)) { | 786 cinfo.output_height - cinfo.output_scanline)) { |
722 return return_false(cinfo, *bm, "skip rows"); | 787 return return_false(cinfo, bm, "skip rows"); |
723 } | 788 } |
724 jpeg_finish_decompress(&cinfo); | 789 jpeg_finish_decompress(&cinfo); |
725 | 790 |
726 return true; | 791 return true; |
727 } | 792 } |
728 | 793 |
794 bool SkJPEGImageDecoder::decodeToYUV(jpeg_decompress_struct& cinfo) { | |
795 uint8_t* bufferraw[3]; | |
796 uint8_t* bufferraw2[32]; | |
797 bufferraw[0] = (uint8_t*)&bufferraw2[0]; | |
798 bufferraw[1] = (uint8_t*)&bufferraw2[16]; | |
799 bufferraw[2] = (uint8_t*)&bufferraw2[24]; | |
800 int yWidth = cinfo.output_width; | |
801 int yHeight = cinfo.output_height; | |
802 int yMaxH = yHeight - 1; | |
803 int v = cinfo.cur_comp_info[0]->v_samp_factor; | |
804 int uvWidth(0), uvHeight(0); | |
805 compute_uv_size(cinfo, uvWidth, uvHeight); | |
806 int uvMaxH = uvHeight - 1; | |
807 | |
808 SkAutoMalloc lastRowStorage(yWidth * 8); | |
809 uint8_t* yLastRow = (uint8_t*)lastRowStorage.get(); | |
810 uint8_t* uLastRow = yLastRow + 2 * yWidth; | |
811 uint8_t* vLastRow = uLastRow + 2 * yWidth; | |
812 uint8_t* dummyRow = vLastRow + 2 * yWidth; | |
813 | |
814 int scanlinesToRead = DCTSIZE * v; | |
815 while (cinfo.output_scanline < cinfo.output_height) { | |
816 // Request 8 or 16 scanlines: returns 0 or more scanlines. | |
817 bool hasYLastRow(false), hasUVLastRow(false); | |
818 for (int i = 0; i < scanlinesToRead; ++i) { | |
819 int scanline = (cinfo.output_scanline + i); | |
820 if (scanline < yMaxH) { | |
821 bufferraw2[i] = &fYUVBuffers[0][scanline * fRowBytes[0]]; | |
822 } else if (scanline == yMaxH) { | |
823 bufferraw2[i] = yLastRow; | |
824 hasYLastRow = true; | |
825 } else { | |
826 bufferraw2[i] = dummyRow; | |
827 } | |
828 } | |
829 int scaledScanline = cinfo.output_scanline / v; | |
830 for (int i = 0; i < 8; ++i) { | |
831 int scanline = (scaledScanline + i); | |
832 if (scanline < uvMaxH) { | |
833 bufferraw2[16+i] = &fYUVBuffers[1][scanline * fRowBytes[1]]; | |
834 bufferraw2[24+i] = &fYUVBuffers[2][scanline * fRowBytes[2]]; | |
835 } else if (scanline == uvMaxH) { | |
836 bufferraw2[16+i] = uLastRow; | |
837 bufferraw2[24+i] = vLastRow; | |
838 hasUVLastRow = true; | |
839 } else { | |
840 bufferraw2[16+i] = dummyRow; | |
841 bufferraw2[24+i] = dummyRow; | |
842 } | |
843 } | |
844 JDIMENSION scanlinesRead = jpeg_read_raw_data(&cinfo, (JSAMPIMAGE)buffer raw, scanlinesToRead); | |
scroggo
2014/07/18 21:52:41
100 chars
| |
845 if (scanlinesRead == 0) { | |
846 return false; | |
847 } | |
848 if (hasYLastRow) { | |
849 memcpy(&fYUVBuffers[0][ yMaxH * yWidth], yLastRow, yWidth); | |
850 } | |
851 if (hasUVLastRow) { | |
852 memcpy(&fYUVBuffers[1][uvMaxH * uvWidth], uLastRow, uvWidth); | |
853 memcpy(&fYUVBuffers[2][uvMaxH * uvWidth], vLastRow, uvWidth); | |
854 } | |
855 } | |
856 | |
857 if (cinfo.output_scanline > cinfo.output_height) { | |
858 cinfo.output_scanline = cinfo.output_height; | |
859 } | |
860 | |
861 jpeg_finish_decompress(&cinfo); | |
862 | |
863 return true; | |
864 } | |
865 | |
866 void SkJPEGImageDecoder::setYUVBuffers(void* yuv[3], size_t rowBytes[3]) { | |
867 for (int i = 0; i < 3; ++i) { | |
868 fYUVBuffers[i] = (uint8_t*)yuv[i]; | |
869 fRowBytes[i] = rowBytes[i]; | |
870 } | |
871 } | |
872 | |
873 bool SkJPEGImageDecoder::getImageFormat(SkStream* stream, SkISize sizes[3]) { | |
874 JPEGAutoClean autoClean; | |
875 | |
876 jpeg_decompress_struct cinfo; | |
877 skjpeg_source_mgr srcManager(stream, this); | |
878 | |
879 skjpeg_error_mgr errorManager; | |
880 set_error_mgr(&cinfo, &errorManager); | |
881 | |
882 // All objects need to be instantiated before this setjmp call so that | |
883 // they will be cleaned up properly if an error occurs. | |
884 if (setjmp(errorManager.fJmpBuf)) { | |
885 return return_false(cinfo, NULL, "setjmp"); | |
886 } | |
887 | |
888 initialize_info(&cinfo, &srcManager); | |
889 autoClean.set(&cinfo); | |
890 | |
891 int status = jpeg_read_header(&cinfo, true); | |
892 if (status != JPEG_HEADER_OK) { | |
893 return return_false(cinfo, NULL, "read_header"); | |
894 } | |
895 | |
896 if (isSupportedYUVFormat(cinfo)) { | |
897 jpeg_start_decompress(&cinfo); // Compute output width | |
898 sizes[0].set(cinfo.output_width, cinfo.output_height); | |
899 int w(0), h(0); | |
900 compute_uv_size(cinfo, w, h); | |
901 sizes[1].set(w, h); | |
902 sizes[2].set(w, h); | |
903 jpeg_abort_decompress(&cinfo); | |
904 return true; | |
905 } | |
906 return false; | |
907 } | |
908 | |
729 #ifdef SK_BUILD_FOR_ANDROID | 909 #ifdef SK_BUILD_FOR_ANDROID |
730 bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width , int *height) { | 910 bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width , int *height) { |
731 | 911 |
732 SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (str eam, this))); | 912 SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (str eam, this))); |
733 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); | 913 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); |
734 | 914 |
735 skjpeg_error_mgr sk_err; | 915 skjpeg_error_mgr sk_err; |
736 set_error_mgr(cinfo, &sk_err); | 916 set_error_mgr(cinfo, &sk_err); |
737 | 917 |
738 // All objects need to be instantiated before this setjmp call so that | 918 // All objects need to be instantiated before this setjmp call so that |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
842 // swap happening. If no, then we will use alloc to allocate pixels to | 1022 // swap happening. If no, then we will use alloc to allocate pixels to |
843 // prevent garbage collection. | 1023 // prevent garbage collection. |
844 int w = rect.width() / actualSampleSize; | 1024 int w = rect.width() / actualSampleSize; |
845 int h = rect.height() / actualSampleSize; | 1025 int h = rect.height() / actualSampleSize; |
846 bool swapOnly = (rect == region) && bm->isNull() && | 1026 bool swapOnly = (rect == region) && bm->isNull() && |
847 (w == bitmap.width()) && (h == bitmap.height()) && | 1027 (w == bitmap.width()) && (h == bitmap.height()) && |
848 ((startX - rect.x()) / actualSampleSize == 0) && | 1028 ((startX - rect.x()) / actualSampleSize == 0) && |
849 ((startY - rect.y()) / actualSampleSize == 0); | 1029 ((startY - rect.y()) / actualSampleSize == 0); |
850 if (swapOnly) { | 1030 if (swapOnly) { |
851 if (!this->allocPixelRef(&bitmap, NULL)) { | 1031 if (!this->allocPixelRef(&bitmap, NULL)) { |
852 return return_false(*cinfo, bitmap, "allocPixelRef"); | 1032 return return_false(*cinfo, &bitmap, "allocPixelRef"); |
853 } | 1033 } |
854 } else { | 1034 } else { |
855 if (!bitmap.allocPixels()) { | 1035 if (!bitmap.allocPixels()) { |
856 return return_false(*cinfo, bitmap, "allocPixels"); | 1036 return return_false(*cinfo, &bitmap, "allocPixels"); |
857 } | 1037 } |
858 } | 1038 } |
859 | 1039 |
860 SkAutoLockPixels alp(bitmap); | 1040 SkAutoLockPixels alp(bitmap); |
861 | 1041 |
862 #ifdef ANDROID_RGB | 1042 #ifdef ANDROID_RGB |
863 /* short-circuit the SkScaledBitmapSampler when possible, as this gives | 1043 /* short-circuit the SkScaledBitmapSampler when possible, as this gives |
864 a significant performance boost. | 1044 a significant performance boost. |
865 */ | 1045 */ |
866 if (skiaSampleSize == 1 && | 1046 if (skiaSampleSize == 1 && |
867 ((kN32_SkColorType == colorType && cinfo->out_color_space == JCS_RGBA_88 88) || | 1047 ((kN32_SkColorType == colorType && cinfo->out_color_space == JCS_RGBA_88 88) || |
868 (kRGB_565_SkColorType == colorType && cinfo->out_color_space == JCS_RGB _565))) | 1048 (kRGB_565_SkColorType == colorType && cinfo->out_color_space == JCS_RGB _565))) |
869 { | 1049 { |
870 JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); | 1050 JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); |
871 INT32 const bpr = bitmap.rowBytes(); | 1051 INT32 const bpr = bitmap.rowBytes(); |
872 int rowTotalCount = 0; | 1052 int rowTotalCount = 0; |
873 | 1053 |
874 while (rowTotalCount < height) { | 1054 while (rowTotalCount < height) { |
875 int rowCount = jpeg_read_tile_scanline(cinfo, | 1055 int rowCount = jpeg_read_tile_scanline(cinfo, |
876 fImageIndex->huffmanIndex(), | 1056 fImageIndex->huffmanIndex(), |
877 &rowptr); | 1057 &rowptr); |
878 // if rowCount == 0, then we didn't get a scanline, so abort. | 1058 // if rowCount == 0, then we didn't get a scanline, so abort. |
879 // onDecodeSubset() relies on onBuildTileIndex(), which | 1059 // onDecodeSubset() relies on onBuildTileIndex(), which |
880 // needs a complete image to succeed. | 1060 // needs a complete image to succeed. |
881 if (0 == rowCount) { | 1061 if (0 == rowCount) { |
882 return return_false(*cinfo, bitmap, "read_scanlines"); | 1062 return return_false(*cinfo, &bitmap, "read_scanlines"); |
883 } | 1063 } |
884 if (this->shouldCancelDecode()) { | 1064 if (this->shouldCancelDecode()) { |
885 return return_false(*cinfo, bitmap, "shouldCancelDecode"); | 1065 return return_false(*cinfo, &bitmap, "shouldCancelDecode"); |
886 } | 1066 } |
887 rowTotalCount += rowCount; | 1067 rowTotalCount += rowCount; |
888 rowptr += bpr; | 1068 rowptr += bpr; |
889 } | 1069 } |
890 | 1070 |
891 if (swapOnly) { | 1071 if (swapOnly) { |
892 bm->swap(bitmap); | 1072 bm->swap(bitmap); |
893 } else { | 1073 } else { |
894 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), | 1074 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), |
895 region.width(), region.height(), startX, startY); | 1075 region.width(), region.height(), startX, startY); |
896 } | 1076 } |
897 return true; | 1077 return true; |
898 } | 1078 } |
899 #endif | 1079 #endif |
900 | 1080 |
901 // check for supported formats | 1081 // check for supported formats |
902 SkScaledBitmapSampler::SrcConfig sc; | 1082 SkScaledBitmapSampler::SrcConfig sc; |
903 int srcBytesPerPixel; | 1083 int srcBytesPerPixel; |
904 | 1084 |
905 if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) { | 1085 if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) { |
906 return return_false(*cinfo, *bm, "jpeg colorspace"); | 1086 return return_false(*cinfo, bm, "jpeg colorspace"); |
907 } | 1087 } |
908 | 1088 |
909 if (!sampler.begin(&bitmap, sc, *this)) { | 1089 if (!sampler.begin(&bitmap, sc, *this)) { |
910 return return_false(*cinfo, bitmap, "sampler.begin"); | 1090 return return_false(*cinfo, &bitmap, "sampler.begin"); |
911 } | 1091 } |
912 | 1092 |
913 SkAutoMalloc srcStorage(width * srcBytesPerPixel); | 1093 SkAutoMalloc srcStorage(width * srcBytesPerPixel); |
914 uint8_t* srcRow = (uint8_t*)srcStorage.get(); | 1094 uint8_t* srcRow = (uint8_t*)srcStorage.get(); |
915 | 1095 |
916 // Possibly skip initial rows [sampler.srcY0] | 1096 // Possibly skip initial rows [sampler.srcY0] |
917 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler. srcY0())) { | 1097 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler. srcY0())) { |
918 return return_false(*cinfo, bitmap, "skip rows"); | 1098 return return_false(*cinfo, &bitmap, "skip rows"); |
919 } | 1099 } |
920 | 1100 |
921 // now loop through scanlines until y == bitmap->height() - 1 | 1101 // now loop through scanlines until y == bitmap->height() - 1 |
922 for (int y = 0;; y++) { | 1102 for (int y = 0;; y++) { |
923 JSAMPLE* rowptr = (JSAMPLE*)srcRow; | 1103 JSAMPLE* rowptr = (JSAMPLE*)srcRow; |
924 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex (), &rowptr); | 1104 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex (), &rowptr); |
925 // if row_count == 0, then we didn't get a scanline, so abort. | 1105 // if row_count == 0, then we didn't get a scanline, so abort. |
926 // onDecodeSubset() relies on onBuildTileIndex(), which | 1106 // onDecodeSubset() relies on onBuildTileIndex(), which |
927 // needs a complete image to succeed. | 1107 // needs a complete image to succeed. |
928 if (0 == row_count) { | 1108 if (0 == row_count) { |
929 return return_false(*cinfo, bitmap, "read_scanlines"); | 1109 return return_false(*cinfo, &bitmap, "read_scanlines"); |
930 } | 1110 } |
931 if (this->shouldCancelDecode()) { | 1111 if (this->shouldCancelDecode()) { |
932 return return_false(*cinfo, bitmap, "shouldCancelDecode"); | 1112 return return_false(*cinfo, &bitmap, "shouldCancelDecode"); |
933 } | 1113 } |
934 | 1114 |
935 if (JCS_CMYK == cinfo->out_color_space) { | 1115 if (JCS_CMYK == cinfo->out_color_space) { |
936 convert_CMYK_to_RGB(srcRow, width); | 1116 convert_CMYK_to_RGB(srcRow, width); |
937 } | 1117 } |
938 | 1118 |
939 sampler.next(srcRow); | 1119 sampler.next(srcRow); |
940 if (bitmap.height() - 1 == y) { | 1120 if (bitmap.height() - 1 == y) { |
941 // we're done | 1121 // we're done |
942 break; | 1122 break; |
943 } | 1123 } |
944 | 1124 |
945 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, | 1125 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, |
946 sampler.srcDY() - 1)) { | 1126 sampler.srcDY() - 1)) { |
947 return return_false(*cinfo, bitmap, "skip rows"); | 1127 return return_false(*cinfo, &bitmap, "skip rows"); |
948 } | 1128 } |
949 } | 1129 } |
950 if (swapOnly) { | 1130 if (swapOnly) { |
951 bm->swap(bitmap); | 1131 bm->swap(bitmap); |
952 } else { | 1132 } else { |
953 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), | 1133 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), |
954 region.width(), region.height(), startX, startY); | 1134 region.width(), region.height(), startX, startY); |
955 } | 1135 } |
956 return true; | 1136 return true; |
957 } | 1137 } |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1233 return SkImageDecoder::kUnknown_Format; | 1413 return SkImageDecoder::kUnknown_Format; |
1234 } | 1414 } |
1235 | 1415 |
1236 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 1416 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { |
1237 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; | 1417 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; |
1238 } | 1418 } |
1239 | 1419 |
1240 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); | 1420 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); |
1241 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); | 1421 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); |
1242 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); | 1422 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); |
OLD | NEW |