| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
| 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 "SkImageEncoder.h" | 8 #include "SkImageEncoder.h" |
| 9 #include "SkColor.h" | 9 #include "SkColor.h" |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 int bits = SkNextLog2(colorCount); | 96 int bits = SkNextLog2(colorCount); |
| 97 SkASSERT(bits >= 1 && bits <= 8); | 97 SkASSERT(bits >= 1 && bits <= 8); |
| 98 // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8) | 98 // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8) |
| 99 return SkNextPow2(bits); | 99 return SkNextPow2(bits); |
| 100 #else | 100 #else |
| 101 // for the moment, we don't know how to pack bitdepth < 8 | 101 // for the moment, we don't know how to pack bitdepth < 8 |
| 102 return 8; | 102 return 8; |
| 103 #endif | 103 #endif |
| 104 } | 104 } |
| 105 | 105 |
| 106 /* Pack palette[] with the corresponding colors, and if hasAlpha is true, also | 106 /* Pack palette[] with the corresponding colors, and if the image has alpha, al
so |
| 107 pack trans[] and return the number of trans[] entries written. If hasAlpha | 107 pack trans[] and return the number of alphas[] entries written. If the image
is |
| 108 is false, the return value will always be 0. | 108 opaque, the return value will always be 0. |
| 109 */ |
| 110 static inline int pack_palette(SkColorTable* ctable, png_color* SK_RESTRICT pale
tte, |
| 111 png_byte* SK_RESTRICT alphas, SkAlphaType alphaTy
pe) { |
| 112 const SkPMColor* SK_RESTRICT colors = ctable->readColors(); |
| 113 const int count = ctable->count(); |
| 114 int numWithAlpha = 0; |
| 115 if (kOpaque_SkAlphaType != alphaType) { |
| 116 auto getUnpremulColor = [alphaType](uint8_t color, uint8_t alpha) { |
| 117 if (kPremul_SkAlphaType == alphaType) { |
| 118 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleT
able(); |
| 119 const SkUnPreMultiply::Scale scale = table[alpha]; |
| 120 return (uint8_t) SkUnPreMultiply::ApplyScale(scale, color); |
| 121 } else { |
| 122 return color; |
| 123 } |
| 124 }; |
| 109 | 125 |
| 110 Note: this routine takes care of unpremultiplying the RGB values when we | 126 // PNG requires that all non-opaque colors come first in the palette. W
rite these first. |
| 111 have alpha in the colortable, since png doesn't support premul colors | 127 for (int i = 0; i < count; i++) { |
| 112 */ | 128 uint8_t alpha = SkGetPackedA32(colors[i]); |
| 113 static inline int pack_palette(SkColorTable* ctable, | 129 if (0xFF != alpha) { |
| 114 png_color* SK_RESTRICT palette, | 130 alphas[numWithAlpha] = alpha; |
| 115 png_byte* SK_RESTRICT trans, SkAlphaType alphaTyp
e) { | 131 palette[numWithAlpha].red = getUnpremulColor(SkGetPackedR32(co
lors[i]), alpha); |
| 116 const SkPMColor* SK_RESTRICT colors = ctable ? ctable->readColors() : nullpt
r; | 132 palette[numWithAlpha].green = getUnpremulColor(SkGetPackedG32(co
lors[i]), alpha); |
| 117 const int ctCount = ctable->count(); | 133 palette[numWithAlpha].blue = getUnpremulColor(SkGetPackedB32(co
lors[i]), alpha); |
| 118 int i, num_trans = 0; | 134 numWithAlpha++; |
| 119 | |
| 120 if (kOpaque_SkAlphaType != alphaType) { | |
| 121 /* first see if we have some number of fully opaque at the end of the | |
| 122 ctable. PNG allows num_trans < num_palette, but all of the trans | |
| 123 entries must come first in the palette. If I was smarter, I'd | |
| 124 reorder the indices and ctable so that all non-opaque colors came | |
| 125 first in the palette. But, since that would slow down the encode, | |
| 126 I'm leaving the indices and ctable order as is, and just looking | |
| 127 at the tail of the ctable for opaqueness. | |
| 128 */ | |
| 129 num_trans = ctCount; | |
| 130 for (i = ctCount - 1; i >= 0; --i) { | |
| 131 if (SkGetPackedA32(colors[i]) != 0xFF) { | |
| 132 break; | |
| 133 } | |
| 134 num_trans -= 1; | |
| 135 } | |
| 136 | |
| 137 if (kPremul_SkAlphaType == alphaType) { | |
| 138 const SkUnPreMultiply::Scale* SK_RESTRICT table = SkUnPreMultiply::G
etScaleTable(); | |
| 139 for (i = 0; i < num_trans; i++) { | |
| 140 const SkPMColor c = *colors++; | |
| 141 const unsigned a = SkGetPackedA32(c); | |
| 142 const SkUnPreMultiply::Scale s = table[a]; | |
| 143 trans[i] = a; | |
| 144 palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c
)); | |
| 145 palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(
c)); | |
| 146 palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(
c)); | |
| 147 } | |
| 148 } else { | |
| 149 for (i = 0; i < num_trans; i++) { | |
| 150 const SkPMColor c = *colors++; | |
| 151 trans[i] = SkGetPackedA32(c); | |
| 152 palette[i].red = SkGetPackedR32(c); | |
| 153 palette[i].green = SkGetPackedG32(c); | |
| 154 palette[i].blue = SkGetPackedB32(c); | |
| 155 } | 135 } |
| 156 } | 136 } |
| 157 | 137 |
| 158 // now fall out of this if-block to use common code for the trailing | |
| 159 // opaque entries | |
| 160 } | 138 } |
| 161 | 139 |
| 162 // these (remaining) entries are opaque | 140 if (0 == numWithAlpha) { |
| 163 for (i = num_trans; i < ctCount; i++) { | 141 // All of the entries are opaque. |
| 164 SkPMColor c = *colors++; | 142 for (int i = 0; i < count; i++) { |
| 165 palette[i].red = SkGetPackedR32(c); | 143 SkPMColor c = *colors++; |
| 166 palette[i].green = SkGetPackedG32(c); | 144 palette[i].red = SkGetPackedR32(c); |
| 167 palette[i].blue = SkGetPackedB32(c); | 145 palette[i].green = SkGetPackedG32(c); |
| 146 palette[i].blue = SkGetPackedB32(c); |
| 147 } |
| 148 } else { |
| 149 // We have already written the non-opaque colors. Now just write the op
aque colors. |
| 150 int currIndex = numWithAlpha; |
| 151 int i = 0; |
| 152 while (currIndex != count) { |
| 153 uint8_t alpha = SkGetPackedA32(colors[i]); |
| 154 if (0xFF == alpha) { |
| 155 palette[currIndex].red = SkGetPackedR32(colors[i]); |
| 156 palette[currIndex].green = SkGetPackedG32(colors[i]); |
| 157 palette[currIndex].blue = SkGetPackedB32(colors[i]); |
| 158 currIndex++; |
| 159 } |
| 160 |
| 161 i++; |
| 162 } |
| 168 } | 163 } |
| 169 return num_trans; | 164 |
| 165 return numWithAlpha; |
| 170 } | 166 } |
| 171 | 167 |
| 172 class SkPNGImageEncoder : public SkImageEncoder { | 168 class SkPNGImageEncoder : public SkImageEncoder { |
| 173 protected: | 169 protected: |
| 174 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; | 170 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; |
| 175 private: | 171 private: |
| 176 bool doEncode(SkWStream* stream, const SkBitmap& bm, | 172 bool doEncode(SkWStream* stream, const SkBitmap& bm, |
| 177 SkAlphaType alphaType, int colorType, | 173 SkAlphaType alphaType, int colorType, |
| 178 int bitDepth, SkColorType ct, | 174 int bitDepth, SkColorType ct, |
| 179 png_color_8& sig_bit); | 175 png_color_8& sig_bit); |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), | 314 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), |
| 319 bitDepth, colorType, | 315 bitDepth, colorType, |
| 320 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, | 316 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, |
| 321 PNG_FILTER_TYPE_BASE); | 317 PNG_FILTER_TYPE_BASE); |
| 322 | 318 |
| 323 // set our colortable/trans arrays if needed | 319 // set our colortable/trans arrays if needed |
| 324 png_color paletteColors[256]; | 320 png_color paletteColors[256]; |
| 325 png_byte trans[256]; | 321 png_byte trans[256]; |
| 326 if (kIndex_8_SkColorType == ct) { | 322 if (kIndex_8_SkColorType == ct) { |
| 327 SkColorTable* colorTable = bitmap.getColorTable(); | 323 SkColorTable* colorTable = bitmap.getColorTable(); |
| 324 SkASSERT(colorTable); |
| 328 int numTrans = pack_palette(colorTable, paletteColors, trans, alphaType)
; | 325 int numTrans = pack_palette(colorTable, paletteColors, trans, alphaType)
; |
| 329 png_set_PLTE(png_ptr, info_ptr, paletteColors, colorTable->count()); | 326 png_set_PLTE(png_ptr, info_ptr, paletteColors, colorTable->count()); |
| 330 if (numTrans > 0) { | 327 if (numTrans > 0) { |
| 331 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr); | 328 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr); |
| 332 } | 329 } |
| 333 } | 330 } |
| 334 | 331 |
| 335 png_set_sBIT(png_ptr, info_ptr, &sig_bit); | 332 png_set_sBIT(png_ptr, info_ptr, &sig_bit); |
| 336 png_write_info(png_ptr, info_ptr); | 333 png_write_info(png_ptr, info_ptr); |
| 337 | 334 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 356 | 353 |
| 357 /////////////////////////////////////////////////////////////////////////////// | 354 /////////////////////////////////////////////////////////////////////////////// |
| 358 DEFINE_ENCODER_CREATOR(PNGImageEncoder); | 355 DEFINE_ENCODER_CREATOR(PNGImageEncoder); |
| 359 /////////////////////////////////////////////////////////////////////////////// | 356 /////////////////////////////////////////////////////////////////////////////// |
| 360 | 357 |
| 361 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { | 358 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { |
| 362 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; | 359 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; |
| 363 } | 360 } |
| 364 | 361 |
| 365 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); | 362 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); |
| OLD | NEW |