Chromium Code Reviews| 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 | |
|
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 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 | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |