Index: sky/tools/imagediff/image_diff_png.cc |
diff --git a/ui/gfx/codec/png_codec.cc b/sky/tools/imagediff/image_diff_png.cc |
similarity index 53% |
copy from ui/gfx/codec/png_codec.cc |
copy to sky/tools/imagediff/image_diff_png.cc |
index 068a193b334cb7317a4a7eff673c7b4336bb0475..e9d98c8c907a421d4c1d1a884a428dbe1c4294a0 100644 |
--- a/ui/gfx/codec/png_codec.cc |
+++ b/sky/tools/imagediff/image_diff_png.cc |
@@ -1,23 +1,46 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Copyright 2013 The Chromium Authors. All rights reserved. |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "ui/gfx/codec/png_codec.h" |
+#include "sky/tools/imagediff/image_diff_png.h" |
+ |
+#include <stdlib.h> |
+#include <string.h> |
#include "base/logging.h" |
-#include "base/strings/string_util.h" |
+#include "build/build_config.h" |
#include "third_party/libpng/png.h" |
-#include "third_party/skia/include/core/SkBitmap.h" |
-#include "third_party/skia/include/core/SkColorPriv.h" |
-#include "third_party/skia/include/core/SkUnPreMultiply.h" |
#include "third_party/zlib/zlib.h" |
-#include "ui/gfx/size.h" |
-#include "ui/gfx/skia_util.h" |
-namespace gfx { |
+namespace image_diff_png { |
+// This is a duplicate of ui/gfx/codec/png_codec.cc, after removing code related |
+// to Skia, that we can use when running layout tests with minimal dependencies. |
namespace { |
+enum ColorFormat { |
+ // 3 bytes per pixel (packed), in RGB order regardless of endianness. |
+ // This is the native JPEG format. |
+ FORMAT_RGB, |
+ |
+ // 4 bytes per pixel, in RGBA order in memory regardless of endianness. |
+ FORMAT_RGBA, |
+ |
+ // 4 bytes per pixel, in BGRA order in memory regardless of endianness. |
+ // This is the default Windows DIB order. |
+ FORMAT_BGRA, |
+ |
+ // 4 bytes per pixel, in pre-multiplied kARGB_8888_Config format. For use |
+ // with directly writing to a skia bitmap. |
+ FORMAT_SkBitmap |
+}; |
+ |
+// Represents a comment in the tEXt ancillary chunk of the png. |
+struct Comment { |
+ std::string key; |
+ std::string text; |
+}; |
+ |
// Converts BGRA->RGBA and RGBA->BGRA. |
void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width, |
unsigned char* output, bool* is_opaque) { |
@@ -33,35 +56,15 @@ void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width, |
void ConvertRGBAtoRGB(const unsigned char* rgba, int pixel_width, |
unsigned char* rgb, bool* is_opaque) { |
- for (int x = 0; x < pixel_width; x++) |
- memcpy(&rgb[x * 3], &rgba[x * 4], 3); |
-} |
- |
-void ConvertSkiaToRGB(const unsigned char* skia, int pixel_width, |
- unsigned char* rgb, bool* is_opaque) { |
for (int x = 0; x < pixel_width; x++) { |
- const uint32_t pixel_in = *reinterpret_cast<const uint32_t*>(&skia[x * 4]); |
+ const unsigned char* pixel_in = &rgba[x * 4]; |
unsigned char* pixel_out = &rgb[x * 3]; |
- |
- int alpha = SkGetPackedA32(pixel_in); |
- if (alpha != 0 && alpha != 255) { |
- SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel_in); |
- pixel_out[0] = SkColorGetR(unmultiplied); |
- pixel_out[1] = SkColorGetG(unmultiplied); |
- pixel_out[2] = SkColorGetB(unmultiplied); |
- } else { |
- pixel_out[0] = SkGetPackedR32(pixel_in); |
- pixel_out[1] = SkGetPackedG32(pixel_in); |
- pixel_out[2] = SkGetPackedB32(pixel_in); |
- } |
+ pixel_out[0] = pixel_in[0]; |
+ pixel_out[1] = pixel_in[1]; |
+ pixel_out[2] = pixel_in[2]; |
} |
} |
-void ConvertSkiaToRGBA(const unsigned char* skia, int pixel_width, |
- unsigned char* rgba, bool* is_opaque) { |
- gfx::ConvertSkiaToRGBA(skia, pixel_width, rgba); |
-} |
- |
} // namespace |
// Decoder -------------------------------------------------------------------- |
@@ -79,77 +82,61 @@ const double kInverseGamma = 1.0 / kDefaultGamma; |
class PngDecoderState { |
public: |
// Output is a vector<unsigned char>. |
- PngDecoderState(PNGCodec::ColorFormat ofmt, std::vector<unsigned char>* o) |
+ PngDecoderState(ColorFormat ofmt, std::vector<unsigned char>* o) |
: output_format(ofmt), |
output_channels(0), |
- bitmap(NULL), |
is_opaque(true), |
output(o), |
+ row_converter(NULL), |
width(0), |
height(0), |
done(false) { |
} |
- // Output is an SkBitmap. |
- explicit PngDecoderState(SkBitmap* skbitmap) |
- : output_format(PNGCodec::FORMAT_SkBitmap), |
- output_channels(0), |
- bitmap(skbitmap), |
- is_opaque(true), |
- output(NULL), |
- width(0), |
- height(0), |
- done(false) { |
- } |
- |
- PNGCodec::ColorFormat output_format; |
+ ColorFormat output_format; |
int output_channels; |
- // An incoming SkBitmap to write to. If NULL, we write to output instead. |
- SkBitmap* bitmap; |
- |
// Used during the reading of an SkBitmap. Defaults to true until we see a |
// pixel with anything other than an alpha of 255. |
bool is_opaque; |
- // The other way to decode output, where we write into an intermediary buffer |
- // instead of directly to an SkBitmap. |
+ // An intermediary buffer for decode output. |
std::vector<unsigned char>* output; |
+ // Called to convert a row from the library to the correct output format. |
+ // When NULL, no conversion is necessary. |
+ void (*row_converter)(const unsigned char* in, int w, unsigned char* out, |
+ bool* is_opaque); |
+ |
// Size of the image, set in the info callback. |
int width; |
int height; |
// Set to true when we've found the end of the data. |
bool done; |
- |
- private: |
- DISALLOW_COPY_AND_ASSIGN(PngDecoderState); |
}; |
-// User transform (passed to libpng) which converts a row decoded by libpng to |
-// Skia format. Expects the row to have 4 channels, otherwise there won't be |
-// enough room in |data|. |
-void ConvertRGBARowToSkia(png_structp png_ptr, |
- png_row_infop row_info, |
- png_bytep data) { |
- const int channels = row_info->channels; |
- DCHECK_EQ(channels, 4); |
- |
- PngDecoderState* state = |
- static_cast<PngDecoderState*>(png_get_user_transform_ptr(png_ptr)); |
- DCHECK(state) << "LibPNG user transform pointer is NULL"; |
- |
- unsigned char* const end = data + row_info->rowbytes; |
- for (unsigned char* p = data; p < end; p += channels) { |
- uint32_t* sk_pixel = reinterpret_cast<uint32_t*>(p); |
- const unsigned char alpha = p[channels - 1]; |
- if (alpha != 255) { |
- state->is_opaque = false; |
- *sk_pixel = SkPreMultiplyARGB(alpha, p[0], p[1], p[2]); |
- } else { |
- *sk_pixel = SkPackARGB32(alpha, p[0], p[1], p[2]); |
- } |
+void ConvertRGBtoRGBA(const unsigned char* rgb, int pixel_width, |
+ unsigned char* rgba, bool* is_opaque) { |
+ for (int x = 0; x < pixel_width; x++) { |
+ const unsigned char* pixel_in = &rgb[x * 3]; |
+ unsigned char* pixel_out = &rgba[x * 4]; |
+ pixel_out[0] = pixel_in[0]; |
+ pixel_out[1] = pixel_in[1]; |
+ pixel_out[2] = pixel_in[2]; |
+ pixel_out[3] = 0xff; |
+ } |
+} |
+ |
+void ConvertRGBtoBGRA(const unsigned char* rgb, int pixel_width, |
+ unsigned char* bgra, bool* is_opaque) { |
+ for (int x = 0; x < pixel_width; x++) { |
+ const unsigned char* pixel_in = &rgb[x * 3]; |
+ unsigned char* pixel_out = &bgra[x * 4]; |
+ pixel_out[0] = pixel_in[2]; |
+ pixel_out[1] = pixel_in[1]; |
+ pixel_out[2] = pixel_in[0]; |
+ pixel_out[3] = 0xff; |
} |
} |
@@ -160,7 +147,7 @@ void DecodeInfoCallback(png_struct* png_ptr, png_info* info_ptr) { |
png_get_progressive_ptr(png_ptr)); |
int bit_depth, color_type, interlace_type, compression_type; |
- int filter_type; |
+ int filter_type, channels; |
png_uint_32 w, h; |
png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, |
&interlace_type, &compression_type, &filter_type); |
@@ -177,68 +164,19 @@ void DecodeInfoCallback(png_struct* png_ptr, png_info* info_ptr) { |
state->width = static_cast<int>(w); |
state->height = static_cast<int>(h); |
- // The following png_set_* calls have to be done in the order dictated by |
- // the libpng docs. Please take care if you have to move any of them. This |
- // is also why certain things are done outside of the switch, even though |
- // they look like they belong there. |
- |
// Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. |
if (color_type == PNG_COLOR_TYPE_PALETTE || |
(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)) |
png_set_expand(png_ptr); |
- // The '!= 0' is for silencing a Windows compiler warning. |
- bool input_has_alpha = ((color_type & PNG_COLOR_MASK_ALPHA) != 0); |
- |
// Transparency for paletted images. |
- if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { |
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) |
png_set_expand(png_ptr); |
- input_has_alpha = true; |
- } |
// Convert 16-bit to 8-bit. |
if (bit_depth == 16) |
png_set_strip_16(png_ptr); |
- // Pick our row format converter necessary for this data. |
- if (!input_has_alpha) { |
- switch (state->output_format) { |
- case PNGCodec::FORMAT_RGB: |
- state->output_channels = 3; |
- break; |
- case PNGCodec::FORMAT_RGBA: |
- state->output_channels = 4; |
- png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); |
- break; |
- case PNGCodec::FORMAT_BGRA: |
- state->output_channels = 4; |
- png_set_bgr(png_ptr); |
- png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); |
- break; |
- case PNGCodec::FORMAT_SkBitmap: |
- state->output_channels = 4; |
- png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); |
- break; |
- } |
- } else { |
- switch (state->output_format) { |
- case PNGCodec::FORMAT_RGB: |
- state->output_channels = 3; |
- png_set_strip_alpha(png_ptr); |
- break; |
- case PNGCodec::FORMAT_RGBA: |
- state->output_channels = 4; |
- break; |
- case PNGCodec::FORMAT_BGRA: |
- state->output_channels = 4; |
- png_set_bgr(png_ptr); |
- break; |
- case PNGCodec::FORMAT_SkBitmap: |
- state->output_channels = 4; |
- break; |
- } |
- } |
- |
// Expand grayscale to RGB. |
if (color_type == PNG_COLOR_TYPE_GRAY || |
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) |
@@ -256,49 +194,79 @@ void DecodeInfoCallback(png_struct* png_ptr, png_info* info_ptr) { |
png_set_gamma(png_ptr, kDefaultGamma, kInverseGamma); |
} |
- // Setting the user transforms here (as opposed to inside the switch above) |
- // because all png_set_* calls need to be done in the specific order |
- // mandated by libpng. |
- if (state->output_format == PNGCodec::FORMAT_SkBitmap) { |
- png_set_read_user_transform_fn(png_ptr, ConvertRGBARowToSkia); |
- png_set_user_transform_info(png_ptr, state, 0, 0); |
- } |
- |
// Tell libpng to send us rows for interlaced pngs. |
if (interlace_type == PNG_INTERLACE_ADAM7) |
png_set_interlace_handling(png_ptr); |
+ // Update our info now |
png_read_update_info(png_ptr, info_ptr); |
+ channels = png_get_channels(png_ptr, info_ptr); |
- if (state->bitmap) { |
- state->bitmap->allocN32Pixels(state->width, state->height); |
- } else if (state->output) { |
- state->output->resize( |
- state->width * state->output_channels * state->height); |
+ // Pick our row format converter necessary for this data. |
+ if (channels == 3) { |
+ switch (state->output_format) { |
+ case FORMAT_RGB: |
+ state->row_converter = NULL; // no conversion necessary |
+ state->output_channels = 3; |
+ break; |
+ case FORMAT_RGBA: |
+ state->row_converter = &ConvertRGBtoRGBA; |
+ state->output_channels = 4; |
+ break; |
+ case FORMAT_BGRA: |
+ state->row_converter = &ConvertRGBtoBGRA; |
+ state->output_channels = 4; |
+ break; |
+ default: |
+ NOTREACHED() << "Unknown output format"; |
+ break; |
+ } |
+ } else if (channels == 4) { |
+ switch (state->output_format) { |
+ case FORMAT_RGB: |
+ state->row_converter = &ConvertRGBAtoRGB; |
+ state->output_channels = 3; |
+ break; |
+ case FORMAT_RGBA: |
+ state->row_converter = NULL; // no conversion necessary |
+ state->output_channels = 4; |
+ break; |
+ case FORMAT_BGRA: |
+ state->row_converter = &ConvertBetweenBGRAandRGBA; |
+ state->output_channels = 4; |
+ break; |
+ default: |
+ NOTREACHED() << "Unknown output format"; |
+ break; |
+ } |
+ } else { |
+ NOTREACHED() << "Unknown input channels"; |
+ longjmp(png_jmpbuf(png_ptr), 1); |
} |
+ |
+ state->output->resize( |
+ state->width * state->output_channels * state->height); |
} |
void DecodeRowCallback(png_struct* png_ptr, png_byte* new_row, |
png_uint_32 row_num, int pass) { |
- if (!new_row) |
- return; // Interlaced image; row didn't change this pass. |
- |
PngDecoderState* state = static_cast<PngDecoderState*>( |
png_get_progressive_ptr(png_ptr)); |
+ DCHECK(pass == 0); |
if (static_cast<int>(row_num) > state->height) { |
NOTREACHED() << "Invalid row"; |
return; |
} |
unsigned char* base = NULL; |
- if (state->bitmap) |
- base = reinterpret_cast<unsigned char*>(state->bitmap->getAddr32(0, 0)); |
- else if (state->output) |
- base = &state->output->front(); |
+ base = &state->output->front(); |
unsigned char* dest = &base[state->width * state->output_channels * row_num]; |
- png_progressive_combine_row(png_ptr, dest, new_row); |
+ if (state->row_converter) |
+ state->row_converter(new_row, state->width, dest, &state->is_opaque); |
+ else |
+ memcpy(dest, new_row, state->width * state->output_channels); |
} |
void DecodeEndCallback(png_struct* png_ptr, png_info* info) { |
@@ -322,25 +290,6 @@ class PngReadStructDestroyer { |
private: |
png_struct** ps_; |
png_info** pi_; |
- DISALLOW_COPY_AND_ASSIGN(PngReadStructDestroyer); |
-}; |
- |
-// Automatically destroys the given write structs on destruction to make |
-// cleanup and error handling code cleaner. |
-class PngWriteStructDestroyer { |
- public: |
- explicit PngWriteStructDestroyer(png_struct** ps) : ps_(ps), pi_(0) { |
- } |
- ~PngWriteStructDestroyer() { |
- png_destroy_write_struct(ps_, pi_); |
- } |
- void SetInfoStruct(png_info** pi) { |
- pi_ = pi; |
- } |
- private: |
- png_struct** ps_; |
- png_info** pi_; |
- DISALLOW_COPY_AND_ASSIGN(PngWriteStructDestroyer); |
}; |
bool BuildPNGStruct(const unsigned char* input, size_t input_size, |
@@ -365,31 +314,10 @@ bool BuildPNGStruct(const unsigned char* input, size_t input_size, |
return true; |
} |
-// Libpng user error and warning functions which allows us to print libpng |
-// errors and warnings using Chrome's logging facilities instead of stderr. |
- |
-void LogLibPNGDecodeError(png_structp png_ptr, png_const_charp error_msg) { |
- DLOG(ERROR) << "libpng decode error: " << error_msg; |
- longjmp(png_jmpbuf(png_ptr), 1); |
-} |
- |
-void LogLibPNGDecodeWarning(png_structp png_ptr, png_const_charp warning_msg) { |
- DLOG(ERROR) << "libpng decode warning: " << warning_msg; |
-} |
- |
-void LogLibPNGEncodeError(png_structp png_ptr, png_const_charp error_msg) { |
- DLOG(ERROR) << "libpng encode error: " << error_msg; |
- longjmp(png_jmpbuf(png_ptr), 1); |
-} |
- |
-void LogLibPNGEncodeWarning(png_structp png_ptr, png_const_charp warning_msg) { |
- DLOG(ERROR) << "libpng encode warning: " << warning_msg; |
-} |
- |
} // namespace |
// static |
-bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
+bool Decode(const unsigned char* input, size_t input_size, |
ColorFormat format, std::vector<unsigned char>* output, |
int* w, int* h) { |
png_struct* png_ptr = NULL; |
@@ -407,7 +335,6 @@ bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
PngDecoderState state(format, output); |
- png_set_error_fn(png_ptr, NULL, LogLibPNGDecodeError, LogLibPNGDecodeWarning); |
png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback, |
&DecodeRowCallback, &DecodeEndCallback); |
png_process_data(png_ptr, |
@@ -427,43 +354,6 @@ bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
return true; |
} |
-// static |
-bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
- SkBitmap* bitmap) { |
- DCHECK(bitmap); |
- png_struct* png_ptr = NULL; |
- png_info* info_ptr = NULL; |
- if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr)) |
- return false; |
- |
- PngReadStructDestroyer destroyer(&png_ptr, &info_ptr); |
- if (setjmp(png_jmpbuf(png_ptr))) { |
- // The destroyer will ensure that the structures are cleaned up in this |
- // case, even though we may get here as a jump from random parts of the |
- // PNG library called below. |
- return false; |
- } |
- |
- PngDecoderState state(bitmap); |
- |
- png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback, |
- &DecodeRowCallback, &DecodeEndCallback); |
- png_process_data(png_ptr, |
- info_ptr, |
- const_cast<unsigned char*>(input), |
- input_size); |
- |
- if (!state.done) { |
- return false; |
- } |
- |
- // Set the bitmap's opaqueness based on what we saw. |
- bitmap->setAlphaType(state.is_opaque ? |
- kOpaque_SkAlphaType : kPremul_SkAlphaType); |
- |
- return true; |
-} |
- |
// Encoder -------------------------------------------------------------------- |
// |
// This section of the code is based on nsPNGEncoder.cpp in Mozilla |
@@ -505,9 +395,18 @@ void ConvertBGRAtoRGB(const unsigned char* bgra, int pixel_width, |
} |
#ifdef PNG_TEXT_SUPPORTED |
+ |
+inline char* strdup(const char* str) { |
+#if defined(OS_WIN) |
+ return _strdup(str); |
+#else |
+ return ::strdup(str); |
+#endif |
+} |
+ |
class CommentWriter { |
public: |
- explicit CommentWriter(const std::vector<PNGCodec::Comment>& comments) |
+ explicit CommentWriter(const std::vector<Comment>& comments) |
: comments_(comments), |
png_text_(new png_text[comments.size()]) { |
for (size_t i = 0; i < comments.size(); ++i) |
@@ -535,12 +434,12 @@ class CommentWriter { |
} |
private: |
- void AddComment(size_t pos, const PNGCodec::Comment& comment) { |
+ void AddComment(size_t pos, const Comment& comment) { |
png_text_[pos].compression = PNG_TEXT_COMPRESSION_NONE; |
// A PNG comment's key can only be 79 characters long. |
DCHECK(comment.key.length() < 79); |
- png_text_[pos].key = base::strdup(comment.key.substr(0, 78).c_str()); |
- png_text_[pos].text = base::strdup(comment.text.c_str()); |
+ png_text_[pos].key = strdup(comment.key.substr(0, 78).c_str()); |
+ png_text_[pos].text = strdup(comment.text.c_str()); |
png_text_[pos].text_length = comment.text.length(); |
#ifdef PNG_iTXt_SUPPORTED |
png_text_[pos].itxt_length = 0; |
@@ -549,9 +448,7 @@ class CommentWriter { |
#endif |
} |
- DISALLOW_COPY_AND_ASSIGN(CommentWriter); |
- |
- const std::vector<PNGCodec::Comment> comments_; |
+ const std::vector<Comment> comments_; |
png_text* png_text_; |
}; |
#endif // PNG_TEXT_SUPPORTED |
@@ -570,7 +467,7 @@ bool DoLibpngWrite(png_struct* png_ptr, png_info* info_ptr, |
const unsigned char* input, int compression_level, |
int png_output_color_type, int output_color_components, |
FormatConverter converter, |
- const std::vector<PNGCodec::Comment>& comments) { |
+ const std::vector<Comment>& comments) { |
#ifdef PNG_TEXT_SUPPORTED |
CommentWriter comment_writer(comments); |
#endif |
@@ -588,7 +485,6 @@ bool DoLibpngWrite(png_struct* png_ptr, png_info* info_ptr, |
// Set our callback for libpng to give us the data. |
png_set_write_fn(png_ptr, state, EncoderWriteCallback, FakeFlushCallback); |
- png_set_error_fn(png_ptr, NULL, LogLibPNGEncodeError, LogLibPNGEncodeWarning); |
png_set_IHDR(png_ptr, info_ptr, width, height, 8, png_output_color_type, |
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, |
@@ -623,12 +519,14 @@ bool DoLibpngWrite(png_struct* png_ptr, png_info* info_ptr, |
return true; |
} |
-bool EncodeWithCompressionLevel(const unsigned char* input, |
- PNGCodec::ColorFormat format, |
- const Size& size, |
+} // namespace |
+ |
+// static |
+bool EncodeWithCompressionLevel(const unsigned char* input, ColorFormat format, |
+ const int width, const int height, |
int row_byte_width, |
bool discard_transparency, |
- const std::vector<PNGCodec::Comment>& comments, |
+ const std::vector<Comment>& comments, |
int compression_level, |
std::vector<unsigned char>* output) { |
// Run to convert an input row into the output row format, NULL means no |
@@ -638,13 +536,14 @@ bool EncodeWithCompressionLevel(const unsigned char* input, |
int input_color_components, output_color_components; |
int png_output_color_type; |
switch (format) { |
- case PNGCodec::FORMAT_RGB: |
+ case FORMAT_RGB: |
input_color_components = 3; |
output_color_components = 3; |
png_output_color_type = PNG_COLOR_TYPE_RGB; |
+ discard_transparency = false; |
break; |
- case PNGCodec::FORMAT_RGBA: |
+ case FORMAT_RGBA: |
input_color_components = 4; |
if (discard_transparency) { |
output_color_components = 3; |
@@ -657,7 +556,7 @@ bool EncodeWithCompressionLevel(const unsigned char* input, |
} |
break; |
- case PNGCodec::FORMAT_BGRA: |
+ case FORMAT_BGRA: |
input_color_components = 4; |
if (discard_transparency) { |
output_color_components = 3; |
@@ -670,141 +569,75 @@ bool EncodeWithCompressionLevel(const unsigned char* input, |
} |
break; |
- case PNGCodec::FORMAT_SkBitmap: |
- // Compare row_byte_width and size.width() to detect the format of |
- // SkBitmap. kA8_Config (1bpp) and kARGB_8888_Config (4bpp) are the two |
- // supported formats. |
- if (row_byte_width < 4 * size.width()) { |
- // Not 4bpp, so must be 1bpp. |
- // Ignore discard_transparency - it doesn't make sense in this context, |
- // since alpha is the only thing we have and it needs to be used for |
- // color intensity. |
- input_color_components = 1; |
- output_color_components = 1; |
- png_output_color_type = PNG_COLOR_TYPE_GRAY; |
- // |converter| is left as null |
- } else { |
- input_color_components = 4; |
- if (discard_transparency) { |
- output_color_components = 3; |
- png_output_color_type = PNG_COLOR_TYPE_RGB; |
- converter = ConvertSkiaToRGB; |
- } else { |
- output_color_components = 4; |
- png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; |
- converter = ConvertSkiaToRGBA; |
- } |
- } |
- break; |
- |
default: |
NOTREACHED() << "Unknown pixel format"; |
return false; |
} |
// Row stride should be at least as long as the length of the data. |
- DCHECK(input_color_components * size.width() <= row_byte_width); |
+ DCHECK(input_color_components * width <= row_byte_width); |
png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, |
NULL, NULL, NULL); |
if (!png_ptr) |
return false; |
- PngWriteStructDestroyer destroyer(&png_ptr); |
png_info* info_ptr = png_create_info_struct(png_ptr); |
- if (!info_ptr) |
+ if (!info_ptr) { |
+ png_destroy_write_struct(&png_ptr, NULL); |
return false; |
- destroyer.SetInfoStruct(&info_ptr); |
- |
- output->clear(); |
+ } |
PngEncoderState state(output); |
bool success = DoLibpngWrite(png_ptr, info_ptr, &state, |
- size.width(), size.height(), row_byte_width, |
+ width, height, row_byte_width, |
input, compression_level, png_output_color_type, |
output_color_components, converter, comments); |
+ png_destroy_write_struct(&png_ptr, &info_ptr); |
return success; |
} |
-bool InternalEncodeSkBitmap(const SkBitmap& input, |
- bool discard_transparency, |
- int compression_level, |
- std::vector<unsigned char>* output) { |
- if (input.empty() || input.isNull()) |
- return false; |
- int bpp = input.bytesPerPixel(); |
- DCHECK(bpp == 1 || bpp == 4); // We support kA8_Config and kARGB_8888_Config. |
- |
- SkAutoLockPixels lock_input(input); |
- unsigned char* inputAddr = bpp == 1 ? |
- reinterpret_cast<unsigned char*>(input.getAddr8(0, 0)) : |
- reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)); // bpp = 4 |
- return EncodeWithCompressionLevel( |
- inputAddr, |
- PNGCodec::FORMAT_SkBitmap, |
- Size(input.width(), input.height()), |
- static_cast<int>(input.rowBytes()), |
- discard_transparency, |
- std::vector<PNGCodec::Comment>(), |
- compression_level, |
- output); |
-} |
- |
- |
-} // namespace |
- |
// static |
-bool PNGCodec::Encode(const unsigned char* input, |
- ColorFormat format, |
- const Size& size, |
- int row_byte_width, |
- bool discard_transparency, |
- const std::vector<Comment>& comments, |
- std::vector<unsigned char>* output) { |
- return EncodeWithCompressionLevel(input, |
- format, |
- size, |
+bool Encode(const unsigned char* input, ColorFormat format, |
+ const int width, const int height, int row_byte_width, |
+ bool discard_transparency, |
+ const std::vector<Comment>& comments, |
+ std::vector<unsigned char>* output) { |
+ return EncodeWithCompressionLevel(input, format, width, height, |
row_byte_width, |
discard_transparency, |
- comments, |
- Z_DEFAULT_COMPRESSION, |
+ comments, Z_DEFAULT_COMPRESSION, |
output); |
} |
-// static |
-bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input, |
- bool discard_transparency, |
- std::vector<unsigned char>* output) { |
- return InternalEncodeSkBitmap(input, |
- discard_transparency, |
- Z_DEFAULT_COMPRESSION, |
- output); |
-} |
- |
-// static |
-bool PNGCodec::EncodeA8SkBitmap(const SkBitmap& input, |
- std::vector<unsigned char>* output) { |
- return InternalEncodeSkBitmap(input, |
- false, |
- Z_DEFAULT_COMPRESSION, |
- output); |
-} |
- |
-// static |
-bool PNGCodec::FastEncodeBGRASkBitmap(const SkBitmap& input, |
- bool discard_transparency, |
- std::vector<unsigned char>* output) { |
- return InternalEncodeSkBitmap(input, |
- discard_transparency, |
- Z_BEST_SPEED, |
- output); |
+// Decode a PNG into an RGBA pixel array. |
+bool DecodePNG(const unsigned char* input, size_t input_size, |
+ std::vector<unsigned char>* output, |
+ int* width, int* height) { |
+ return Decode(input, input_size, FORMAT_RGBA, output, width, height); |
} |
-PNGCodec::Comment::Comment(const std::string& k, const std::string& t) |
- : key(k), text(t) { |
+// Encode an RGBA pixel array into a PNG. |
+bool EncodeRGBAPNG(const unsigned char* input, |
+ int width, |
+ int height, |
+ int row_byte_width, |
+ std::vector<unsigned char>* output) { |
+ return Encode(input, FORMAT_RGBA, |
+ width, height, row_byte_width, false, |
+ std::vector<Comment>(), output); |
} |
-PNGCodec::Comment::~Comment() { |
+// Encode an BGRA pixel array into a PNG. |
+bool EncodeBGRAPNG(const unsigned char* input, |
+ int width, |
+ int height, |
+ int row_byte_width, |
+ bool discard_transparency, |
+ std::vector<unsigned char>* output) { |
+ return Encode(input, FORMAT_BGRA, |
+ width, height, row_byte_width, discard_transparency, |
+ std::vector<Comment>(), output); |
} |
-} // namespace gfx |
+} // image_diff_png |