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