OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
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 #include "SkCodec.h" | 8 #include "SkCodec.h" |
9 #include "SkMSAN.h" | 9 #include "SkMSAN.h" |
10 #include "SkJpegCodec.h" | 10 #include "SkJpegCodec.h" |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 , fSwizzleSrcRow(nullptr) | 271 , fSwizzleSrcRow(nullptr) |
272 , fColorXformSrcRow(nullptr) | 272 , fColorXformSrcRow(nullptr) |
273 , fSwizzlerSubset(SkIRect::MakeEmpty()) | 273 , fSwizzlerSubset(SkIRect::MakeEmpty()) |
274 , fICCData(std::move(iccData)) | 274 , fICCData(std::move(iccData)) |
275 {} | 275 {} |
276 | 276 |
277 /* | 277 /* |
278 * Return the row bytes of a particular image type and width | 278 * Return the row bytes of a particular image type and width |
279 */ | 279 */ |
280 static size_t get_row_bytes(const j_decompress_ptr dinfo) { | 280 static size_t get_row_bytes(const j_decompress_ptr dinfo) { |
281 #ifdef TURBO_HAS_565 | |
282 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 : | 281 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 : |
283 dinfo->out_color_components; | 282 dinfo->out_color_components; |
284 #else | |
285 const size_t colorBytes = dinfo->out_color_components; | |
286 #endif | |
287 return dinfo->output_width * colorBytes; | 283 return dinfo->output_width * colorBytes; |
288 | 284 |
289 } | 285 } |
290 | 286 |
291 /* | 287 /* |
292 * Calculate output dimensions based on the provided factors. | 288 * Calculate output dimensions based on the provided factors. |
293 * | 289 * |
294 * Not to be used on the actual jpeg_decompress_struct used for decoding, since
it will | 290 * Not to be used on the actual jpeg_decompress_struct used for decoding, since
it will |
295 * incorrectly modify num_components. | 291 * incorrectly modify num_components. |
296 */ | 292 */ |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 } | 342 } |
347 SkASSERT(nullptr != decoderMgr); | 343 SkASSERT(nullptr != decoderMgr); |
348 fDecoderMgr.reset(decoderMgr); | 344 fDecoderMgr.reset(decoderMgr); |
349 | 345 |
350 fSwizzler.reset(nullptr); | 346 fSwizzler.reset(nullptr); |
351 fSwizzleSrcRow = nullptr; | 347 fSwizzleSrcRow = nullptr; |
352 fColorXformSrcRow = nullptr; | 348 fColorXformSrcRow = nullptr; |
353 fStorage.reset(); | 349 fStorage.reset(); |
354 fColorXform.reset(nullptr); | 350 fColorXform.reset(nullptr); |
355 | 351 |
356 #if !defined(TURBO_HAS_SKIP) | |
357 fSkipStorage.reset(); | |
358 #endif | |
359 | |
360 return true; | 352 return true; |
361 } | 353 } |
362 | 354 |
363 /* | 355 /* |
364 * Checks if the conversion between the input image and the requested output | 356 * Checks if the conversion between the input image and the requested output |
365 * image has been implemented | 357 * image has been implemented |
366 * Sets the output color space | 358 * Sets the output color space |
367 */ | 359 */ |
368 bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo, bool needsColo
rXform) { | 360 bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo, bool needsColo
rXform) { |
369 if (kUnknown_SkAlphaType == dstInfo.alphaType()) { | 361 if (kUnknown_SkAlphaType == dstInfo.alphaType()) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 } | 393 } |
402 return true; | 394 return true; |
403 case kRGB_565_SkColorType: | 395 case kRGB_565_SkColorType: |
404 if (needsColorXform) { | 396 if (needsColorXform) { |
405 return false; | 397 return false; |
406 } | 398 } |
407 | 399 |
408 if (isCMYK) { | 400 if (isCMYK) { |
409 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; | 401 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; |
410 } else { | 402 } else { |
411 #ifdef TURBO_HAS_565 | |
412 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE; | 403 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE; |
413 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565; | 404 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565; |
414 #else | |
415 fDecoderMgr->dinfo()->out_color_space = JCS_RGB; | |
416 #endif | |
417 } | 405 } |
418 return true; | 406 return true; |
419 case kGray_8_SkColorType: | 407 case kGray_8_SkColorType: |
420 if (needsColorXform || JCS_GRAYSCALE != encodedColorType) { | 408 if (needsColorXform || JCS_GRAYSCALE != encodedColorType) { |
421 return false; | 409 return false; |
422 } | 410 } |
423 | 411 |
424 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE; | 412 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE; |
425 return true; | 413 return true; |
426 case kRGBA_F16_SkColorType: | 414 case kRGBA_F16_SkColorType: |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
569 | 557 |
570 if (!jpeg_start_decompress(dinfo)) { | 558 if (!jpeg_start_decompress(dinfo)) { |
571 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); | 559 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); |
572 } | 560 } |
573 | 561 |
574 // The recommended output buffer height should always be 1 in high quality m
odes. | 562 // The recommended output buffer height should always be 1 in high quality m
odes. |
575 // If it's not, we want to know because it means our strategy is not optimal
. | 563 // If it's not, we want to know because it means our strategy is not optimal
. |
576 SkASSERT(1 == dinfo->rec_outbuf_height); | 564 SkASSERT(1 == dinfo->rec_outbuf_height); |
577 | 565 |
578 J_COLOR_SPACE colorSpace = dinfo->out_color_space; | 566 J_COLOR_SPACE colorSpace = dinfo->out_color_space; |
579 if (JCS_CMYK == colorSpace || JCS_RGB == colorSpace) { | 567 if (JCS_CMYK == colorSpace) { |
580 this->initializeSwizzler(dstInfo, options); | 568 this->initializeSwizzler(dstInfo, options); |
581 } | 569 } |
582 | 570 |
583 this->allocateStorage(dstInfo); | 571 this->allocateStorage(dstInfo); |
584 | 572 |
585 int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height()); | 573 int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height()); |
586 if (rows < dstInfo.height()) { | 574 if (rows < dstInfo.height()) { |
587 *rowsDecoded = rows; | 575 *rowsDecoded = rows; |
588 return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteIn
put); | 576 return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteIn
put); |
589 } | 577 } |
(...skipping 24 matching lines...) Expand all Loading... |
614 fColorXformSrcRow = (xformBytes > 0) ? | 602 fColorXformSrcRow = (xformBytes > 0) ? |
615 SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr; | 603 SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr; |
616 } | 604 } |
617 } | 605 } |
618 | 606 |
619 void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options&
options) { | 607 void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options&
options) { |
620 // libjpeg-turbo may have already performed color conversion. We must indic
ate the | 608 // libjpeg-turbo may have already performed color conversion. We must indic
ate the |
621 // appropriate format to the swizzler. | 609 // appropriate format to the swizzler. |
622 SkEncodedInfo swizzlerInfo = this->getEncodedInfo(); | 610 SkEncodedInfo swizzlerInfo = this->getEncodedInfo(); |
623 bool preSwizzled = true; | 611 bool preSwizzled = true; |
624 switch (fDecoderMgr->dinfo()->out_color_space) { | 612 if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { |
625 case JCS_RGB: | 613 preSwizzled = false; |
626 preSwizzled = false; | 614 swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kInvertedCMYK_Color, |
627 swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kRGB_Color, | 615 swizzlerInfo.alpha(), |
628 swizzlerInfo.alpha(), | 616 swizzlerInfo.bitsPerComponent()); |
629 swizzlerInfo.bitsPerComponent()); | |
630 break; | |
631 case JCS_CMYK: | |
632 preSwizzled = false; | |
633 swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kInvertedCMYK_Colo
r, | |
634 swizzlerInfo.alpha(), | |
635 swizzlerInfo.bitsPerComponent()); | |
636 break; | |
637 default: | |
638 break; | |
639 } | 617 } |
640 | 618 |
641 Options swizzlerOptions = options; | 619 Options swizzlerOptions = options; |
642 if (options.fSubset) { | 620 if (options.fSubset) { |
643 // Use fSwizzlerSubset if this is a subset decode. This is necessary in
the case | 621 // Use fSwizzlerSubset if this is a subset decode. This is necessary in
the case |
644 // where libjpeg-turbo provides a subset and then we need to subset it f
urther. | 622 // where libjpeg-turbo provides a subset and then we need to subset it f
urther. |
645 // Also, verify that fSwizzlerSubset is initialized and valid. | 623 // Also, verify that fSwizzlerSubset is initialized and valid. |
646 SkASSERT(!fSwizzlerSubset.isEmpty() && fSwizzlerSubset.x() <= options.fS
ubset->x() && | 624 SkASSERT(!fSwizzlerSubset.isEmpty() && fSwizzlerSubset.x() <= options.fS
ubset->x() && |
647 fSwizzlerSubset.width() == options.fSubset->width()); | 625 fSwizzlerSubset.width() == options.fSubset->width()); |
648 swizzlerOptions.fSubset = &fSwizzlerSubset; | 626 swizzlerOptions.fSubset = &fSwizzlerSubset; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
691 | 669 |
692 if (!this->initializeColorXform(dstInfo, needsColorXform)) { | 670 if (!this->initializeColorXform(dstInfo, needsColorXform)) { |
693 return fDecoderMgr->returnFailure("initializeColorXform", kInvalidParame
ters); | 671 return fDecoderMgr->returnFailure("initializeColorXform", kInvalidParame
ters); |
694 } | 672 } |
695 | 673 |
696 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { | 674 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { |
697 SkCodecPrintf("start decompress failed\n"); | 675 SkCodecPrintf("start decompress failed\n"); |
698 return kInvalidInput; | 676 return kInvalidInput; |
699 } | 677 } |
700 | 678 |
701 #ifdef TURBO_HAS_CROP | |
702 if (options.fSubset) { | 679 if (options.fSubset) { |
703 uint32_t startX = options.fSubset->x(); | 680 uint32_t startX = options.fSubset->x(); |
704 uint32_t width = options.fSubset->width(); | 681 uint32_t width = options.fSubset->width(); |
705 | 682 |
706 // libjpeg-turbo may need to align startX to a multiple of the IDCT | 683 // libjpeg-turbo may need to align startX to a multiple of the IDCT |
707 // block size. If this is the case, it will decrease the value of | 684 // block size. If this is the case, it will decrease the value of |
708 // startX to the appropriate alignment and also increase the value | 685 // startX to the appropriate alignment and also increase the value |
709 // of width so that the right edge of the requested subset remains | 686 // of width so that the right edge of the requested subset remains |
710 // the same. | 687 // the same. |
711 jpeg_crop_scanline(fDecoderMgr->dinfo(), &startX, &width); | 688 jpeg_crop_scanline(fDecoderMgr->dinfo(), &startX, &width); |
(...skipping 21 matching lines...) Expand all Loading... |
733 if (startX != (uint32_t) options.fSubset->x() || | 710 if (startX != (uint32_t) options.fSubset->x() || |
734 width != (uint32_t) options.fSubset->width()) { | 711 width != (uint32_t) options.fSubset->width()) { |
735 this->initializeSwizzler(dstInfo, options); | 712 this->initializeSwizzler(dstInfo, options); |
736 } | 713 } |
737 } | 714 } |
738 | 715 |
739 // Make sure we have a swizzler if we are converting from CMYK. | 716 // Make sure we have a swizzler if we are converting from CMYK. |
740 if (!fSwizzler && JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { | 717 if (!fSwizzler && JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { |
741 this->initializeSwizzler(dstInfo, options); | 718 this->initializeSwizzler(dstInfo, options); |
742 } | 719 } |
743 #else | |
744 if (options.fSubset) { | |
745 fSwizzlerSubset = *options.fSubset; | |
746 } | |
747 | |
748 // We will need a swizzler if we are performing a subset decode or | |
749 // converting from CMYK. | |
750 J_COLOR_SPACE colorSpace = fDecoderMgr->dinfo()->out_color_space; | |
751 if (options.fSubset || JCS_CMYK == colorSpace || JCS_RGB == colorSpace) { | |
752 this->initializeSwizzler(dstInfo, options); | |
753 } | |
754 #endif | |
755 | 720 |
756 this->allocateStorage(dstInfo); | 721 this->allocateStorage(dstInfo); |
757 | 722 |
758 return kSuccess; | 723 return kSuccess; |
759 } | 724 } |
760 | 725 |
761 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { | 726 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { |
762 int rows = this->readRows(this->dstInfo(), dst, dstRowBytes, count); | 727 int rows = this->readRows(this->dstInfo(), dst, dstRowBytes, count); |
763 if (rows < count) { | 728 if (rows < count) { |
764 // This allows us to skip calling jpeg_finish_decompress(). | 729 // This allows us to skip calling jpeg_finish_decompress(). |
765 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); | 730 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); |
766 } | 731 } |
767 | 732 |
768 return rows; | 733 return rows; |
769 } | 734 } |
770 | 735 |
771 bool SkJpegCodec::onSkipScanlines(int count) { | 736 bool SkJpegCodec::onSkipScanlines(int count) { |
772 // Set the jump location for libjpeg errors | 737 // Set the jump location for libjpeg errors |
773 if (setjmp(fDecoderMgr->getJmpBuf())) { | 738 if (setjmp(fDecoderMgr->getJmpBuf())) { |
774 return fDecoderMgr->returnFalse("onSkipScanlines"); | 739 return fDecoderMgr->returnFalse("onSkipScanlines"); |
775 } | 740 } |
776 | 741 |
777 #ifdef TURBO_HAS_SKIP | |
778 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); | 742 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); |
779 #else | |
780 uint8_t* ptr = fSkipStorage.get(); | |
781 if (!ptr) { | |
782 fSkipStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); | |
783 ptr = fSkipStorage.get(); | |
784 } | |
785 | |
786 for (int y = 0; y < count; y++) { | |
787 if (1 != jpeg_read_scanlines(fDecoderMgr->dinfo(), &ptr, 1)) { | |
788 return false; | |
789 } | |
790 } | |
791 return true; | |
792 #endif | |
793 } | 743 } |
794 | 744 |
795 static bool is_yuv_supported(jpeg_decompress_struct* dinfo) { | 745 static bool is_yuv_supported(jpeg_decompress_struct* dinfo) { |
796 // Scaling is not supported in raw data mode. | 746 // Scaling is not supported in raw data mode. |
797 SkASSERT(dinfo->scale_num == dinfo->scale_denom); | 747 SkASSERT(dinfo->scale_num == dinfo->scale_denom); |
798 | 748 |
799 // I can't imagine that this would ever change, but we do depend on it. | 749 // I can't imagine that this would ever change, but we do depend on it. |
800 static_assert(8 == DCTSIZE, "DCTSIZE (defined in jpeg library) should always
be 8."); | 750 static_assert(8 == DCTSIZE, "DCTSIZE (defined in jpeg library) should always
be 8."); |
801 | 751 |
802 if (JCS_YCbCr != dinfo->jpeg_color_space) { | 752 if (JCS_YCbCr != dinfo->jpeg_color_space) { |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
982 | 932 |
983 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); | 933 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); |
984 if (linesRead < remainingRows) { | 934 if (linesRead < remainingRows) { |
985 // FIXME: Handle incomplete YUV decodes without signalling an error. | 935 // FIXME: Handle incomplete YUV decodes without signalling an error. |
986 return kInvalidInput; | 936 return kInvalidInput; |
987 } | 937 } |
988 } | 938 } |
989 | 939 |
990 return kSuccess; | 940 return kSuccess; |
991 } | 941 } |
OLD | NEW |