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

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

Issue 2330053002: Encode kIndex8 to PNG more efficiently (Closed)
Patch Set: Skip loop if all colors are non-opaque, add back in SK_RESTRICT 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* 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 (i < count && currIndex != count) {
scroggo 2016/09/12 17:12:48 I don't think you need to check currIndex on each
msarett 2016/09/12 17:17:13 Yeah I wrote that at first. I think the advantage
scroggo 2016/09/12 17:19:44 Ah, so this would let us exit early if for example
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 i++;
160 }
161 }
168 } 162 }
169 return num_trans; 163
164 return numWithAlpha;
170 } 165 }
171 166
172 class SkPNGImageEncoder : public SkImageEncoder { 167 class SkPNGImageEncoder : public SkImageEncoder {
173 protected: 168 protected:
174 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; 169 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override;
175 private: 170 private:
176 bool doEncode(SkWStream* stream, const SkBitmap& bm, 171 bool doEncode(SkWStream* stream, const SkBitmap& bm,
177 SkAlphaType alphaType, int colorType, 172 SkAlphaType alphaType, int colorType,
178 int bitDepth, SkColorType ct, 173 int bitDepth, SkColorType ct,
179 png_color_8& sig_bit); 174 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(), 315 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(),
321 bitDepth, colorType, 316 bitDepth, colorType,
322 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, 317 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
323 PNG_FILTER_TYPE_BASE); 318 PNG_FILTER_TYPE_BASE);
324 319
325 // set our colortable/trans arrays if needed 320 // set our colortable/trans arrays if needed
326 png_color paletteColors[256]; 321 png_color paletteColors[256];
327 png_byte trans[256]; 322 png_byte trans[256];
328 if (kIndex_8_SkColorType == ct) { 323 if (kIndex_8_SkColorType == ct) {
329 SkColorTable* ct = bitmap.getColorTable(); 324 SkColorTable* ct = bitmap.getColorTable();
325 SkASSERT(ct);
330 int numTrans = pack_palette(ct, paletteColors, trans, alphaType); 326 int numTrans = pack_palette(ct, paletteColors, trans, alphaType);
331 png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count()); 327 png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count());
332 if (numTrans > 0) { 328 if (numTrans > 0) {
333 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr); 329 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr);
334 } 330 }
335 } 331 }
336 332
337 png_set_sBIT(png_ptr, info_ptr, &sig_bit); 333 png_set_sBIT(png_ptr, info_ptr, &sig_bit);
338 png_write_info(png_ptr, info_ptr); 334 png_write_info(png_ptr, info_ptr);
339 335
(...skipping 18 matching lines...) Expand all
358 354
359 /////////////////////////////////////////////////////////////////////////////// 355 ///////////////////////////////////////////////////////////////////////////////
360 DEFINE_ENCODER_CREATOR(PNGImageEncoder); 356 DEFINE_ENCODER_CREATOR(PNGImageEncoder);
361 /////////////////////////////////////////////////////////////////////////////// 357 ///////////////////////////////////////////////////////////////////////////////
362 358
363 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { 359 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) {
364 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; 360 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr;
365 } 361 }
366 362
367 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); 363 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