| 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 |