1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/gfx/codec/png_codec.h" 6 7 #include "base/logging.h" 8 #include "base/strings/string_util.h" 9 #include "third_party/libpng/png.h" 10 #include "third_party/skia/include/core/SkBitmap.h" 11 #include "third_party/skia/include/core/SkColorPriv.h" 12 #include "third_party/skia/include/core/SkUnPreMultiply.h" 13 #include "third_party/zlib/zlib.h" 14 #include "ui/gfx/size.h" 15 #include "ui/gfx/skia_util.h" 16 17 namespace gfx { 18 19 namespace { 20 21 // Converts BGRA->RGBA and RGBA->BGRA. 22 void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width, 23 unsigned char* output, bool* is_opaque) { 24 for (int x = 0; x < pixel_width; x++) { 25 const unsigned char* pixel_in = &input[x * 4]; 26 unsigned char* pixel_out = &output[x * 4]; 27 pixel_out[0] = pixel_in[2]; 28 pixel_out[1] = pixel_in[1]; 29 pixel_out[2] = pixel_in[0]; 30 pixel_out[3] = pixel_in[3]; 31 } 32 } 33 34 void ConvertRGBAtoRGB(const unsigned char* rgba, int pixel_width, 35 unsigned char* rgb, bool* is_opaque) { 36 for (int x = 0; x < pixel_width; x++) 37 memcpy(&rgb[x * 3], &rgba[x * 4], 3); 38 } 39 40 void ConvertSkiaToRGB(const unsigned char* skia, int pixel_width, 41 unsigned char* rgb, bool* is_opaque) { 42 for (int x = 0; x < pixel_width; x++) { 43 const uint32_t pixel_in = *reinterpret_cast<const uint32_t*>(&skia[x * 4]); 44 unsigned char* pixel_out = &rgb[x * 3]; 45 46 int alpha = SkGetPackedA32(pixel_in); 47 if (alpha != 0 && alpha != 255) { 48 SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel_in); 49 pixel_out[0] = SkColorGetR(unmultiplied); 50 pixel_out[1] = SkColorGetG(unmultiplied); 51 pixel_out[2] = SkColorGetB(unmultiplied); 52 } else { 53 pixel_out[0] = SkGetPackedR32(pixel_in); 54 pixel_out[1] = SkGetPackedG32(pixel_in); 55 pixel_out[2] = SkGetPackedB32(pixel_in); 56 } 57 } 58 } 59 60 void ConvertSkiaToRGBA(const unsigned char* skia, int pixel_width, 61 unsigned char* rgba, bool* is_opaque) { 62 gfx::ConvertSkiaToRGBA(skia, pixel_width, rgba); 63 } 64 65 } // namespace 66 67 // Decoder -------------------------------------------------------------------- 68 // 69 // This code is based on WebKit libpng interface (PNGImageDecoder), which is 70 // in turn based on the Mozilla png decoder. 71 72 namespace { 73 74 // Gamma constants: We assume we're on Windows which uses a gamma of 2.2. 75 const double kMaxGamma = 21474.83; // Maximum gamma accepted by png library. 76 const double kDefaultGamma = 2.2; 77 const double kInverseGamma = 1.0 / kDefaultGamma; 78 79 class PngDecoderState { 80 public: 81 // Output is a vector<unsigned char>. 82 PngDecoderState(PNGCodec::ColorFormat ofmt, std::vector<unsigned char>* o) 83 : output_format(ofmt), 84 output_channels(0), 85 bitmap(NULL), 86 is_opaque(true), 87 output(o), 88 width(0), 89 height(0), 90 done(false) { 91 } 92 93 // Output is an SkBitmap. 94 explicit PngDecoderState(SkBitmap* skbitmap) 95 : output_format(PNGCodec::FORMAT_SkBitmap), 96 output_channels(0), 97 bitmap(skbitmap), 98 is_opaque(true), 99 output(NULL), 100 width(0), 101 height(0), 102 done(false) { 103 } 104 105 PNGCodec::ColorFormat output_format; 106 int output_channels; 107 108 // An incoming SkBitmap to write to. If NULL, we write to output instead. 109 SkBitmap* bitmap; 110 111 // Used during the reading of an SkBitmap. Defaults to true until we see a 112 // pixel with anything other than an alpha of 255. 113 bool is_opaque; 114 115 // The other way to decode output, where we write into an intermediary buffer 116 // instead of directly to an SkBitmap. 117 std::vector<unsigned char>* output; 118 119 // Size of the image, set in the info callback. 120 int width; 121 int height; 122 123 // Set to true when we've found the end of the data. 124 bool done; 125 126 private: 127 DISALLOW_COPY_AND_ASSIGN(PngDecoderState); 128 }; 129 130 // User transform (passed to libpng) which converts a row decoded by libpng to 131 // Skia format. Expects the row to have 4 channels, otherwise there won't be 132 // enough room in |data|. 133 void ConvertRGBARowToSkia(png_structp png_ptr, 134 png_row_infop row_info, 135 png_bytep data) { 136 const int channels = row_info->channels; 137 DCHECK_EQ(channels, 4); 138 139 PngDecoderState* state = 140 static_cast<PngDecoderState*>(png_get_user_transform_ptr(png_ptr)); 141 DCHECK(state) << "LibPNG user transform pointer is NULL"; 142 143 unsigned char* const end = data + row_info->rowbytes; 144 for (unsigned char* p = data; p < end; p += channels) { 145 uint32_t* sk_pixel = reinterpret_cast<uint32_t*>(p); 146 const unsigned char alpha = p[channels - 1]; 147 if (alpha != 255) { 148 state->is_opaque = false; 149 *sk_pixel = SkPreMultiplyARGB(alpha, p[0], p[1], p[2]); 150 } else { 151 *sk_pixel = SkPackARGB32(alpha, p[0], p[1], p[2]); 152 } 153 } 154 } 155 156 // Called when the png header has been read. This code is based on the WebKit 157 // PNGImageDecoder 158 void DecodeInfoCallback(png_struct* png_ptr, png_info* info_ptr) { 159 PngDecoderState* state = static_cast<PngDecoderState*>( 160 png_get_progressive_ptr(png_ptr)); 161 162 int bit_depth, color_type, interlace_type, compression_type; 163 int filter_type; 164 png_uint_32 w, h; 165 png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 166 &interlace_type, &compression_type, &filter_type); 167 168 // Bounds check. When the image is unreasonably big, we'll error out and 169 // end up back at the setjmp call when we set up decoding. "Unreasonably big" 170 // means "big enough that w * h * 32bpp might overflow an int"; we choose this 171 // threshold to match WebKit and because a number of places in code assume 172 // that an image's size (in bytes) fits in a (signed) int. 173 unsigned long long total_size = 174 static_cast<unsigned long long>(w) * static_cast<unsigned long long>(h); 175 if (total_size > ((1 << 29) - 1)) 176 longjmp(png_jmpbuf(png_ptr), 1); 177 state->width = static_cast<int>(w); 178 state->height = static_cast<int>(h); 179 180 // The following png_set_* calls have to be done in the order dictated by 181 // the libpng docs. Please take care if you have to move any of them. This 182 // is also why certain things are done outside of the switch, even though 183 // they look like they belong there. 184 185 // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. 186 if (color_type == PNG_COLOR_TYPE_PALETTE || 187 (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)) 188 png_set_expand(png_ptr); 189 190 // The '!= 0' is for silencing a Windows compiler warning. 191 bool input_has_alpha = ((color_type & PNG_COLOR_MASK_ALPHA) != 0); 192 193 // Transparency for paletted images. 194 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 195 png_set_expand(png_ptr); 196 input_has_alpha = true; 197 } 198 199 // Convert 16-bit to 8-bit. 200 if (bit_depth == 16) 201 png_set_strip_16(png_ptr); 202 203 // Pick our row format converter necessary for this data. 204 if (!input_has_alpha) { 205 switch (state->output_format) { 206 case PNGCodec::FORMAT_RGB: 207 state->output_channels = 3; 208 break; 209 case PNGCodec::FORMAT_RGBA: 210 state->output_channels = 4; 211 png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); 212 break; 213 case PNGCodec::FORMAT_BGRA: 214 state->output_channels = 4; 215 png_set_bgr(png_ptr); 216 png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); 217 break; 218 case PNGCodec::FORMAT_SkBitmap: 219 state->output_channels = 4; 220 png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); 221 break; 222 } 223 } else { 224 switch (state->output_format) { 225 case PNGCodec::FORMAT_RGB: 226 state->output_channels = 3; 227 png_set_strip_alpha(png_ptr); 228 break; 229 case PNGCodec::FORMAT_RGBA: 230 state->output_channels = 4; 231 break; 232 case PNGCodec::FORMAT_BGRA: 233 state->output_channels = 4; 234 png_set_bgr(png_ptr); 235 break; 236 case PNGCodec::FORMAT_SkBitmap: 237 state->output_channels = 4; 238 break; 239 } 240 } 241 242 // Expand grayscale to RGB. 243 if (color_type == PNG_COLOR_TYPE_GRAY || 244 color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 245 png_set_gray_to_rgb(png_ptr); 246 247 // Deal with gamma and keep it under our control. 248 double gamma; 249 if (png_get_gAMA(png_ptr, info_ptr, &gamma)) { 250 if (gamma <= 0.0 || gamma > kMaxGamma) { 251 gamma = kInverseGamma; 252 png_set_gAMA(png_ptr, info_ptr, gamma); 253 } 254 png_set_gamma(png_ptr, kDefaultGamma, gamma); 255 } else { 256 png_set_gamma(png_ptr, kDefaultGamma, kInverseGamma); 257 } 258 259 // Setting the user transforms here (as opposed to inside the switch above) 260 // because all png_set_* calls need to be done in the specific order 261 // mandated by libpng. 262 if (state->output_format == PNGCodec::FORMAT_SkBitmap) { 263 png_set_read_user_transform_fn(png_ptr, ConvertRGBARowToSkia); 264 png_set_user_transform_info(png_ptr, state, 0, 0); 265 } 266 267 // Tell libpng to send us rows for interlaced pngs. 268 if (interlace_type == PNG_INTERLACE_ADAM7) 269 png_set_interlace_handling(png_ptr); 270 271 png_read_update_info(png_ptr, info_ptr); 272 273 if (state->bitmap) { 274 state->bitmap->allocN32Pixels(state->width, state->height); 275 } else if (state->output) { 276 state->output->resize( 277 state->width * state->output_channels * state->height); 278 } 279 } 280 281 void DecodeRowCallback(png_struct* png_ptr, png_byte* new_row, 282 png_uint_32 row_num, int pass) { 283 if (!new_row) 284 return; // Interlaced image; row didn't change this pass. 285 286 PngDecoderState* state = static_cast<PngDecoderState*>( 287 png_get_progressive_ptr(png_ptr)); 288 289 if (static_cast<int>(row_num) > state->height) { 290 NOTREACHED() << "Invalid row"; 291 return; 292 } 293 294 unsigned char* base = NULL; 295 if (state->bitmap) 296 base = reinterpret_cast<unsigned char*>(state->bitmap->getAddr32(0, 0)); 297 else if (state->output) 298 base = &state->output->front(); 299 300 unsigned char* dest = &base[state->width * state->output_channels * row_num]; 301 png_progressive_combine_row(png_ptr, dest, new_row); 302 } 303 304 void DecodeEndCallback(png_struct* png_ptr, png_info* info) { 305 PngDecoderState* state = static_cast<PngDecoderState*>( 306 png_get_progressive_ptr(png_ptr)); 307 308 // Mark the image as complete, this will tell the Decode function that we 309 // have successfully found the end of the data. 310 state->done = true; 311 } 312 313 // Automatically destroys the given read structs on destruction to make 314 // cleanup and error handling code cleaner. 315 class PngReadStructDestroyer { 316 public: 317 PngReadStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) { 318 } 319 ~PngReadStructDestroyer() { 320 png_destroy_read_struct(ps_, pi_, NULL); 321 } 322 private: 323 png_struct** ps_; 324 png_info** pi_; 325 DISALLOW_COPY_AND_ASSIGN(PngReadStructDestroyer); 326 }; 327 328 // Automatically destroys the given write structs on destruction to make 329 // cleanup and error handling code cleaner. 330 class PngWriteStructDestroyer { 331 public: 332 explicit PngWriteStructDestroyer(png_struct** ps) : ps_(ps), pi_(0) { 333 } 334 ~PngWriteStructDestroyer() { 335 png_destroy_write_struct(ps_, pi_); 336 } 337 void SetInfoStruct(png_info** pi) { 338 pi_ = pi; 339 } 340 private: 341 png_struct** ps_; 342 png_info** pi_; 343 DISALLOW_COPY_AND_ASSIGN(PngWriteStructDestroyer); 344 }; 345 346 bool BuildPNGStruct(const unsigned char* input, size_t input_size, 347 png_struct** png_ptr, png_info** info_ptr) { 348 if (input_size < 8) 349 return false; // Input data too small to be a png 350 351 // Have libpng check the signature, it likes the first 8 bytes. 352 if (png_sig_cmp(const_cast<unsigned char*>(input), 0, 8) != 0) 353 return false; 354 355 *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 356 if (!*png_ptr) 357 return false; 358 359 *info_ptr = png_create_info_struct(*png_ptr); 360 if (!*info_ptr) { 361 png_destroy_read_struct(png_ptr, NULL, NULL); 362 return false; 363 } 364 365 return true; 366 } 367 368 // Libpng user error and warning functions which allows us to print libpng 369 // errors and warnings using Chrome's logging facilities instead of stderr. 370 371 void LogLibPNGDecodeError(png_structp png_ptr, png_const_charp error_msg) { 372 DLOG(ERROR) << "libpng decode error: " << error_msg; 373 longjmp(png_jmpbuf(png_ptr), 1); 374 } 375 376 void LogLibPNGDecodeWarning(png_structp png_ptr, png_const_charp warning_msg) { 377 DLOG(ERROR) << "libpng decode warning: " << warning_msg; 378 } 379 380 void LogLibPNGEncodeError(png_structp png_ptr, png_const_charp error_msg) { 381 DLOG(ERROR) << "libpng encode error: " << error_msg; 382 longjmp(png_jmpbuf(png_ptr), 1); 383 } 384 385 void LogLibPNGEncodeWarning(png_structp png_ptr, png_const_charp warning_msg) { 386 DLOG(ERROR) << "libpng encode warning: " << warning_msg; 387 } 388 389 } // namespace 390 391 // static 392 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, 393 ColorFormat format, std::vector<unsigned char>* output, 394 int* w, int* h) { 395 png_struct* png_ptr = NULL; 396 png_info* info_ptr = NULL; 397 if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr)) 398 return false; 399 400 PngReadStructDestroyer destroyer(&png_ptr, &info_ptr); 401 if (setjmp(png_jmpbuf(png_ptr))) { 402 // The destroyer will ensure that the structures are cleaned up in this 403 // case, even though we may get here as a jump from random parts of the 404 // PNG library called below. 405 return false; 406 } 407 408 PngDecoderState state(format, output); 409 410 png_set_error_fn(png_ptr, NULL, LogLibPNGDecodeError, LogLibPNGDecodeWarning); 411 png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback, 412 &DecodeRowCallback, &DecodeEndCallback); 413 png_process_data(png_ptr, 414 info_ptr, 415 const_cast<unsigned char*>(input), 416 input_size); 417 418 if (!state.done) { 419 // Fed it all the data but the library didn't think we got all the data, so 420 // this file must be truncated. 421 output->clear(); 422 return false; 423 } 424 425 *w = state.width; 426 *h = state.height; 427 return true; 428 } 429 430 // static 431 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, 432 SkBitmap* bitmap) { 433 DCHECK(bitmap); 434 png_struct* png_ptr = NULL; 435 png_info* info_ptr = NULL; 436 if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr)) 437 return false; 438 439 PngReadStructDestroyer destroyer(&png_ptr, &info_ptr); 440 if (setjmp(png_jmpbuf(png_ptr))) { 441 // The destroyer will ensure that the structures are cleaned up in this 442 // case, even though we may get here as a jump from random parts of the 443 // PNG library called below. 444 return false; 445 } 446 447 PngDecoderState state(bitmap); 448 449 png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback, 450 &DecodeRowCallback, &DecodeEndCallback); 451 png_process_data(png_ptr, 452 info_ptr, 453 const_cast<unsigned char*>(input), 454 input_size); 455 456 if (!state.done) { 457 return false; 458 } 459 460 // Set the bitmap's opaqueness based on what we saw. 461 bitmap->setAlphaType(state.is_opaque ? 462 kOpaque_SkAlphaType : kPremul_SkAlphaType); 463 464 return true; 465 } 466 467 // Encoder -------------------------------------------------------------------- 468 // 469 // This section of the code is based on nsPNGEncoder.cpp in Mozilla 470 // (Copyright 2005 Google Inc.) 471 472 namespace { 473 474 // Passed around as the io_ptr in the png structs so our callbacks know where 475 // to write data. 476 struct PngEncoderState { 477 explicit PngEncoderState(std::vector<unsigned char>* o) : out(o) {} 478 std::vector<unsigned char>* out; 479 }; 480 481 // Called by libpng to flush its internal buffer to ours. 482 void EncoderWriteCallback(png_structp png, png_bytep data, png_size_t size) { 483 PngEncoderState* state = static_cast<PngEncoderState*>(png_get_io_ptr(png)); 484 DCHECK(state->out); 485 486 size_t old_size = state->out->size(); 487 state->out->resize(old_size + size); 488 memcpy(&(*state->out)[old_size], data, size); 489 } 490 491 void FakeFlushCallback(png_structp png) { 492 // We don't need to perform any flushing since we aren't doing real IO, but 493 // we're required to provide this function by libpng. 494 } 495 496 void ConvertBGRAtoRGB(const unsigned char* bgra, int pixel_width, 497 unsigned char* rgb, bool* is_opaque) { 498 for (int x = 0; x < pixel_width; x++) { 499 const unsigned char* pixel_in = &bgra[x * 4]; 500 unsigned char* pixel_out = &rgb[x * 3]; 501 pixel_out[0] = pixel_in[2]; 502 pixel_out[1] = pixel_in[1]; 503 pixel_out[2] = pixel_in[0]; 504 } 505 } 506 507 #ifdef PNG_TEXT_SUPPORTED 508 class CommentWriter { 509 public: 510 explicit CommentWriter(const std::vector<PNGCodec::Comment>& comments) 511 : comments_(comments), 512 png_text_(new png_text[comments.size()]) { 513 for (size_t i = 0; i < comments.size(); ++i) 514 AddComment(i, comments[i]); 515 } 516 517 ~CommentWriter() { 518 for (size_t i = 0; i < comments_.size(); ++i) { 519 free(png_text_[i].key); 520 free(png_text_[i].text); 521 } 522 delete [] png_text_; 523 } 524 525 bool HasComments() { 526 return !comments_.empty(); 527 } 528 529 png_text* get_png_text() { 530 return png_text_; 531 } 532 533 int size() { 534 return static_cast<int>(comments_.size()); 535 } 536 537 private: 538 void AddComment(size_t pos, const PNGCodec::Comment& comment) { 539 png_text_[pos].compression = PNG_TEXT_COMPRESSION_NONE; 540 // A PNG comment's key can only be 79 characters long. 541 DCHECK(comment.key.length() < 79); 542 png_text_[pos].key = base::strdup(comment.key.substr(0, 78).c_str()); 543 png_text_[pos].text = base::strdup(comment.text.c_str()); 544 png_text_[pos].text_length = comment.text.length(); 545 #ifdef PNG_iTXt_SUPPORTED 546 png_text_[pos].itxt_length = 0; 547 png_text_[pos].lang = 0; 548 png_text_[pos].lang_key = 0; 549 #endif 550 } 551 552 DISALLOW_COPY_AND_ASSIGN(CommentWriter); 553 554 const std::vector<PNGCodec::Comment> comments_; 555 png_text* png_text_; 556 }; 557 #endif // PNG_TEXT_SUPPORTED 558 559 // The type of functions usable for converting between pixel formats. 560 typedef void (*FormatConverter)(const unsigned char* in, int w, 561 unsigned char* out, bool* is_opaque); 562 563 // libpng uses a wacky setjmp-based API, which makes the compiler nervous. 564 // We constrain all of the calls we make to libpng where the setjmp() is in 565 // place to this function. 566 // Returns true on success. 567 bool DoLibpngWrite(png_struct* png_ptr, png_info* info_ptr, 568 PngEncoderState* state, 569 int width, int height, int row_byte_width, 570 const unsigned char* input, int compression_level, 571 int png_output_color_type, int output_color_components, 572 FormatConverter converter, 573 const std::vector<PNGCodec::Comment>& comments) { 574 #ifdef PNG_TEXT_SUPPORTED 575 CommentWriter comment_writer(comments); 576 #endif 577 unsigned char* row_buffer = NULL; 578 579 // Make sure to not declare any locals here -- locals in the presence 580 // of setjmp() in C++ code makes gcc complain. 581 582 if (setjmp(png_jmpbuf(png_ptr))) { 583 delete[] row_buffer; 584 return false; 585 } 586 587 png_set_compression_level(png_ptr, compression_level); 588 589 // Set our callback for libpng to give us the data. 590 png_set_write_fn(png_ptr, state, EncoderWriteCallback, FakeFlushCallback); 591 png_set_error_fn(png_ptr, NULL, LogLibPNGEncodeError, LogLibPNGEncodeWarning); 592 593 png_set_IHDR(png_ptr, info_ptr, width, height, 8, png_output_color_type, 594 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, 595 PNG_FILTER_TYPE_DEFAULT); 596 597 #ifdef PNG_TEXT_SUPPORTED 598 if (comment_writer.HasComments()) { 599 png_set_text(png_ptr, info_ptr, comment_writer.get_png_text(), 600 comment_writer.size()); 601 } 602 #endif 603 604 png_write_info(png_ptr, info_ptr); 605 606 if (!converter) { 607 // No conversion needed, give the data directly to libpng. 608 for (int y = 0; y < height; y ++) { 609 png_write_row(png_ptr, 610 const_cast<unsigned char*>(&input[y * row_byte_width])); 611 } 612 } else { 613 // Needs conversion using a separate buffer. 614 row_buffer = new unsigned char[width * output_color_components]; 615 for (int y = 0; y < height; y ++) { 616 converter(&input[y * row_byte_width], width, row_buffer, NULL); 617 png_write_row(png_ptr, row_buffer); 618 } 619 delete[] row_buffer; 620 } 621 622 png_write_end(png_ptr, info_ptr); 623 return true; 624 } 625 626 bool EncodeWithCompressionLevel(const unsigned char* input, 627 PNGCodec::ColorFormat format, 628 const Size& size, 629 int row_byte_width, 630 bool discard_transparency, 631 const std::vector<PNGCodec::Comment>& comments, 632 int compression_level, 633 std::vector<unsigned char>* output) { 634 // Run to convert an input row into the output row format, NULL means no 635 // conversion is necessary. 636 FormatConverter converter = NULL; 637 638 int input_color_components, output_color_components; 639 int png_output_color_type; 640 switch (format) { 641 case PNGCodec::FORMAT_RGB: 642 input_color_components = 3; 643 output_color_components = 3; 644 png_output_color_type = PNG_COLOR_TYPE_RGB; 645 break; 646 647 case PNGCodec::FORMAT_RGBA: 648 input_color_components = 4; 649 if (discard_transparency) { 650 output_color_components = 3; 651 png_output_color_type = PNG_COLOR_TYPE_RGB; 652 converter = ConvertRGBAtoRGB; 653 } else { 654 output_color_components = 4; 655 png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; 656 converter = NULL; 657 } 658 break; 659 660 case PNGCodec::FORMAT_BGRA: 661 input_color_components = 4; 662 if (discard_transparency) { 663 output_color_components = 3; 664 png_output_color_type = PNG_COLOR_TYPE_RGB; 665 converter = ConvertBGRAtoRGB; 666 } else { 667 output_color_components = 4; 668 png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; 669 converter = ConvertBetweenBGRAandRGBA; 670 } 671 break; 672 673 case PNGCodec::FORMAT_SkBitmap: 674 // Compare row_byte_width and size.width() to detect the format of 675 // SkBitmap. kA8_Config (1bpp) and kARGB_8888_Config (4bpp) are the two 676 // supported formats. 677 if (row_byte_width < 4 * size.width()) { 678 // Not 4bpp, so must be 1bpp. 679 // Ignore discard_transparency - it doesn't make sense in this context, 680 // since alpha is the only thing we have and it needs to be used for 681 // color intensity. 682 input_color_components = 1; 683 output_color_components = 1; 684 png_output_color_type = PNG_COLOR_TYPE_GRAY; 685 // |converter| is left as null 686 } else { 687 input_color_components = 4; 688 if (discard_transparency) { 689 output_color_components = 3; 690 png_output_color_type = PNG_COLOR_TYPE_RGB; 691 converter = ConvertSkiaToRGB; 692 } else { 693 output_color_components = 4; 694 png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; 695 converter = ConvertSkiaToRGBA; 696 } 697 } 698 break; 699 700 default: 701 NOTREACHED() << "Unknown pixel format"; 702 return false; 703 } 704 705 // Row stride should be at least as long as the length of the data. 706 DCHECK(input_color_components * size.width() <= row_byte_width); 707 708 png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 709 NULL, NULL, NULL); 710 if (!png_ptr) 711 return false; 712 PngWriteStructDestroyer destroyer(&png_ptr); 713 png_info* info_ptr = png_create_info_struct(png_ptr); 714 if (!info_ptr) 715 return false; 716 destroyer.SetInfoStruct(&info_ptr); 717 718 output->clear(); 719 720 PngEncoderState state(output); 721 bool success = DoLibpngWrite(png_ptr, info_ptr, &state, 722 size.width(), size.height(), row_byte_width, 723 input, compression_level, png_output_color_type, 724 output_color_components, converter, comments); 725 726 return success; 727 } 728 729 bool InternalEncodeSkBitmap(const SkBitmap& input, 730 bool discard_transparency, 731 int compression_level, 732 std::vector<unsigned char>* output) { 733 if (input.empty() || input.isNull()) 734 return false; 735 int bpp = input.bytesPerPixel(); 736 DCHECK(bpp == 1 || bpp == 4); // We support kA8_Config and kARGB_8888_Config. 737 738 SkAutoLockPixels lock_input(input); 739 unsigned char* inputAddr = bpp == 1 ? 740 reinterpret_cast<unsigned char*>(input.getAddr8(0, 0)) : 741 reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)); // bpp = 4 742 return EncodeWithCompressionLevel( 743 inputAddr, 744 PNGCodec::FORMAT_SkBitmap, 745 Size(input.width(), input.height()), 746 static_cast<int>(input.rowBytes()), 747 discard_transparency, 748 std::vector<PNGCodec::Comment>(), 749 compression_level, 750 output); 751 } 752 753 754 } // namespace 755 756 // static 757 bool PNGCodec::Encode(const unsigned char* input, 758 ColorFormat format, 759 const Size& size, 760 int row_byte_width, 761 bool discard_transparency, 762 const std::vector<Comment>& comments, 763 std::vector<unsigned char>* output) { 764 return EncodeWithCompressionLevel(input, 765 format, 766 size, 767 row_byte_width, 768 discard_transparency, 769 comments, 770 Z_DEFAULT_COMPRESSION, 771 output); 772 } 773 774 // static 775 bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input, 776 bool discard_transparency, 777 std::vector<unsigned char>* output) { 778 return InternalEncodeSkBitmap(input, 779 discard_transparency, 780 Z_DEFAULT_COMPRESSION, 781 output); 782 } 783 784 // static 785 bool PNGCodec::EncodeA8SkBitmap(const SkBitmap& input, 786 std::vector<unsigned char>* output) { 787 return InternalEncodeSkBitmap(input, 788 false, 789 Z_DEFAULT_COMPRESSION, 790 output); 791 } 792 793 // static 794 bool PNGCodec::FastEncodeBGRASkBitmap(const SkBitmap& input, 795 bool discard_transparency, 796 std::vector<unsigned char>* output) { 797 return InternalEncodeSkBitmap(input, 798 discard_transparency, 799 Z_BEST_SPEED, 800 output); 801 } 802 803 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) 804 : key(k), text(t) { 805 } 806 807 PNGCodec::Comment::~Comment() { 808 } 809 810 } // namespace gfx 811