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

Side by Side Diff: src/images/SkPNGImageEncoder.cpp

Issue 2330053002: Encode kIndex8 to PNG more efficiently (Closed)
Patch Set: Created 4 years, 3 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 | « no previous file | 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 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
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* palette, png_byt e* alphas,
111 SkAlphaType alphaType) {
112 const SkPMColor* 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;
scroggo 2016/09/12 16:40:57 Why did you remove SK_RESTRICT?
msarett 2016/09/12 16:58:31 SK_RESTRICT can sometimes allow the compiler to ma
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.
scroggo 2016/09/12 16:40:57 I think you could skip this if numWithAlpha == cou
msarett 2016/09/12 16:58:31 Yes nice catch, let's skip it.
150 int currIndex = numWithAlpha;
151 for (int i = 0; i < count; i++) {
152 uint8_t alpha = SkGetPackedA32(colors[i]);
153 if (0xFF == alpha) {
154 palette[currIndex].red = SkGetPackedR32(colors[i]);
155 palette[currIndex].green = SkGetPackedG32(colors[i]);
156 palette[currIndex].blue = SkGetPackedB32(colors[i]);
157 currIndex++;
158 }
159 }
168 } 160 }
169 return num_trans; 161
162 return numWithAlpha;
170 } 163 }
171 164
172 class SkPNGImageEncoder : public SkImageEncoder { 165 class SkPNGImageEncoder : public SkImageEncoder {
173 protected: 166 protected:
174 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; 167 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override;
175 private: 168 private:
176 bool doEncode(SkWStream* stream, const SkBitmap& bm, 169 bool doEncode(SkWStream* stream, const SkBitmap& bm,
177 SkAlphaType alphaType, int colorType, 170 SkAlphaType alphaType, int colorType,
178 int bitDepth, SkColorType ct, 171 int bitDepth, SkColorType ct,
179 png_color_8& sig_bit); 172 png_color_8& sig_bit);
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), 313 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(),
321 bitDepth, colorType, 314 bitDepth, colorType,
322 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, 315 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
323 PNG_FILTER_TYPE_BASE); 316 PNG_FILTER_TYPE_BASE);
324 317
325 // set our colortable/trans arrays if needed 318 // set our colortable/trans arrays if needed
326 png_color paletteColors[256]; 319 png_color paletteColors[256];
327 png_byte trans[256]; 320 png_byte trans[256];
328 if (kIndex_8_SkColorType == ct) { 321 if (kIndex_8_SkColorType == ct) {
329 SkColorTable* ct = bitmap.getColorTable(); 322 SkColorTable* ct = bitmap.getColorTable();
323 SkASSERT(ct);
330 int numTrans = pack_palette(ct, paletteColors, trans, alphaType); 324 int numTrans = pack_palette(ct, paletteColors, trans, alphaType);
331 png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count()); 325 png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count());
332 if (numTrans > 0) { 326 if (numTrans > 0) {
333 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr); 327 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr);
334 } 328 }
335 } 329 }
336 330
337 png_set_sBIT(png_ptr, info_ptr, &sig_bit); 331 png_set_sBIT(png_ptr, info_ptr, &sig_bit);
338 png_write_info(png_ptr, info_ptr); 332 png_write_info(png_ptr, info_ptr);
339 333
(...skipping 18 matching lines...) Expand all
358 352
359 /////////////////////////////////////////////////////////////////////////////// 353 ///////////////////////////////////////////////////////////////////////////////
360 DEFINE_ENCODER_CREATOR(PNGImageEncoder); 354 DEFINE_ENCODER_CREATOR(PNGImageEncoder);
361 /////////////////////////////////////////////////////////////////////////////// 355 ///////////////////////////////////////////////////////////////////////////////
362 356
363 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { 357 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) {
364 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; 358 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr;
365 } 359 }
366 360
367 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); 361 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory);
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698