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.
5 #include "ui/gfx/codec/png_codec.h"
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"
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];
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);
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];
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
);
53 pixel_out
[0] = SkGetPackedR32(pixel_in
);
54 pixel_out
[1] = SkGetPackedG32(pixel_in
);
55 pixel_out
[2] = SkGetPackedB32(pixel_in
);
60 void ConvertSkiaToRGBA(const unsigned char* skia
, int pixel_width
,
61 unsigned char* rgba
, bool* is_opaque
) {
62 gfx::ConvertSkiaToRGBA(skia
, pixel_width
, rgba
);
67 // Decoder --------------------------------------------------------------------
69 // This code is based on WebKit libpng interface (PNGImageDecoder), which is
70 // in turn based on the Mozilla png decoder.
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
;
79 class PngDecoderState
{
81 // Output is a vector<unsigned char>.
82 PngDecoderState(PNGCodec::ColorFormat ofmt
, std::vector
<unsigned char>* o
)
83 : output_format(ofmt
),
93 // Output is an SkBitmap.
94 explicit PngDecoderState(SkBitmap
* skbitmap
)
95 : output_format(PNGCodec::FORMAT_SkBitmap
),
105 PNGCodec::ColorFormat output_format
;
108 // An incoming SkBitmap to write to. If NULL, we write to output instead.
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.
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
;
119 // Size of the image, set in the info callback.
123 // Set to true when we've found the end of the data.
127 DISALLOW_COPY_AND_ASSIGN(PngDecoderState
);
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
,
136 const int channels
= row_info
->channels
;
137 DCHECK_EQ(channels
, 4);
139 PngDecoderState
* state
=
140 static_cast<PngDecoderState
*>(png_get_user_transform_ptr(png_ptr
));
141 DCHECK(state
) << "LibPNG user transform pointer is NULL";
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];
148 state
->is_opaque
= false;
149 *sk_pixel
= SkPreMultiplyARGB(alpha
, p
[0], p
[1], p
[2]);
151 *sk_pixel
= SkPackARGB32(alpha
, p
[0], p
[1], p
[2]);
156 // Called when the png header has been read. This code is based on the WebKit
158 void DecodeInfoCallback(png_struct
* png_ptr
, png_info
* info_ptr
) {
159 PngDecoderState
* state
= static_cast<PngDecoderState
*>(
160 png_get_progressive_ptr(png_ptr
));
162 int bit_depth
, color_type
, interlace_type
, compression_type
;
165 png_get_IHDR(png_ptr
, info_ptr
, &w
, &h
, &bit_depth
, &color_type
,
166 &interlace_type
, &compression_type
, &filter_type
);
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
);
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.
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
);
190 // The '!= 0' is for silencing a Windows compiler warning.
191 bool input_has_alpha
= ((color_type
& PNG_COLOR_MASK_ALPHA
) != 0);
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;
199 // Convert 16-bit to 8-bit.
201 png_set_strip_16(png_ptr
);
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;
209 case PNGCodec::FORMAT_RGBA
:
210 state
->output_channels
= 4;
211 png_set_add_alpha(png_ptr
, 0xFF, PNG_FILLER_AFTER
);
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
);
218 case PNGCodec::FORMAT_SkBitmap
:
219 state
->output_channels
= 4;
220 png_set_add_alpha(png_ptr
, 0xFF, PNG_FILLER_AFTER
);
224 switch (state
->output_format
) {
225 case PNGCodec::FORMAT_RGB
:
226 state
->output_channels
= 3;
227 png_set_strip_alpha(png_ptr
);
229 case PNGCodec::FORMAT_RGBA
:
230 state
->output_channels
= 4;
232 case PNGCodec::FORMAT_BGRA
:
233 state
->output_channels
= 4;
234 png_set_bgr(png_ptr
);
236 case PNGCodec::FORMAT_SkBitmap
:
237 state
->output_channels
= 4;
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
);
247 // Deal with gamma and keep it under our control.
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
);
254 png_set_gamma(png_ptr
, kDefaultGamma
, gamma
);
256 png_set_gamma(png_ptr
, kDefaultGamma
, kInverseGamma
);
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);
267 // Tell libpng to send us rows for interlaced pngs.
268 if (interlace_type
== PNG_INTERLACE_ADAM7
)
269 png_set_interlace_handling(png_ptr
);
271 png_read_update_info(png_ptr
, info_ptr
);
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
);
281 void DecodeRowCallback(png_struct
* png_ptr
, png_byte
* new_row
,
282 png_uint_32 row_num
, int pass
) {
284 return; // Interlaced image; row didn't change this pass.
286 PngDecoderState
* state
= static_cast<PngDecoderState
*>(
287 png_get_progressive_ptr(png_ptr
));
289 if (static_cast<int>(row_num
) > state
->height
) {
290 NOTREACHED() << "Invalid row";
294 unsigned char* base
= NULL
;
296 base
= reinterpret_cast<unsigned char*>(state
->bitmap
->getAddr32(0, 0));
297 else if (state
->output
)
298 base
= &state
->output
->front();
300 unsigned char* dest
= &base
[state
->width
* state
->output_channels
* row_num
];
301 png_progressive_combine_row(png_ptr
, dest
, new_row
);
304 void DecodeEndCallback(png_struct
* png_ptr
, png_info
* info
) {
305 PngDecoderState
* state
= static_cast<PngDecoderState
*>(
306 png_get_progressive_ptr(png_ptr
));
308 // Mark the image as complete, this will tell the Decode function that we
309 // have successfully found the end of the data.
313 // Automatically destroys the given read structs on destruction to make
314 // cleanup and error handling code cleaner.
315 class PngReadStructDestroyer
{
317 PngReadStructDestroyer(png_struct
** ps
, png_info
** pi
) : ps_(ps
), pi_(pi
) {
319 ~PngReadStructDestroyer() {
320 png_destroy_read_struct(ps_
, pi_
, NULL
);
325 DISALLOW_COPY_AND_ASSIGN(PngReadStructDestroyer
);
328 // Automatically destroys the given write structs on destruction to make
329 // cleanup and error handling code cleaner.
330 class PngWriteStructDestroyer
{
332 explicit PngWriteStructDestroyer(png_struct
** ps
) : ps_(ps
), pi_(0) {
334 ~PngWriteStructDestroyer() {
335 png_destroy_write_struct(ps_
, pi_
);
337 void SetInfoStruct(png_info
** pi
) {
343 DISALLOW_COPY_AND_ASSIGN(PngWriteStructDestroyer
);
346 bool BuildPNGStruct(const unsigned char* input
, size_t input_size
,
347 png_struct
** png_ptr
, png_info
** info_ptr
) {
349 return false; // Input data too small to be a png
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)
355 *png_ptr
= png_create_read_struct(PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
359 *info_ptr
= png_create_info_struct(*png_ptr
);
361 png_destroy_read_struct(png_ptr
, NULL
, NULL
);
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.
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);
376 void LogLibPNGDecodeWarning(png_structp png_ptr
, png_const_charp warning_msg
) {
377 DLOG(ERROR
) << "libpng decode warning: " << warning_msg
;
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);
385 void LogLibPNGEncodeWarning(png_structp png_ptr
, png_const_charp warning_msg
) {
386 DLOG(ERROR
) << "libpng encode warning: " << warning_msg
;
392 bool PNGCodec::Decode(const unsigned char* input
, size_t input_size
,
393 ColorFormat format
, std::vector
<unsigned char>* output
,
395 png_struct
* png_ptr
= NULL
;
396 png_info
* info_ptr
= NULL
;
397 if (!BuildPNGStruct(input
, input_size
, &png_ptr
, &info_ptr
))
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.
408 PngDecoderState
state(format
, output
);
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
,
415 const_cast<unsigned char*>(input
),
419 // Fed it all the data but the library didn't think we got all the data, so
420 // this file must be truncated.
431 bool PNGCodec::Decode(const unsigned char* input
, size_t input_size
,
434 png_struct
* png_ptr
= NULL
;
435 png_info
* info_ptr
= NULL
;
436 if (!BuildPNGStruct(input
, input_size
, &png_ptr
, &info_ptr
))
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.
447 PngDecoderState
state(bitmap
);
449 png_set_progressive_read_fn(png_ptr
, &state
, &DecodeInfoCallback
,
450 &DecodeRowCallback
, &DecodeEndCallback
);
451 png_process_data(png_ptr
,
453 const_cast<unsigned char*>(input
),
460 // Set the bitmap's opaqueness based on what we saw.
461 bitmap
->setAlphaType(state
.is_opaque
?
462 kOpaque_SkAlphaType
: kPremul_SkAlphaType
);
467 // Encoder --------------------------------------------------------------------
469 // This section of the code is based on nsPNGEncoder.cpp in Mozilla
470 // (Copyright 2005 Google Inc.)
474 // Passed around as the io_ptr in the png structs so our callbacks know where
476 struct PngEncoderState
{
477 explicit PngEncoderState(std::vector
<unsigned char>* o
) : out(o
) {}
478 std::vector
<unsigned char>* out
;
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
));
486 size_t old_size
= state
->out
->size();
487 state
->out
->resize(old_size
+ size
);
488 memcpy(&(*state
->out
)[old_size
], data
, size
);
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.
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];
507 #ifdef PNG_TEXT_SUPPORTED
508 class CommentWriter
{
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
]);
518 for (size_t i
= 0; i
< comments_
.size(); ++i
) {
519 free(png_text_
[i
].key
);
520 free(png_text_
[i
].text
);
526 return !comments_
.empty();
529 png_text
* get_png_text() {
534 return static_cast<int>(comments_
.size());
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;
552 DISALLOW_COPY_AND_ASSIGN(CommentWriter
);
554 const std::vector
<PNGCodec::Comment
> comments_
;
557 #endif // PNG_TEXT_SUPPORTED
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
);
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
);
577 unsigned char* row_buffer
= NULL
;
579 // Make sure to not declare any locals here -- locals in the presence
580 // of setjmp() in C++ code makes gcc complain.
582 if (setjmp(png_jmpbuf(png_ptr
))) {
587 png_set_compression_level(png_ptr
, compression_level
);
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
);
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
);
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());
604 png_write_info(png_ptr
, info_ptr
);
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
]));
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
);
622 png_write_end(png_ptr
, info_ptr
);
626 bool EncodeWithCompressionLevel(const unsigned char* input
,
627 PNGCodec::ColorFormat format
,
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
;
638 int input_color_components
, output_color_components
;
639 int png_output_color_type
;
641 case PNGCodec::FORMAT_RGB
:
642 input_color_components
= 3;
643 output_color_components
= 3;
644 png_output_color_type
= PNG_COLOR_TYPE_RGB
;
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
;
654 output_color_components
= 4;
655 png_output_color_type
= PNG_COLOR_TYPE_RGB_ALPHA
;
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
;
667 output_color_components
= 4;
668 png_output_color_type
= PNG_COLOR_TYPE_RGB_ALPHA
;
669 converter
= ConvertBetweenBGRAandRGBA
;
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
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
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
;
693 output_color_components
= 4;
694 png_output_color_type
= PNG_COLOR_TYPE_RGB_ALPHA
;
695 converter
= ConvertSkiaToRGBA
;
701 NOTREACHED() << "Unknown pixel format";
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
);
708 png_struct
* png_ptr
= png_create_write_struct(PNG_LIBPNG_VER_STRING
,
712 PngWriteStructDestroyer
destroyer(&png_ptr
);
713 png_info
* info_ptr
= png_create_info_struct(png_ptr
);
716 destroyer
.SetInfoStruct(&info_ptr
);
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
);
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())
735 int bpp
= input
.bytesPerPixel();
736 DCHECK(bpp
== 1 || bpp
== 4); // We support kA8_Config and kARGB_8888_Config.
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(
744 PNGCodec::FORMAT_SkBitmap
,
745 Size(input
.width(), input
.height()),
746 static_cast<int>(input
.rowBytes()),
747 discard_transparency
,
748 std::vector
<PNGCodec::Comment
>(),
757 bool PNGCodec::Encode(const unsigned char* input
,
761 bool discard_transparency
,
762 const std::vector
<Comment
>& comments
,
763 std::vector
<unsigned char>* output
) {
764 return EncodeWithCompressionLevel(input
,
768 discard_transparency
,
770 Z_DEFAULT_COMPRESSION
,
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
,
785 bool PNGCodec::EncodeA8SkBitmap(const SkBitmap
& input
,
786 std::vector
<unsigned char>* output
) {
787 return InternalEncodeSkBitmap(input
,
789 Z_DEFAULT_COMPRESSION
,
794 bool PNGCodec::FastEncodeBGRASkBitmap(const SkBitmap
& input
,
795 bool discard_transparency
,
796 std::vector
<unsigned char>* output
) {
797 return InternalEncodeSkBitmap(input
,
798 discard_transparency
,
803 PNGCodec::Comment::Comment(const std::string
& k
, const std::string
& t
)
807 PNGCodec::Comment::~Comment() {