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 "SkBitmap.h" | 8 #include "SkBitmap.h" |
9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
(...skipping 421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 return true; | 432 return true; |
433 } | 433 } |
434 | 434 |
435 SkPngCodec::SkPngCodec(int width, int height, const SkEncodedInfo& info, SkStrea
m* stream, | 435 SkPngCodec::SkPngCodec(int width, int height, const SkEncodedInfo& info, SkStrea
m* stream, |
436 SkPngChunkReader* chunkReader, png_structp png_ptr, png_i
nfop info_ptr, | 436 SkPngChunkReader* chunkReader, png_structp png_ptr, png_i
nfop info_ptr, |
437 int bitDepth, int numberPasses, sk_sp<SkColorSpace> color
Space) | 437 int bitDepth, int numberPasses, sk_sp<SkColorSpace> color
Space) |
438 : INHERITED(width, height, info, stream, colorSpace) | 438 : INHERITED(width, height, info, stream, colorSpace) |
439 , fPngChunkReader(SkSafeRef(chunkReader)) | 439 , fPngChunkReader(SkSafeRef(chunkReader)) |
440 , fPng_ptr(png_ptr) | 440 , fPng_ptr(png_ptr) |
441 , fInfo_ptr(info_ptr) | 441 , fInfo_ptr(info_ptr) |
442 , fSrcConfig(SkSwizzler::kUnknown) | |
443 , fNumberPasses(numberPasses) | 442 , fNumberPasses(numberPasses) |
444 , fBitDepth(bitDepth) | 443 , fBitDepth(bitDepth) |
445 {} | 444 {} |
446 | 445 |
447 SkPngCodec::~SkPngCodec() { | 446 SkPngCodec::~SkPngCodec() { |
448 this->destroyReadStruct(); | 447 this->destroyReadStruct(); |
449 } | 448 } |
450 | 449 |
451 void SkPngCodec::destroyReadStruct() { | 450 void SkPngCodec::destroyReadStruct() { |
452 if (fPng_ptr) { | 451 if (fPng_ptr) { |
(...skipping 14 matching lines...) Expand all Loading... |
467 SkPMColor ctable[], | 466 SkPMColor ctable[], |
468 int* ctableCount) { | 467 int* ctableCount) { |
469 // FIXME: Could we use the return value of setjmp to specify the type of | 468 // FIXME: Could we use the return value of setjmp to specify the type of |
470 // error? | 469 // error? |
471 if (setjmp(png_jmpbuf(fPng_ptr))) { | 470 if (setjmp(png_jmpbuf(fPng_ptr))) { |
472 SkCodecPrintf("setjmp long jump!\n"); | 471 SkCodecPrintf("setjmp long jump!\n"); |
473 return kInvalidInput; | 472 return kInvalidInput; |
474 } | 473 } |
475 png_read_update_info(fPng_ptr, fInfo_ptr); | 474 png_read_update_info(fPng_ptr, fInfo_ptr); |
476 | 475 |
477 // suggestedColorType was determined in read_header() based on the encodedCo
lorType | 476 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) { |
478 const SkColorType suggestedColorType = this->getInfo().colorType(); | 477 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType(
), ctableCount)) { |
479 | 478 return kInvalidInput; |
480 switch (suggestedColorType) { | |
481 case kIndex_8_SkColorType: | |
482 //decode palette to Skia format | |
483 fSrcConfig = SkSwizzler::kIndex; | |
484 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT
ype(), | |
485 ctableCount)) { | |
486 return kInvalidInput; | |
487 } | |
488 break; | |
489 case kGray_8_SkColorType: | |
490 fSrcConfig = SkSwizzler::kGray; | |
491 break; | |
492 case kN32_SkColorType: { | |
493 const uint8_t encodedColorType = png_get_color_type(fPng_ptr, fInfo_
ptr); | |
494 if (PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType || | |
495 PNG_COLOR_TYPE_GRAY == encodedColorType) { | |
496 // If encodedColorType is GRAY, there must be a transparent chun
k. | |
497 // Otherwise, suggestedColorType would be kGray. We have alread
y | |
498 // instructed libpng to convert the transparent chunk to alpha, | |
499 // so we can treat both GRAY and GRAY_ALPHA as kGrayAlpha. | |
500 SkASSERT(encodedColorType == PNG_COLOR_TYPE_GRAY_ALPHA || | |
501 png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)); | |
502 | |
503 fSrcConfig = SkSwizzler::kGrayAlpha; | |
504 } else { | |
505 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { | |
506 fSrcConfig = SkSwizzler::kRGB; | |
507 } else { | |
508 fSrcConfig = SkSwizzler::kRGBA; | |
509 } | |
510 } | |
511 break; | |
512 } | 479 } |
513 default: | |
514 // We will always recommend one of the above colorTypes. | |
515 SkASSERT(false); | |
516 } | 480 } |
517 | 481 |
518 // Copy the color table to the client if they request kIndex8 mode | 482 // Copy the color table to the client if they request kIndex8 mode |
519 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); | 483 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); |
520 | 484 |
521 // Create the swizzler. SkPngCodec retains ownership of the color table. | 485 // Create the swizzler. SkPngCodec retains ownership of the color table. |
522 const SkPMColor* colors = get_color_ptr(fColorTable.get()); | 486 const SkPMColor* colors = get_color_ptr(fColorTable.get()); |
523 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo
, options)); | 487 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, r
equestedInfo, |
| 488 options)); |
524 SkASSERT(fSwizzler); | 489 SkASSERT(fSwizzler); |
525 | 490 |
526 return kSuccess; | 491 return kSuccess; |
527 } | 492 } |
528 | 493 |
529 | 494 |
530 bool SkPngCodec::onRewind() { | 495 bool SkPngCodec::onRewind() { |
531 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header | 496 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header |
532 // succeeds, they will be repopulated, and if it fails, they will | 497 // succeeds, they will be repopulated, and if it fails, they will |
533 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will | 498 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will |
534 // come through this function which will rewind and again attempt | 499 // come through this function which will rewind and again attempt |
535 // to reinitialize them. | 500 // to reinitialize them. |
536 this->destroyReadStruct(); | 501 this->destroyReadStruct(); |
537 | 502 |
538 png_structp png_ptr; | 503 png_structp png_ptr; |
539 png_infop info_ptr; | 504 png_infop info_ptr; |
540 if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr, | 505 if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr, |
541 nullptr, nullptr, nullptr, nullptr, nullptr)) { | 506 nullptr, nullptr, nullptr, nullptr, nullptr)) { |
542 return false; | 507 return false; |
543 } | 508 } |
544 | 509 |
545 fPng_ptr = png_ptr; | 510 fPng_ptr = png_ptr; |
546 fInfo_ptr = info_ptr; | 511 fInfo_ptr = info_ptr; |
547 return true; | 512 return true; |
548 } | 513 } |
549 | 514 |
| 515 static int bytes_per_pixel(int bitsPerPixel) { |
| 516 // Note that we will have to change this implementation if we start |
| 517 // supporting outputs from libpng that are less than 8-bits per component. |
| 518 return bitsPerPixel / 8; |
| 519 } |
| 520 |
550 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, | 521 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, |
551 size_t dstRowBytes, const Options& optio
ns, | 522 size_t dstRowBytes, const Options& optio
ns, |
552 SkPMColor ctable[], int* ctableCount, | 523 SkPMColor ctable[], int* ctableCount, |
553 int* rowsDecoded) { | 524 int* rowsDecoded) { |
554 if (!conversion_possible(requestedInfo, this->getInfo())) { | 525 if (!conversion_possible(requestedInfo, this->getInfo())) { |
555 return kInvalidConversion; | 526 return kInvalidConversion; |
556 } | 527 } |
557 if (options.fSubset) { | 528 if (options.fSubset) { |
558 // Subsets are not supported. | 529 // Subsets are not supported. |
559 return kUnimplemented; | 530 return kUnimplemented; |
560 } | 531 } |
561 | 532 |
562 // Note that ctable and ctableCount may be modified if there is a color tabl
e | 533 // Note that ctable and ctableCount may be modified if there is a color tabl
e |
563 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl
e, ctableCount); | 534 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl
e, ctableCount); |
564 if (result != kSuccess) { | 535 if (result != kSuccess) { |
565 return result; | 536 return result; |
566 } | 537 } |
567 | 538 |
568 const int width = requestedInfo.width(); | 539 const int width = requestedInfo.width(); |
569 const int height = requestedInfo.height(); | 540 const int height = requestedInfo.height(); |
570 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); | 541 const int bpp = bytes_per_pixel(this->getEncodedInfo().bitsPerPixel()); |
571 const size_t srcRowBytes = width * bpp; | 542 const size_t srcRowBytes = width * bpp; |
572 | 543 |
573 // FIXME: Could we use the return value of setjmp to specify the type of | 544 // FIXME: Could we use the return value of setjmp to specify the type of |
574 // error? | 545 // error? |
575 int row = 0; | 546 int row = 0; |
576 // This must be declared above the call to setjmp to avoid memory leaks on i
ncomplete images. | 547 // This must be declared above the call to setjmp to avoid memory leaks on i
ncomplete images. |
577 SkAutoTMalloc<uint8_t> storage; | 548 SkAutoTMalloc<uint8_t> storage; |
578 if (setjmp(png_jmpbuf(fPng_ptr))) { | 549 if (setjmp(png_jmpbuf(fPng_ptr))) { |
579 // Assume that any error that occurs while reading rows is caused by an
incomplete input. | 550 // Assume that any error that occurs while reading rows is caused by an
incomplete input. |
580 if (fNumberPasses > 1) { | 551 if (fNumberPasses > 1) { |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 if (!conversion_possible(dstInfo, this->getInfo())) { | 628 if (!conversion_possible(dstInfo, this->getInfo())) { |
658 return kInvalidConversion; | 629 return kInvalidConversion; |
659 } | 630 } |
660 | 631 |
661 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 632 const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
662 ctableCount); | 633 ctableCount); |
663 if (result != kSuccess) { | 634 if (result != kSuccess) { |
664 return result; | 635 return result; |
665 } | 636 } |
666 | 637 |
667 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig())); | 638 fStorage.reset(this->getInfo().width() * |
| 639 (bytes_per_pixel(this->getEncodedInfo().bitsPerPixel()))); |
668 fSrcRow = fStorage.get(); | 640 fSrcRow = fStorage.get(); |
669 | 641 |
670 return kSuccess; | 642 return kSuccess; |
671 } | 643 } |
672 | 644 |
673 int onGetScanlines(void* dst, int count, size_t rowBytes) override { | 645 int onGetScanlines(void* dst, int count, size_t rowBytes) override { |
674 // Assume that an error in libpng indicates an incomplete input. | 646 // Assume that an error in libpng indicates an incomplete input. |
675 int row = 0; | 647 int row = 0; |
676 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 648 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
677 SkCodecPrintf("setjmp long jump!\n"); | 649 SkCodecPrintf("setjmp long jump!\n"); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
729 } | 701 } |
730 | 702 |
731 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 703 const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
732 ctableCount); | 704 ctableCount); |
733 if (result != kSuccess) { | 705 if (result != kSuccess) { |
734 return result; | 706 return result; |
735 } | 707 } |
736 | 708 |
737 fHeight = dstInfo.height(); | 709 fHeight = dstInfo.height(); |
738 // FIXME: This need not be called on a second call to onStartScanlineDec
ode. | 710 // FIXME: This need not be called on a second call to onStartScanlineDec
ode. |
739 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig()); | 711 fSrcRowBytes = this->getInfo().width() * |
| 712 (bytes_per_pixel(this->getEncodedInfo().bitsPerPixel())); |
740 fGarbageRow.reset(fSrcRowBytes); | 713 fGarbageRow.reset(fSrcRowBytes); |
741 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 714 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
742 fCanSkipRewind = true; | 715 fCanSkipRewind = true; |
743 | 716 |
744 return SkCodec::kSuccess; | 717 return SkCodec::kSuccess; |
745 } | 718 } |
746 | 719 |
747 int onGetScanlines(void* dst, int count, size_t dstRowBytes) override { | 720 int onGetScanlines(void* dst, int count, size_t dstRowBytes) override { |
748 // rewind stream if have previously called onGetScanlines, | 721 // rewind stream if have previously called onGetScanlines, |
749 // since we need entire progressive image to get scanlines | 722 // since we need entire progressive image to get scanlines |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 | 824 |
852 if (1 == numberPasses) { | 825 if (1 == numberPasses) { |
853 return new SkPngScanlineDecoder(width, height, imageInfo, streamDeleter.
release(), | 826 return new SkPngScanlineDecoder(width, height, imageInfo, streamDeleter.
release(), |
854 chunkReader, png_ptr, info_ptr, bitDepth
, colorSpace); | 827 chunkReader, png_ptr, info_ptr, bitDepth
, colorSpace); |
855 } | 828 } |
856 | 829 |
857 return new SkPngInterlacedScanlineDecoder(width, height, imageInfo, streamDe
leter.release(), | 830 return new SkPngInterlacedScanlineDecoder(width, height, imageInfo, streamDe
leter.release(), |
858 chunkReader, png_ptr, info_ptr, bi
tDepth, | 831 chunkReader, png_ptr, info_ptr, bi
tDepth, |
859 numberPasses, colorSpace); | 832 numberPasses, colorSpace); |
860 } | 833 } |
OLD | NEW |