Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| 11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
| 12 #include "third_party/libpng/png.h" | 12 #include "third_party/libpng/png.h" |
| 13 #include "third_party/skia/include/core/SkBitmap.h" | 13 #include "third_party/skia/include/core/SkBitmap.h" |
| 14 #include "third_party/skia/include/core/SkColorPriv.h" | 14 #include "third_party/skia/include/core/SkColorPriv.h" |
| 15 #include "third_party/skia/include/core/SkUnPreMultiply.h" | 15 #include "third_party/skia/include/core/SkUnPreMultiply.h" |
| 16 #include "third_party/skia/include/encode/SkPngEncoder.h" | |
| 16 #include "third_party/zlib/zlib.h" | 17 #include "third_party/zlib/zlib.h" |
| 18 #include "ui/gfx/codec/vector_wstream.h" | |
| 17 #include "ui/gfx/geometry/size.h" | 19 #include "ui/gfx/geometry/size.h" |
| 18 #include "ui/gfx/skia_util.h" | 20 #include "ui/gfx/skia_util.h" |
| 19 | 21 |
| 20 namespace gfx { | 22 namespace gfx { |
| 21 | 23 |
| 22 namespace { | |
| 23 | |
| 24 // Converts BGRA->RGBA and RGBA->BGRA. | |
| 25 void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width, | |
| 26 unsigned char* output, bool* is_opaque) { | |
| 27 for (int x = 0; x < pixel_width; x++) { | |
| 28 const unsigned char* pixel_in = &input[x * 4]; | |
| 29 unsigned char* pixel_out = &output[x * 4]; | |
| 30 pixel_out[0] = pixel_in[2]; | |
| 31 pixel_out[1] = pixel_in[1]; | |
| 32 pixel_out[2] = pixel_in[0]; | |
| 33 pixel_out[3] = pixel_in[3]; | |
| 34 } | |
| 35 } | |
| 36 | |
| 37 void ConvertRGBAtoRGB(const unsigned char* rgba, int pixel_width, | |
| 38 unsigned char* rgb, bool* is_opaque) { | |
| 39 for (int x = 0; x < pixel_width; x++) | |
| 40 memcpy(&rgb[x * 3], &rgba[x * 4], 3); | |
| 41 } | |
| 42 | |
| 43 void ConvertSkiaToRGB(const unsigned char* skia, int pixel_width, | |
| 44 unsigned char* rgb, bool* is_opaque) { | |
| 45 for (int x = 0; x < pixel_width; x++) { | |
| 46 const uint32_t pixel_in = *reinterpret_cast<const uint32_t*>(&skia[x * 4]); | |
| 47 unsigned char* pixel_out = &rgb[x * 3]; | |
| 48 | |
| 49 int alpha = SkGetPackedA32(pixel_in); | |
| 50 if (alpha != 0 && alpha != 255) { | |
| 51 SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel_in); | |
| 52 pixel_out[0] = SkColorGetR(unmultiplied); | |
| 53 pixel_out[1] = SkColorGetG(unmultiplied); | |
| 54 pixel_out[2] = SkColorGetB(unmultiplied); | |
| 55 } else { | |
| 56 pixel_out[0] = SkGetPackedR32(pixel_in); | |
| 57 pixel_out[1] = SkGetPackedG32(pixel_in); | |
| 58 pixel_out[2] = SkGetPackedB32(pixel_in); | |
| 59 } | |
| 60 } | |
| 61 } | |
| 62 | |
| 63 void ConvertSkiaToRGBA(const unsigned char* skia, int pixel_width, | |
| 64 unsigned char* rgba, bool* is_opaque) { | |
| 65 gfx::ConvertSkiaToRGBA(skia, pixel_width, rgba); | |
| 66 } | |
| 67 | |
| 68 } // namespace | |
| 69 | |
| 70 // Decoder -------------------------------------------------------------------- | 24 // Decoder -------------------------------------------------------------------- |
| 71 // | 25 // |
| 72 // This code is based on WebKit libpng interface (PNGImageDecoder), which is | 26 // This code is based on WebKit libpng interface (PNGImageDecoder), which is |
| 73 // in turn based on the Mozilla png decoder. | 27 // in turn based on the Mozilla png decoder. |
| 74 | 28 |
| 75 namespace { | 29 namespace { |
| 76 | 30 |
| 77 // Gamma constants: We assume we're on Windows which uses a gamma of 2.2. | 31 // Gamma constants: We assume we're on Windows which uses a gamma of 2.2. |
| 78 const double kMaxGamma = 21474.83; // Maximum gamma accepted by png library. | 32 const double kMaxGamma = 21474.83; // Maximum gamma accepted by png library. |
| 79 const double kDefaultGamma = 2.2; | 33 const double kDefaultGamma = 2.2; |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 362 | 316 |
| 363 void LogLibPNGDecodeError(png_structp png_ptr, png_const_charp error_msg) { | 317 void LogLibPNGDecodeError(png_structp png_ptr, png_const_charp error_msg) { |
| 364 DLOG(ERROR) << "libpng decode error: " << error_msg; | 318 DLOG(ERROR) << "libpng decode error: " << error_msg; |
| 365 longjmp(png_jmpbuf(png_ptr), 1); | 319 longjmp(png_jmpbuf(png_ptr), 1); |
| 366 } | 320 } |
| 367 | 321 |
| 368 void LogLibPNGDecodeWarning(png_structp png_ptr, png_const_charp warning_msg) { | 322 void LogLibPNGDecodeWarning(png_structp png_ptr, png_const_charp warning_msg) { |
| 369 DLOG(ERROR) << "libpng decode warning: " << warning_msg; | 323 DLOG(ERROR) << "libpng decode warning: " << warning_msg; |
| 370 } | 324 } |
| 371 | 325 |
| 372 void LogLibPNGEncodeError(png_structp png_ptr, png_const_charp error_msg) { | |
| 373 DLOG(ERROR) << "libpng encode error: " << error_msg; | |
| 374 longjmp(png_jmpbuf(png_ptr), 1); | |
| 375 } | |
| 376 | |
| 377 void LogLibPNGEncodeWarning(png_structp png_ptr, png_const_charp warning_msg) { | |
| 378 DLOG(ERROR) << "libpng encode warning: " << warning_msg; | |
| 379 } | |
| 380 | |
| 381 } // namespace | 326 } // namespace |
| 382 | 327 |
| 383 // static | 328 // static |
| 384 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, | 329 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
| 385 ColorFormat format, std::vector<unsigned char>* output, | 330 ColorFormat format, std::vector<unsigned char>* output, |
| 386 int* w, int* h) { | 331 int* w, int* h) { |
| 387 PngReadStructInfo si; | 332 PngReadStructInfo si; |
| 388 if (!si.Build(input, input_size)) | 333 if (!si.Build(input, input_size)) |
| 389 return false; | 334 return false; |
| 390 | 335 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 447 } | 392 } |
| 448 | 393 |
| 449 // Set the bitmap's opaqueness based on what we saw. | 394 // Set the bitmap's opaqueness based on what we saw. |
| 450 bitmap->setAlphaType(state.is_opaque ? | 395 bitmap->setAlphaType(state.is_opaque ? |
| 451 kOpaque_SkAlphaType : kPremul_SkAlphaType); | 396 kOpaque_SkAlphaType : kPremul_SkAlphaType); |
| 452 | 397 |
| 453 return true; | 398 return true; |
| 454 } | 399 } |
| 455 | 400 |
| 456 // Encoder -------------------------------------------------------------------- | 401 // Encoder -------------------------------------------------------------------- |
| 457 // | |
| 458 // This section of the code is based on nsPNGEncoder.cpp in Mozilla | |
| 459 // (Copyright 2005 Google Inc.) | |
| 460 | 402 |
| 461 namespace { | 403 namespace { |
| 462 | 404 |
| 463 // Passed around as the io_ptr in the png structs so our callbacks know where | 405 static void AddComments(SkPngEncoder::Options& options, |
| 464 // to write data. | 406 const std::vector<PNGCodec::Comment>& comments) { |
| 465 struct PngEncoderState { | 407 std::vector<const char*> comment_pointers; |
| 466 explicit PngEncoderState(std::vector<unsigned char>* o) : out(o) {} | 408 std::vector<size_t> comment_sizes; |
| 467 std::vector<unsigned char>* out; | 409 for (const auto& comment : comments) { |
| 468 }; | 410 comment_pointers.push_back(comment.key.c_str()); |
| 469 | 411 comment_pointers.push_back(comment.text.c_str()); |
| 470 // Called by libpng to flush its internal buffer to ours. | 412 comment_sizes.push_back(comment.key.length() + 1); |
| 471 void EncoderWriteCallback(png_structp png, png_bytep data, png_size_t size) { | 413 comment_sizes.push_back(comment.text.length() + 1); |
| 472 PngEncoderState* state = static_cast<PngEncoderState*>(png_get_io_ptr(png)); | 414 } |
| 473 DCHECK(state->out); | 415 options.fComments = SkDataTable::MakeCopyArrays( |
| 474 | 416 (void const* const*)comment_pointers.data(), comment_sizes.data(), |
| 475 size_t old_size = state->out->size(); | 417 comment_pointers.size()); |
| 476 state->out->resize(old_size + size); | |
| 477 memcpy(&(*state->out)[old_size], data, size); | |
| 478 } | 418 } |
| 479 | 419 |
| 480 void FakeFlushCallback(png_structp png) { | 420 } // namespace |
| 481 // We don't need to perform any flushing since we aren't doing real IO, but | 421 |
| 482 // we're required to provide this function by libpng. | 422 static bool EncodeSkPixmap(const SkPixmap& src, |
| 423 const std::vector<PNGCodec::Comment>& comments, | |
| 424 std::vector<unsigned char>* output, | |
| 425 int zlib_level) { | |
| 426 output->clear(); | |
| 427 VectorWStream dst(output); | |
| 428 | |
| 429 SkPngEncoder::Options options; | |
| 430 AddComments(options, comments); | |
| 431 options.fZLibLevel = zlib_level; | |
| 432 return SkPngEncoder::Encode(&dst, src, options); | |
| 483 } | 433 } |
| 484 | 434 |
| 485 void ConvertBGRAtoRGB(const unsigned char* bgra, int pixel_width, | 435 static bool EncodeSkPixmap(const SkPixmap& src, |
| 486 unsigned char* rgb, bool* is_opaque) { | 436 bool discard_transparency, |
| 487 for (int x = 0; x < pixel_width; x++) { | 437 const std::vector<PNGCodec::Comment>& comments, |
| 488 const unsigned char* pixel_in = &bgra[x * 4]; | 438 std::vector<unsigned char>* output, |
| 489 unsigned char* pixel_out = &rgb[x * 3]; | 439 int zlib_level) { |
| 490 pixel_out[0] = pixel_in[2]; | 440 if (discard_transparency) { |
| 491 pixel_out[1] = pixel_in[1]; | 441 SkImageInfo opaque_info = src.info().makeAlphaType(kOpaque_SkAlphaType); |
| 492 pixel_out[2] = pixel_in[0]; | 442 SkBitmap copy; |
| 443 if (!copy.tryAllocPixels(opaque_info)) { | |
| 444 return false; | |
| 445 } | |
| 446 SkPixmap opaque_pixmap; | |
| 447 SkASSERT(copy.peekPixels(&opaque_pixmap)); | |
|
scroggo_chromium
2017/07/11 16:01:06
This only happens in debug. Maybe you want:
bool
liyuqian
2017/07/11 19:24:55
Done.
| |
| 448 // The following step does the unpremul as we set the dst alpha type to be | |
| 449 // kUnpremul_SkAlphaType. Later, because opaque_pixmap has | |
| 450 // kOpaque_SkAlphaType, we'll discard the transparency as required. | |
| 451 SkASSERT(src.readPixels(opaque_info.makeAlphaType(kUnpremul_SkAlphaType), | |
|
scroggo_chromium
2017/07/11 16:01:06
Again, this only happens in debug, and we should b
liyuqian
2017/07/11 19:24:55
Done.
| |
| 452 opaque_pixmap.writable_addr(), | |
| 453 opaque_pixmap.rowBytes())); | |
| 454 return EncodeSkPixmap(opaque_pixmap, comments, output, zlib_level); | |
| 493 } | 455 } |
| 456 return EncodeSkPixmap(src, comments, output, zlib_level); | |
| 494 } | 457 } |
| 495 | 458 |
| 496 #ifdef PNG_TEXT_SUPPORTED | |
| 497 class CommentWriter { | |
| 498 public: | |
| 499 explicit CommentWriter(const std::vector<PNGCodec::Comment>& comments) | |
| 500 : comments_(comments), | |
| 501 png_text_(new png_text[comments.size()]) { | |
| 502 for (size_t i = 0; i < comments.size(); ++i) | |
| 503 AddComment(i, comments[i]); | |
| 504 } | |
| 505 | |
| 506 ~CommentWriter() { | |
| 507 for (size_t i = 0; i < comments_.size(); ++i) { | |
| 508 free(png_text_[i].key); | |
| 509 free(png_text_[i].text); | |
| 510 } | |
| 511 delete [] png_text_; | |
| 512 } | |
| 513 | |
| 514 bool HasComments() { | |
| 515 return !comments_.empty(); | |
| 516 } | |
| 517 | |
| 518 png_text* get_png_text() { | |
| 519 return png_text_; | |
| 520 } | |
| 521 | |
| 522 int size() { | |
| 523 return static_cast<int>(comments_.size()); | |
| 524 } | |
| 525 | |
| 526 private: | |
| 527 void AddComment(size_t pos, const PNGCodec::Comment& comment) { | |
| 528 png_text_[pos].compression = PNG_TEXT_COMPRESSION_NONE; | |
| 529 // A PNG comment's key can only be 79 characters long. | |
| 530 DCHECK(comment.key.length() < 79); | |
| 531 png_text_[pos].key = base::strdup(comment.key.substr(0, 78).c_str()); | |
| 532 png_text_[pos].text = base::strdup(comment.text.c_str()); | |
| 533 png_text_[pos].text_length = comment.text.length(); | |
| 534 #ifdef PNG_iTXt_SUPPORTED | |
| 535 png_text_[pos].itxt_length = 0; | |
| 536 png_text_[pos].lang = 0; | |
| 537 png_text_[pos].lang_key = 0; | |
| 538 #endif | |
| 539 } | |
| 540 | |
| 541 DISALLOW_COPY_AND_ASSIGN(CommentWriter); | |
| 542 | |
| 543 const std::vector<PNGCodec::Comment> comments_; | |
| 544 png_text* png_text_; | |
| 545 }; | |
| 546 #endif // PNG_TEXT_SUPPORTED | |
| 547 | |
| 548 // The type of functions usable for converting between pixel formats. | |
| 549 typedef void (*FormatConverter)(const unsigned char* in, int w, | |
| 550 unsigned char* out, bool* is_opaque); | |
| 551 | |
| 552 // libpng uses a wacky setjmp-based API, which makes the compiler nervous. | |
| 553 // We constrain all of the calls we make to libpng where the setjmp() is in | |
| 554 // place to this function. | |
| 555 // Returns true on success. | |
| 556 bool DoLibpngWrite(png_struct* png_ptr, png_info* info_ptr, | |
| 557 PngEncoderState* state, | |
| 558 int width, int height, int row_byte_width, | |
| 559 const unsigned char* input, int compression_level, | |
| 560 int png_output_color_type, int output_color_components, | |
| 561 FormatConverter converter, | |
| 562 const std::vector<PNGCodec::Comment>& comments) { | |
| 563 #ifdef PNG_TEXT_SUPPORTED | |
| 564 CommentWriter comment_writer(comments); | |
| 565 #endif | |
| 566 unsigned char* row_buffer = NULL; | |
| 567 | |
| 568 // Make sure to not declare any locals here -- locals in the presence | |
| 569 // of setjmp() in C++ code makes gcc complain. | |
| 570 | |
| 571 if (setjmp(png_jmpbuf(png_ptr))) { | |
| 572 delete[] row_buffer; | |
| 573 return false; | |
| 574 } | |
| 575 | |
| 576 png_set_compression_level(png_ptr, compression_level); | |
| 577 | |
| 578 // Set our callback for libpng to give us the data. | |
| 579 png_set_write_fn(png_ptr, state, EncoderWriteCallback, FakeFlushCallback); | |
| 580 png_set_error_fn(png_ptr, NULL, LogLibPNGEncodeError, LogLibPNGEncodeWarning); | |
| 581 | |
| 582 png_set_IHDR(png_ptr, info_ptr, width, height, 8, png_output_color_type, | |
| 583 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, | |
| 584 PNG_FILTER_TYPE_DEFAULT); | |
| 585 | |
| 586 #ifdef PNG_TEXT_SUPPORTED | |
| 587 if (comment_writer.HasComments()) { | |
| 588 png_set_text(png_ptr, info_ptr, comment_writer.get_png_text(), | |
| 589 comment_writer.size()); | |
| 590 } | |
| 591 #endif | |
| 592 | |
| 593 png_write_info(png_ptr, info_ptr); | |
| 594 | |
| 595 if (!converter) { | |
| 596 // No conversion needed, give the data directly to libpng. | |
| 597 for (int y = 0; y < height; y ++) { | |
| 598 png_write_row(png_ptr, | |
| 599 const_cast<unsigned char*>(&input[y * row_byte_width])); | |
| 600 } | |
| 601 } else { | |
| 602 // Needs conversion using a separate buffer. | |
| 603 row_buffer = new unsigned char[width * output_color_components]; | |
| 604 for (int y = 0; y < height; y ++) { | |
| 605 converter(&input[y * row_byte_width], width, row_buffer, NULL); | |
| 606 png_write_row(png_ptr, row_buffer); | |
| 607 } | |
| 608 delete[] row_buffer; | |
| 609 } | |
| 610 | |
| 611 png_write_end(png_ptr, info_ptr); | |
| 612 return true; | |
| 613 } | |
| 614 | |
| 615 bool EncodeWithCompressionLevel(const unsigned char* input, | |
| 616 PNGCodec::ColorFormat format, | |
| 617 const Size& size, | |
| 618 int row_byte_width, | |
| 619 bool discard_transparency, | |
| 620 const std::vector<PNGCodec::Comment>& comments, | |
| 621 int compression_level, | |
| 622 std::vector<unsigned char>* output) { | |
| 623 // Run to convert an input row into the output row format, NULL means no | |
| 624 // conversion is necessary. | |
| 625 FormatConverter converter = NULL; | |
| 626 | |
| 627 int input_color_components, output_color_components; | |
| 628 int png_output_color_type; | |
| 629 switch (format) { | |
| 630 case PNGCodec::FORMAT_RGBA: | |
| 631 input_color_components = 4; | |
| 632 if (discard_transparency) { | |
| 633 output_color_components = 3; | |
| 634 png_output_color_type = PNG_COLOR_TYPE_RGB; | |
| 635 converter = ConvertRGBAtoRGB; | |
| 636 } else { | |
| 637 output_color_components = 4; | |
| 638 png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; | |
| 639 converter = NULL; | |
| 640 } | |
| 641 break; | |
| 642 | |
| 643 case PNGCodec::FORMAT_BGRA: | |
| 644 input_color_components = 4; | |
| 645 if (discard_transparency) { | |
| 646 output_color_components = 3; | |
| 647 png_output_color_type = PNG_COLOR_TYPE_RGB; | |
| 648 converter = ConvertBGRAtoRGB; | |
| 649 } else { | |
| 650 output_color_components = 4; | |
| 651 png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; | |
| 652 converter = ConvertBetweenBGRAandRGBA; | |
| 653 } | |
| 654 break; | |
| 655 | |
| 656 case PNGCodec::FORMAT_SkBitmap: | |
| 657 // Compare row_byte_width and size.width() to detect the format of | |
| 658 // SkBitmap. kA8_Config (1bpp) and kARGB_8888_Config (4bpp) are the two | |
| 659 // supported formats. | |
| 660 if (row_byte_width < 4 * size.width()) { | |
| 661 // Not 4bpp, so must be 1bpp. | |
| 662 // Ignore discard_transparency - it doesn't make sense in this context, | |
| 663 // since alpha is the only thing we have and it needs to be used for | |
| 664 // color intensity. | |
| 665 input_color_components = 1; | |
| 666 output_color_components = 1; | |
| 667 png_output_color_type = PNG_COLOR_TYPE_GRAY; | |
| 668 // |converter| is left as null | |
| 669 } else { | |
| 670 input_color_components = 4; | |
| 671 if (discard_transparency) { | |
| 672 output_color_components = 3; | |
| 673 png_output_color_type = PNG_COLOR_TYPE_RGB; | |
| 674 converter = ConvertSkiaToRGB; | |
| 675 } else { | |
| 676 output_color_components = 4; | |
| 677 png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; | |
| 678 converter = ConvertSkiaToRGBA; | |
| 679 } | |
| 680 } | |
| 681 break; | |
| 682 | |
| 683 default: | |
| 684 NOTREACHED() << "Unknown pixel format"; | |
| 685 return false; | |
| 686 } | |
| 687 | |
| 688 // Row stride should be at least as long as the length of the data. | |
| 689 DCHECK(input_color_components * size.width() <= row_byte_width); | |
| 690 | |
| 691 PngWriteStructInfo si; | |
| 692 si.png_ptr_ = png_create_write_struct(PNG_LIBPNG_VER_STRING, | |
| 693 NULL, NULL, NULL); | |
| 694 if (!si.png_ptr_) | |
| 695 return false; | |
| 696 | |
| 697 si.info_ptr_ = png_create_info_struct(si.png_ptr_); | |
| 698 if (!si.info_ptr_) | |
| 699 return false; | |
| 700 | |
| 701 output->clear(); | |
| 702 | |
| 703 PngEncoderState state(output); | |
| 704 bool success = DoLibpngWrite(si.png_ptr_, si.info_ptr_, &state, | |
| 705 size.width(), size.height(), row_byte_width, | |
| 706 input, compression_level, png_output_color_type, | |
| 707 output_color_components, converter, comments); | |
| 708 | |
| 709 return success; | |
| 710 } | |
| 711 | |
| 712 bool InternalEncodeSkBitmap(const SkBitmap& input, | |
| 713 bool discard_transparency, | |
| 714 int compression_level, | |
| 715 std::vector<unsigned char>* output) { | |
| 716 if (input.empty() || input.isNull()) | |
| 717 return false; | |
| 718 int bpp = input.bytesPerPixel(); | |
| 719 DCHECK(bpp == 1 || bpp == 4); // We support kA8_Config and kARGB_8888_Config. | |
| 720 | |
| 721 unsigned char* inputAddr = bpp == 1 ? | |
| 722 reinterpret_cast<unsigned char*>(input.getAddr8(0, 0)) : | |
| 723 reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)); // bpp = 4 | |
| 724 return EncodeWithCompressionLevel( | |
| 725 inputAddr, | |
| 726 PNGCodec::FORMAT_SkBitmap, | |
| 727 Size(input.width(), input.height()), | |
| 728 static_cast<int>(input.rowBytes()), | |
| 729 discard_transparency, | |
| 730 std::vector<PNGCodec::Comment>(), | |
| 731 compression_level, | |
| 732 output); | |
| 733 } | |
| 734 | |
| 735 | |
| 736 } // namespace | |
| 737 | |
| 738 // static | 459 // static |
| 739 bool PNGCodec::Encode(const unsigned char* input, | 460 bool PNGCodec::Encode(const unsigned char* input, |
| 740 ColorFormat format, | 461 ColorFormat format, |
| 741 const Size& size, | 462 const Size& size, |
| 742 int row_byte_width, | 463 int row_byte_width, |
| 743 bool discard_transparency, | 464 bool discard_transparency, |
| 744 const std::vector<Comment>& comments, | 465 const std::vector<Comment>& comments, |
| 745 std::vector<unsigned char>* output) { | 466 std::vector<unsigned char>* output) { |
| 746 return EncodeWithCompressionLevel(input, | 467 auto colorType = |
| 747 format, | 468 format == FORMAT_RGBA ? kRGBA_8888_SkColorType : kBGRA_8888_SkColorType; |
|
scroggo_chromium
2017/07/11 16:01:06
Just to make sure I understand - if format is FORM
liyuqian
2017/07/11 19:24:55
I'm also very confused because:
1. The method is
scroggo_chromium
2017/07/11 19:33:09
Yeah, Configs were replaced with SkColorTypes befo
liyuqian
2017/07/11 19:59:25
Acknowledged.
| |
| 748 size, | 469 auto alphaType = |
| 749 row_byte_width, | 470 format == FORMAT_SkBitmap ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; |
| 750 discard_transparency, | 471 SkImageInfo info = |
| 751 comments, | 472 SkImageInfo::Make(size.width(), size.height(), colorType, alphaType); |
| 752 Z_DEFAULT_COMPRESSION, | 473 SkPixmap src(info, input, row_byte_width); |
| 753 output); | 474 return EncodeSkPixmap(src, discard_transparency, comments, output, |
| 475 DEFAULT_ZLIB_COMPRESSION); | |
| 476 } | |
| 477 | |
| 478 static bool EncodeSkBitmap(const SkBitmap& input, | |
| 479 bool discard_transparency, | |
| 480 std::vector<unsigned char>* output, | |
| 481 int zlib_level) { | |
| 482 SkPixmap src; | |
| 483 if (!input.peekPixels(&src)) { | |
| 484 return false; | |
| 485 } | |
| 486 std::vector<PNGCodec::Comment> empty_comments; | |
|
scroggo_chromium
2017/07/11 16:01:06
Too bad we need to create this empty vector just t
liyuqian
2017/07/11 19:24:55
Agree. I can use {} in Mac but Linux can only comp
scroggo_chromium
2017/07/11 19:33:09
Maybe it should take a pointer, which can be null?
liyuqian
2017/07/11 19:59:25
That sounds good. However, it will require the pub
scroggo_chromium
2017/07/11 20:09:30
Sgtm
| |
| 487 return EncodeSkPixmap(src, discard_transparency, empty_comments, output, | |
| 488 zlib_level); | |
| 754 } | 489 } |
| 755 | 490 |
| 756 // static | 491 // static |
| 757 bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input, | 492 bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input, |
| 758 bool discard_transparency, | 493 bool discard_transparency, |
| 759 std::vector<unsigned char>* output) { | 494 std::vector<unsigned char>* output) { |
| 760 return InternalEncodeSkBitmap(input, | 495 return EncodeSkBitmap(input, discard_transparency, output, |
| 761 discard_transparency, | 496 DEFAULT_ZLIB_COMPRESSION); |
| 762 Z_DEFAULT_COMPRESSION, | |
| 763 output); | |
| 764 } | 497 } |
| 765 | 498 |
| 766 // static | 499 // static |
| 767 bool PNGCodec::EncodeA8SkBitmap(const SkBitmap& input, | 500 bool PNGCodec::EncodeA8SkBitmap(const SkBitmap& input, |
| 768 std::vector<unsigned char>* output) { | 501 std::vector<unsigned char>* output) { |
| 769 return InternalEncodeSkBitmap(input, | 502 SkASSERT(input.colorType() == kAlpha_8_SkColorType); |
|
scroggo_chromium
2017/07/11 16:01:06
DCHECK. There might be a DCHECK_EQ, so this could
liyuqian
2017/07/11 19:24:55
Done.
| |
| 770 false, | 503 auto info = input.info() |
| 771 Z_DEFAULT_COMPRESSION, | 504 .makeColorType(kGray_8_SkColorType) |
| 772 output); | 505 .makeAlphaType(kOpaque_SkAlphaType); |
| 506 SkPixmap src(info, input.getAddr(0, 0), input.rowBytes()); | |
|
scroggo_chromium
2017/07/11 16:01:06
You could instead use readPixels here, as you do e
liyuqian
2017/07/11 19:24:55
In the other place, we need to do unpremul and cop
scroggo_chromium
2017/07/11 19:33:09
Oh, oops, you are correct.
| |
| 507 std::vector<Comment> empty_comments; | |
| 508 return EncodeSkPixmap(src, empty_comments, output, DEFAULT_ZLIB_COMPRESSION); | |
| 773 } | 509 } |
| 774 | 510 |
| 775 // static | 511 // static |
| 776 bool PNGCodec::FastEncodeBGRASkBitmap(const SkBitmap& input, | 512 bool PNGCodec::FastEncodeBGRASkBitmap(const SkBitmap& input, |
| 777 bool discard_transparency, | 513 bool discard_transparency, |
| 778 std::vector<unsigned char>* output) { | 514 std::vector<unsigned char>* output) { |
| 779 return InternalEncodeSkBitmap(input, | 515 return EncodeSkBitmap(input, discard_transparency, output, Z_BEST_SPEED); |
| 780 discard_transparency, | |
| 781 Z_BEST_SPEED, | |
| 782 output); | |
| 783 } | 516 } |
| 784 | 517 |
| 785 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) | 518 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) |
| 786 : key(k), text(t) { | 519 : key(k), text(t) { |
| 787 } | 520 } |
| 788 | 521 |
| 789 PNGCodec::Comment::~Comment() { | 522 PNGCodec::Comment::~Comment() { |
| 790 } | 523 } |
| 791 | 524 |
| 792 } // namespace gfx | 525 } // namespace gfx |
| OLD | NEW |