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/codec/SkPngCodec.cpp

Issue 1643623004: A variety of SkPngCodec clean-ups (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Response to comments Created 4 years, 10 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
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;
151 png_colorp palette;
152 png_bytep trans;
153 108
154 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) { 109 int numColors;
110 png_color* palette;
111 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) {
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;
161 117
162 int numTrans; 118 // The optimized code depends on a 3-byte png_color struct with the colors
163 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { 119 // in RGB order. These checks make sure it is safe to use.
164 png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, nullptr); 120 static_assert(3 == sizeof(png_color), "png_color struct has changed. Opts a re broken.");
165 } else { 121 #ifdef SK_DEBUG
166 numTrans = 0; 122 if (numColors > 0) {
123 SkASSERT(&palette->red < &palette->green);
124 SkASSERT(&palette->green < &palette->blue);
125 }
126 #endif
127
128 #ifdef SK_PMCOLOR_IS_RGBA
129 SkOpts::RGB_to_RGB1(colorPtr, palette, numColors);
130 #else
131 SkOpts::RGB_to_BGR1(colorPtr, palette, numColors);
132 #endif
133
134 png_bytep alphas;
135 int numColorsWithAlpha;
136 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr) ) {
137 for (int i = 0; i < numColorsWithAlpha; i++) {
138 // We have already swapped (or not swapped) color channels to
139 // match native byte ordering. Here we only need to premultiply.
140 uint8_t a = alphas[i];
141 uint8_t b = SkMulDiv255Round(colorPtr[i] >> 16, a);
scroggo 2016/01/29 15:40:27 Are these names misleading? It sounds like this ma
msarett 2016/01/29 18:56:08 This has been changed.
142 uint8_t g = SkMulDiv255Round(colorPtr[i] >> 8, a);
143 uint8_t r = SkMulDiv255Round(colorPtr[i] >> 0, a);
144 colorPtr[i] = (uint32_t)a << 24
145 | (uint32_t)b << 16
146 | (uint32_t)g << 8
147 | (uint32_t)r << 0;
148 }
167 } 149 }
168 150
169 // check for bad images that might make us crash 151 // Pad the color table with the last color in the table (or black) in the ca se that
170 if (numTrans > numPalette) { 152 // invalid pixel indices exceed the number of colors in the table.
171 numTrans = numPalette; 153 const int maxColors = 1 << fBitDepth;
154 if (numColors < maxColors) {
155 SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_Color BLACK;
156 sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors);
172 } 157 }
173 158
174 int index = 0; 159 // Set the new color count.
175 160 if (ctableCount != nullptr) {
176 // Choose which function to use to create the color table. If the final dest ination's 161 *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 } 162 }
188 163
189 for (; index < numPalette; index++) { 164 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; 165 return true;
215 } 166 }
216 167
217 /////////////////////////////////////////////////////////////////////////////// 168 ///////////////////////////////////////////////////////////////////////////////
218 // Creation 169 // Creation
219 /////////////////////////////////////////////////////////////////////////////// 170 ///////////////////////////////////////////////////////////////////////////////
220 171
221 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) { 172 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) {
222 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead); 173 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead);
223 } 174 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 if (chunkReader) { 227 if (chunkReader) {
277 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte* )"", 0); 228 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); 229 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_use r_chunk);
279 } 230 }
280 #endif 231 #endif
281 232
282 // The call to png_read_info() gives us all of the information from the 233 // The call to png_read_info() gives us all of the information from the
283 // PNG file before the first IDAT (image data chunk). 234 // PNG file before the first IDAT (image data chunk).
284 png_read_info(png_ptr, info_ptr); 235 png_read_info(png_ptr, info_ptr);
285 png_uint_32 origWidth, origHeight; 236 png_uint_32 origWidth, origHeight;
286 int bitDepth, colorType; 237 int bitDepth, encodedColorType;
287 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, 238 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
288 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); 239 &encodedColorType, nullptr, nullptr, nullptr);
289 240
290 if (bitDepthPtr) { 241 if (bitDepthPtr) {
291 *bitDepthPtr = bitDepth; 242 *bitDepthPtr = bitDepth;
292 } 243 }
293 244
294 // sanity check for size 245 // Tell libpng to strip 16 bit/color files down to 8 bits/color.
295 { 246 // TODO: Should we handle this in SkSwizzler? Could this also benefit
296 int64_t size = sk_64_mul(origWidth, origHeight); 247 // RAW decodes?
297 // now check that if we are 4-bytes per pixel, we also don't overflow 248 if (bitDepth == 16) {
298 if (size < 0 || size > (0x7FFFFFFF >> 2)) { 249 SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType);
299 return false; 250 png_set_strip_16(png_ptr);
300 }
301 } 251 }
302 252
303 // Tell libpng to strip 16 bit/color files down to 8 bits/color 253 // Now determine the default colorType and alphaType and set the required tr ansforms.
304 if (bitDepth == 16) { 254 // Often, we depend on SkSwizzler to perform any transforms that we need. H owever, we
305 png_set_strip_16(png_ptr); 255 // still depend on libpng for many of the rare and PNG-specific cases.
306 } 256 SkColorType colorType = kUnknown_SkColorType;
307 #ifdef PNG_READ_PACK_SUPPORTED 257 SkAlphaType alphaType = kUnknown_SkAlphaType;
308 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single 258 switch (encodedColorType) {
309 // byte into separate bytes (useful for paletted and grayscale images). 259 case PNG_COLOR_TYPE_PALETTE:
310 if (bitDepth < 8) { 260 // Extract multiple pixels with bit depths of 1, 2, and 4 from a sin gle
311 png_set_packing(png_ptr); 261 // byte into separate bytes (useful for paletted and grayscale image s).
312 } 262 if (bitDepth < 8) {
313 #endif 263 // TODO: Should we use SkSwizzler here?
314 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. 264 png_set_packing(png_ptr);
315 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { 265 }
316 png_set_expand_gray_1_2_4_to_8(png_ptr);
317 }
318 266
319 // Now determine the default SkColorType and SkAlphaType and set required tr ansforms 267 colorType = kIndex_8_SkColorType;
320 SkColorType skColorType = kUnknown_SkColorType; 268 // Set the alpha type depending on if a transparency chunk exists.
321 SkAlphaType skAlphaType = kUnknown_SkAlphaType; 269 alphaType = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ?
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; 270 kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
327 break; 271 break;
328 case PNG_COLOR_TYPE_RGB: 272 case PNG_COLOR_TYPE_RGB:
329 if (has_transparency_in_tRNS(png_ptr, info_ptr)) { 273 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
330 //convert to RGBA with tranparency information in tRNS chunk if it exists 274 // Convert to RGBA if transparency chunk exists.
331 png_set_tRNS_to_alpha(png_ptr); 275 png_set_tRNS_to_alpha(png_ptr);
332 skAlphaType = kUnpremul_SkAlphaType; 276 alphaType = kUnpremul_SkAlphaType;
333 } else { 277 } else {
334 skAlphaType = kOpaque_SkAlphaType; 278 alphaType = kOpaque_SkAlphaType;
335 } 279 }
336 skColorType = kN32_SkColorType; 280 colorType = kN32_SkColorType;
337 break; 281 break;
338 case PNG_COLOR_TYPE_GRAY: 282 case PNG_COLOR_TYPE_GRAY:
339 if (has_transparency_in_tRNS(png_ptr, info_ptr)) { 283 // 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 284 if (bitDepth < 8) {
341 //convert to RGBA if there is transparentcy info in the tRNS chu nk 285 // TODO: Should we use SkSwizzler here?
286 png_set_expand_gray_1_2_4_to_8(png_ptr);
287 }
288
289 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
290 // Convert to RGBA if there is a transparency chunk.
342 png_set_tRNS_to_alpha(png_ptr); 291 png_set_tRNS_to_alpha(png_ptr);
343 png_set_gray_to_rgb(png_ptr); 292 png_set_gray_to_rgb(png_ptr);
344 skColorType = kN32_SkColorType; 293 colorType = kN32_SkColorType;
345 skAlphaType = kUnpremul_SkAlphaType; 294 alphaType = kUnpremul_SkAlphaType;
346 } else { 295 } else {
347 skColorType = kGray_8_SkColorType; 296 colorType = kGray_8_SkColorType;
348 skAlphaType = kOpaque_SkAlphaType; 297 alphaType = kOpaque_SkAlphaType;
349 } 298 }
350 break; 299 break;
351 case PNG_COLOR_TYPE_GRAY_ALPHA: 300 case PNG_COLOR_TYPE_GRAY_ALPHA:
352 //FIXME: support gray with alpha as a color type 301 // Convert to RGBA if the image has alpha.
353 //convert to RGBA
354 png_set_gray_to_rgb(png_ptr); 302 png_set_gray_to_rgb(png_ptr);
355 skColorType = kN32_SkColorType; 303 colorType = kN32_SkColorType;
356 skAlphaType = kUnpremul_SkAlphaType; 304 alphaType = kUnpremul_SkAlphaType;
357 break; 305 break;
358 case PNG_COLOR_TYPE_RGBA: 306 case PNG_COLOR_TYPE_RGBA:
359 skColorType = kN32_SkColorType; 307 colorType = kN32_SkColorType;
360 skAlphaType = kUnpremul_SkAlphaType; 308 alphaType = kUnpremul_SkAlphaType;
361 break; 309 break;
362 default: 310 default:
363 //all the color types have been covered above 311 // All the color types have been covered above.
364 SkASSERT(false); 312 SkASSERT(false);
365 } 313 }
366 314
367 int numberPasses = png_set_interlace_handling(png_ptr); 315 int numberPasses = png_set_interlace_handling(png_ptr);
368 if (numberPassesPtr) { 316 if (numberPassesPtr) {
369 *numberPassesPtr = numberPasses; 317 *numberPassesPtr = numberPasses;
370 } 318 }
371 319
372 // FIXME: Also need to check for sRGB ( https://bug.skia.org/3471 ). 320 // FIXME: Also need to check for sRGB ( https://bug.skia.org/3471 ).
373 321
374 if (imageInfo) { 322 if (imageInfo) {
375 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlp haType); 323 *imageInfo = SkImageInfo::Make(origWidth, origHeight, colorType, alphaTy pe);
376 } 324 }
377 autoClean.detach(); 325 autoClean.detach();
378 if (png_ptrp) { 326 if (png_ptrp) {
379 *png_ptrp = png_ptr; 327 *png_ptrp = png_ptr;
380 } 328 }
381 if (info_ptrp) { 329 if (info_ptrp) {
382 *info_ptrp = info_ptr; 330 *info_ptrp = info_ptr;
383 } 331 }
384 332
385 return true; 333 return true;
(...skipping 11 matching lines...) Expand all
397 {} 345 {}
398 346
399 SkPngCodec::~SkPngCodec() { 347 SkPngCodec::~SkPngCodec() {
400 this->destroyReadStruct(); 348 this->destroyReadStruct();
401 } 349 }
402 350
403 void SkPngCodec::destroyReadStruct() { 351 void SkPngCodec::destroyReadStruct() {
404 if (fPng_ptr) { 352 if (fPng_ptr) {
405 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr 353 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
406 SkASSERT(fInfo_ptr); 354 SkASSERT(fInfo_ptr);
407 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); 355 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, nullptr);
408 fPng_ptr = nullptr; 356 fPng_ptr = nullptr;
409 fInfo_ptr = nullptr; 357 fInfo_ptr = nullptr;
410 } 358 }
411 } 359 }
412 360
413 /////////////////////////////////////////////////////////////////////////////// 361 ///////////////////////////////////////////////////////////////////////////////
414 // Getting the pixels 362 // Getting the pixels
415 /////////////////////////////////////////////////////////////////////////////// 363 ///////////////////////////////////////////////////////////////////////////////
416 364
417 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, 365 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
418 const Options& options, 366 const Options& options,
419 SkPMColor ctable[], 367 SkPMColor ctable[],
420 int* ctableCount) { 368 int* ctableCount) {
421 // FIXME: Could we use the return value of setjmp to specify the type of 369 // FIXME: Could we use the return value of setjmp to specify the type of
422 // error? 370 // error?
423 if (setjmp(png_jmpbuf(fPng_ptr))) { 371 if (setjmp(png_jmpbuf(fPng_ptr))) {
424 SkCodecPrintf("setjmp long jump!\n"); 372 SkCodecPrintf("setjmp long jump!\n");
425 return kInvalidInput; 373 return kInvalidInput;
426 } 374 }
427 png_read_update_info(fPng_ptr, fInfo_ptr); 375 png_read_update_info(fPng_ptr, fInfo_ptr);
428 376
429 //srcColorType was determined in read_header() which determined png color ty pe 377 // srcColorType was determined in read_header() which determined png color t ype
430 const SkColorType srcColorType = this->getInfo().colorType(); 378 const SkColorType srcColorType = this->getInfo().colorType();
431 379
432 switch (srcColorType) { 380 switch (srcColorType) {
433 case kIndex_8_SkColorType: 381 case kIndex_8_SkColorType:
434 //decode palette to Skia format 382 //decode palette to Skia format
435 fSrcConfig = SkSwizzler::kIndex; 383 fSrcConfig = SkSwizzler::kIndex;
436 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(), 384 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(),
437 ctableCount)) { 385 ctableCount)) {
438 return kInvalidInput; 386 return kInvalidInput;
439 } 387 }
440 break; 388 break;
441 case kGray_8_SkColorType: 389 case kGray_8_SkColorType:
442 fSrcConfig = SkSwizzler::kGray; 390 fSrcConfig = SkSwizzler::kGray;
443 break; 391 break;
444 case kN32_SkColorType: 392 case kN32_SkColorType:
445 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { 393 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) {
446 fSrcConfig = SkSwizzler::kRGB; 394 fSrcConfig = SkSwizzler::kRGB;
447 } else { 395 } else {
448 fSrcConfig = SkSwizzler::kRGBA; 396 fSrcConfig = SkSwizzler::kRGBA;
449 } 397 }
450 break; 398 break;
451 default: 399 default:
452 //would have exited before now if the colorType was supported by png 400 // We will always recommend one of the above colorTypes.
453 SkASSERT(false); 401 SkASSERT(false);
454 } 402 }
455 403
456 // Copy the color table to the client if they request kIndex8 mode 404 // Copy the color table to the client if they request kIndex8 mode
457 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); 405 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount);
458 406
459 // Create the swizzler. SkPngCodec retains ownership of the color table. 407 // Create the swizzler. SkPngCodec retains ownership of the color table.
460 const SkPMColor* colors = get_color_ptr(fColorTable.get()); 408 const SkPMColor* colors = get_color_ptr(fColorTable.get());
461 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , options)); 409 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , options));
462 if (!fSwizzler) { 410 SkASSERT(fSwizzler);
463 // FIXME: CreateSwizzler could fail for another reason. 411
464 return kUnimplemented;
465 }
466 return kSuccess; 412 return kSuccess;
467 } 413 }
468 414
469 415
470 bool SkPngCodec::onRewind() { 416 bool SkPngCodec::onRewind() {
471 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header 417 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
472 // succeeds, they will be repopulated, and if it fails, they will 418 // succeeds, they will be repopulated, and if it fails, they will
473 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will 419 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
474 // come through this function which will rewind and again attempt 420 // come through this function which will rewind and again attempt
475 // to reinitialize them. 421 // to reinitialize them.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); 484 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig);
539 const size_t srcRowBytes = width * bpp; 485 const size_t srcRowBytes = width * bpp;
540 486
541 storage.reset(width * height * bpp); 487 storage.reset(width * height * bpp);
542 uint8_t* const base = storage.get(); 488 uint8_t* const base = storage.get();
543 489
544 for (int i = 0; i < fNumberPasses; i++) { 490 for (int i = 0; i < fNumberPasses; i++) {
545 uint8_t* srcRow = base; 491 uint8_t* srcRow = base;
546 for (int y = 0; y < height; y++) { 492 for (int y = 0; y < height; y++) {
547 uint8_t* bmRow = srcRow; 493 uint8_t* bmRow = srcRow;
548 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); 494 png_read_rows(fPng_ptr, &bmRow, nullptr, 1);
549 srcRow += srcRowBytes; 495 srcRow += srcRowBytes;
550 } 496 }
551 } 497 }
552 498
553 // Now swizzle it. 499 // Now swizzle it.
554 uint8_t* srcRow = base; 500 uint8_t* srcRow = base;
555 for (int y = 0; y < height; y++) { 501 for (int y = 0; y < height; y++) {
556 fSwizzler->swizzle(dstRow, srcRow); 502 fSwizzler->swizzle(dstRow, srcRow);
557 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 503 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
558 srcRow += srcRowBytes; 504 srcRow += srcRowBytes;
559 } 505 }
560 } else { 506 } else {
561 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig)); 507 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig));
562 uint8_t* srcRow = storage.get(); 508 uint8_t* srcRow = storage.get();
563 for (; row < requestedInfo.height(); row++) { 509 for (; row < requestedInfo.height(); row++) {
564 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); 510 png_read_rows(fPng_ptr, &srcRow, nullptr, 1);
565 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines. 511 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines.
566 fSwizzler->swizzle(dstRow, srcRow); 512 fSwizzler->swizzle(dstRow, srcRow);
567 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 513 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
568 } 514 }
569 } 515 }
570 516
571 // FIXME: do we need substituteTranspColor? Note that we cannot do it for
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))) { 517 if (setjmp(png_jmpbuf(fPng_ptr))) {
576 // We've already read all the scanlines. This is a success. 518 // We've already read all the scanlines. This is a success.
577 return kSuccess; 519 return kSuccess;
578 } 520 }
579 521
580 // read rest of file, and get additional comment and time chunks in info_ptr 522 // read rest of file, and get additional comment and time chunks in info_ptr
581 png_read_end(fPng_ptr, fInfo_ptr); 523 png_read_end(fPng_ptr, fInfo_ptr);
582 524
583 return kSuccess; 525 return kSuccess;
584 } 526 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 int onGetScanlines(void* dst, int count, size_t rowBytes) override { 563 int onGetScanlines(void* dst, int count, size_t rowBytes) override {
622 // Assume that an error in libpng indicates an incomplete input. 564 // Assume that an error in libpng indicates an incomplete input.
623 int row = 0; 565 int row = 0;
624 if (setjmp(png_jmpbuf(this->png_ptr()))) { 566 if (setjmp(png_jmpbuf(this->png_ptr()))) {
625 SkCodecPrintf("setjmp long jump!\n"); 567 SkCodecPrintf("setjmp long jump!\n");
626 return row; 568 return row;
627 } 569 }
628 570
629 void* dstRow = dst; 571 void* dstRow = dst;
630 for (; row < count; row++) { 572 for (; row < count; row++) {
631 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); 573 png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1);
632 this->swizzler()->swizzle(dstRow, fSrcRow); 574 this->swizzler()->swizzle(dstRow, fSrcRow);
633 dstRow = SkTAddOffset<void>(dstRow, rowBytes); 575 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
634 } 576 }
635 577
636 return row; 578 return row;
637 } 579 }
638 580
639 bool onSkipScanlines(int count) override { 581 bool onSkipScanlines(int count) override {
640 // Assume that an error in libpng indicates an incomplete input. 582 // Assume that an error in libpng indicates an incomplete input.
641 if (setjmp(png_jmpbuf(this->png_ptr()))) { 583 if (setjmp(png_jmpbuf(this->png_ptr()))) {
642 SkCodecPrintf("setjmp long jump!\n"); 584 SkCodecPrintf("setjmp long jump!\n");
643 return false; 585 return false;
644 } 586 }
645 //there is a potential tradeoff of memory vs speed created by putting th is in a loop. 587 //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 588 //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. 589 //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++) { 590 for (int row = 0; row < count; row++) {
649 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); 591 png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1);
650 } 592 }
651 return true; 593 return true;
652 } 594 }
653 595
654 private: 596 private:
655 SkAutoTMalloc<uint8_t> fStorage; 597 SkAutoTMalloc<uint8_t> fStorage;
656 uint8_t* fSrcRow; 598 uint8_t* fSrcRow;
657 599
658 typedef SkPngCodec INHERITED; 600 typedef SkPngCodec INHERITED;
659 }; 601 };
(...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. 665 // fail on the first pass, we can still report than some scanlines a re initialized.
724 return 0; 666 return 0;
725 } 667 }
726 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes); 668 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes);
727 uint8_t* storagePtr = storage.get(); 669 uint8_t* storagePtr = storage.get();
728 uint8_t* srcRow; 670 uint8_t* srcRow;
729 const int startRow = this->nextScanline(); 671 const int startRow = this->nextScanline();
730 for (int i = 0; i < this->numberPasses(); i++) { 672 for (int i = 0; i < this->numberPasses(); i++) {
731 // read rows we planned to skip into garbage row 673 // read rows we planned to skip into garbage row
732 for (int y = 0; y < startRow; y++){ 674 for (int y = 0; y < startRow; y++){
733 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1); 675 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1);
734 } 676 }
735 // read rows we care about into buffer 677 // read rows we care about into buffer
736 srcRow = storagePtr; 678 srcRow = storagePtr;
737 for (int y = 0; y < count; y++) { 679 for (int y = 0; y < count; y++) {
738 png_read_rows(this->png_ptr(), &srcRow, png_bytepp_NULL, 1); 680 png_read_rows(this->png_ptr(), &srcRow, nullptr, 1);
739 srcRow += fSrcRowBytes; 681 srcRow += fSrcRowBytes;
740 } 682 }
741 // read rows we don't want into garbage buffer 683 // read rows we don't want into garbage buffer
742 for (int y = 0; y < fHeight - startRow - count; y++) { 684 for (int y = 0; y < fHeight - startRow - count; y++) {
743 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1); 685 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1);
744 } 686 }
745 } 687 }
746 //swizzle the rows we care about 688 //swizzle the rows we care about
747 srcRow = storagePtr; 689 srcRow = storagePtr;
748 void* dstRow = dst; 690 void* dstRow = dst;
749 for (int y = 0; y < count; y++) { 691 for (int y = 0; y < count; y++) {
750 this->swizzler()->swizzle(dstRow, srcRow); 692 this->swizzler()->swizzle(dstRow, srcRow);
751 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 693 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
752 srcRow += fSrcRowBytes; 694 srcRow += fSrcRowBytes;
753 } 695 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
796 } 738 }
797 739
798 if (1 == numberPasses) { 740 if (1 == numberPasses) {
799 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader, 741 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader,
800 png_ptr, info_ptr, bitDepth); 742 png_ptr, info_ptr, bitDepth);
801 } 743 }
802 744
803 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, 745 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader,
804 png_ptr, info_ptr, bitDepth, numbe rPasses); 746 png_ptr, info_ptr, bitDepth, numbe rPasses);
805 } 747 }
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