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

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

Issue 1643623004: A variety of SkPngCodec clean-ups (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 11 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 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 "SkCodecPriv.h" 8 #include "SkCodecPriv.h"
9 #include "SkColorPriv.h" 9 #include "SkColorPriv.h"
10 #include "SkColorTable.h" 10 #include "SkColorTable.h"
11 #include "SkBitmap.h" 11 #include "SkBitmap.h"
12 #include "SkMath.h" 12 #include "SkMath.h"
13 #include "SkOpts.h"
13 #include "SkPngCodec.h" 14 #include "SkPngCodec.h"
14 #include "SkPngFilters.h" 15 #include "SkPngFilters.h"
15 #include "SkSize.h" 16 #include "SkSize.h"
16 #include "SkStream.h" 17 #include "SkStream.h"
17 #include "SkSwizzler.h" 18 #include "SkSwizzler.h"
18 #include "SkTemplates.h" 19 #include "SkTemplates.h"
19 20
20 #if defined(__SSE2__) 21 #if defined(__SSE2__)
21 #include "pngstruct.h" 22 #include "pngstruct.h"
22 23
23 extern "C" void sk_png_init_filter_functions_sse2(png_structp png, unsigned int bpp) { 24 extern "C" void sk_png_init_filter_functions_sse2(png_structp png, unsigned int bpp) {
24 if (bpp == 3) { 25 if (bpp == 3) {
25 png->read_filter[PNG_FILTER_VALUE_SUB -1] = sk_sub3_sse2; 26 png->read_filter[PNG_FILTER_VALUE_SUB -1] = sk_sub3_sse2;
26 png->read_filter[PNG_FILTER_VALUE_AVG -1] = sk_avg3_sse2; 27 png->read_filter[PNG_FILTER_VALUE_AVG -1] = sk_avg3_sse2;
27 png->read_filter[PNG_FILTER_VALUE_PAETH-1] = sk_paeth3_sse2; 28 png->read_filter[PNG_FILTER_VALUE_PAETH-1] = sk_paeth3_sse2;
28 } 29 }
29 if (bpp == 4) { 30 if (bpp == 4) {
30 png->read_filter[PNG_FILTER_VALUE_SUB -1] = sk_sub4_sse2; 31 png->read_filter[PNG_FILTER_VALUE_SUB -1] = sk_sub4_sse2;
31 png->read_filter[PNG_FILTER_VALUE_AVG -1] = sk_avg4_sse2; 32 png->read_filter[PNG_FILTER_VALUE_AVG -1] = sk_avg4_sse2;
32 png->read_filter[PNG_FILTER_VALUE_PAETH-1] = sk_paeth4_sse2; 33 png->read_filter[PNG_FILTER_VALUE_PAETH-1] = sk_paeth4_sse2;
33 } 34 }
34 } 35 }
35 #endif 36 #endif
36 37
37 /////////////////////////////////////////////////////////////////////////////// 38 ///////////////////////////////////////////////////////////////////////////////
38 // Helper macros
msarett 2016/01/28 01:26:18 IMO these don't help much. We need to be compiled
scroggo 2016/01/28 21:07:32 They were added to the original SkImageDecoder in
msarett 2016/01/28 22:19:24 Thanks for the reference. Looking at those notes,
39 ///////////////////////////////////////////////////////////////////////////////
40
41 #ifndef png_jmpbuf
42 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
43 #endif
44
45 /* These were dropped in libpng >= 1.4 */
46 #ifndef png_infopp_NULL
47 #define png_infopp_NULL nullptr
48 #endif
49
50 #ifndef png_bytepp_NULL
51 #define png_bytepp_NULL nullptr
52 #endif
53
54 #ifndef int_p_NULL
55 #define int_p_NULL nullptr
56 #endif
57
58 #ifndef png_flush_ptr_NULL
59 #define png_flush_ptr_NULL nullptr
60 #endif
61
62 ///////////////////////////////////////////////////////////////////////////////
63 // Callback functions 39 // Callback functions
64 /////////////////////////////////////////////////////////////////////////////// 40 ///////////////////////////////////////////////////////////////////////////////
65 41
66 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { 42 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
67 SkCodecPrintf("------ png error %s\n", msg); 43 SkCodecPrintf("------ png error %s\n", msg);
68 longjmp(png_jmpbuf(png_ptr), 1); 44 longjmp(png_jmpbuf(png_ptr), 1);
69 } 45 }
70 46
71 void sk_warning_fn(png_structp, png_const_charp msg) { 47 void sk_warning_fn(png_structp, png_const_charp msg) {
72 SkCodecPrintf("----- png warning %s\n", msg); 48 SkCodecPrintf("----- png warning %s\n", msg);
(...skipping 26 matching lines...) Expand all
99 class AutoCleanPng : public SkNoncopyable { 75 class AutoCleanPng : public SkNoncopyable {
100 public: 76 public:
101 AutoCleanPng(png_structp png_ptr) 77 AutoCleanPng(png_structp png_ptr)
102 : fPng_ptr(png_ptr) 78 : fPng_ptr(png_ptr)
103 , fInfo_ptr(nullptr) {} 79 , fInfo_ptr(nullptr) {}
104 80
105 ~AutoCleanPng() { 81 ~AutoCleanPng() {
106 // fInfo_ptr will never be non-nullptr unless fPng_ptr is. 82 // fInfo_ptr will never be non-nullptr unless fPng_ptr is.
107 if (fPng_ptr) { 83 if (fPng_ptr) {
108 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr; 84 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr;
109 png_destroy_read_struct(&fPng_ptr, info_pp, png_infopp_NULL); 85 png_destroy_read_struct(&fPng_ptr, info_pp, nullptr);
110 } 86 }
111 } 87 }
112 88
113 void setInfoPtr(png_infop info_ptr) { 89 void setInfoPtr(png_infop info_ptr) {
114 SkASSERT(nullptr == fInfo_ptr); 90 SkASSERT(nullptr == fInfo_ptr);
115 fInfo_ptr = info_ptr; 91 fInfo_ptr = info_ptr;
116 } 92 }
117 93
118 void detach() { 94 void detach() {
119 fPng_ptr = nullptr; 95 fPng_ptr = nullptr;
120 fInfo_ptr = nullptr; 96 fInfo_ptr = nullptr;
121 } 97 }
122 98
123 private: 99 private:
124 png_structp fPng_ptr; 100 png_structp fPng_ptr;
125 png_infop fInfo_ptr; 101 png_infop fInfo_ptr;
126 }; 102 };
127 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng) 103 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
128 104
129 //checks if there is transparency info in the tRNS chunk
130 //image types which could have data in the tRNS chunk include: Index8, Gray8, RG B
131 static bool has_transparency_in_tRNS(png_structp png_ptr,
132 png_infop info_ptr) {
133 if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
134 return false;
135 }
136
137 png_bytep trans;
138 int num_trans;
139 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, nullptr);
140 return num_trans > 0;
141 }
142
143 // Method for coverting to either an SkPMColor or a similarly packed
144 // unpremultiplied color.
145 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
146
147 // Note: SkColorTable claims to store SkPMColors, which is not necessarily 105 // Note: SkColorTable claims to store SkPMColors, which is not necessarily
148 // the case here. 106 // the case here.
149 bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { 107 bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) {
150 int numPalette; 108
109 int numColors;
151 png_colorp palette; 110 png_colorp palette;
152 png_bytep trans; 111 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) {
153
154 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) {
155 return false; 112 return false;
156 } 113 }
157 114
158 // Note: These are not necessarily SkPMColors 115 // Note: These are not necessarily SkPMColors.
159 SkPMColor colorStorage[256]; // worst-case storage 116 SkPMColor colorPtr[256];
160 SkPMColor* colorPtr = colorStorage; 117 #ifdef SK_PMCOLOR_IS_RGBA
118 SkOpts::RGB_to_RGB1(colorPtr, palette, numColors);
msarett 2016/01/28 01:26:18 It's a little frustrating to optimize this knowing
msarett 2016/01/28 02:06:45 Here we treat a pointer to the png_color struct as
scroggo 2016/01/28 21:07:33 I can think of two places we memcpy: - Into the Sk
scroggo 2016/01/28 21:07:33 Can you add these comments plus some asserts here?
msarett 2016/01/28 22:19:25 Yes not going to worry about the memcpys() in this
119 #else
120 SkOpts::RGB_to_BGR1(colorPtr, palette, numColors);
scroggo 2016/01/28 21:07:33 Should we also consider the case where the client
msarett 2016/01/28 22:19:25 I'm not sure I completely understand. I think SkC
scroggo 2016/01/29 15:40:27 I think this is a good change, I just wanted to th
msarett 2016/01/29 18:56:08 Thanks, adding a TODO.
121 #endif
161 122
162 int numTrans; 123
163 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { 124 png_bytep alphas;
164 png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, nullptr); 125 int numColorsWithAlpha;
165 } else { 126 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr) ) {
166 numTrans = 0; 127 for (int i = 0; i < numColorsWithAlpha; i++) {
msarett 2016/01/28 01:26:18 I don't SIMD premuls will do much here for two rea
msarett 2016/01/28 02:06:45 Maybe we should check if alpha is zero (which it w
scroggo 2016/01/28 21:07:32 SkPremultiplyARGBInline does. It also calls SkMulD
msarett 2016/01/28 22:19:25 Changed to use SkMulDiv255Round.
128 // Note that we inline this because we need to make sure that we don 't
scroggo 2016/01/28 21:07:32 I didn't understand this comment at first. I think
msarett 2016/01/28 22:19:25 Yes this is unclear. I'll fix the comment for now
msarett 2016/01/29 18:56:08 I think you're right. My version was less clear a
129 // swap color channels.
130 uint8_t a = alphas[i];
131 uint8_t b = colorPtr[i] >> 16;
132 uint8_t g = colorPtr[i] >> 8;
133 uint8_t r = colorPtr[i] >> 0;
134 b = (b*a+127)/255;
135 g = (g*a+127)/255;
136 r = (r*a+127)/255;
137 colorPtr[i] = (uint32_t)a << 24
138 | (uint32_t)b << 16
139 | (uint32_t)g << 8
140 | (uint32_t)r << 0;
141 }
167 } 142 }
168 143
169 // check for bad images that might make us crash 144 // Pad the color table with the last color in the table (or black) in the ca se that
scroggo 2016/01/28 21:07:32 But you forgot to include "BUGGY IMAGE WORKAROUND"
msarett 2016/01/28 22:19:25 Agreed. I almost removed the black part completel
170 if (numTrans > numPalette) { 145 // invalid pixel indices exceed the number of colors in the table.
171 numTrans = numPalette; 146 const int maxColors = 1 << fBitDepth;
147 if (numColors < maxColors) {
148 SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_Color BLACK;
149 sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors);
172 } 150 }
173 151
174 int index = 0; 152 // Set the new color count.
175 153 if (ctableCount != nullptr) {
176 // Choose which function to use to create the color table. If the final dest ination's 154 *ctableCount = maxColors;
177 // colortype is unpremultiplied, the color table will store unpremultiplied colors.
178 PackColorProc proc;
179 if (premultiply) {
180 proc = &SkPreMultiplyARGB;
181 } else {
182 proc = &SkPackARGB32NoCheck;
183 }
184 for (; index < numTrans; index++) {
185 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue );
186 palette++;
187 } 155 }
188 156
189 for (; index < numPalette; index++) { 157 fColorTable.reset(new SkColorTable(colorPtr, maxColors));
190 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue);
191 palette++;
192 }
193
194 /* BUGGY IMAGE WORKAROUND
195 Invalid images could contain pixel values that are greater than the numb er of palette
196 entries. Since we use pixel values as indices into the palette this coul d result in reading
197 beyond the end of the palette which could leak the contents of uninitial ized memory. To
198 ensure this doesn't happen, we grow the colortable to the maximum size t hat can be
199 addressed by the bitdepth of the image and fill it with the last palette color or black if
200 the palette is empty (really broken image).
201 */
202 int colorCount = SkTMax(numPalette, 1 << SkTMin(fBitDepth, 8));
203 SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0) ;
204 for (; index < colorCount; index++) {
205 *colorPtr++ = lastColor;
206 }
207
208 // Set the new color count
209 if (ctableCount != nullptr) {
210 *ctableCount = colorCount;
211 }
212
213 fColorTable.reset(new SkColorTable(colorStorage, colorCount));
214 return true; 158 return true;
215 } 159 }
216 160
217 /////////////////////////////////////////////////////////////////////////////// 161 ///////////////////////////////////////////////////////////////////////////////
218 // Creation 162 // Creation
219 /////////////////////////////////////////////////////////////////////////////// 163 ///////////////////////////////////////////////////////////////////////////////
220 164
221 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) { 165 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) {
222 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead); 166 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead);
223 } 167 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 if (chunkReader) { 220 if (chunkReader) {
277 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte* )"", 0); 221 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte* )"", 0);
278 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_use r_chunk); 222 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_use r_chunk);
279 } 223 }
280 #endif 224 #endif
281 225
282 // The call to png_read_info() gives us all of the information from the 226 // The call to png_read_info() gives us all of the information from the
283 // PNG file before the first IDAT (image data chunk). 227 // PNG file before the first IDAT (image data chunk).
284 png_read_info(png_ptr, info_ptr); 228 png_read_info(png_ptr, info_ptr);
285 png_uint_32 origWidth, origHeight; 229 png_uint_32 origWidth, origHeight;
286 int bitDepth, colorType; 230 int bitDepth, encodedColorType;
287 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, 231 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
288 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); 232 &encodedColorType, nullptr, nullptr, nullptr);
289 233
290 if (bitDepthPtr) { 234 if (bitDepthPtr) {
291 *bitDepthPtr = bitDepth; 235 *bitDepthPtr = bitDepth;
292 } 236 }
293 237
294 // sanity check for size 238 // Tell libpng to strip 16 bit/color files down to 8 bits/color.
scroggo 2016/01/28 21:07:33 I mentioned this in the RAW code review - would it
msarett 2016/01/28 22:19:25 We could certainly handle this case faster in the
295 { 239 if (bitDepth == 16) {
296 int64_t size = sk_64_mul(origWidth, origHeight); 240 SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType);
scroggo 2016/01/28 21:07:32 Looks like this got removed. Can you add that to t
msarett 2016/01/28 22:19:25 Done.
297 // now check that if we are 4-bytes per pixel, we also don't overflow 241 png_set_strip_16(png_ptr);
298 if (size < 0 || size > (0x7FFFFFFF >> 2)) {
299 return false;
300 }
301 } 242 }
302 243
303 // Tell libpng to strip 16 bit/color files down to 8 bits/color 244 // Now determine the default colorType and alphaType and set the required tr ansforms.
304 if (bitDepth == 16) { 245 // Often, we depend on SkSwizzler to perform any transforms that we need. H owever, we
305 png_set_strip_16(png_ptr); 246 // still depend on libpng for many of the rare and PNG-specific cases.
306 } 247 SkColorType colorType = kUnknown_SkColorType;
307 #ifdef PNG_READ_PACK_SUPPORTED 248 SkAlphaType alphaType = kUnknown_SkAlphaType;
scroggo 2016/01/28 21:07:32 Why did you remove this?
msarett 2016/01/28 22:19:25 AFAICT if READ_PACK isn't supported we'll decode t
308 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single 249 switch (encodedColorType) {
309 // byte into separate bytes (useful for paletted and grayscale images). 250 case PNG_COLOR_TYPE_PALETTE:
310 if (bitDepth < 8) { 251 // Extract multiple pixels with bit depths of 1, 2, and 4 from a sin gle
311 png_set_packing(png_ptr); 252 // byte into separate bytes (useful for paletted and grayscale image s).
312 } 253 if (bitDepth < 8) {
313 #endif 254 png_set_packing(png_ptr);
scroggo 2016/01/28 21:07:32 Could we instead use SkSwizzler::kIndex1 etc?
msarett 2016/01/28 22:19:25 Yes. Adding a TODO.
314 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. 255 }
315 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
316 png_set_expand_gray_1_2_4_to_8(png_ptr);
317 }
318 256
319 // Now determine the default SkColorType and SkAlphaType and set required tr ansforms 257 colorType = kIndex_8_SkColorType;
320 SkColorType skColorType = kUnknown_SkColorType; 258 // Set the alpha type depending on if a transparency chunk exists.
321 SkAlphaType skAlphaType = kUnknown_SkAlphaType; 259 alphaType = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ?
scroggo 2016/01/28 21:07:32 So we no longer check to see how many transparent
msarett 2016/01/28 22:19:25 In libpng, a "valid" tRNS chunk has at least one c
322 switch (colorType) {
323 case PNG_COLOR_TYPE_PALETTE:
324 skColorType = kIndex_8_SkColorType;
325 skAlphaType = has_transparency_in_tRNS(png_ptr, info_ptr) ?
326 kUnpremul_SkAlphaType : kOpaque_SkAlphaType; 260 kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
327 break; 261 break;
328 case PNG_COLOR_TYPE_RGB: 262 case PNG_COLOR_TYPE_RGB:
329 if (has_transparency_in_tRNS(png_ptr, info_ptr)) { 263 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
330 //convert to RGBA with tranparency information in tRNS chunk if it exists 264 // Convert to RGBA if transparency chunk exists.
331 png_set_tRNS_to_alpha(png_ptr); 265 png_set_tRNS_to_alpha(png_ptr);
332 skAlphaType = kUnpremul_SkAlphaType; 266 alphaType = kUnpremul_SkAlphaType;
333 } else { 267 } else {
334 skAlphaType = kOpaque_SkAlphaType; 268 alphaType = kOpaque_SkAlphaType;
335 } 269 }
336 skColorType = kN32_SkColorType; 270 colorType = kN32_SkColorType;
337 break; 271 break;
338 case PNG_COLOR_TYPE_GRAY: 272 case PNG_COLOR_TYPE_GRAY:
339 if (has_transparency_in_tRNS(png_ptr, info_ptr)) { 273 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/p ixel.
340 //FIXME: support gray with alpha as a color type 274 if (bitDepth < 8) {
341 //convert to RGBA if there is transparentcy info in the tRNS chu nk 275 png_set_expand_gray_1_2_4_to_8(png_ptr);
scroggo 2016/01/28 21:07:32 Swizzler instead? (I'd be fine with a TODO for the
msarett 2016/01/28 22:19:24 Yes I'll add TODOs. I haven't gotten to these rar
276 }
277
278 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
279 // Convert to RGBA if there is a transparency chunk.
342 png_set_tRNS_to_alpha(png_ptr); 280 png_set_tRNS_to_alpha(png_ptr);
343 png_set_gray_to_rgb(png_ptr); 281 png_set_gray_to_rgb(png_ptr);
344 skColorType = kN32_SkColorType; 282 colorType = kN32_SkColorType;
345 skAlphaType = kUnpremul_SkAlphaType; 283 alphaType = kUnpremul_SkAlphaType;
346 } else { 284 } else {
347 skColorType = kGray_8_SkColorType; 285 colorType = kGray_8_SkColorType;
348 skAlphaType = kOpaque_SkAlphaType; 286 alphaType = kOpaque_SkAlphaType;
349 } 287 }
350 break; 288 break;
351 case PNG_COLOR_TYPE_GRAY_ALPHA: 289 case PNG_COLOR_TYPE_GRAY_ALPHA:
352 //FIXME: support gray with alpha as a color type 290 // Convert to RGBA if the image has alpha.
353 //convert to RGBA
354 png_set_gray_to_rgb(png_ptr); 291 png_set_gray_to_rgb(png_ptr);
355 skColorType = kN32_SkColorType; 292 colorType = kN32_SkColorType;
356 skAlphaType = kUnpremul_SkAlphaType; 293 alphaType = kUnpremul_SkAlphaType;
357 break; 294 break;
358 case PNG_COLOR_TYPE_RGBA: 295 case PNG_COLOR_TYPE_RGBA:
359 skColorType = kN32_SkColorType; 296 colorType = kN32_SkColorType;
360 skAlphaType = kUnpremul_SkAlphaType; 297 alphaType = kUnpremul_SkAlphaType;
361 break; 298 break;
362 default: 299 default:
363 //all the color types have been covered above 300 // All the color types have been covered above.
364 SkASSERT(false); 301 SkASSERT(false);
365 } 302 }
366 303
367 int numberPasses = png_set_interlace_handling(png_ptr); 304 int numberPasses = png_set_interlace_handling(png_ptr);
368 if (numberPassesPtr) { 305 if (numberPassesPtr) {
369 *numberPassesPtr = numberPasses; 306 *numberPassesPtr = numberPasses;
370 } 307 }
371 308
372 // FIXME: Also need to check for sRGB ( https://bug.skia.org/3471 ). 309 // FIXME: Also need to check for sRGB ( https://bug.skia.org/3471 ).
373 310
374 if (imageInfo) { 311 if (imageInfo) {
375 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlp haType); 312 *imageInfo = SkImageInfo::Make(origWidth, origHeight, colorType, alphaTy pe);
376 } 313 }
377 autoClean.detach(); 314 autoClean.detach();
378 if (png_ptrp) { 315 if (png_ptrp) {
379 *png_ptrp = png_ptr; 316 *png_ptrp = png_ptr;
380 } 317 }
381 if (info_ptrp) { 318 if (info_ptrp) {
382 *info_ptrp = info_ptr; 319 *info_ptrp = info_ptr;
383 } 320 }
384 321
385 return true; 322 return true;
(...skipping 11 matching lines...) Expand all
397 {} 334 {}
398 335
399 SkPngCodec::~SkPngCodec() { 336 SkPngCodec::~SkPngCodec() {
400 this->destroyReadStruct(); 337 this->destroyReadStruct();
401 } 338 }
402 339
403 void SkPngCodec::destroyReadStruct() { 340 void SkPngCodec::destroyReadStruct() {
404 if (fPng_ptr) { 341 if (fPng_ptr) {
405 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr 342 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
406 SkASSERT(fInfo_ptr); 343 SkASSERT(fInfo_ptr);
407 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); 344 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, nullptr);
408 fPng_ptr = nullptr; 345 fPng_ptr = nullptr;
409 fInfo_ptr = nullptr; 346 fInfo_ptr = nullptr;
410 } 347 }
411 } 348 }
412 349
413 /////////////////////////////////////////////////////////////////////////////// 350 ///////////////////////////////////////////////////////////////////////////////
414 // Getting the pixels 351 // Getting the pixels
415 /////////////////////////////////////////////////////////////////////////////// 352 ///////////////////////////////////////////////////////////////////////////////
416 353
417 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, 354 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
418 const Options& options, 355 const Options& options,
419 SkPMColor ctable[], 356 SkPMColor ctable[],
420 int* ctableCount) { 357 int* ctableCount) {
421 // FIXME: Could we use the return value of setjmp to specify the type of 358 // FIXME: Could we use the return value of setjmp to specify the type of
422 // error? 359 // error?
423 if (setjmp(png_jmpbuf(fPng_ptr))) { 360 if (setjmp(png_jmpbuf(fPng_ptr))) {
424 SkCodecPrintf("setjmp long jump!\n"); 361 SkCodecPrintf("setjmp long jump!\n");
425 return kInvalidInput; 362 return kInvalidInput;
426 } 363 }
427 png_read_update_info(fPng_ptr, fInfo_ptr); 364 png_read_update_info(fPng_ptr, fInfo_ptr);
428 365
429 //srcColorType was determined in read_header() which determined png color ty pe 366 // srcColorType was determined in read_header() which determined png color t ype
430 const SkColorType srcColorType = this->getInfo().colorType(); 367 const SkColorType srcColorType = this->getInfo().colorType();
431 368
432 switch (srcColorType) { 369 switch (srcColorType) {
433 case kIndex_8_SkColorType: 370 case kIndex_8_SkColorType:
434 //decode palette to Skia format 371 //decode palette to Skia format
435 fSrcConfig = SkSwizzler::kIndex; 372 fSrcConfig = SkSwizzler::kIndex;
436 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(), 373 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(),
437 ctableCount)) { 374 ctableCount)) {
438 return kInvalidInput; 375 return kInvalidInput;
439 } 376 }
440 break; 377 break;
441 case kGray_8_SkColorType: 378 case kGray_8_SkColorType:
442 fSrcConfig = SkSwizzler::kGray; 379 fSrcConfig = SkSwizzler::kGray;
443 break; 380 break;
444 case kN32_SkColorType: 381 case kN32_SkColorType:
445 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { 382 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) {
446 fSrcConfig = SkSwizzler::kRGB; 383 fSrcConfig = SkSwizzler::kRGB;
447 } else { 384 } else {
448 fSrcConfig = SkSwizzler::kRGBA; 385 fSrcConfig = SkSwizzler::kRGBA;
449 } 386 }
450 break; 387 break;
451 default: 388 default:
452 //would have exited before now if the colorType was supported by png 389 // We will always recommend one the above colorTypes.
scroggo 2016/01/28 21:07:32 one of*
msarett 2016/01/28 22:19:25 Done.
453 SkASSERT(false); 390 SkASSERT(false);
454 } 391 }
455 392
456 // Copy the color table to the client if they request kIndex8 mode 393 // Copy the color table to the client if they request kIndex8 mode
457 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); 394 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount);
458 395
459 // Create the swizzler. SkPngCodec retains ownership of the color table. 396 // Create the swizzler. SkPngCodec retains ownership of the color table.
460 const SkPMColor* colors = get_color_ptr(fColorTable.get()); 397 const SkPMColor* colors = get_color_ptr(fColorTable.get());
461 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , options)); 398 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , options));
462 if (!fSwizzler) { 399 SkASSERT(fSwizzler);
463 // FIXME: CreateSwizzler could fail for another reason. 400
464 return kUnimplemented;
465 }
466 return kSuccess; 401 return kSuccess;
467 } 402 }
468 403
469 404
470 bool SkPngCodec::onRewind() { 405 bool SkPngCodec::onRewind() {
471 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header 406 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
472 // succeeds, they will be repopulated, and if it fails, they will 407 // succeeds, they will be repopulated, and if it fails, they will
473 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will 408 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
474 // come through this function which will rewind and again attempt 409 // come through this function which will rewind and again attempt
475 // to reinitialize them. 410 // to reinitialize them.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); 473 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig);
539 const size_t srcRowBytes = width * bpp; 474 const size_t srcRowBytes = width * bpp;
540 475
541 storage.reset(width * height * bpp); 476 storage.reset(width * height * bpp);
542 uint8_t* const base = storage.get(); 477 uint8_t* const base = storage.get();
543 478
544 for (int i = 0; i < fNumberPasses; i++) { 479 for (int i = 0; i < fNumberPasses; i++) {
545 uint8_t* srcRow = base; 480 uint8_t* srcRow = base;
546 for (int y = 0; y < height; y++) { 481 for (int y = 0; y < height; y++) {
547 uint8_t* bmRow = srcRow; 482 uint8_t* bmRow = srcRow;
548 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); 483 png_read_rows(fPng_ptr, &bmRow, nullptr, 1);
549 srcRow += srcRowBytes; 484 srcRow += srcRowBytes;
550 } 485 }
551 } 486 }
552 487
553 // Now swizzle it. 488 // Now swizzle it.
554 uint8_t* srcRow = base; 489 uint8_t* srcRow = base;
555 for (int y = 0; y < height; y++) { 490 for (int y = 0; y < height; y++) {
556 fSwizzler->swizzle(dstRow, srcRow); 491 fSwizzler->swizzle(dstRow, srcRow);
557 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 492 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
558 srcRow += srcRowBytes; 493 srcRow += srcRowBytes;
559 } 494 }
560 } else { 495 } else {
561 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig)); 496 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig));
562 uint8_t* srcRow = storage.get(); 497 uint8_t* srcRow = storage.get();
563 for (; row < requestedInfo.height(); row++) { 498 for (; row < requestedInfo.height(); row++) {
564 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); 499 png_read_rows(fPng_ptr, &srcRow, nullptr, 1);
565 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines. 500 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines.
566 fSwizzler->swizzle(dstRow, srcRow); 501 fSwizzler->swizzle(dstRow, srcRow);
567 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 502 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
568 } 503 }
569 } 504 }
570 505
571 // FIXME: do we need substituteTranspColor? Note that we cannot do it for
msarett 2016/01/28 02:06:46 Substituting in a "transparent color" is necessary
scroggo 2016/01/28 21:07:32 Good to know. This would be a good thing to specif
msarett 2016/01/28 22:19:25 Done.
572 // scanline decoding, but we could do it here. Alternatively, we could do
573 // it as we go, instead of in post-processing like SkPNGImageDecoder.
574
575 if (setjmp(png_jmpbuf(fPng_ptr))) { 506 if (setjmp(png_jmpbuf(fPng_ptr))) {
576 // We've already read all the scanlines. This is a success. 507 // We've already read all the scanlines. This is a success.
577 return kSuccess; 508 return kSuccess;
578 } 509 }
579 510
580 // read rest of file, and get additional comment and time chunks in info_ptr 511 // read rest of file, and get additional comment and time chunks in info_ptr
581 png_read_end(fPng_ptr, fInfo_ptr); 512 png_read_end(fPng_ptr, fInfo_ptr);
582 513
583 return kSuccess; 514 return kSuccess;
584 } 515 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 int onGetScanlines(void* dst, int count, size_t rowBytes) override { 552 int onGetScanlines(void* dst, int count, size_t rowBytes) override {
622 // Assume that an error in libpng indicates an incomplete input. 553 // Assume that an error in libpng indicates an incomplete input.
623 int row = 0; 554 int row = 0;
624 if (setjmp(png_jmpbuf(this->png_ptr()))) { 555 if (setjmp(png_jmpbuf(this->png_ptr()))) {
625 SkCodecPrintf("setjmp long jump!\n"); 556 SkCodecPrintf("setjmp long jump!\n");
626 return row; 557 return row;
627 } 558 }
628 559
629 void* dstRow = dst; 560 void* dstRow = dst;
630 for (; row < count; row++) { 561 for (; row < count; row++) {
631 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); 562 png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1);
632 this->swizzler()->swizzle(dstRow, fSrcRow); 563 this->swizzler()->swizzle(dstRow, fSrcRow);
633 dstRow = SkTAddOffset<void>(dstRow, rowBytes); 564 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
634 } 565 }
635 566
636 return row; 567 return row;
637 } 568 }
638 569
639 bool onSkipScanlines(int count) override { 570 bool onSkipScanlines(int count) override {
640 // Assume that an error in libpng indicates an incomplete input. 571 // Assume that an error in libpng indicates an incomplete input.
641 if (setjmp(png_jmpbuf(this->png_ptr()))) { 572 if (setjmp(png_jmpbuf(this->png_ptr()))) {
642 SkCodecPrintf("setjmp long jump!\n"); 573 SkCodecPrintf("setjmp long jump!\n");
643 return false; 574 return false;
644 } 575 }
645 //there is a potential tradeoff of memory vs speed created by putting th is in a loop. 576 //there is a potential tradeoff of memory vs speed created by putting th is in a loop.
646 //calling png_read_rows in a loop is insignificantly slower than calling it once with count 577 //calling png_read_rows in a loop is insignificantly slower than calling it once with count
647 //as png_read_rows has it's own loop which calls png_read_row count time s. 578 //as png_read_rows has it's own loop which calls png_read_row count time s.
648 for (int row = 0; row < count; row++) { 579 for (int row = 0; row < count; row++) {
649 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); 580 png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1);
650 } 581 }
651 return true; 582 return true;
652 } 583 }
653 584
654 private: 585 private:
655 SkAutoTMalloc<uint8_t> fStorage; 586 SkAutoTMalloc<uint8_t> fStorage;
656 uint8_t* fSrcRow; 587 uint8_t* fSrcRow;
657 588
658 typedef SkPngCodec INHERITED; 589 typedef SkPngCodec INHERITED;
659 }; 590 };
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
723 // fail on the first pass, we can still report than some scanlines a re initialized. 654 // fail on the first pass, we can still report than some scanlines a re initialized.
724 return 0; 655 return 0;
725 } 656 }
726 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes); 657 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes);
727 uint8_t* storagePtr = storage.get(); 658 uint8_t* storagePtr = storage.get();
728 uint8_t* srcRow; 659 uint8_t* srcRow;
729 const int startRow = this->nextScanline(); 660 const int startRow = this->nextScanline();
730 for (int i = 0; i < this->numberPasses(); i++) { 661 for (int i = 0; i < this->numberPasses(); i++) {
731 // read rows we planned to skip into garbage row 662 // read rows we planned to skip into garbage row
732 for (int y = 0; y < startRow; y++){ 663 for (int y = 0; y < startRow; y++){
733 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1); 664 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1);
734 } 665 }
735 // read rows we care about into buffer 666 // read rows we care about into buffer
736 srcRow = storagePtr; 667 srcRow = storagePtr;
737 for (int y = 0; y < count; y++) { 668 for (int y = 0; y < count; y++) {
738 png_read_rows(this->png_ptr(), &srcRow, png_bytepp_NULL, 1); 669 png_read_rows(this->png_ptr(), &srcRow, nullptr, 1);
739 srcRow += fSrcRowBytes; 670 srcRow += fSrcRowBytes;
740 } 671 }
741 // read rows we don't want into garbage buffer 672 // read rows we don't want into garbage buffer
742 for (int y = 0; y < fHeight - startRow - count; y++) { 673 for (int y = 0; y < fHeight - startRow - count; y++) {
743 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1); 674 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1);
744 } 675 }
745 } 676 }
746 //swizzle the rows we care about 677 //swizzle the rows we care about
747 srcRow = storagePtr; 678 srcRow = storagePtr;
748 void* dstRow = dst; 679 void* dstRow = dst;
749 for (int y = 0; y < count; y++) { 680 for (int y = 0; y < count; y++) {
750 this->swizzler()->swizzle(dstRow, srcRow); 681 this->swizzler()->swizzle(dstRow, srcRow);
751 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 682 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
752 srcRow += fSrcRowBytes; 683 srcRow += fSrcRowBytes;
753 } 684 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
796 } 727 }
797 728
798 if (1 == numberPasses) { 729 if (1 == numberPasses) {
799 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader, 730 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader,
800 png_ptr, info_ptr, bitDepth); 731 png_ptr, info_ptr, bitDepth);
801 } 732 }
802 733
803 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, 734 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader,
804 png_ptr, info_ptr, bitDepth, numbe rPasses); 735 png_ptr, info_ptr, bitDepth, numbe rPasses);
805 } 736 }
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