Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(283)

Unified Diff: ui/gfx/codec/png_codec.cc

Issue 2944633002: Use SkPngEncoder in gfx jpeg_codec (Closed)
Patch Set: Cast Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/gfx/codec/png_codec.h ('k') | ui/gfx/codec/vector_wstream.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/gfx/codec/png_codec.cc
diff --git a/ui/gfx/codec/png_codec.cc b/ui/gfx/codec/png_codec.cc
index fe4020596fc9c3ba32609719060a727554b07e81..f2176e92024a67d3c605567745c6eca49beb096c 100644
--- a/ui/gfx/codec/png_codec.cc
+++ b/ui/gfx/codec/png_codec.cc
@@ -13,60 +13,14 @@
#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/skia/include/encode/SkPngEncoder.h"
#include "third_party/zlib/zlib.h"
+#include "ui/gfx/codec/vector_wstream.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/skia_util.h"
namespace gfx {
-namespace {
-
-// Converts BGRA->RGBA and RGBA->BGRA.
-void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width,
- unsigned char* output, bool* is_opaque) {
- for (int x = 0; x < pixel_width; x++) {
- const unsigned char* pixel_in = &input[x * 4];
- unsigned char* pixel_out = &output[x * 4];
- pixel_out[0] = pixel_in[2];
- pixel_out[1] = pixel_in[1];
- pixel_out[2] = pixel_in[0];
- pixel_out[3] = pixel_in[3];
- }
-}
-
-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]);
- 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);
- }
- }
-}
-
-void ConvertSkiaToRGBA(const unsigned char* skia, int pixel_width,
- unsigned char* rgba, bool* is_opaque) {
- gfx::ConvertSkiaToRGBA(skia, pixel_width, rgba);
-}
-
-} // namespace
-
// Decoder --------------------------------------------------------------------
//
// This code is based on WebKit libpng interface (PNGImageDecoder), which is
@@ -369,15 +323,6 @@ 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
@@ -454,287 +399,65 @@ bool PNGCodec::Decode(const unsigned char* input, size_t input_size,
}
// Encoder --------------------------------------------------------------------
-//
-// This section of the code is based on nsPNGEncoder.cpp in Mozilla
-// (Copyright 2005 Google Inc.)
namespace {
-// Passed around as the io_ptr in the png structs so our callbacks know where
-// to write data.
-struct PngEncoderState {
- explicit PngEncoderState(std::vector<unsigned char>* o) : out(o) {}
- std::vector<unsigned char>* out;
-};
-
-// Called by libpng to flush its internal buffer to ours.
-void EncoderWriteCallback(png_structp png, png_bytep data, png_size_t size) {
- PngEncoderState* state = static_cast<PngEncoderState*>(png_get_io_ptr(png));
- DCHECK(state->out);
-
- size_t old_size = state->out->size();
- state->out->resize(old_size + size);
- memcpy(&(*state->out)[old_size], data, size);
-}
-
-void FakeFlushCallback(png_structp png) {
- // We don't need to perform any flushing since we aren't doing real IO, but
- // we're required to provide this function by libpng.
-}
-
-void ConvertBGRAtoRGB(const unsigned char* bgra, int pixel_width,
- unsigned char* rgb, bool* is_opaque) {
- for (int x = 0; x < pixel_width; x++) {
- const unsigned char* pixel_in = &bgra[x * 4];
- unsigned char* pixel_out = &rgb[x * 3];
- pixel_out[0] = pixel_in[2];
- pixel_out[1] = pixel_in[1];
- pixel_out[2] = pixel_in[0];
+static void AddComments(SkPngEncoder::Options& options,
+ const std::vector<PNGCodec::Comment>& comments) {
+ std::vector<const char*> comment_pointers;
+ std::vector<size_t> comment_sizes;
+ for (const auto& comment : comments) {
+ comment_pointers.push_back(comment.key.c_str());
+ comment_pointers.push_back(comment.text.c_str());
+ comment_sizes.push_back(comment.key.length() + 1);
+ comment_sizes.push_back(comment.text.length() + 1);
}
+ options.fComments = SkDataTable::MakeCopyArrays(
+ (void const* const*)comment_pointers.data(), comment_sizes.data(),
+ static_cast<int>(comment_pointers.size()));
}
-#ifdef PNG_TEXT_SUPPORTED
-class CommentWriter {
- public:
- explicit CommentWriter(const std::vector<PNGCodec::Comment>& comments)
- : comments_(comments),
- png_text_(new png_text[comments.size()]) {
- for (size_t i = 0; i < comments.size(); ++i)
- AddComment(i, comments[i]);
- }
-
- ~CommentWriter() {
- for (size_t i = 0; i < comments_.size(); ++i) {
- free(png_text_[i].key);
- free(png_text_[i].text);
- }
- delete [] png_text_;
- }
-
- bool HasComments() {
- return !comments_.empty();
- }
-
- png_text* get_png_text() {
- return png_text_;
- }
-
- int size() {
- return static_cast<int>(comments_.size());
- }
-
- private:
- void AddComment(size_t pos, const PNGCodec::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].text_length = comment.text.length();
-#ifdef PNG_iTXt_SUPPORTED
- png_text_[pos].itxt_length = 0;
- png_text_[pos].lang = 0;
- png_text_[pos].lang_key = 0;
-#endif
- }
-
- DISALLOW_COPY_AND_ASSIGN(CommentWriter);
-
- const std::vector<PNGCodec::Comment> comments_;
- png_text* png_text_;
-};
-#endif // PNG_TEXT_SUPPORTED
-
-// The type of functions usable for converting between pixel formats.
-typedef void (*FormatConverter)(const unsigned char* in, int w,
- unsigned char* out, bool* is_opaque);
-
-// libpng uses a wacky setjmp-based API, which makes the compiler nervous.
-// We constrain all of the calls we make to libpng where the setjmp() is in
-// place to this function.
-// Returns true on success.
-bool DoLibpngWrite(png_struct* png_ptr, png_info* info_ptr,
- PngEncoderState* state,
- int width, int height, int row_byte_width,
- const unsigned char* input, int compression_level,
- int png_output_color_type, int output_color_components,
- FormatConverter converter,
- const std::vector<PNGCodec::Comment>& comments) {
-#ifdef PNG_TEXT_SUPPORTED
- CommentWriter comment_writer(comments);
-#endif
- unsigned char* row_buffer = NULL;
-
- // Make sure to not declare any locals here -- locals in the presence
- // of setjmp() in C++ code makes gcc complain.
-
- if (setjmp(png_jmpbuf(png_ptr))) {
- delete[] row_buffer;
- return false;
- }
-
- png_set_compression_level(png_ptr, compression_level);
-
- // 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,
- PNG_FILTER_TYPE_DEFAULT);
-
-#ifdef PNG_TEXT_SUPPORTED
- if (comment_writer.HasComments()) {
- png_set_text(png_ptr, info_ptr, comment_writer.get_png_text(),
- comment_writer.size());
- }
-#endif
-
- png_write_info(png_ptr, info_ptr);
+} // namespace
- if (!converter) {
- // No conversion needed, give the data directly to libpng.
- for (int y = 0; y < height; y ++) {
- png_write_row(png_ptr,
- const_cast<unsigned char*>(&input[y * row_byte_width]));
- }
- } else {
- // Needs conversion using a separate buffer.
- row_buffer = new unsigned char[width * output_color_components];
- for (int y = 0; y < height; y ++) {
- converter(&input[y * row_byte_width], width, row_buffer, NULL);
- png_write_row(png_ptr, row_buffer);
- }
- delete[] row_buffer;
- }
+static bool EncodeSkPixmap(const SkPixmap& src,
+ const std::vector<PNGCodec::Comment>& comments,
+ std::vector<unsigned char>* output,
+ int zlib_level) {
+ output->clear();
+ VectorWStream dst(output);
- png_write_end(png_ptr, info_ptr);
- return true;
+ SkPngEncoder::Options options;
+ AddComments(options, comments);
+ options.fZLibLevel = zlib_level;
+ return SkPngEncoder::Encode(&dst, src, options);
}
-bool EncodeWithCompressionLevel(const unsigned char* input,
- PNGCodec::ColorFormat format,
- const Size& size,
- int row_byte_width,
- bool discard_transparency,
- const std::vector<PNGCodec::Comment>& comments,
- int compression_level,
- std::vector<unsigned char>* output) {
- // Run to convert an input row into the output row format, NULL means no
- // conversion is necessary.
- FormatConverter converter = NULL;
-
- int input_color_components, output_color_components;
- int png_output_color_type;
- switch (format) {
- case PNGCodec::FORMAT_RGBA:
- input_color_components = 4;
- if (discard_transparency) {
- output_color_components = 3;
- png_output_color_type = PNG_COLOR_TYPE_RGB;
- converter = ConvertRGBAtoRGB;
- } else {
- output_color_components = 4;
- png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
- converter = NULL;
- }
- break;
-
- case PNGCodec::FORMAT_BGRA:
- input_color_components = 4;
- if (discard_transparency) {
- output_color_components = 3;
- png_output_color_type = PNG_COLOR_TYPE_RGB;
- converter = ConvertBGRAtoRGB;
- } else {
- output_color_components = 4;
- png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
- converter = ConvertBetweenBGRAandRGBA;
- }
- 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";
+static bool EncodeSkPixmap(const SkPixmap& src,
+ bool discard_transparency,
+ const std::vector<PNGCodec::Comment>& comments,
+ std::vector<unsigned char>* output,
+ int zlib_level) {
+ if (discard_transparency) {
+ SkImageInfo opaque_info = src.info().makeAlphaType(kOpaque_SkAlphaType);
+ SkBitmap copy;
+ if (!copy.tryAllocPixels(opaque_info)) {
return false;
+ }
+ SkPixmap opaque_pixmap;
+ bool success = copy.peekPixels(&opaque_pixmap);
+ DCHECK(success);
+ // The following step does the unpremul as we set the dst alpha type to be
+ // kUnpremul_SkAlphaType. Later, because opaque_pixmap has
+ // kOpaque_SkAlphaType, we'll discard the transparency as required.
+ success =
+ src.readPixels(opaque_info.makeAlphaType(kUnpremul_SkAlphaType),
+ opaque_pixmap.writable_addr(), opaque_pixmap.rowBytes());
+ DCHECK(success);
+ return EncodeSkPixmap(opaque_pixmap, comments, output, zlib_level);
}
-
- // Row stride should be at least as long as the length of the data.
- DCHECK(input_color_components * size.width() <= row_byte_width);
-
- PngWriteStructInfo si;
- si.png_ptr_ = png_create_write_struct(PNG_LIBPNG_VER_STRING,
- NULL, NULL, NULL);
- if (!si.png_ptr_)
- return false;
-
- si.info_ptr_ = png_create_info_struct(si.png_ptr_);
- if (!si.info_ptr_)
- return false;
-
- output->clear();
-
- PngEncoderState state(output);
- bool success = DoLibpngWrite(si.png_ptr_, si.info_ptr_, &state,
- size.width(), size.height(), row_byte_width,
- input, compression_level, png_output_color_type,
- output_color_components, converter, comments);
-
- 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.
-
- 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);
+ return EncodeSkPixmap(src, comments, output, zlib_level);
}
-
-} // namespace
-
// static
bool PNGCodec::Encode(const unsigned char* input,
ColorFormat format,
@@ -743,43 +466,65 @@ bool PNGCodec::Encode(const unsigned char* input,
bool discard_transparency,
const std::vector<Comment>& comments,
std::vector<unsigned char>* output) {
- return EncodeWithCompressionLevel(input,
- format,
- size,
- row_byte_width,
- discard_transparency,
- comments,
- Z_DEFAULT_COMPRESSION,
- output);
+ // Initialization required for Windows although the switch covers all cases.
+ SkColorType colorType = kN32_SkColorType;
+ switch (format) {
+ case FORMAT_RGBA:
+ colorType = kRGBA_8888_SkColorType;
+ break;
+ case FORMAT_BGRA:
+ colorType = kBGRA_8888_SkColorType;
+ break;
+ case FORMAT_SkBitmap:
+ colorType = kN32_SkColorType;
+ break;
+ }
+ auto alphaType =
+ format == FORMAT_SkBitmap ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
+ SkImageInfo info =
+ SkImageInfo::Make(size.width(), size.height(), colorType, alphaType);
+ SkPixmap src(info, input, row_byte_width);
+ return EncodeSkPixmap(src, discard_transparency, comments, output,
+ DEFAULT_ZLIB_COMPRESSION);
+}
+
+static bool EncodeSkBitmap(const SkBitmap& input,
+ bool discard_transparency,
+ std::vector<unsigned char>* output,
+ int zlib_level) {
+ SkPixmap src;
+ if (!input.peekPixels(&src)) {
+ return false;
+ }
+ return EncodeSkPixmap(src, discard_transparency,
+ std::vector<PNGCodec::Comment>(), output, zlib_level);
}
// static
bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input,
bool discard_transparency,
std::vector<unsigned char>* output) {
- return InternalEncodeSkBitmap(input,
- discard_transparency,
- Z_DEFAULT_COMPRESSION,
- output);
+ return EncodeSkBitmap(input, discard_transparency, output,
+ DEFAULT_ZLIB_COMPRESSION);
}
// static
bool PNGCodec::EncodeA8SkBitmap(const SkBitmap& input,
std::vector<unsigned char>* output) {
- return InternalEncodeSkBitmap(input,
- false,
- Z_DEFAULT_COMPRESSION,
- output);
+ DCHECK_EQ(input.colorType(), kAlpha_8_SkColorType);
+ auto info = input.info()
+ .makeColorType(kGray_8_SkColorType)
+ .makeAlphaType(kOpaque_SkAlphaType);
+ SkPixmap src(info, input.getAddr(0, 0), input.rowBytes());
+ return EncodeSkPixmap(src, std::vector<PNGCodec::Comment>(), output,
+ DEFAULT_ZLIB_COMPRESSION);
}
// static
bool PNGCodec::FastEncodeBGRASkBitmap(const SkBitmap& input,
bool discard_transparency,
std::vector<unsigned char>* output) {
- return InternalEncodeSkBitmap(input,
- discard_transparency,
- Z_BEST_SPEED,
- output);
+ return EncodeSkBitmap(input, discard_transparency, output, Z_BEST_SPEED);
}
PNGCodec::Comment::Comment(const std::string& k, const std::string& t)
« no previous file with comments | « ui/gfx/codec/png_codec.h ('k') | ui/gfx/codec/vector_wstream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698