OLD | NEW |
1 // Copyright (c) 2009 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 "gfx/codec/png_codec.h" | 5 #include "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 "base/scoped_ptr.h" |
9 #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" | 10 #include "third_party/skia/include/core/SkUnPreMultiply.h" |
(...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
534 unsigned char* rgb, bool* is_opaque) { | 534 unsigned char* rgb, bool* is_opaque) { |
535 for (int x = 0; x < pixel_width; x++) { | 535 for (int x = 0; x < pixel_width; x++) { |
536 const unsigned char* pixel_in = &bgra[x * 4]; | 536 const unsigned char* pixel_in = &bgra[x * 4]; |
537 unsigned char* pixel_out = &rgb[x * 3]; | 537 unsigned char* pixel_out = &rgb[x * 3]; |
538 pixel_out[0] = pixel_in[2]; | 538 pixel_out[0] = pixel_in[2]; |
539 pixel_out[1] = pixel_in[1]; | 539 pixel_out[1] = pixel_in[1]; |
540 pixel_out[2] = pixel_in[0]; | 540 pixel_out[2] = pixel_in[0]; |
541 } | 541 } |
542 } | 542 } |
543 | 543 |
544 // Automatically destroys the given write structs on destruction to make | 544 // The type of functions usable for converting between pixel formats. |
545 // cleanup and error handling code cleaner. | 545 typedef void (*FormatConverter)(const unsigned char* in, int w, |
546 class PngWriteStructDestroyer { | 546 unsigned char* out, bool* is_opaque); |
547 public: | 547 |
548 PngWriteStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) { | 548 // libpng uses a wacky setjmp-based API, which makes the compiler nervous. |
| 549 // We constrain all of the calls we make to libpng where the setjmp() is in |
| 550 // place to this function. |
| 551 // Returns true on success. |
| 552 bool DoLibpngWrite(png_struct* png_ptr, png_info* info_ptr, |
| 553 PngEncoderState* state, |
| 554 int width, int height, int row_byte_width, |
| 555 const unsigned char* input, |
| 556 int png_output_color_type, int output_color_components, |
| 557 FormatConverter converter) { |
| 558 // Make sure to not declare any locals here -- locals in the presence |
| 559 // of setjmp() in C++ code makes gcc complain. |
| 560 |
| 561 if (setjmp(png_jmpbuf(png_ptr))) |
| 562 return false; |
| 563 |
| 564 // Set our callback for libpng to give us the data. |
| 565 png_set_write_fn(png_ptr, state, EncoderWriteCallback, NULL); |
| 566 |
| 567 png_set_IHDR(png_ptr, info_ptr, width, height, 8, png_output_color_type, |
| 568 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, |
| 569 PNG_FILTER_TYPE_DEFAULT); |
| 570 png_write_info(png_ptr, info_ptr); |
| 571 |
| 572 if (!converter) { |
| 573 // No conversion needed, give the data directly to libpng. |
| 574 for (int y = 0; y < height; y ++) { |
| 575 png_write_row(png_ptr, |
| 576 const_cast<unsigned char*>(&input[y * row_byte_width])); |
| 577 } |
| 578 } else { |
| 579 // Needs conversion using a separate buffer. |
| 580 unsigned char* row = new unsigned char[width * output_color_components]; |
| 581 for (int y = 0; y < height; y ++) { |
| 582 converter(&input[y * row_byte_width], width, row, NULL); |
| 583 png_write_row(png_ptr, row); |
| 584 } |
| 585 delete[] row; |
549 } | 586 } |
550 ~PngWriteStructDestroyer() { | |
551 png_destroy_write_struct(ps_, pi_); | |
552 } | |
553 private: | |
554 png_struct** ps_; | |
555 png_info** pi_; | |
556 | 587 |
557 DISALLOW_EVIL_CONSTRUCTORS(PngWriteStructDestroyer); | 588 png_write_end(png_ptr, info_ptr); |
558 }; | 589 return true; |
| 590 } |
559 | 591 |
560 } // namespace | 592 } // namespace |
561 | 593 |
562 // static | 594 // static |
563 bool PNGCodec::Encode(const unsigned char* input, ColorFormat format, | 595 bool PNGCodec::Encode(const unsigned char* input, ColorFormat format, |
564 int w, int h, int row_byte_width, | 596 int w, int h, int row_byte_width, |
565 bool discard_transparency, | 597 bool discard_transparency, |
566 std::vector<unsigned char>* output) { | 598 std::vector<unsigned char>* output) { |
567 // Run to convert an input row into the output row format, NULL means no | 599 // Run to convert an input row into the output row format, NULL means no |
568 // conversion is necessary. | 600 // conversion is necessary. |
569 void (*converter)(const unsigned char* in, int w, unsigned char* out, | 601 FormatConverter converter = NULL; |
570 bool* is_opaque) = NULL; | |
571 | 602 |
572 int input_color_components, output_color_components; | 603 int input_color_components, output_color_components; |
573 int png_output_color_type; | 604 int png_output_color_type; |
574 switch (format) { | 605 switch (format) { |
575 case FORMAT_RGB: | 606 case FORMAT_RGB: |
576 input_color_components = 3; | 607 input_color_components = 3; |
577 output_color_components = 3; | 608 output_color_components = 3; |
578 png_output_color_type = PNG_COLOR_TYPE_RGB; | 609 png_output_color_type = PNG_COLOR_TYPE_RGB; |
579 discard_transparency = false; | 610 discard_transparency = false; |
580 break; | 611 break; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
628 | 659 |
629 png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, | 660 png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, |
630 NULL, NULL, NULL); | 661 NULL, NULL, NULL); |
631 if (!png_ptr) | 662 if (!png_ptr) |
632 return false; | 663 return false; |
633 png_info* info_ptr = png_create_info_struct(png_ptr); | 664 png_info* info_ptr = png_create_info_struct(png_ptr); |
634 if (!info_ptr) { | 665 if (!info_ptr) { |
635 png_destroy_write_struct(&png_ptr, NULL); | 666 png_destroy_write_struct(&png_ptr, NULL); |
636 return false; | 667 return false; |
637 } | 668 } |
638 PngWriteStructDestroyer destroyer(&png_ptr, &info_ptr); | |
639 | 669 |
640 if (setjmp(png_jmpbuf(png_ptr))) { | 670 PngEncoderState state(output); |
641 // The destroyer will ensure that the structures are cleaned up in this | 671 bool success = DoLibpngWrite(png_ptr, info_ptr, &state, |
642 // case, even though we may get here as a jump from random parts of the | 672 w, h, row_byte_width, input, |
643 // PNG library called below. | 673 png_output_color_type, output_color_components, |
644 return false; | 674 converter); |
645 } | 675 png_destroy_write_struct(&png_ptr, &info_ptr); |
646 | 676 |
647 // Set our callback for libpng to give us the data. | 677 return success; |
648 PngEncoderState state(output); | |
649 png_set_write_fn(png_ptr, &state, EncoderWriteCallback, NULL); | |
650 | |
651 png_set_IHDR(png_ptr, info_ptr, w, h, 8, png_output_color_type, | |
652 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, | |
653 PNG_FILTER_TYPE_DEFAULT); | |
654 png_write_info(png_ptr, info_ptr); | |
655 | |
656 if (!converter) { | |
657 // No conversion needed, give the data directly to libpng. | |
658 for (int y = 0; y < h; y ++) { | |
659 png_write_row(png_ptr, | |
660 const_cast<unsigned char*>(&input[y * row_byte_width])); | |
661 } | |
662 } else { | |
663 // Needs conversion using a separate buffer. | |
664 unsigned char* row = new unsigned char[w * output_color_components]; | |
665 for (int y = 0; y < h; y ++) { | |
666 converter(&input[y * row_byte_width], w, row, NULL); | |
667 png_write_row(png_ptr, row); | |
668 } | |
669 delete[] row; | |
670 } | |
671 | |
672 png_write_end(png_ptr, info_ptr); | |
673 return true; | |
674 } | 678 } |
675 | 679 |
676 // static | 680 // static |
677 bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input, | 681 bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input, |
678 bool discard_transparency, | 682 bool discard_transparency, |
679 std::vector<unsigned char>* output) { | 683 std::vector<unsigned char>* output) { |
680 static const int bbp = 4; | 684 static const int bbp = 4; |
681 | 685 |
682 SkAutoLockPixels lock_input(input); | 686 SkAutoLockPixels lock_input(input); |
683 DCHECK(input.empty() || input.bytesPerPixel() == bbp); | 687 DCHECK(input.empty() || input.bytesPerPixel() == bbp); |
684 | 688 |
685 return Encode(reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)), | 689 return Encode(reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)), |
686 FORMAT_SkBitmap, input.width(), input.height(), | 690 FORMAT_SkBitmap, input.width(), input.height(), |
687 input.width() * bbp, discard_transparency, output); | 691 input.width() * bbp, discard_transparency, output); |
688 } | 692 } |
689 | 693 |
690 } // namespace gfx | 694 } // namespace gfx |
OLD | NEW |