Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Side by Side Diff: src/codec/SkPngCodec.cpp

Issue 1835083002: Support RGBA/BGRA swizzles using SkEncodedInfo (Closed) Base URL: https://skia.googlesource.com/skia.git@skencodedinfo
Patch Set: Fix bugs Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/codec/SkPngCodec.h ('k') | src/codec/SkRawCodec.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 fPng_ptr = nullptr; 79 fPng_ptr = nullptr;
80 fInfo_ptr = nullptr; 80 fInfo_ptr = nullptr;
81 } 81 }
82 82
83 private: 83 private:
84 png_structp fPng_ptr; 84 png_structp fPng_ptr;
85 png_infop fInfo_ptr; 85 png_infop fInfo_ptr;
86 }; 86 };
87 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng) 87 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
88 88
89 // Method for coverting to either an SkPMColor or a similarly packed
90 // unpremultiplied color.
91 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
92
93 // Note: SkColorTable claims to store SkPMColors, which is not necessarily 89 // Note: SkColorTable claims to store SkPMColors, which is not necessarily
94 // the case here. 90 // the case here.
95 // TODO: If we add support for non-native swizzles, we'll need to handle that he re. 91 // TODO: If we add support for non-native swizzles, we'll need to handle that he re.
96 bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { 92 bool SkPngCodec::decodePalette(bool premultiply, SkColorType dstColorType, int* ctableCount) {
97 93
98 int numColors; 94 int numColors;
99 png_color* palette; 95 png_color* palette;
100 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) { 96 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) {
101 return false; 97 return false;
102 } 98 }
103 99
104 // Note: These are not necessarily SkPMColors. 100 // Note: These are not necessarily SkPMColors.
105 SkPMColor colorPtr[256]; 101 SkPMColor colorPtr[256];
106 102
107 png_bytep alphas; 103 png_bytep alphas;
108 int numColorsWithAlpha = 0; 104 int numColorsWithAlpha = 0;
109 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr) ) { 105 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr) ) {
110 // Choose which function to use to create the color table. If the final destination's 106 // Choose which function to use to create the color table. If the final destination's
111 // colortype is unpremultiplied, the color table will store unpremultipl ied colors. 107 // colortype is unpremultiplied, the color table will store unpremultipl ied colors.
112 PackColorProc proc; 108 PackColorProc proc = choose_pack_color_proc(premultiply, dstColorType);
113 if (premultiply) {
114 proc = &SkPremultiplyARGBInline;
115 } else {
116 proc = &SkPackARGB32NoCheck;
117 }
118 109
119 for (int i = 0; i < numColorsWithAlpha; i++) { 110 for (int i = 0; i < numColorsWithAlpha; i++) {
120 // We don't have a function in SkOpts that combines a set of alphas with a set 111 // We don't have a function in SkOpts that combines a set of alphas with a set
121 // of RGBs. We could write one, but it's hardly worth it, given tha t this 112 // of RGBs. We could write one, but it's hardly worth it, given tha t this
122 // is such a small fraction of the total decode time. 113 // is such a small fraction of the total decode time.
123 colorPtr[i] = proc(alphas[i], palette->red, palette->green, palette- >blue); 114 colorPtr[i] = proc(alphas[i], palette->red, palette->green, palette- >blue);
124 palette++; 115 palette++;
125 } 116 }
126 } 117 }
127 118
128 if (numColorsWithAlpha < numColors) { 119 if (numColorsWithAlpha < numColors) {
129 // The optimized code depends on a 3-byte png_color struct with the colo rs 120 // The optimized code depends on a 3-byte png_color struct with the colo rs
130 // in RGB order. These checks make sure it is safe to use. 121 // in RGB order. These checks make sure it is safe to use.
131 static_assert(3 == sizeof(png_color), "png_color struct has changed. Op ts are broken."); 122 static_assert(3 == sizeof(png_color), "png_color struct has changed. Op ts are broken.");
132 #ifdef SK_DEBUG 123 #ifdef SK_DEBUG
133 SkASSERT(&palette->red < &palette->green); 124 SkASSERT(&palette->red < &palette->green);
134 SkASSERT(&palette->green < &palette->blue); 125 SkASSERT(&palette->green < &palette->blue);
135 #endif 126 #endif
136 127
137 #ifdef SK_PMCOLOR_IS_RGBA 128 if (is_rgba(dstColorType)) {
138 SkOpts::RGB_to_RGB1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha); 129 SkOpts::RGB_to_RGB1(colorPtr + numColorsWithAlpha, palette,
139 #else 130 numColors - numColorsWithAlpha);
140 SkOpts::RGB_to_BGR1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha); 131 } else {
141 #endif 132 SkOpts::RGB_to_BGR1(colorPtr + numColorsWithAlpha, palette,
133 numColors - numColorsWithAlpha);
134 }
142 } 135 }
143 136
144 // Pad the color table with the last color in the table (or black) in the ca se that 137 // Pad the color table with the last color in the table (or black) in the ca se that
145 // invalid pixel indices exceed the number of colors in the table. 138 // invalid pixel indices exceed the number of colors in the table.
146 const int maxColors = 1 << fBitDepth; 139 const int maxColors = 1 << fBitDepth;
147 if (numColors < maxColors) { 140 if (numColors < maxColors) {
148 SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_Color BLACK; 141 SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_Color BLACK;
149 sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors); 142 sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors);
150 } 143 }
151 144
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 return true; 411 return true;
419 } 412 }
420 413
421 SkPngCodec::SkPngCodec(const SkEncodedInfo& info, SkStream* stream, SkPngChunkRe ader* chunkReader, 414 SkPngCodec::SkPngCodec(const SkEncodedInfo& info, SkStream* stream, SkPngChunkRe ader* chunkReader,
422 png_structp png_ptr, png_infop info_ptr, int bitDepth, in t numberPasses, 415 png_structp png_ptr, png_infop info_ptr, int bitDepth, in t numberPasses,
423 sk_sp<SkColorSpace> colorSpace) 416 sk_sp<SkColorSpace> colorSpace)
424 : INHERITED(info, stream, colorSpace) 417 : INHERITED(info, stream, colorSpace)
425 , fPngChunkReader(SkSafeRef(chunkReader)) 418 , fPngChunkReader(SkSafeRef(chunkReader))
426 , fPng_ptr(png_ptr) 419 , fPng_ptr(png_ptr)
427 , fInfo_ptr(info_ptr) 420 , fInfo_ptr(info_ptr)
428 , fSrcConfig(SkSwizzler::kUnknown)
429 , fNumberPasses(numberPasses) 421 , fNumberPasses(numberPasses)
430 , fBitDepth(bitDepth) 422 , fBitDepth(bitDepth)
431 {} 423 {}
432 424
433 SkPngCodec::~SkPngCodec() { 425 SkPngCodec::~SkPngCodec() {
434 this->destroyReadStruct(); 426 this->destroyReadStruct();
435 } 427 }
436 428
437 void SkPngCodec::destroyReadStruct() { 429 void SkPngCodec::destroyReadStruct() {
438 if (fPng_ptr) { 430 if (fPng_ptr) {
(...skipping 14 matching lines...) Expand all
453 SkPMColor ctable[], 445 SkPMColor ctable[],
454 int* ctableCount) { 446 int* ctableCount) {
455 // FIXME: Could we use the return value of setjmp to specify the type of 447 // FIXME: Could we use the return value of setjmp to specify the type of
456 // error? 448 // error?
457 if (setjmp(png_jmpbuf(fPng_ptr))) { 449 if (setjmp(png_jmpbuf(fPng_ptr))) {
458 SkCodecPrintf("setjmp long jump!\n"); 450 SkCodecPrintf("setjmp long jump!\n");
459 return kInvalidInput; 451 return kInvalidInput;
460 } 452 }
461 png_read_update_info(fPng_ptr, fInfo_ptr); 453 png_read_update_info(fPng_ptr, fInfo_ptr);
462 454
463 // suggestedColorType was determined in read_header() based on the encodedCo lorType 455 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) {
464 const SkColorType suggestedColorType = this->getInfo().colorType(); 456 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType( ),
465 457 requestedInfo.colorType(), ctableCount)) {
466 switch (suggestedColorType) { 458 return kInvalidInput;
467 case kIndex_8_SkColorType:
468 //decode palette to Skia format
469 fSrcConfig = SkSwizzler::kIndex;
470 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(),
471 ctableCount)) {
472 return kInvalidInput;
473 }
474 break;
475 case kGray_8_SkColorType:
476 fSrcConfig = SkSwizzler::kGray;
477 break;
478 case kN32_SkColorType: {
479 const uint8_t encodedColorType = png_get_color_type(fPng_ptr, fInfo_ ptr);
480 if (PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType ||
481 PNG_COLOR_TYPE_GRAY == encodedColorType) {
482 // If encodedColorType is GRAY, there must be a transparent chun k.
483 // Otherwise, suggestedColorType would be kGray. We have alread y
484 // instructed libpng to convert the transparent chunk to alpha,
485 // so we can treat both GRAY and GRAY_ALPHA as kGrayAlpha.
486 SkASSERT(encodedColorType == PNG_COLOR_TYPE_GRAY_ALPHA ||
487 png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS));
488
489 fSrcConfig = SkSwizzler::kGrayAlpha;
490 } else {
491 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) {
492 fSrcConfig = SkSwizzler::kRGB;
493 } else {
494 fSrcConfig = SkSwizzler::kRGBA;
495 }
496 }
497 break;
498 } 459 }
499 default:
500 // We will always recommend one of the above colorTypes.
501 SkASSERT(false);
502 } 460 }
503 461
504 // Copy the color table to the client if they request kIndex8 mode 462 // Copy the color table to the client if they request kIndex8 mode
505 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); 463 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount);
506 464
507 // Create the swizzler. SkPngCodec retains ownership of the color table. 465 // Create the swizzler. SkPngCodec retains ownership of the color table.
508 const SkPMColor* colors = get_color_ptr(fColorTable.get()); 466 const SkPMColor* colors = get_color_ptr(fColorTable.get());
509 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , options)); 467 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, r equestedInfo,
468 options));
510 SkASSERT(fSwizzler); 469 SkASSERT(fSwizzler);
511 470
512 return kSuccess; 471 return kSuccess;
513 } 472 }
514 473
515 474
516 bool SkPngCodec::onRewind() { 475 bool SkPngCodec::onRewind() {
517 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header 476 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
518 // succeeds, they will be repopulated, and if it fails, they will 477 // succeeds, they will be repopulated, and if it fails, they will
519 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will 478 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
(...skipping 26 matching lines...) Expand all
546 } 505 }
547 506
548 // Note that ctable and ctableCount may be modified if there is a color tabl e 507 // Note that ctable and ctableCount may be modified if there is a color tabl e
549 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl e, ctableCount); 508 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl e, ctableCount);
550 if (result != kSuccess) { 509 if (result != kSuccess) {
551 return result; 510 return result;
552 } 511 }
553 512
554 const int width = requestedInfo.width(); 513 const int width = requestedInfo.width();
555 const int height = requestedInfo.height(); 514 const int height = requestedInfo.height();
556 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); 515 const int bpp = this->getEncodedInfo().bytesPerPixel();
557 const size_t srcRowBytes = width * bpp; 516 const size_t srcRowBytes = width * bpp;
558 517
559 // FIXME: Could we use the return value of setjmp to specify the type of 518 // FIXME: Could we use the return value of setjmp to specify the type of
560 // error? 519 // error?
561 int row = 0; 520 int row = 0;
562 // This must be declared above the call to setjmp to avoid memory leaks on i ncomplete images. 521 // This must be declared above the call to setjmp to avoid memory leaks on i ncomplete images.
563 SkAutoTMalloc<uint8_t> storage; 522 SkAutoTMalloc<uint8_t> storage;
564 if (setjmp(png_jmpbuf(fPng_ptr))) { 523 if (setjmp(png_jmpbuf(fPng_ptr))) {
565 // Assume that any error that occurs while reading rows is caused by an incomplete input. 524 // Assume that any error that occurs while reading rows is caused by an incomplete input.
566 if (fNumberPasses > 1) { 525 if (fNumberPasses > 1) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 if (!conversion_possible(dstInfo, this->getInfo())) { 601 if (!conversion_possible(dstInfo, this->getInfo())) {
643 return kInvalidConversion; 602 return kInvalidConversion;
644 } 603 }
645 604
646 const Result result = this->initializeSwizzler(dstInfo, options, ctable, 605 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
647 ctableCount); 606 ctableCount);
648 if (result != kSuccess) { 607 if (result != kSuccess) {
649 return result; 608 return result;
650 } 609 }
651 610
652 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig())); 611 fStorage.reset(this->getInfo().width() * this->getEncodedInfo().bytesPer Pixel());
653 fSrcRow = fStorage.get(); 612 fSrcRow = fStorage.get();
654 613
655 return kSuccess; 614 return kSuccess;
656 } 615 }
657 616
658 int onGetScanlines(void* dst, int count, size_t rowBytes) override { 617 int onGetScanlines(void* dst, int count, size_t rowBytes) override {
659 // Assume that an error in libpng indicates an incomplete input. 618 // Assume that an error in libpng indicates an incomplete input.
660 int row = 0; 619 int row = 0;
661 if (setjmp(png_jmpbuf(this->png_ptr()))) { 620 if (setjmp(png_jmpbuf(this->png_ptr()))) {
662 SkCodecPrintf("setjmp long jump!\n"); 621 SkCodecPrintf("setjmp long jump!\n");
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
714 } 673 }
715 674
716 const Result result = this->initializeSwizzler(dstInfo, options, ctable, 675 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
717 ctableCount); 676 ctableCount);
718 if (result != kSuccess) { 677 if (result != kSuccess) {
719 return result; 678 return result;
720 } 679 }
721 680
722 fHeight = dstInfo.height(); 681 fHeight = dstInfo.height();
723 // FIXME: This need not be called on a second call to onStartScanlineDec ode. 682 // FIXME: This need not be called on a second call to onStartScanlineDec ode.
724 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig()); 683 fSrcRowBytes = this->getInfo().width() * this->getEncodedInfo().bytesPer Pixel();
725 fGarbageRow.reset(fSrcRowBytes); 684 fGarbageRow.reset(fSrcRowBytes);
726 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); 685 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
727 fCanSkipRewind = true; 686 fCanSkipRewind = true;
728 687
729 return SkCodec::kSuccess; 688 return SkCodec::kSuccess;
730 } 689 }
731 690
732 int onGetScanlines(void* dst, int count, size_t dstRowBytes) override { 691 int onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
733 // rewind stream if have previously called onGetScanlines, 692 // rewind stream if have previously called onGetScanlines,
734 // since we need entire progressive image to get scanlines 693 // since we need entire progressive image to get scanlines
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
835 794
836 if (1 == numberPasses) { 795 if (1 == numberPasses) {
837 return new SkPngScanlineDecoder(imageInfo, streamDeleter.release(), chun kReader, 796 return new SkPngScanlineDecoder(imageInfo, streamDeleter.release(), chun kReader,
838 png_ptr, info_ptr, bitDepth, colorSpace) ; 797 png_ptr, info_ptr, bitDepth, colorSpace) ;
839 } 798 }
840 799
841 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.release() , chunkReader, 800 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.release() , chunkReader,
842 png_ptr, info_ptr, bitDepth, numbe rPasses, 801 png_ptr, info_ptr, bitDepth, numbe rPasses,
843 colorSpace); 802 colorSpace);
844 } 803 }
OLDNEW
« no previous file with comments | « src/codec/SkPngCodec.h ('k') | src/codec/SkRawCodec.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698