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

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

Issue 2246143002: Support color xforms for kIndex8 pngs (Closed) Base URL: https://skia.googlesource.com/skia.git@xformpremul
Patch Set: Response to comments Created 4 years, 4 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') | no next file » | 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 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 fPng_ptr = nullptr; 85 fPng_ptr = nullptr;
86 fInfo_ptr = nullptr; 86 fInfo_ptr = nullptr;
87 } 87 }
88 88
89 private: 89 private:
90 png_structp fPng_ptr; 90 png_structp fPng_ptr;
91 png_infop fInfo_ptr; 91 png_infop fInfo_ptr;
92 }; 92 };
93 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng) 93 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
94 94
95 static inline SkAlphaType xform_alpha_type(SkAlphaType dstAlphaType, SkAlphaType srcAlphaType) {
96 return (kOpaque_SkAlphaType == srcAlphaType) ? kOpaque_SkAlphaType : dstAlph aType;
97 }
98
95 // Note: SkColorTable claims to store SkPMColors, which is not necessarily the c ase here. 99 // Note: SkColorTable claims to store SkPMColors, which is not necessarily the c ase here.
96 bool SkPngCodec::createColorTable(SkColorType dstColorType, bool premultiply, in t* ctableCount) { 100 bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount) {
97 101
98 int numColors; 102 int numColors;
99 png_color* palette; 103 png_color* palette;
100 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) { 104 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) {
101 return false; 105 return false;
102 } 106 }
103 107
104 // Note: These are not necessarily SkPMColors. 108 // Contents depend on tableColorType and our choice of if/when to premultipl y:
105 SkPMColor colorPtr[256]; 109 // { kPremul, kUnpremul, kOpaque } x { RGBA, BGRA }
110 SkPMColor colorTable[256];
111 SkColorType tableColorType = fColorXform ? kRGBA_8888_SkColorType : dstInfo. colorType();
106 112
107 png_bytep alphas; 113 png_bytep alphas;
108 int numColorsWithAlpha = 0; 114 int numColorsWithAlpha = 0;
109 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr) ) { 115 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr) ) {
116 // If we are performing a color xform, it will handle the premultiply. Otherwise,
117 // we'll do it here.
118 bool premultiply = !fColorXform && needs_premul(dstInfo, this->getInfo( ));
119
110 // Choose which function to use to create the color table. If the final destination's 120 // 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. 121 // colortype is unpremultiplied, the color table will store unpremultipl ied colors.
112 PackColorProc proc = choose_pack_color_proc(premultiply, dstColorType); 122 PackColorProc proc = choose_pack_color_proc(premultiply, tableColorType) ;
113 123
114 for (int i = 0; i < numColorsWithAlpha; i++) { 124 for (int i = 0; i < numColorsWithAlpha; i++) {
115 // We don't have a function in SkOpts that combines a set of alphas with a set 125 // We don't have a function in SkOpts that combines a set of alphas with a set
116 // of RGBs. We could write one, but it's hardly worth it, given tha t this 126 // of RGBs. We could write one, but it's hardly worth it, given tha t this
117 // is such a small fraction of the total decode time. 127 // is such a small fraction of the total decode time.
118 colorPtr[i] = proc(alphas[i], palette->red, palette->green, palette- >blue); 128 colorTable[i] = proc(alphas[i], palette->red, palette->green, palett e->blue);
119 palette++; 129 palette++;
120 } 130 }
121 } 131 }
122 132
123 if (numColorsWithAlpha < numColors) { 133 if (numColorsWithAlpha < numColors) {
124 // The optimized code depends on a 3-byte png_color struct with the colo rs 134 // The optimized code depends on a 3-byte png_color struct with the colo rs
125 // in RGB order. These checks make sure it is safe to use. 135 // in RGB order. These checks make sure it is safe to use.
126 static_assert(3 == sizeof(png_color), "png_color struct has changed. Op ts are broken."); 136 static_assert(3 == sizeof(png_color), "png_color struct has changed. Op ts are broken.");
127 #ifdef SK_DEBUG 137 #ifdef SK_DEBUG
128 SkASSERT(&palette->red < &palette->green); 138 SkASSERT(&palette->red < &palette->green);
129 SkASSERT(&palette->green < &palette->blue); 139 SkASSERT(&palette->green < &palette->blue);
130 #endif 140 #endif
131 141
132 if (is_rgba(dstColorType)) { 142 if (is_rgba(tableColorType)) {
133 SkOpts::RGB_to_RGB1(colorPtr + numColorsWithAlpha, palette, 143 SkOpts::RGB_to_RGB1(colorTable + numColorsWithAlpha, palette,
134 numColors - numColorsWithAlpha); 144 numColors - numColorsWithAlpha);
135 } else { 145 } else {
136 SkOpts::RGB_to_BGR1(colorPtr + numColorsWithAlpha, palette, 146 SkOpts::RGB_to_BGR1(colorTable + numColorsWithAlpha, palette,
137 numColors - numColorsWithAlpha); 147 numColors - numColorsWithAlpha);
138 } 148 }
139 } 149 }
140 150
151 // If we are not decoding to F16, we can color xform now and store the resul ts
152 // in the color table.
153 if (fColorXform && kRGBA_F16_SkColorType != dstInfo.colorType()) {
154 SkColorType xformColorType = is_rgba(dstInfo.colorType()) ?
155 kRGBA_8888_SkColorType : kBGRA_8888_SkColorType;
156 SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(),
157 this->getInfo().alphaType( ));
158 fColorXform->apply(colorTable, colorTable, numColors, xformColorType, xf ormAlphaType);
159 }
160
141 // Pad the color table with the last color in the table (or black) in the ca se that 161 // Pad the color table with the last color in the table (or black) in the ca se that
142 // invalid pixel indices exceed the number of colors in the table. 162 // invalid pixel indices exceed the number of colors in the table.
143 const int maxColors = 1 << fBitDepth; 163 const int maxColors = 1 << fBitDepth;
144 if (numColors < maxColors) { 164 if (numColors < maxColors) {
145 SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_Color BLACK; 165 SkPMColor lastColor = numColors > 0 ? colorTable[numColors - 1] : SK_Col orBLACK;
146 sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors); 166 sk_memset32(colorTable + numColors, lastColor, maxColors - numColors);
147 } 167 }
148 168
149 // Set the new color count. 169 // Set the new color count.
150 if (ctableCount != nullptr) { 170 if (ctableCount != nullptr) {
151 *ctableCount = maxColors; 171 *ctableCount = maxColors;
152 } 172 }
153 173
154 fColorTable.reset(new SkColorTable(colorPtr, maxColors)); 174 fColorTable.reset(new SkColorTable(colorTable, maxColors));
155 return true; 175 return true;
156 } 176 }
157 177
158 /////////////////////////////////////////////////////////////////////////////// 178 ///////////////////////////////////////////////////////////////////////////////
159 // Creation 179 // Creation
160 /////////////////////////////////////////////////////////////////////////////// 180 ///////////////////////////////////////////////////////////////////////////////
161 181
162 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) { 182 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) {
163 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead); 183 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead);
164 } 184 }
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 380
361 void SkPngCodec::allocateStorage() { 381 void SkPngCodec::allocateStorage() {
362 size_t colorXformBytes = fColorXform ? fSwizzler->swizzleWidth() * sizeof(ui nt32_t) : 0; 382 size_t colorXformBytes = fColorXform ? fSwizzler->swizzleWidth() * sizeof(ui nt32_t) : 0;
363 383
364 fStorage.reset(SkAlign4(fSrcRowBytes) + colorXformBytes); 384 fStorage.reset(SkAlign4(fSrcRowBytes) + colorXformBytes);
365 fSwizzlerSrcRow = fStorage.get(); 385 fSwizzlerSrcRow = fStorage.get();
366 fColorXformSrcRow = 386 fColorXformSrcRow =
367 fColorXform ? SkTAddOffset<uint32_t>(fSwizzlerSrcRow, SkAlign4(fSrcR owBytes)) : 0; 387 fColorXform ? SkTAddOffset<uint32_t>(fSwizzlerSrcRow, SkAlign4(fSrcR owBytes)) : 0;
368 } 388 }
369 389
390 static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo ::Color srcColor) {
391 // We will apply the color xform when reading the color table, unless F16 is requested.
392 return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType == dstColorType;
393 }
394
370 class SkPngNormalCodec : public SkPngCodec { 395 class SkPngNormalCodec : public SkPngCodec {
371 public: 396 public:
372 SkPngNormalCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageI nfo, 397 SkPngNormalCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageI nfo,
373 SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr , 398 SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr ,
374 png_infop info_ptr, int bitDepth) 399 png_infop info_ptr, int bitDepth)
375 : INHERITED(encodedInfo, imageInfo, stream, chunkReader, png_ptr, info_p tr, bitDepth, 1) 400 : INHERITED(encodedInfo, imageInfo, stream, chunkReader, png_ptr, info_p tr, bitDepth, 1)
376 {} 401 {}
377 402
378 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, 403 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
379 SkPMColor ctable[], int* ctableCount) override { 404 SkPMColor ctable[], int* ctableCount) override {
(...skipping 13 matching lines...) Expand all
393 418
394 // Assume that an error in libpng indicates an incomplete input. 419 // Assume that an error in libpng indicates an incomplete input.
395 int y = 0; 420 int y = 0;
396 if (setjmp(png_jmpbuf(fPng_ptr))) { 421 if (setjmp(png_jmpbuf(fPng_ptr))) {
397 SkCodecPrintf("Failed to read row.\n"); 422 SkCodecPrintf("Failed to read row.\n");
398 return y; 423 return y;
399 } 424 }
400 425
401 void* swizzlerDstRow = dst; 426 void* swizzlerDstRow = dst;
402 size_t swizzlerDstRowBytes = rowBytes; 427 size_t swizzlerDstRowBytes = rowBytes;
403 if (fColorXform) { 428
429 bool colorXform = fColorXform &&
430 apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo( ).color());
431 if (colorXform) {
404 swizzlerDstRow = fColorXformSrcRow; 432 swizzlerDstRow = fColorXformSrcRow;
405 swizzlerDstRowBytes = 0; 433 swizzlerDstRowBytes = 0;
406 } 434 }
407 435
408 SkAlphaType xformAlphaType = (kOpaque_SkAlphaType == this->getInfo().alp haType()) ? 436 SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(),
409 kOpaque_SkAlphaType : dstInfo.alphaType(); 437 this->getInfo().alphaType( ));
410 for (; y < count; y++) { 438 for (; y < count; y++) {
411 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr); 439 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr);
412 fSwizzler->swizzle(swizzlerDstRow, fSwizzlerSrcRow); 440 fSwizzler->swizzle(swizzlerDstRow, fSwizzlerSrcRow);
413 441
414 if (fColorXform) { 442 if (colorXform) {
415 fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizz ler->swizzleWidth(), 443 fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizz ler->swizzleWidth(),
416 dstInfo.colorType(), xformAlphaType); 444 dstInfo.colorType(), xformAlphaType);
417 dst = SkTAddOffset<void>(dst, rowBytes); 445 dst = SkTAddOffset<void>(dst, rowBytes);
418 } 446 }
419 447
420 swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBy tes); 448 swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBy tes);
421 } 449 }
422 450
423 return y; 451 return y;
424 } 452 }
(...skipping 10 matching lines...) Expand all
435 463
436 for (int row = 0; row < count; row++) { 464 for (int row = 0; row < count; row++) {
437 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr); 465 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr);
438 } 466 }
439 return true; 467 return true;
440 } 468 }
441 469
442 typedef SkPngCodec INHERITED; 470 typedef SkPngCodec INHERITED;
443 }; 471 };
444 472
445
446 class SkPngInterlacedCodec : public SkPngCodec { 473 class SkPngInterlacedCodec : public SkPngCodec {
447 public: 474 public:
448 SkPngInterlacedCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& im ageInfo, 475 SkPngInterlacedCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& im ageInfo,
449 SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr , 476 SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr ,
450 png_infop info_ptr, int bitDepth, int numberPasses) 477 png_infop info_ptr, int bitDepth, int numberPasses)
451 : INHERITED(encodedInfo, imageInfo, stream, chunkReader, png_ptr, info_p tr, bitDepth, 478 : INHERITED(encodedInfo, imageInfo, stream, chunkReader, png_ptr, info_p tr, bitDepth,
452 numberPasses) 479 numberPasses)
453 , fCanSkipRewind(false) 480 , fCanSkipRewind(false)
454 { 481 {
455 SkASSERT(numberPasses != 1); 482 SkASSERT(numberPasses != 1);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
493 } 520 }
494 // Discard rows that we don't need. 521 // Discard rows that we don't need.
495 for (int y = 0; y < this->getInfo().height() - startRow - count; y++ ) { 522 for (int y = 0; y < this->getInfo().height() - startRow - count; y++ ) {
496 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr); 523 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr);
497 } 524 }
498 } 525 }
499 526
500 // Swizzle and xform the rows we care about 527 // Swizzle and xform the rows we care about
501 void* swizzlerDstRow = dst; 528 void* swizzlerDstRow = dst;
502 size_t swizzlerDstRowBytes = rowBytes; 529 size_t swizzlerDstRowBytes = rowBytes;
503 if (fColorXform) { 530
531 bool colorXform = fColorXform &&
532 apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo( ).color());
533 if (colorXform) {
504 swizzlerDstRow = fColorXformSrcRow; 534 swizzlerDstRow = fColorXformSrcRow;
505 swizzlerDstRowBytes = 0; 535 swizzlerDstRowBytes = 0;
506 } 536 }
507 537
508 SkAlphaType xformAlphaType = (kOpaque_SkAlphaType == this->getInfo().alp haType()) ? 538 SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(),
509 kOpaque_SkAlphaType : dstInfo.alphaType(); 539 this->getInfo().alphaType( ));
510 srcRow = storage.get(); 540 srcRow = storage.get();
511 for (int y = 0; y < count; y++) { 541 for (int y = 0; y < count; y++) {
512 fSwizzler->swizzle(swizzlerDstRow, srcRow); 542 fSwizzler->swizzle(swizzlerDstRow, srcRow);
513 srcRow = SkTAddOffset<uint8_t>(srcRow, fSrcRowBytes); 543 srcRow = SkTAddOffset<uint8_t>(srcRow, fSrcRowBytes);
514 544
515 if (fColorXform) { 545 if (colorXform) {
516 if (fColorXform) { 546 fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizz ler->swizzleWidth(),
517 fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, 547 dstInfo.colorType(), xformAlphaType);
518 fSwizzler->swizzleWidth(), dstInfo.colorT ype(), 548 dst = SkTAddOffset<void>(dst, rowBytes);
519 xformAlphaType);
520 dst = SkTAddOffset<void>(dst, rowBytes);
521 }
522 } 549 }
523 550
524 swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBy tes); 551 swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBy tes);
525 } 552 }
526 553
527 return count; 554 return count;
528 } 555 }
529 556
530 int onGetScanlines(void* dst, int count, size_t rowBytes) override { 557 int onGetScanlines(void* dst, int count, size_t rowBytes) override {
531 // rewind stream if have previously called onGetScanlines, 558 // rewind stream if have previously called onGetScanlines,
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
795 if (needsColorXform) { 822 if (needsColorXform) {
796 switch (dstInfo.colorType()) { 823 switch (dstInfo.colorType()) {
797 case kRGBA_8888_SkColorType: 824 case kRGBA_8888_SkColorType:
798 case kBGRA_8888_SkColorType: 825 case kBGRA_8888_SkColorType:
799 case kRGBA_F16_SkColorType: 826 case kRGBA_F16_SkColorType:
800 swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType ); 827 swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType );
801 if (kPremul_SkAlphaType == dstInfo.alphaType()) { 828 if (kPremul_SkAlphaType == dstInfo.alphaType()) {
802 swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaT ype); 829 swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaT ype);
803 } 830 }
804 break; 831 break;
832 case kIndex_8_SkColorType:
833 break;
805 default: 834 default:
806 return false; 835 return false;
807 } 836 }
808 837
809 fColorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpac e()), 838 fColorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpac e()),
810 sk_ref_sp(dstInfo.colorSpace())); 839 sk_ref_sp(dstInfo.colorSpace()));
811 840
812 if (!fColorXform && kRGBA_F16_SkColorType == dstInfo.colorType()) { 841 if (!fColorXform && kRGBA_F16_SkColorType == dstInfo.colorType()) {
813 return false; 842 return false;
814 } 843 }
815 } 844 }
816 845
817 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) { 846 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) {
818 if (!this->createColorTable(swizzlerInfo.colorType(), 847 if (!this->createColorTable(dstInfo, ctableCount)) {
819 kPremul_SkAlphaType == swizzlerInfo.alphaTyp e(), ctableCount)) {
820 return false; 848 return false;
821 } 849 }
822 } 850 }
823 851
824 // Copy the color table to the client if they request kIndex8 mode 852 // Copy the color table to the client if they request kIndex8 mode
825 copy_color_table(swizzlerInfo, fColorTable, ctable, ctableCount); 853 copy_color_table(swizzlerInfo, fColorTable, ctable, ctableCount);
826 854
827 // Create the swizzler. SkPngCodec retains ownership of the color table. 855 // Create the swizzler. SkPngCodec retains ownership of the color table.
828 const SkPMColor* colors = get_color_ptr(fColorTable.get()); 856 const SkPMColor* colors = get_color_ptr(fColorTable.get());
829 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, s wizzlerInfo, 857 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, s wizzlerInfo,
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
889 SkCodec* outCodec; 917 SkCodec* outCodec;
890 if (read_header(stream, chunkReader, &outCodec, nullptr, nullptr)) { 918 if (read_header(stream, chunkReader, &outCodec, nullptr, nullptr)) {
891 // Codec has taken ownership of the stream. 919 // Codec has taken ownership of the stream.
892 SkASSERT(outCodec); 920 SkASSERT(outCodec);
893 streamDeleter.release(); 921 streamDeleter.release();
894 return outCodec; 922 return outCodec;
895 } 923 }
896 924
897 return nullptr; 925 return nullptr;
898 } 926 }
OLDNEW
« no previous file with comments | « src/codec/SkPngCodec.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698