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