| OLD | NEW | 
|---|
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "base/gfx/png_decoder.h" | 5 #include "app/gfx/codec/png_codec.h" | 
| 6 | 6 | 
| 7 #include "base/logging.h" | 7 #include "base/logging.h" | 
|  | 8 #include "base/scoped_ptr.h" | 
| 8 #include "third_party/skia/include/core/SkBitmap.h" | 9 #include "third_party/skia/include/core/SkBitmap.h" | 
|  | 10 #include "third_party/skia/include/core/SkUnPreMultiply.h" | 
| 9 | 11 | 
| 10 extern "C" { | 12 extern "C" { | 
| 11 #if defined(USE_SYSTEM_LIBPNG) | 13 #if defined(USE_SYSTEM_LIBPNG) | 
| 12 #include <png.h> | 14 #include <png.h> | 
| 13 #else | 15 #else | 
| 14 #include "third_party/libpng/png.h" | 16 #include "third_party/libpng/png.h" | 
| 15 #endif | 17 #endif | 
| 16 } | 18 } | 
| 17 | 19 | 
|  | 20 namespace gfx { | 
|  | 21 | 
| 18 namespace { | 22 namespace { | 
| 19 | 23 | 
| 20 // Converts BGRA->RGBA and RGBA->BGRA. | 24 // Converts BGRA->RGBA and RGBA->BGRA. | 
| 21 void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width, | 25 void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width, | 
| 22                                unsigned char* output) { | 26                                unsigned char* output) { | 
| 23   for (int x = 0; x < pixel_width; x++) { | 27   for (int x = 0; x < pixel_width; x++) { | 
| 24     const unsigned char* pixel_in = &input[x * 4]; | 28     const unsigned char* pixel_in = &input[x * 4]; | 
| 25     unsigned char* pixel_out = &output[x * 4]; | 29     unsigned char* pixel_out = &output[x * 4]; | 
| 26     pixel_out[0] = pixel_in[2]; | 30     pixel_out[0] = pixel_in[2]; | 
| 27     pixel_out[1] = pixel_in[1]; | 31     pixel_out[1] = pixel_in[1]; | 
| (...skipping 22 matching lines...) Expand all  Loading... | 
| 50 | 54 | 
| 51 namespace { | 55 namespace { | 
| 52 | 56 | 
| 53 // Gamma constants: We assume we're on Windows which uses a gamma of 2.2. | 57 // Gamma constants: We assume we're on Windows which uses a gamma of 2.2. | 
| 54 const double kMaxGamma = 21474.83;  // Maximum gamma accepted by png library. | 58 const double kMaxGamma = 21474.83;  // Maximum gamma accepted by png library. | 
| 55 const double kDefaultGamma = 2.2; | 59 const double kDefaultGamma = 2.2; | 
| 56 const double kInverseGamma = 1.0 / kDefaultGamma; | 60 const double kInverseGamma = 1.0 / kDefaultGamma; | 
| 57 | 61 | 
| 58 class PngDecoderState { | 62 class PngDecoderState { | 
| 59  public: | 63  public: | 
| 60   PngDecoderState(PNGDecoder::ColorFormat ofmt, std::vector<unsigned char>* o) | 64   PngDecoderState(PNGCodec::ColorFormat ofmt, std::vector<unsigned char>* o) | 
| 61       : output_format(ofmt), | 65       : output_format(ofmt), | 
| 62         output_channels(0), | 66         output_channels(0), | 
| 63         output(o), | 67         output(o), | 
| 64         row_converter(NULL), | 68         row_converter(NULL), | 
| 65         width(0), | 69         width(0), | 
| 66         height(0), | 70         height(0), | 
| 67         done(false) { | 71         done(false) { | 
| 68   } | 72   } | 
| 69 | 73 | 
| 70   PNGDecoder::ColorFormat output_format; | 74   PNGCodec::ColorFormat output_format; | 
| 71   int output_channels; | 75   int output_channels; | 
| 72 | 76 | 
| 73   std::vector<unsigned char>* output; | 77   std::vector<unsigned char>* output; | 
| 74 | 78 | 
| 75   // Called to convert a row from the library to the correct output format. | 79   // Called to convert a row from the library to the correct output format. | 
| 76   // When NULL, no conversion is necessary. | 80   // When NULL, no conversion is necessary. | 
| 77   void (*row_converter)(const unsigned char* in, int w, unsigned char* out); | 81   void (*row_converter)(const unsigned char* in, int w, unsigned char* out); | 
| 78 | 82 | 
| 79   // Size of the image, set in the info callback. | 83   // Size of the image, set in the info callback. | 
| 80   int width; | 84   int width; | 
| 81   int height; | 85   int height; | 
| 82 | 86 | 
| 83   // Set to true when we've found the end of the data. | 87   // Set to true when we've found the end of the data. | 
| 84   bool done; | 88   bool done; | 
| 85 | 89 | 
| 86  private: | 90  private: | 
| 87   DISALLOW_EVIL_CONSTRUCTORS(PngDecoderState); | 91   DISALLOW_COPY_AND_ASSIGN(PngDecoderState); | 
| 88 }; | 92 }; | 
| 89 | 93 | 
| 90 void ConvertRGBtoRGBA(const unsigned char* rgb, int pixel_width, | 94 void ConvertRGBtoRGBA(const unsigned char* rgb, int pixel_width, | 
| 91                       unsigned char* rgba) { | 95                       unsigned char* rgba) { | 
| 92   for (int x = 0; x < pixel_width; x++) { | 96   for (int x = 0; x < pixel_width; x++) { | 
| 93     const unsigned char* pixel_in = &rgb[x * 3]; | 97     const unsigned char* pixel_in = &rgb[x * 3]; | 
| 94     unsigned char* pixel_out = &rgba[x * 4]; | 98     unsigned char* pixel_out = &rgba[x * 4]; | 
| 95     pixel_out[0] = pixel_in[0]; | 99     pixel_out[0] = pixel_in[0]; | 
| 96     pixel_out[1] = pixel_in[1]; | 100     pixel_out[1] = pixel_in[1]; | 
| 97     pixel_out[2] = pixel_in[2]; | 101     pixel_out[2] = pixel_in[2]; | 
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 169   if (interlace_type == PNG_INTERLACE_ADAM7) | 173   if (interlace_type == PNG_INTERLACE_ADAM7) | 
| 170     png_set_interlace_handling(png_ptr); | 174     png_set_interlace_handling(png_ptr); | 
| 171 | 175 | 
| 172   // Update our info now | 176   // Update our info now | 
| 173   png_read_update_info(png_ptr, info_ptr); | 177   png_read_update_info(png_ptr, info_ptr); | 
| 174   channels = png_get_channels(png_ptr, info_ptr); | 178   channels = png_get_channels(png_ptr, info_ptr); | 
| 175 | 179 | 
| 176   // Pick our row format converter necessary for this data. | 180   // Pick our row format converter necessary for this data. | 
| 177   if (channels == 3) { | 181   if (channels == 3) { | 
| 178     switch (state->output_format) { | 182     switch (state->output_format) { | 
| 179       case PNGDecoder::FORMAT_RGB: | 183       case PNGCodec::FORMAT_RGB: | 
| 180         state->row_converter = NULL;  // no conversion necessary | 184         state->row_converter = NULL;  // no conversion necessary | 
| 181         state->output_channels = 3; | 185         state->output_channels = 3; | 
| 182         break; | 186         break; | 
| 183       case PNGDecoder::FORMAT_RGBA: | 187       case PNGCodec::FORMAT_RGBA: | 
| 184         state->row_converter = &ConvertRGBtoRGBA; | 188         state->row_converter = &ConvertRGBtoRGBA; | 
| 185         state->output_channels = 4; | 189         state->output_channels = 4; | 
| 186         break; | 190         break; | 
| 187       case PNGDecoder::FORMAT_BGRA: | 191       case PNGCodec::FORMAT_BGRA: | 
| 188         state->row_converter = &ConvertRGBtoBGRA; | 192         state->row_converter = &ConvertRGBtoBGRA; | 
| 189         state->output_channels = 4; | 193         state->output_channels = 4; | 
| 190         break; | 194         break; | 
| 191       default: | 195       default: | 
| 192         NOTREACHED() << "Unknown output format"; | 196         NOTREACHED() << "Unknown output format"; | 
| 193         break; | 197         break; | 
| 194     } | 198     } | 
| 195   } else if (channels == 4) { | 199   } else if (channels == 4) { | 
| 196     switch (state->output_format) { | 200     switch (state->output_format) { | 
| 197       case PNGDecoder::FORMAT_RGB: | 201       case PNGCodec::FORMAT_RGB: | 
| 198         state->row_converter = &ConvertRGBAtoRGB; | 202         state->row_converter = &ConvertRGBAtoRGB; | 
| 199         state->output_channels = 3; | 203         state->output_channels = 3; | 
| 200         break; | 204         break; | 
| 201       case PNGDecoder::FORMAT_RGBA: | 205       case PNGCodec::FORMAT_RGBA: | 
| 202         state->row_converter = NULL;  // no conversion necessary | 206         state->row_converter = NULL;  // no conversion necessary | 
| 203         state->output_channels = 4; | 207         state->output_channels = 4; | 
| 204         break; | 208         break; | 
| 205       case PNGDecoder::FORMAT_BGRA: | 209       case PNGCodec::FORMAT_BGRA: | 
| 206         state->row_converter = &ConvertBetweenBGRAandRGBA; | 210         state->row_converter = &ConvertBetweenBGRAandRGBA; | 
| 207         state->output_channels = 4; | 211         state->output_channels = 4; | 
| 208         break; | 212         break; | 
| 209       default: | 213       default: | 
| 210         NOTREACHED() << "Unknown output format"; | 214         NOTREACHED() << "Unknown output format"; | 
| 211         break; | 215         break; | 
| 212     } | 216     } | 
| 213   } else { | 217   } else { | 
| 214     NOTREACHED() << "Unknown input channels"; | 218     NOTREACHED() << "Unknown input channels"; | 
| 215     longjmp(png_ptr->jmpbuf, 1); | 219     longjmp(png_ptr->jmpbuf, 1); | 
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 257     png_destroy_read_struct(ps_, pi_, NULL); | 261     png_destroy_read_struct(ps_, pi_, NULL); | 
| 258   } | 262   } | 
| 259  private: | 263  private: | 
| 260   png_struct** ps_; | 264   png_struct** ps_; | 
| 261   png_info** pi_; | 265   png_info** pi_; | 
| 262 }; | 266 }; | 
| 263 | 267 | 
| 264 }  // namespace | 268 }  // namespace | 
| 265 | 269 | 
| 266 // static | 270 // static | 
| 267 bool PNGDecoder::Decode(const unsigned char* input, size_t input_size, | 271 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, | 
| 268                         ColorFormat format, std::vector<unsigned char>* output, | 272                       ColorFormat format, std::vector<unsigned char>* output, | 
| 269                         int* w, int* h) { | 273                       int* w, int* h) { | 
| 270   if (input_size < 8) | 274   if (input_size < 8) | 
| 271     return false;  // Input data too small to be a png | 275     return false;  // Input data too small to be a png | 
| 272 | 276 | 
| 273   // Have libpng check the signature, it likes the first 8 bytes. | 277   // Have libpng check the signature, it likes the first 8 bytes. | 
| 274   if (png_sig_cmp(const_cast<unsigned char*>(input), 0, 8) != 0) | 278   if (png_sig_cmp(const_cast<unsigned char*>(input), 0, 8) != 0) | 
| 275     return false; | 279     return false; | 
| 276 | 280 | 
| 277   png_struct* png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, | 281   png_struct* png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, | 
| 278                                                png_voidp_NULL, | 282                                                png_voidp_NULL, | 
| 279                                                png_error_ptr_NULL, | 283                                                png_error_ptr_NULL, | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
| 310     output->clear(); | 314     output->clear(); | 
| 311     return false; | 315     return false; | 
| 312   } | 316   } | 
| 313 | 317 | 
| 314   *w = state.width; | 318   *w = state.width; | 
| 315   *h = state.height; | 319   *h = state.height; | 
| 316   return true; | 320   return true; | 
| 317 } | 321 } | 
| 318 | 322 | 
| 319 // static | 323 // static | 
| 320 bool PNGDecoder::Decode(const std::vector<unsigned char>* data, | 324 bool PNGCodec::Decode(const std::vector<unsigned char>* data, | 
| 321                         SkBitmap* bitmap) { | 325                       SkBitmap* bitmap) { | 
| 322   DCHECK(bitmap); | 326   DCHECK(bitmap); | 
| 323   if (!data || data->empty()) | 327   if (!data || data->empty()) | 
| 324     return false; | 328     return false; | 
| 325   int width, height; | 329   int width, height; | 
| 326   std::vector<unsigned char> decoded_data; | 330   std::vector<unsigned char> decoded_data; | 
| 327   if (PNGDecoder::Decode(&data->front(), data->size(), PNGDecoder::FORMAT_BGRA, | 331   if (PNGCodec::Decode(&data->front(), data->size(), PNGCodec::FORMAT_BGRA, | 
| 328                          &decoded_data, &width, &height)) { | 332                        &decoded_data, &width, &height)) { | 
| 329     bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); | 333     bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); | 
| 330     bitmap->allocPixels(); | 334     bitmap->allocPixels(); | 
| 331     unsigned char* bitmap_data = | 335     unsigned char* bitmap_data = | 
| 332         reinterpret_cast<unsigned char*>(bitmap->getAddr32(0, 0)); | 336         reinterpret_cast<unsigned char*>(bitmap->getAddr32(0, 0)); | 
| 333     for (int i = width * height * 4 - 4; i >= 0; i -= 4) { | 337     for (int i = width * height * 4 - 4; i >= 0; i -= 4) { | 
| 334       unsigned char alpha = decoded_data[i + 3]; | 338       unsigned char alpha = decoded_data[i + 3]; | 
| 335       if (alpha != 0 && alpha != 255) { | 339       if (alpha != 0 && alpha != 255) { | 
| 336         SkColor premultiplied = SkPreMultiplyARGB(alpha, | 340         SkColor premultiplied = SkPreMultiplyARGB(alpha, | 
| 337             decoded_data[i], decoded_data[i + 1], decoded_data[i + 2]); | 341             decoded_data[i], decoded_data[i + 1], decoded_data[i + 2]); | 
| 338         bitmap_data[i + 3] = alpha; | 342         bitmap_data[i + 3] = alpha; | 
| 339         bitmap_data[i] = SkColorGetR(premultiplied); | 343         bitmap_data[i] = SkColorGetR(premultiplied); | 
| 340         bitmap_data[i + 1] = SkColorGetG(premultiplied); | 344         bitmap_data[i + 1] = SkColorGetG(premultiplied); | 
| 341         bitmap_data[i + 2] = SkColorGetB(premultiplied); | 345         bitmap_data[i + 2] = SkColorGetB(premultiplied); | 
| 342       } else { | 346       } else { | 
| 343         bitmap_data[i + 3] = alpha; | 347         bitmap_data[i + 3] = alpha; | 
| 344         bitmap_data[i] = decoded_data[i]; | 348         bitmap_data[i] = decoded_data[i]; | 
| 345         bitmap_data[i + 1] = decoded_data[i + 1]; | 349         bitmap_data[i + 1] = decoded_data[i + 1]; | 
| 346         bitmap_data[i + 2] = decoded_data[i + 2]; | 350         bitmap_data[i + 2] = decoded_data[i + 2]; | 
| 347       } | 351       } | 
| 348     } | 352     } | 
| 349     return true; | 353     return true; | 
| 350   } | 354   } | 
| 351   return false; | 355   return false; | 
| 352 } | 356 } | 
| 353 | 357 | 
| 354 //static | 358 // static | 
| 355 SkBitmap* PNGDecoder::CreateSkBitmapFromBGRAFormat( | 359 SkBitmap* PNGCodec::CreateSkBitmapFromBGRAFormat( | 
| 356     std::vector<unsigned char>& bgra, int width, int height) { | 360     std::vector<unsigned char>& bgra, int width, int height) { | 
| 357   SkBitmap* bitmap = new SkBitmap(); | 361   SkBitmap* bitmap = new SkBitmap(); | 
| 358   bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); | 362   bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); | 
| 359   bitmap->allocPixels(); | 363   bitmap->allocPixels(); | 
| 360 | 364 | 
| 361   bool opaque = false; | 365   bool opaque = false; | 
| 362   unsigned char* bitmap_data = | 366   unsigned char* bitmap_data = | 
| 363       reinterpret_cast<unsigned char*>(bitmap->getAddr32(0, 0)); | 367       reinterpret_cast<unsigned char*>(bitmap->getAddr32(0, 0)); | 
| 364   for (int i = width * height * 4 - 4; i >= 0; i -= 4) { | 368   for (int i = width * height * 4 - 4; i >= 0; i -= 4) { | 
| 365     unsigned char alpha = bgra[i + 3]; | 369     unsigned char alpha = bgra[i + 3]; | 
| 366     if (!opaque && alpha != 255) { | 370     if (!opaque && alpha != 255) { | 
| 367       opaque = false; | 371       opaque = false; | 
| 368     } | 372     } | 
| 369     bitmap_data[i + 3] = alpha; | 373     bitmap_data[i + 3] = alpha; | 
| 370     bitmap_data[i] = (bgra[i] * alpha) >> 8; | 374     bitmap_data[i] = (bgra[i] * alpha) >> 8; | 
| 371     bitmap_data[i + 1] = (bgra[i + 1] * alpha) >> 8; | 375     bitmap_data[i + 1] = (bgra[i + 1] * alpha) >> 8; | 
| 372     bitmap_data[i + 2] = (bgra[i + 2] * alpha) >> 8; | 376     bitmap_data[i + 2] = (bgra[i + 2] * alpha) >> 8; | 
| 373   } | 377   } | 
| 374 | 378 | 
| 375   bitmap->setIsOpaque(opaque); | 379   bitmap->setIsOpaque(opaque); | 
| 376   return bitmap; | 380   return bitmap; | 
| 377 } | 381 } | 
|  | 382 | 
|  | 383 // Encoder -------------------------------------------------------------------- | 
|  | 384 // | 
|  | 385 // This section of the code is based on nsPNGEncoder.cpp in Mozilla | 
|  | 386 // (Copyright 2005 Google Inc.) | 
|  | 387 | 
|  | 388 namespace { | 
|  | 389 | 
|  | 390 // Passed around as the io_ptr in the png structs so our callbacks know where | 
|  | 391 // to write data. | 
|  | 392 struct PngEncoderState { | 
|  | 393   PngEncoderState(std::vector<unsigned char>* o) : out(o) {} | 
|  | 394   std::vector<unsigned char>* out; | 
|  | 395 }; | 
|  | 396 | 
|  | 397 // Called by libpng to flush its internal buffer to ours. | 
|  | 398 void EncoderWriteCallback(png_structp png, png_bytep data, png_size_t size) { | 
|  | 399   PngEncoderState* state = static_cast<PngEncoderState*>(png_get_io_ptr(png)); | 
|  | 400   DCHECK(state->out); | 
|  | 401 | 
|  | 402   size_t old_size = state->out->size(); | 
|  | 403   state->out->resize(old_size + size); | 
|  | 404   memcpy(&(*state->out)[old_size], data, size); | 
|  | 405 } | 
|  | 406 | 
|  | 407 void ConvertBGRAtoRGB(const unsigned char* bgra, int pixel_width, | 
|  | 408                       unsigned char* rgb) { | 
|  | 409   for (int x = 0; x < pixel_width; x++) { | 
|  | 410     const unsigned char* pixel_in = &bgra[x * 4]; | 
|  | 411     unsigned char* pixel_out = &rgb[x * 3]; | 
|  | 412     pixel_out[0] = pixel_in[2]; | 
|  | 413     pixel_out[1] = pixel_in[1]; | 
|  | 414     pixel_out[2] = pixel_in[0]; | 
|  | 415   } | 
|  | 416 } | 
|  | 417 | 
|  | 418 // Automatically destroys the given write structs on destruction to make | 
|  | 419 // cleanup and error handling code cleaner. | 
|  | 420 class PngWriteStructDestroyer { | 
|  | 421  public: | 
|  | 422   PngWriteStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) { | 
|  | 423   } | 
|  | 424   ~PngWriteStructDestroyer() { | 
|  | 425     png_destroy_write_struct(ps_, pi_); | 
|  | 426   } | 
|  | 427  private: | 
|  | 428   png_struct** ps_; | 
|  | 429   png_info** pi_; | 
|  | 430 | 
|  | 431   DISALLOW_EVIL_CONSTRUCTORS(PngWriteStructDestroyer); | 
|  | 432 }; | 
|  | 433 | 
|  | 434 }  // namespace | 
|  | 435 | 
|  | 436 // static | 
|  | 437 bool PNGCodec::Encode(const unsigned char* input, ColorFormat format, | 
|  | 438                       int w, int h, int row_byte_width, | 
|  | 439                       bool discard_transparency, | 
|  | 440                       std::vector<unsigned char>* output) { | 
|  | 441   // Run to convert an input row into the output row format, NULL means no | 
|  | 442   // conversion is necessary. | 
|  | 443   void (*converter)(const unsigned char* in, int w, unsigned char* out) = NULL; | 
|  | 444 | 
|  | 445   int input_color_components, output_color_components; | 
|  | 446   int png_output_color_type; | 
|  | 447   switch (format) { | 
|  | 448     case FORMAT_RGB: | 
|  | 449       input_color_components = 3; | 
|  | 450       output_color_components = 3; | 
|  | 451       png_output_color_type = PNG_COLOR_TYPE_RGB; | 
|  | 452       discard_transparency = false; | 
|  | 453       break; | 
|  | 454 | 
|  | 455     case FORMAT_RGBA: | 
|  | 456       input_color_components = 4; | 
|  | 457       if (discard_transparency) { | 
|  | 458         output_color_components = 3; | 
|  | 459         png_output_color_type = PNG_COLOR_TYPE_RGB; | 
|  | 460         converter = ConvertRGBAtoRGB; | 
|  | 461       } else { | 
|  | 462         output_color_components = 4; | 
|  | 463         png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; | 
|  | 464         converter = NULL; | 
|  | 465       } | 
|  | 466       break; | 
|  | 467 | 
|  | 468     case FORMAT_BGRA: | 
|  | 469       input_color_components = 4; | 
|  | 470       if (discard_transparency) { | 
|  | 471         output_color_components = 3; | 
|  | 472         png_output_color_type = PNG_COLOR_TYPE_RGB; | 
|  | 473         converter = ConvertBGRAtoRGB; | 
|  | 474       } else { | 
|  | 475         output_color_components = 4; | 
|  | 476         png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; | 
|  | 477         converter = ConvertBetweenBGRAandRGBA; | 
|  | 478       } | 
|  | 479       break; | 
|  | 480 | 
|  | 481     default: | 
|  | 482       NOTREACHED() << "Unknown pixel format"; | 
|  | 483       return false; | 
|  | 484   } | 
|  | 485 | 
|  | 486   // Row stride should be at least as long as the length of the data. | 
|  | 487   DCHECK(input_color_components * w <= row_byte_width); | 
|  | 488 | 
|  | 489   png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, | 
|  | 490                                                 png_voidp_NULL, | 
|  | 491                                                 png_error_ptr_NULL, | 
|  | 492                                                 png_error_ptr_NULL); | 
|  | 493   if (!png_ptr) | 
|  | 494     return false; | 
|  | 495   png_info* info_ptr = png_create_info_struct(png_ptr); | 
|  | 496   if (!info_ptr) { | 
|  | 497     png_destroy_write_struct(&png_ptr, NULL); | 
|  | 498     return false; | 
|  | 499   } | 
|  | 500   PngWriteStructDestroyer destroyer(&png_ptr, &info_ptr); | 
|  | 501 | 
|  | 502   if (setjmp(png_jmpbuf(png_ptr))) { | 
|  | 503     // The destroyer will ensure that the structures are cleaned up in this | 
|  | 504     // case, even though we may get here as a jump from random parts of the | 
|  | 505     // PNG library called below. | 
|  | 506     return false; | 
|  | 507   } | 
|  | 508 | 
|  | 509   // Set our callback for libpng to give us the data. | 
|  | 510   PngEncoderState state(output); | 
|  | 511   png_set_write_fn(png_ptr, &state, EncoderWriteCallback, NULL); | 
|  | 512 | 
|  | 513   png_set_IHDR(png_ptr, info_ptr, w, h, 8, png_output_color_type, | 
|  | 514                PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, | 
|  | 515                PNG_FILTER_TYPE_DEFAULT); | 
|  | 516   png_write_info(png_ptr, info_ptr); | 
|  | 517 | 
|  | 518   if (!converter) { | 
|  | 519     // No conversion needed, give the data directly to libpng. | 
|  | 520     for (int y = 0; y < h; y ++) | 
|  | 521       png_write_row(png_ptr, | 
|  | 522                     const_cast<unsigned char*>(&input[y * row_byte_width])); | 
|  | 523   } else { | 
|  | 524     // Needs conversion using a separate buffer. | 
|  | 525     unsigned char* row = new unsigned char[w * output_color_components]; | 
|  | 526     for (int y = 0; y < h; y ++) { | 
|  | 527       converter(&input[y * row_byte_width], w, row); | 
|  | 528       png_write_row(png_ptr, row); | 
|  | 529     } | 
|  | 530     delete[] row; | 
|  | 531   } | 
|  | 532 | 
|  | 533   png_write_end(png_ptr, info_ptr); | 
|  | 534   return true; | 
|  | 535 } | 
|  | 536 | 
|  | 537 // static | 
|  | 538 bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input, | 
|  | 539                                   bool discard_transparency, | 
|  | 540                                   std::vector<unsigned char>* output) { | 
|  | 541   static const int bbp = 4; | 
|  | 542 | 
|  | 543   SkAutoLockPixels lock_input(input); | 
|  | 544   DCHECK(input.empty() || input.bytesPerPixel() == bbp); | 
|  | 545 | 
|  | 546   // SkBitmaps are premultiplied, we need to unpremultiply them. | 
|  | 547   scoped_array<unsigned char> divided( | 
|  | 548       new unsigned char[input.width() * input.height() * bbp]); | 
|  | 549 | 
|  | 550   int i = 0; | 
|  | 551   for (int y = 0; y < input.height(); y++) { | 
|  | 552     for (int x = 0; x < input.width(); x++) { | 
|  | 553       uint32 pixel = input.getAddr32(0, y)[x]; | 
|  | 554 | 
|  | 555       int alpha = SkColorGetA(pixel); | 
|  | 556       if (alpha != 0 && alpha != 255) { | 
|  | 557         SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel); | 
|  | 558         divided[i + 0] = SkColorGetR(unmultiplied); | 
|  | 559         divided[i + 1] = SkColorGetG(unmultiplied); | 
|  | 560         divided[i + 2] = SkColorGetB(unmultiplied); | 
|  | 561         divided[i + 3] = alpha; | 
|  | 562       } else { | 
|  | 563         divided[i + 0] = SkColorGetR(pixel); | 
|  | 564         divided[i + 1] = SkColorGetG(pixel); | 
|  | 565         divided[i + 2] = SkColorGetB(pixel); | 
|  | 566         divided[i + 3] = alpha; | 
|  | 567       } | 
|  | 568       i += bbp; | 
|  | 569     } | 
|  | 570   } | 
|  | 571 | 
|  | 572   return Encode(divided.get(), | 
|  | 573                 PNGCodec::FORMAT_RGBA, input.width(), input.height(), | 
|  | 574                 input.width() * bbp, discard_transparency, output); | 
|  | 575 } | 
|  | 576 | 
|  | 577 }  // namespace gfx | 
| OLD | NEW | 
|---|