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/string_util.h"
9 #include "ui/gfx/size.h"
10 #include "ui/gfx/skia_util.h"
11 #include "third_party/libpng/png.h"
12 #include "third_party/skia/include/core/SkBitmap.h"
13 #include "third_party/skia/include/core/SkUnPreMultiply.h"
14 #include "third_party/skia/include/core/SkColorPriv.h"
15 #include "third_party/zlib/zlib.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 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];
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];
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
);
58 pixel_out
[0] = SkGetPackedR32(pixel_in
);
59 pixel_out
[1] = SkGetPackedG32(pixel_in
);
60 pixel_out
[2] = SkGetPackedB32(pixel_in
);
65 void ConvertSkiatoRGBA(const unsigned char* skia
, int pixel_width
,
66 unsigned char* rgba
, bool* is_opaque
) {
67 gfx::ConvertSkiaToRGBA(skia
, pixel_width
, rgba
);
72 // Decoder --------------------------------------------------------------------
74 // This code is based on WebKit libpng interface (PNGImageDecoder), which is
75 // in turn based on the Mozilla png decoder.
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
;
84 class PngDecoderState
{
86 // Output is a vector<unsigned char>.
87 PngDecoderState(PNGCodec::ColorFormat ofmt
, std::vector
<unsigned char>* o
)
88 : output_format(ofmt
),
98 // Output is an SkBitmap.
99 explicit PngDecoderState(SkBitmap
* skbitmap
)
100 : output_format(PNGCodec::FORMAT_SkBitmap
),
110 PNGCodec::ColorFormat output_format
;
113 // An incoming SkBitmap to write to. If NULL, we write to output instead.
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.
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
;
124 // Size of the image, set in the info callback.
128 // Set to true when we've found the end of the data.
132 DISALLOW_COPY_AND_ASSIGN(PngDecoderState
);
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
,
141 const int channels
= row_info
->channels
;
142 DCHECK_EQ(channels
, 4);
144 PngDecoderState
* state
=
145 static_cast<PngDecoderState
*>(png_get_user_transform_ptr(png_ptr
));
146 DCHECK(state
) << "LibPNG user transform pointer is NULL";
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];
153 state
->is_opaque
= false;
154 *sk_pixel
= SkPreMultiplyARGB(alpha
, p
[0], p
[1], p
[2]);
156 *sk_pixel
= SkPackARGB32(alpha
, p
[0], p
[1], p
[2]);
161 // Called when the png header has been read. This code is based on the WebKit
163 void DecodeInfoCallback(png_struct
* png_ptr
, png_info
* info_ptr
) {
164 PngDecoderState
* state
= static_cast<PngDecoderState
*>(
165 png_get_progressive_ptr(png_ptr
));
167 int bit_depth
, color_type
, interlace_type
, compression_type
;
170 png_get_IHDR(png_ptr
, info_ptr
, &w
, &h
, &bit_depth
, &color_type
,
171 &interlace_type
, &compression_type
, &filter_type
);
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
);
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.
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
);
195 // The '!= 0' is for silencing a Windows compiler warning.
196 bool input_has_alpha
= ((color_type
& PNG_COLOR_MASK_ALPHA
) != 0);
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;
204 // Convert 16-bit to 8-bit.
206 png_set_strip_16(png_ptr
);
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;
214 case PNGCodec::FORMAT_RGBA
:
215 state
->output_channels
= 4;
216 png_set_add_alpha(png_ptr
, 0xFF, PNG_FILLER_AFTER
);
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
);
223 case PNGCodec::FORMAT_SkBitmap
:
224 state
->output_channels
= 4;
225 png_set_add_alpha(png_ptr
, 0xFF, PNG_FILLER_AFTER
);
229 switch (state
->output_format
) {
230 case PNGCodec::FORMAT_RGB
:
231 state
->output_channels
= 3;
232 png_set_strip_alpha(png_ptr
);
234 case PNGCodec::FORMAT_RGBA
:
235 state
->output_channels
= 4;
237 case PNGCodec::FORMAT_BGRA
:
238 state
->output_channels
= 4;
239 png_set_bgr(png_ptr
);
241 case PNGCodec::FORMAT_SkBitmap
:
242 state
->output_channels
= 4;
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
);
252 // Deal with gamma and keep it under our control.
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
);
259 png_set_gamma(png_ptr
, kDefaultGamma
, gamma
);
261 png_set_gamma(png_ptr
, kDefaultGamma
, kInverseGamma
);
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);
272 // Tell libpng to send us rows for interlaced pngs.
273 if (interlace_type
== PNG_INTERLACE_ADAM7
)
274 png_set_interlace_handling(png_ptr
);
276 png_read_update_info(png_ptr
, info_ptr
);
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
);
288 void DecodeRowCallback(png_struct
* png_ptr
, png_byte
* new_row
,
289 png_uint_32 row_num
, int pass
) {
291 return; // Interlaced image; row didn't change this pass.
293 PngDecoderState
* state
= static_cast<PngDecoderState
*>(
294 png_get_progressive_ptr(png_ptr
));
296 if (static_cast<int>(row_num
) > state
->height
) {
297 NOTREACHED() << "Invalid row";
301 unsigned char* base
= NULL
;
303 base
= reinterpret_cast<unsigned char*>(state
->bitmap
->getAddr32(0, 0));
304 else if (state
->output
)
305 base
= &state
->output
->front();
307 unsigned char* dest
= &base
[state
->width
* state
->output_channels
* row_num
];
308 png_progressive_combine_row(png_ptr
, dest
, new_row
);
311 void DecodeEndCallback(png_struct
* png_ptr
, png_info
* info
) {
312 PngDecoderState
* state
= static_cast<PngDecoderState
*>(
313 png_get_progressive_ptr(png_ptr
));
315 // Mark the image as complete, this will tell the Decode function that we
316 // have successfully found the end of the data.
320 // Automatically destroys the given read structs on destruction to make
321 // cleanup and error handling code cleaner.
322 class PngReadStructDestroyer
{
324 PngReadStructDestroyer(png_struct
** ps
, png_info
** pi
) : ps_(ps
), pi_(pi
) {
326 ~PngReadStructDestroyer() {
327 png_destroy_read_struct(ps_
, pi_
, NULL
);
332 DISALLOW_COPY_AND_ASSIGN(PngReadStructDestroyer
);
335 // Automatically destroys the given write structs on destruction to make
336 // cleanup and error handling code cleaner.
337 class PngWriteStructDestroyer
{
339 explicit PngWriteStructDestroyer(png_struct
** ps
) : ps_(ps
), pi_(0) {
341 ~PngWriteStructDestroyer() {
342 png_destroy_write_struct(ps_
, pi_
);
344 void SetInfoStruct(png_info
** pi
) {
350 DISALLOW_COPY_AND_ASSIGN(PngWriteStructDestroyer
);
353 bool BuildPNGStruct(const unsigned char* input
, size_t input_size
,
354 png_struct
** png_ptr
, png_info
** info_ptr
) {
356 return false; // Input data too small to be a png
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)
362 *png_ptr
= png_create_read_struct(PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
366 *info_ptr
= png_create_info_struct(*png_ptr
);
368 png_destroy_read_struct(png_ptr
, NULL
, NULL
);
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.
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);
383 void LogLibPNGDecodeWarning(png_structp png_ptr
, png_const_charp warning_msg
) {
384 DLOG(ERROR
) << "libpng decode warning: " << warning_msg
;
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);
392 void LogLibPNGEncodeWarning(png_structp png_ptr
, png_const_charp warning_msg
) {
393 DLOG(ERROR
) << "libpng encode warning: " << warning_msg
;
399 bool PNGCodec::Decode(const unsigned char* input
, size_t input_size
,
400 ColorFormat format
, std::vector
<unsigned char>* output
,
402 png_struct
* png_ptr
= NULL
;
403 png_info
* info_ptr
= NULL
;
404 if (!BuildPNGStruct(input
, input_size
, &png_ptr
, &info_ptr
))
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.
415 PngDecoderState
state(format
, output
);
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
,
422 const_cast<unsigned char*>(input
),
426 // Fed it all the data but the library didn't think we got all the data, so
427 // this file must be truncated.
438 bool PNGCodec::Decode(const unsigned char* input
, size_t input_size
,
441 png_struct
* png_ptr
= NULL
;
442 png_info
* info_ptr
= NULL
;
443 if (!BuildPNGStruct(input
, input_size
, &png_ptr
, &info_ptr
))
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.
454 PngDecoderState
state(bitmap
);
456 png_set_progressive_read_fn(png_ptr
, &state
, &DecodeInfoCallback
,
457 &DecodeRowCallback
, &DecodeEndCallback
);
458 png_process_data(png_ptr
,
460 const_cast<unsigned char*>(input
),
467 // Set the bitmap's opaqueness based on what we saw.
468 bitmap
->setIsOpaque(state
.is_opaque
);
474 SkBitmap
* PNGCodec::CreateSkBitmapFromBGRAFormat(
475 std::vector
<unsigned char>& bgra
, int width
, int height
) {
476 SkBitmap
* bitmap
= new SkBitmap();
477 bitmap
->setConfig(SkBitmap::kARGB_8888_Config
, width
, height
);
478 bitmap
->allocPixels();
481 unsigned char* bitmap_data
=
482 reinterpret_cast<unsigned char*>(bitmap
->getAddr32(0, 0));
483 for (int i
= width
* height
* 4 - 4; i
>= 0; i
-= 4) {
484 unsigned char alpha
= bgra
[i
+ 3];
485 if (!opaque
&& alpha
!= 255) {
488 bitmap_data
[i
+ 3] = alpha
;
489 bitmap_data
[i
] = (bgra
[i
] * alpha
) >> 8;
490 bitmap_data
[i
+ 1] = (bgra
[i
+ 1] * alpha
) >> 8;
491 bitmap_data
[i
+ 2] = (bgra
[i
+ 2] * alpha
) >> 8;
494 bitmap
->setIsOpaque(opaque
);
498 // Encoder --------------------------------------------------------------------
500 // This section of the code is based on nsPNGEncoder.cpp in Mozilla
501 // (Copyright 2005 Google Inc.)
505 // Passed around as the io_ptr in the png structs so our callbacks know where
507 struct PngEncoderState
{
508 explicit PngEncoderState(std::vector
<unsigned char>* o
) : out(o
) {}
509 std::vector
<unsigned char>* out
;
512 // Called by libpng to flush its internal buffer to ours.
513 void EncoderWriteCallback(png_structp png
, png_bytep data
, png_size_t size
) {
514 PngEncoderState
* state
= static_cast<PngEncoderState
*>(png_get_io_ptr(png
));
517 size_t old_size
= state
->out
->size();
518 state
->out
->resize(old_size
+ size
);
519 memcpy(&(*state
->out
)[old_size
], data
, size
);
522 void FakeFlushCallback(png_structp png
) {
523 // We don't need to perform any flushing since we aren't doing real IO, but
524 // we're required to provide this function by libpng.
527 void ConvertBGRAtoRGB(const unsigned char* bgra
, int pixel_width
,
528 unsigned char* rgb
, bool* is_opaque
) {
529 for (int x
= 0; x
< pixel_width
; x
++) {
530 const unsigned char* pixel_in
= &bgra
[x
* 4];
531 unsigned char* pixel_out
= &rgb
[x
* 3];
532 pixel_out
[0] = pixel_in
[2];
533 pixel_out
[1] = pixel_in
[1];
534 pixel_out
[2] = pixel_in
[0];
538 #ifdef PNG_TEXT_SUPPORTED
539 class CommentWriter
{
541 explicit CommentWriter(const std::vector
<PNGCodec::Comment
>& comments
)
542 : comments_(comments
),
543 png_text_(new png_text
[comments
.size()]) {
544 for (size_t i
= 0; i
< comments
.size(); ++i
)
545 AddComment(i
, comments
[i
]);
549 for (size_t i
= 0; i
< comments_
.size(); ++i
) {
550 free(png_text_
[i
].key
);
551 free(png_text_
[i
].text
);
557 return !comments_
.empty();
560 png_text
* get_png_text() {
565 return static_cast<int>(comments_
.size());
569 void AddComment(size_t pos
, const PNGCodec::Comment
& comment
) {
570 png_text_
[pos
].compression
= PNG_TEXT_COMPRESSION_NONE
;
571 // A PNG comment's key can only be 79 characters long.
572 DCHECK(comment
.key
.length() < 79);
573 png_text_
[pos
].key
= base::strdup(comment
.key
.substr(0, 78).c_str());
574 png_text_
[pos
].text
= base::strdup(comment
.text
.c_str());
575 png_text_
[pos
].text_length
= comment
.text
.length();
576 #ifdef PNG_iTXt_SUPPORTED
577 png_text_
[pos
].itxt_length
= 0;
578 png_text_
[pos
].lang
= 0;
579 png_text_
[pos
].lang_key
= 0;
583 DISALLOW_COPY_AND_ASSIGN(CommentWriter
);
585 const std::vector
<PNGCodec::Comment
> comments_
;
588 #endif // PNG_TEXT_SUPPORTED
590 // The type of functions usable for converting between pixel formats.
591 typedef void (*FormatConverter
)(const unsigned char* in
, int w
,
592 unsigned char* out
, bool* is_opaque
);
594 // libpng uses a wacky setjmp-based API, which makes the compiler nervous.
595 // We constrain all of the calls we make to libpng where the setjmp() is in
596 // place to this function.
597 // Returns true on success.
598 bool DoLibpngWrite(png_struct
* png_ptr
, png_info
* info_ptr
,
599 PngEncoderState
* state
,
600 int width
, int height
, int row_byte_width
,
601 const unsigned char* input
, int compression_level
,
602 int png_output_color_type
, int output_color_components
,
603 FormatConverter converter
,
604 const std::vector
<PNGCodec::Comment
>& comments
) {
605 #ifdef PNG_TEXT_SUPPORTED
606 CommentWriter
comment_writer(comments
);
608 unsigned char* row_buffer
= NULL
;
610 // Make sure to not declare any locals here -- locals in the presence
611 // of setjmp() in C++ code makes gcc complain.
613 if (setjmp(png_jmpbuf(png_ptr
))) {
618 png_set_compression_level(png_ptr
, compression_level
);
620 // Set our callback for libpng to give us the data.
621 png_set_write_fn(png_ptr
, state
, EncoderWriteCallback
, FakeFlushCallback
);
622 png_set_error_fn(png_ptr
, NULL
, LogLibPNGEncodeError
, LogLibPNGEncodeWarning
);
624 png_set_IHDR(png_ptr
, info_ptr
, width
, height
, 8, png_output_color_type
,
625 PNG_INTERLACE_NONE
, PNG_COMPRESSION_TYPE_DEFAULT
,
626 PNG_FILTER_TYPE_DEFAULT
);
628 #ifdef PNG_TEXT_SUPPORTED
629 if (comment_writer
.HasComments()) {
630 png_set_text(png_ptr
, info_ptr
, comment_writer
.get_png_text(),
631 comment_writer
.size());
635 png_write_info(png_ptr
, info_ptr
);
638 // No conversion needed, give the data directly to libpng.
639 for (int y
= 0; y
< height
; y
++) {
640 png_write_row(png_ptr
,
641 const_cast<unsigned char*>(&input
[y
* row_byte_width
]));
644 // Needs conversion using a separate buffer.
645 row_buffer
= new unsigned char[width
* output_color_components
];
646 for (int y
= 0; y
< height
; y
++) {
647 converter(&input
[y
* row_byte_width
], width
, row_buffer
, NULL
);
648 png_write_row(png_ptr
, row_buffer
);
653 png_write_end(png_ptr
, info_ptr
);
660 bool PNGCodec::Encode(const unsigned char* input
, ColorFormat format
,
661 const Size
& size
, int row_byte_width
,
662 bool discard_transparency
,
663 const std::vector
<Comment
>& comments
,
664 std::vector
<unsigned char>* output
) {
665 return PNGCodec::EncodeWithCompressionLevel(input
, format
, size
,
667 discard_transparency
,
668 comments
, Z_DEFAULT_COMPRESSION
,
673 bool PNGCodec::EncodeWithCompressionLevel(const unsigned char* input
,
674 ColorFormat format
, const Size
& size
,
676 bool discard_transparency
,
677 const std::vector
<Comment
>& comments
,
678 int compression_level
,
679 std::vector
<unsigned char>* output
) {
680 // Run to convert an input row into the output row format, NULL means no
681 // conversion is necessary.
682 FormatConverter converter
= NULL
;
684 int input_color_components
, output_color_components
;
685 int png_output_color_type
;
688 input_color_components
= 3;
689 output_color_components
= 3;
690 png_output_color_type
= PNG_COLOR_TYPE_RGB
;
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
= ConvertRGBAtoRGB
;
700 output_color_components
= 4;
701 png_output_color_type
= PNG_COLOR_TYPE_RGB_ALPHA
;
707 input_color_components
= 4;
708 if (discard_transparency
) {
709 output_color_components
= 3;
710 png_output_color_type
= PNG_COLOR_TYPE_RGB
;
711 converter
= ConvertBGRAtoRGB
;
713 output_color_components
= 4;
714 png_output_color_type
= PNG_COLOR_TYPE_RGB_ALPHA
;
715 converter
= ConvertBetweenBGRAandRGBA
;
719 case FORMAT_SkBitmap
:
720 input_color_components
= 4;
721 if (discard_transparency
) {
722 output_color_components
= 3;
723 png_output_color_type
= PNG_COLOR_TYPE_RGB
;
724 converter
= ConvertSkiatoRGB
;
726 output_color_components
= 4;
727 png_output_color_type
= PNG_COLOR_TYPE_RGB_ALPHA
;
728 converter
= ConvertSkiatoRGBA
;
733 NOTREACHED() << "Unknown pixel format";
737 // Row stride should be at least as long as the length of the data.
738 DCHECK(input_color_components
* size
.width() <= row_byte_width
);
740 png_struct
* png_ptr
= png_create_write_struct(PNG_LIBPNG_VER_STRING
,
744 PngWriteStructDestroyer
destroyer(&png_ptr
);
745 png_info
* info_ptr
= png_create_info_struct(png_ptr
);
748 destroyer
.SetInfoStruct(&info_ptr
);
752 PngEncoderState
state(output
);
753 bool success
= DoLibpngWrite(png_ptr
, info_ptr
, &state
,
754 size
.width(), size
.height(), row_byte_width
,
755 input
, compression_level
, png_output_color_type
,
756 output_color_components
, converter
, comments
);
762 bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap
& input
,
763 bool discard_transparency
,
764 std::vector
<unsigned char>* output
) {
765 static const int bbp
= 4;
767 SkAutoLockPixels
lock_input(input
);
770 DCHECK(input
.bytesPerPixel() == bbp
);
771 DCHECK(static_cast<int>(input
.rowBytes()) >= input
.width() * bbp
);
773 return Encode(reinterpret_cast<unsigned char*>(input
.getAddr32(0, 0)),
774 FORMAT_SkBitmap
, Size(input
.width(), input
.height()),
775 static_cast<int>(input
.rowBytes()), discard_transparency
,
776 std::vector
<Comment
>(), output
);
779 PNGCodec::Comment::Comment(const std::string
& k
, const std::string
& t
)
783 PNGCodec::Comment::~Comment() {