Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gfx/codec/png_codec.h" | 5 #include "ui/gfx/codec/png_codec.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "ui/gfx/size.h" | 10 #include "ui/gfx/size.h" |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 47 unsigned char* rgb, bool* is_opaque) { | 47 unsigned char* rgb, bool* is_opaque) { |
| 48 for (int x = 0; x < pixel_width; x++) { | 48 for (int x = 0; x < pixel_width; x++) { |
| 49 const unsigned char* pixel_in = &rgba[x * 4]; | 49 const unsigned char* pixel_in = &rgba[x * 4]; |
| 50 unsigned char* pixel_out = &rgb[x * 3]; | 50 unsigned char* pixel_out = &rgb[x * 3]; |
| 51 pixel_out[0] = pixel_in[0]; | 51 pixel_out[0] = pixel_in[0]; |
| 52 pixel_out[1] = pixel_in[1]; | 52 pixel_out[1] = pixel_in[1]; |
| 53 pixel_out[2] = pixel_in[2]; | 53 pixel_out[2] = pixel_in[2]; |
| 54 } | 54 } |
| 55 } | 55 } |
| 56 | 56 |
| 57 void ConvertRGBtoSkia(const unsigned char* rgb, int pixel_width, | |
| 58 unsigned char* rgba, bool* is_opaque) { | |
| 59 for (int x = 0; x < pixel_width; x++) { | |
| 60 const unsigned char* pixel_in = &rgb[x * 3]; | |
| 61 uint32_t* pixel_out = reinterpret_cast<uint32_t*>(&rgba[x * 4]); | |
| 62 *pixel_out = SkPackARGB32(0xFF, pixel_in[0], pixel_in[1], pixel_in[2]); | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 void ConvertRGBAtoSkia(const unsigned char* rgb, int pixel_width, | |
| 67 unsigned char* rgba, bool* is_opaque) { | |
| 68 int total_length = pixel_width * 4; | |
| 69 for (int x = 0; x < total_length; x += 4) { | |
| 70 const unsigned char* pixel_in = &rgb[x]; | |
| 71 uint32_t* pixel_out = reinterpret_cast<uint32_t*>(&rgba[x]); | |
| 72 | |
| 73 unsigned char alpha = pixel_in[3]; | |
| 74 if (alpha != 255) { | |
| 75 *is_opaque = false; | |
| 76 *pixel_out = SkPreMultiplyARGB(alpha, | |
| 77 pixel_in[0], pixel_in[1], pixel_in[2]); | |
| 78 } else { | |
| 79 *pixel_out = SkPackARGB32(alpha, | |
| 80 pixel_in[0], pixel_in[1], pixel_in[2]); | |
| 81 } | |
|
Francois
2012/02/29 09:12:29
The work done by this converter and the one above
| |
| 82 } | |
| 83 } | |
| 84 | |
| 85 void ConvertSkiatoRGB(const unsigned char* skia, int pixel_width, | 57 void ConvertSkiatoRGB(const unsigned char* skia, int pixel_width, |
| 86 unsigned char* rgb, bool* is_opaque) { | 58 unsigned char* rgb, bool* is_opaque) { |
| 87 for (int x = 0; x < pixel_width; x++) { | 59 for (int x = 0; x < pixel_width; x++) { |
| 88 const uint32_t pixel_in = *reinterpret_cast<const uint32_t*>(&skia[x * 4]); | 60 const uint32_t pixel_in = *reinterpret_cast<const uint32_t*>(&skia[x * 4]); |
| 89 unsigned char* pixel_out = &rgb[x * 3]; | 61 unsigned char* pixel_out = &rgb[x * 3]; |
| 90 | 62 |
| 91 int alpha = SkGetPackedA32(pixel_in); | 63 int alpha = SkGetPackedA32(pixel_in); |
| 92 if (alpha != 0 && alpha != 255) { | 64 if (alpha != 0 && alpha != 255) { |
| 93 SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel_in); | 65 SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel_in); |
| 94 pixel_out[0] = SkColorGetR(unmultiplied); | 66 pixel_out[0] = SkColorGetR(unmultiplied); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 141 | 113 |
| 142 class PngDecoderState { | 114 class PngDecoderState { |
| 143 public: | 115 public: |
| 144 // Output is a vector<unsigned char>. | 116 // Output is a vector<unsigned char>. |
| 145 PngDecoderState(PNGCodec::ColorFormat ofmt, std::vector<unsigned char>* o) | 117 PngDecoderState(PNGCodec::ColorFormat ofmt, std::vector<unsigned char>* o) |
| 146 : output_format(ofmt), | 118 : output_format(ofmt), |
| 147 output_channels(0), | 119 output_channels(0), |
| 148 bitmap(NULL), | 120 bitmap(NULL), |
| 149 is_opaque(true), | 121 is_opaque(true), |
| 150 output(o), | 122 output(o), |
| 151 row_converter(NULL), | |
| 152 width(0), | 123 width(0), |
| 153 height(0), | 124 height(0), |
| 154 done(false) { | 125 done(false) { |
| 155 } | 126 } |
| 156 | 127 |
| 157 // Output is an SkBitmap. | 128 // Output is an SkBitmap. |
| 158 explicit PngDecoderState(SkBitmap* skbitmap) | 129 explicit PngDecoderState(SkBitmap* skbitmap) |
| 159 : output_format(PNGCodec::FORMAT_SkBitmap), | 130 : output_format(PNGCodec::FORMAT_SkBitmap), |
| 160 output_channels(0), | 131 output_channels(0), |
| 161 bitmap(skbitmap), | 132 bitmap(skbitmap), |
| 162 is_opaque(true), | 133 is_opaque(true), |
| 163 output(NULL), | 134 output(NULL), |
| 164 row_converter(NULL), | |
| 165 width(0), | 135 width(0), |
| 166 height(0), | 136 height(0), |
| 167 done(false) { | 137 done(false) { |
| 168 } | 138 } |
| 169 | 139 |
| 170 PNGCodec::ColorFormat output_format; | 140 PNGCodec::ColorFormat output_format; |
| 171 int output_channels; | 141 int output_channels; |
| 172 | 142 |
| 173 // An incoming SkBitmap to write to. If NULL, we write to output instead. | 143 // An incoming SkBitmap to write to. If NULL, we write to output instead. |
| 174 SkBitmap* bitmap; | 144 SkBitmap* bitmap; |
| 175 | 145 |
| 176 // Used during the reading of an SkBitmap. Defaults to true until we see a | 146 // Used during the reading of an SkBitmap. Defaults to true until we see a |
| 177 // pixel with anything other than an alpha of 255. | 147 // pixel with anything other than an alpha of 255. |
| 178 bool is_opaque; | 148 bool is_opaque; |
| 179 | 149 |
| 180 // The other way to decode output, where we write into an intermediary buffer | 150 // The other way to decode output, where we write into an intermediary buffer |
| 181 // instead of directly to an SkBitmap. | 151 // instead of directly to an SkBitmap. |
| 182 std::vector<unsigned char>* output; | 152 std::vector<unsigned char>* output; |
| 183 | 153 |
| 184 // Called to convert a row from the library to the correct output format. | |
| 185 // When NULL, no conversion is necessary. | |
| 186 void (*row_converter)(const unsigned char* in, int w, unsigned char* out, | |
| 187 bool* is_opaque); | |
|
Francois
2012/02/29 09:12:29
All decode converters have been removed in favor o
| |
| 188 | |
| 189 // Size of the image, set in the info callback. | 154 // Size of the image, set in the info callback. |
| 190 int width; | 155 int width; |
| 191 int height; | 156 int height; |
| 192 | 157 |
| 193 // Set to true when we've found the end of the data. | 158 // Set to true when we've found the end of the data. |
| 194 bool done; | 159 bool done; |
| 195 | 160 |
| 196 private: | 161 private: |
| 197 DISALLOW_COPY_AND_ASSIGN(PngDecoderState); | 162 DISALLOW_COPY_AND_ASSIGN(PngDecoderState); |
| 198 }; | 163 }; |
| 199 | 164 |
| 200 void ConvertRGBtoRGBA(const unsigned char* rgb, int pixel_width, | 165 // User transform (passed to libpng) which converts a row decoded by libpng to |
| 201 unsigned char* rgba, bool* is_opaque) { | 166 // Skia format. Expects the row to have 4 channels, otherwise there won't be |
| 202 for (int x = 0; x < pixel_width; x++) { | 167 // enough room in |data|. |
| 203 const unsigned char* pixel_in = &rgb[x * 3]; | 168 void ConvertRGBARowToSkia(png_structp png_ptr, |
| 204 unsigned char* pixel_out = &rgba[x * 4]; | 169 png_row_infop row_info, |
| 205 pixel_out[0] = pixel_in[0]; | 170 png_bytep data) { |
| 206 pixel_out[1] = pixel_in[1]; | 171 const int channels = row_info->channels; |
| 207 pixel_out[2] = pixel_in[2]; | 172 DCHECK_EQ(channels, 4); |
| 208 pixel_out[3] = 0xff; | 173 |
|
Francois
2012/02/29 09:12:29
This converter's work is now done by libpng itself
| |
| 174 PngDecoderState* state = | |
| 175 static_cast<PngDecoderState*>(png_get_user_transform_ptr(png_ptr)); | |
| 176 DCHECK(state) << "LibPNG user transform pointer is NULL"; | |
| 177 | |
| 178 unsigned char* const end = data + row_info->rowbytes; | |
| 179 for (unsigned char* p = data; p < end; p += channels) { | |
| 180 uint32_t* sk_pixel = reinterpret_cast<uint32_t*>(p); | |
| 181 const unsigned char alpha = p[channels - 1]; | |
| 182 if (alpha != 255) { | |
| 183 state->is_opaque = false; | |
| 184 *sk_pixel = SkPreMultiplyARGB(alpha, p[0], p[1], p[2]); | |
| 185 } else { | |
| 186 *sk_pixel = SkPackARGB32(alpha, p[0], p[1], p[2]); | |
| 187 } | |
|
Francois
2012/02/29 09:12:29
This is the libpng user transform which replaces t
| |
| 209 } | 188 } |
| 210 } | 189 } |
| 211 | 190 |
| 212 void ConvertRGBtoBGRA(const unsigned char* rgb, int pixel_width, | |
| 213 unsigned char* bgra, bool* is_opaque) { | |
| 214 for (int x = 0; x < pixel_width; x++) { | |
| 215 const unsigned char* pixel_in = &rgb[x * 3]; | |
| 216 unsigned char* pixel_out = &bgra[x * 4]; | |
| 217 pixel_out[0] = pixel_in[2]; | |
| 218 pixel_out[1] = pixel_in[1]; | |
| 219 pixel_out[2] = pixel_in[0]; | |
| 220 pixel_out[3] = 0xff; | |
| 221 } | |
| 222 } | |
| 223 | |
|
Francois
2012/02/29 09:12:29
This converter's work is now done by libpng itself
| |
| 224 // Called when the png header has been read. This code is based on the WebKit | 191 // Called when the png header has been read. This code is based on the WebKit |
| 225 // PNGImageDecoder | 192 // PNGImageDecoder |
| 226 void DecodeInfoCallback(png_struct* png_ptr, png_info* info_ptr) { | 193 void DecodeInfoCallback(png_struct* png_ptr, png_info* info_ptr) { |
| 227 PngDecoderState* state = static_cast<PngDecoderState*>( | 194 PngDecoderState* state = static_cast<PngDecoderState*>( |
| 228 png_get_progressive_ptr(png_ptr)); | 195 png_get_progressive_ptr(png_ptr)); |
| 229 | 196 |
| 230 int bit_depth, color_type, interlace_type, compression_type; | 197 int bit_depth, color_type, interlace_type; |
| 231 int filter_type, channels; | |
| 232 png_uint_32 w, h; | 198 png_uint_32 w, h; |
| 199 | |
| 233 png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, | 200 png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, |
| 234 &interlace_type, &compression_type, &filter_type); | 201 &interlace_type, NULL, NULL); |
| 235 | 202 |
| 236 // Bounds check. When the image is unreasonably big, we'll error out and | 203 // Bounds check. When the image is unreasonably big, we'll error out and |
| 237 // end up back at the setjmp call when we set up decoding. "Unreasonably big" | 204 // end up back at the setjmp call when we set up decoding. "Unreasonably big" |
| 238 // means "big enough that w * h * 32bpp might overflow an int"; we choose this | 205 // means "big enough that w * h * 32bpp might overflow an int"; we choose this |
| 239 // threshold to match WebKit and because a number of places in code assume | 206 // threshold to match WebKit and because a number of places in code assume |
| 240 // that an image's size (in bytes) fits in a (signed) int. | 207 // that an image's size (in bytes) fits in a (signed) int. |
| 241 unsigned long long total_size = | 208 unsigned long long total_size = |
| 242 static_cast<unsigned long long>(w) * static_cast<unsigned long long>(h); | 209 static_cast<unsigned long long>(w) * static_cast<unsigned long long>(h); |
| 243 if (total_size > ((1 << 29) - 1)) | 210 if (total_size > ((1 << 29) - 1)) |
| 244 longjmp(png_jmpbuf(png_ptr), 1); | 211 longjmp(png_jmpbuf(png_ptr), 1); |
| 212 | |
| 245 state->width = static_cast<int>(w); | 213 state->width = static_cast<int>(w); |
| 246 state->height = static_cast<int>(h); | 214 state->height = static_cast<int>(h); |
| 247 | 215 |
| 216 // The following png_set_* calls have to be done in the order dictated by | |
| 217 // the libpng docs. This is why certain things are done outside of the | |
| 218 // switch, even though they look like they belong there. | |
| 219 | |
| 248 // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. | 220 // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. |
| 249 if (color_type == PNG_COLOR_TYPE_PALETTE || | 221 if (color_type == PNG_COLOR_TYPE_PALETTE || |
| 250 (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)) | 222 (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)) |
| 251 png_set_expand(png_ptr); | 223 png_set_expand(png_ptr); |
| 252 | 224 |
| 225 bool input_has_alpha = (color_type & PNG_COLOR_MASK_ALPHA); | |
| 226 | |
| 253 // Transparency for paletted images. | 227 // Transparency for paletted images. |
| 254 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) | 228 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { |
| 255 png_set_expand(png_ptr); | 229 png_set_expand(png_ptr); |
| 230 input_has_alpha = true; | |
| 231 } | |
| 256 | 232 |
| 257 // Convert 16-bit to 8-bit. | 233 // Convert 16-bit to 8-bit. |
| 258 if (bit_depth == 16) | 234 if (bit_depth == 16) |
| 259 png_set_strip_16(png_ptr); | 235 png_set_strip_16(png_ptr); |
| 260 | 236 |
| 237 // See comment about png_set_* call ordering, above. | |
| 238 if (state->output_format == PNGCodec::FORMAT_BGRA) | |
| 239 png_set_bgr(png_ptr); | |
| 240 | |
| 241 switch (state->output_format) { | |
| 242 case PNGCodec::FORMAT_RGB: | |
| 243 state->output_channels = 3; | |
| 244 if (input_has_alpha) | |
| 245 png_set_strip_alpha(png_ptr); | |
| 246 break; | |
| 247 case PNGCodec::FORMAT_RGBA: | |
| 248 case PNGCodec::FORMAT_BGRA: | |
| 249 case PNGCodec::FORMAT_SkBitmap: | |
| 250 state->output_channels = 4; | |
| 251 if (!input_has_alpha) | |
| 252 png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); | |
| 253 break; | |
| 254 default: | |
| 255 NOTREACHED() << "Unknown output format"; | |
| 256 break; | |
| 257 } | |
| 258 | |
| 261 // Expand grayscale to RGB. | 259 // Expand grayscale to RGB. |
| 262 if (color_type == PNG_COLOR_TYPE_GRAY || | 260 if (color_type == PNG_COLOR_TYPE_GRAY || |
| 263 color_type == PNG_COLOR_TYPE_GRAY_ALPHA) | 261 color_type == PNG_COLOR_TYPE_GRAY_ALPHA) |
| 264 png_set_gray_to_rgb(png_ptr); | 262 png_set_gray_to_rgb(png_ptr); |
| 265 | 263 |
| 266 // Deal with gamma and keep it under our control. | 264 // Deal with gamma and keep it under our control. |
| 267 double gamma; | 265 double gamma; |
| 268 if (png_get_gAMA(png_ptr, info_ptr, &gamma)) { | 266 if (png_get_gAMA(png_ptr, info_ptr, &gamma)) { |
| 269 if (gamma <= 0.0 || gamma > kMaxGamma) { | 267 if (gamma <= 0.0 || gamma > kMaxGamma) { |
| 270 gamma = kInverseGamma; | 268 gamma = kInverseGamma; |
| 271 png_set_gAMA(png_ptr, info_ptr, gamma); | 269 png_set_gAMA(png_ptr, info_ptr, gamma); |
| 272 } | 270 } |
| 273 png_set_gamma(png_ptr, kDefaultGamma, gamma); | 271 png_set_gamma(png_ptr, kDefaultGamma, gamma); |
| 274 } else { | 272 } else { |
| 275 png_set_gamma(png_ptr, kDefaultGamma, kInverseGamma); | 273 png_set_gamma(png_ptr, kDefaultGamma, kInverseGamma); |
| 276 } | 274 } |
| 277 | 275 |
| 276 // See comment about png_set_* call ordering, above. | |
| 277 if (state->output_format == PNGCodec::FORMAT_SkBitmap) { | |
| 278 png_set_read_user_transform_fn(png_ptr, ConvertRGBARowToSkia); | |
| 279 png_set_user_transform_info(png_ptr, state, 0, 0); | |
| 280 } | |
| 281 | |
| 278 // Tell libpng to send us rows for interlaced pngs. | 282 // Tell libpng to send us rows for interlaced pngs. |
| 279 if (interlace_type == PNG_INTERLACE_ADAM7) | 283 if (interlace_type == PNG_INTERLACE_ADAM7) |
| 280 png_set_interlace_handling(png_ptr); | 284 png_set_interlace_handling(png_ptr); |
| 281 | 285 |
| 282 // Update our info now | |
| 283 png_read_update_info(png_ptr, info_ptr); | 286 png_read_update_info(png_ptr, info_ptr); |
| 284 channels = png_get_channels(png_ptr, info_ptr); | |
| 285 | |
| 286 // Pick our row format converter necessary for this data. | |
| 287 if (channels == 3) { | |
| 288 switch (state->output_format) { | |
| 289 case PNGCodec::FORMAT_RGB: | |
| 290 state->row_converter = NULL; // no conversion necessary | |
| 291 state->output_channels = 3; | |
| 292 break; | |
| 293 case PNGCodec::FORMAT_RGBA: | |
| 294 state->row_converter = &ConvertRGBtoRGBA; | |
| 295 state->output_channels = 4; | |
| 296 break; | |
| 297 case PNGCodec::FORMAT_BGRA: | |
| 298 state->row_converter = &ConvertRGBtoBGRA; | |
| 299 state->output_channels = 4; | |
| 300 break; | |
| 301 case PNGCodec::FORMAT_SkBitmap: | |
| 302 state->row_converter = &ConvertRGBtoSkia; | |
| 303 state->output_channels = 4; | |
| 304 break; | |
| 305 default: | |
| 306 NOTREACHED() << "Unknown output format"; | |
| 307 break; | |
| 308 } | |
| 309 } else if (channels == 4) { | |
| 310 switch (state->output_format) { | |
| 311 case PNGCodec::FORMAT_RGB: | |
| 312 state->row_converter = &ConvertRGBAtoRGB; | |
| 313 state->output_channels = 3; | |
| 314 break; | |
| 315 case PNGCodec::FORMAT_RGBA: | |
| 316 state->row_converter = NULL; // no conversion necessary | |
| 317 state->output_channels = 4; | |
| 318 break; | |
| 319 case PNGCodec::FORMAT_BGRA: | |
| 320 state->row_converter = &ConvertBetweenBGRAandRGBA; | |
| 321 state->output_channels = 4; | |
| 322 break; | |
| 323 case PNGCodec::FORMAT_SkBitmap: | |
| 324 state->row_converter = &ConvertRGBAtoSkia; | |
| 325 state->output_channels = 4; | |
| 326 break; | |
| 327 default: | |
| 328 NOTREACHED() << "Unknown output format"; | |
| 329 break; | |
| 330 } | |
| 331 } else { | |
| 332 NOTREACHED() << "Unknown input channels"; | |
| 333 longjmp(png_jmpbuf(png_ptr), 1); | |
| 334 } | |
| 335 | 287 |
| 336 if (state->bitmap) { | 288 if (state->bitmap) { |
| 337 state->bitmap->setConfig(SkBitmap::kARGB_8888_Config, | 289 state->bitmap->setConfig(SkBitmap::kARGB_8888_Config, |
| 338 state->width, state->height); | 290 state->width, state->height); |
| 339 state->bitmap->allocPixels(); | 291 state->bitmap->allocPixels(); |
| 340 } else if (state->output) { | 292 } else if (state->output) { |
| 341 state->output->resize( | 293 state->output->resize( |
| 342 state->width * state->output_channels * state->height); | 294 state->width * state->output_channels * state->height); |
| 343 } | 295 } |
| 344 } | 296 } |
| 345 | 297 |
| 346 void DecodeRowCallback(png_struct* png_ptr, png_byte* new_row, | 298 void DecodeRowCallback(png_struct* png_ptr, png_byte* new_row, |
| 347 png_uint_32 row_num, int pass) { | 299 png_uint_32 row_num, int pass) { |
| 300 if (!new_row) return; // Interlaced image; row didn't change this pass. | |
|
tony
2012/02/29 18:57:57
Nit: Put the return on it's own line.
Francois
2012/03/01 07:53:15
Done.
| |
| 301 | |
| 348 PngDecoderState* state = static_cast<PngDecoderState*>( | 302 PngDecoderState* state = static_cast<PngDecoderState*>( |
| 349 png_get_progressive_ptr(png_ptr)); | 303 png_get_progressive_ptr(png_ptr)); |
| 350 | 304 |
| 351 DCHECK(pass == 0) << "We didn't turn on interlace handling, but libpng is " | |
| 352 "giving us interlaced data."; | |
| 353 if (static_cast<int>(row_num) > state->height) { | 305 if (static_cast<int>(row_num) > state->height) { |
| 354 NOTREACHED() << "Invalid row"; | 306 NOTREACHED() << "Invalid row"; |
| 355 return; | 307 return; |
| 356 } | 308 } |
| 357 | 309 |
| 358 unsigned char* base = NULL; | 310 unsigned char* base = NULL; |
| 359 if (state->bitmap) | 311 if (state->bitmap) |
| 360 base = reinterpret_cast<unsigned char*>(state->bitmap->getAddr32(0, 0)); | 312 base = reinterpret_cast<unsigned char*>(state->bitmap->getAddr32(0, 0)); |
| 361 else if (state->output) | 313 else if (state->output) |
| 362 base = &state->output->front(); | 314 base = &state->output->front(); |
| 315 unsigned char* dest = &base[state->width * state->output_channels * row_num]; | |
| 363 | 316 |
| 364 unsigned char* dest = &base[state->width * state->output_channels * row_num]; | 317 png_progressive_combine_row(png_ptr, dest, new_row); |
|
Francois
2012/02/29 09:12:29
This call merges the latest changes to the rows of
| |
| 365 if (state->row_converter) | |
| 366 state->row_converter(new_row, state->width, dest, &state->is_opaque); | |
| 367 else | |
| 368 memcpy(dest, new_row, state->width * state->output_channels); | |
| 369 } | 318 } |
| 370 | 319 |
| 371 void DecodeEndCallback(png_struct* png_ptr, png_info* info) { | 320 void DecodeEndCallback(png_struct* png_ptr, png_info* info) { |
| 372 PngDecoderState* state = static_cast<PngDecoderState*>( | 321 PngDecoderState* state = static_cast<PngDecoderState*>( |
| 373 png_get_progressive_ptr(png_ptr)); | 322 png_get_progressive_ptr(png_ptr)); |
| 374 | 323 |
| 375 // Mark the image as complete, this will tell the Decode function that we | 324 // Mark the image as complete, this will tell the Decode function that we |
| 376 // have successfully found the end of the data. | 325 // have successfully found the end of the data. |
| 377 state->done = true; | 326 state->done = true; |
| 378 } | 327 } |
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 785 } | 734 } |
| 786 | 735 |
| 787 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) | 736 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) |
| 788 : key(k), text(t) { | 737 : key(k), text(t) { |
| 789 } | 738 } |
| 790 | 739 |
| 791 PNGCodec::Comment::~Comment() { | 740 PNGCodec::Comment::~Comment() { |
| 792 } | 741 } |
| 793 | 742 |
| 794 } // namespace gfx | 743 } // namespace gfx |
| OLD | NEW |