| 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
|
|
|