| Index: app/gfx/codec/png_codec.cc
|
| ===================================================================
|
| --- app/gfx/codec/png_codec.cc (revision 0)
|
| +++ app/gfx/codec/png_codec.cc (working copy)
|
| @@ -1,11 +1,13 @@
|
| -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
| +// Copyright (c) 2009 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 "base/gfx/png_decoder.h"
|
| +#include "app/gfx/codec/png_codec.h"
|
|
|
| #include "base/logging.h"
|
| +#include "base/scoped_ptr.h"
|
| #include "third_party/skia/include/core/SkBitmap.h"
|
| +#include "third_party/skia/include/core/SkUnPreMultiply.h"
|
|
|
| extern "C" {
|
| #if defined(USE_SYSTEM_LIBPNG)
|
| @@ -15,6 +17,8 @@
|
| #endif
|
| }
|
|
|
| +namespace gfx {
|
| +
|
| namespace {
|
|
|
| // Converts BGRA->RGBA and RGBA->BGRA.
|
| @@ -57,7 +61,7 @@
|
|
|
| class PngDecoderState {
|
| public:
|
| - PngDecoderState(PNGDecoder::ColorFormat ofmt, std::vector<unsigned char>* o)
|
| + PngDecoderState(PNGCodec::ColorFormat ofmt, std::vector<unsigned char>* o)
|
| : output_format(ofmt),
|
| output_channels(0),
|
| output(o),
|
| @@ -67,7 +71,7 @@
|
| done(false) {
|
| }
|
|
|
| - PNGDecoder::ColorFormat output_format;
|
| + PNGCodec::ColorFormat output_format;
|
| int output_channels;
|
|
|
| std::vector<unsigned char>* output;
|
| @@ -84,7 +88,7 @@
|
| bool done;
|
|
|
| private:
|
| - DISALLOW_EVIL_CONSTRUCTORS(PngDecoderState);
|
| + DISALLOW_COPY_AND_ASSIGN(PngDecoderState);
|
| };
|
|
|
| void ConvertRGBtoRGBA(const unsigned char* rgb, int pixel_width,
|
| @@ -176,15 +180,15 @@
|
| // Pick our row format converter necessary for this data.
|
| if (channels == 3) {
|
| switch (state->output_format) {
|
| - case PNGDecoder::FORMAT_RGB:
|
| + case PNGCodec::FORMAT_RGB:
|
| state->row_converter = NULL; // no conversion necessary
|
| state->output_channels = 3;
|
| break;
|
| - case PNGDecoder::FORMAT_RGBA:
|
| + case PNGCodec::FORMAT_RGBA:
|
| state->row_converter = &ConvertRGBtoRGBA;
|
| state->output_channels = 4;
|
| break;
|
| - case PNGDecoder::FORMAT_BGRA:
|
| + case PNGCodec::FORMAT_BGRA:
|
| state->row_converter = &ConvertRGBtoBGRA;
|
| state->output_channels = 4;
|
| break;
|
| @@ -194,15 +198,15 @@
|
| }
|
| } else if (channels == 4) {
|
| switch (state->output_format) {
|
| - case PNGDecoder::FORMAT_RGB:
|
| + case PNGCodec::FORMAT_RGB:
|
| state->row_converter = &ConvertRGBAtoRGB;
|
| state->output_channels = 3;
|
| break;
|
| - case PNGDecoder::FORMAT_RGBA:
|
| + case PNGCodec::FORMAT_RGBA:
|
| state->row_converter = NULL; // no conversion necessary
|
| state->output_channels = 4;
|
| break;
|
| - case PNGDecoder::FORMAT_BGRA:
|
| + case PNGCodec::FORMAT_BGRA:
|
| state->row_converter = &ConvertBetweenBGRAandRGBA;
|
| state->output_channels = 4;
|
| break;
|
| @@ -264,9 +268,9 @@
|
| } // namespace
|
|
|
| // static
|
| -bool PNGDecoder::Decode(const unsigned char* input, size_t input_size,
|
| - ColorFormat format, std::vector<unsigned char>* output,
|
| - int* w, int* h) {
|
| +bool PNGCodec::Decode(const unsigned char* input, size_t input_size,
|
| + ColorFormat format, std::vector<unsigned char>* output,
|
| + int* w, int* h) {
|
| if (input_size < 8)
|
| return false; // Input data too small to be a png
|
|
|
| @@ -317,15 +321,15 @@
|
| }
|
|
|
| // static
|
| -bool PNGDecoder::Decode(const std::vector<unsigned char>* data,
|
| - SkBitmap* bitmap) {
|
| +bool PNGCodec::Decode(const std::vector<unsigned char>* data,
|
| + SkBitmap* bitmap) {
|
| DCHECK(bitmap);
|
| if (!data || data->empty())
|
| return false;
|
| int width, height;
|
| std::vector<unsigned char> decoded_data;
|
| - if (PNGDecoder::Decode(&data->front(), data->size(), PNGDecoder::FORMAT_BGRA,
|
| - &decoded_data, &width, &height)) {
|
| + if (PNGCodec::Decode(&data->front(), data->size(), PNGCodec::FORMAT_BGRA,
|
| + &decoded_data, &width, &height)) {
|
| bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
|
| bitmap->allocPixels();
|
| unsigned char* bitmap_data =
|
| @@ -351,8 +355,8 @@
|
| return false;
|
| }
|
|
|
| -//static
|
| -SkBitmap* PNGDecoder::CreateSkBitmapFromBGRAFormat(
|
| +// static
|
| +SkBitmap* PNGCodec::CreateSkBitmapFromBGRAFormat(
|
| std::vector<unsigned char>& bgra, int width, int height) {
|
| SkBitmap* bitmap = new SkBitmap();
|
| bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
|
| @@ -375,3 +379,199 @@
|
| bitmap->setIsOpaque(opaque);
|
| return bitmap;
|
| }
|
| +
|
| +// 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 {
|
| + 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 ConvertBGRAtoRGB(const unsigned char* bgra, int pixel_width,
|
| + unsigned char* rgb) {
|
| + 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];
|
| + }
|
| +}
|
| +
|
| +// Automatically destroys the given write structs on destruction to make
|
| +// cleanup and error handling code cleaner.
|
| +class PngWriteStructDestroyer {
|
| + public:
|
| + PngWriteStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) {
|
| + }
|
| + ~PngWriteStructDestroyer() {
|
| + png_destroy_write_struct(ps_, pi_);
|
| + }
|
| + private:
|
| + png_struct** ps_;
|
| + png_info** pi_;
|
| +
|
| + DISALLOW_EVIL_CONSTRUCTORS(PngWriteStructDestroyer);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +// static
|
| +bool PNGCodec::Encode(const unsigned char* input, ColorFormat format,
|
| + int w, int h, int row_byte_width,
|
| + bool discard_transparency,
|
| + std::vector<unsigned char>* output) {
|
| + // Run to convert an input row into the output row format, NULL means no
|
| + // conversion is necessary.
|
| + void (*converter)(const unsigned char* in, int w, unsigned char* out) = NULL;
|
| +
|
| + int input_color_components, output_color_components;
|
| + int png_output_color_type;
|
| + switch (format) {
|
| + case FORMAT_RGB:
|
| + input_color_components = 3;
|
| + output_color_components = 3;
|
| + png_output_color_type = PNG_COLOR_TYPE_RGB;
|
| + discard_transparency = false;
|
| + break;
|
| +
|
| + case 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 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;
|
| +
|
| + 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 * w <= row_byte_width);
|
| +
|
| + png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
| + png_voidp_NULL,
|
| + png_error_ptr_NULL,
|
| + png_error_ptr_NULL);
|
| + if (!png_ptr)
|
| + return false;
|
| + png_info* info_ptr = png_create_info_struct(png_ptr);
|
| + if (!info_ptr) {
|
| + png_destroy_write_struct(&png_ptr, NULL);
|
| + return false;
|
| + }
|
| + PngWriteStructDestroyer 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;
|
| + }
|
| +
|
| + // Set our callback for libpng to give us the data.
|
| + PngEncoderState state(output);
|
| + png_set_write_fn(png_ptr, &state, EncoderWriteCallback, NULL);
|
| +
|
| + png_set_IHDR(png_ptr, info_ptr, w, h, 8, png_output_color_type,
|
| + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
| + PNG_FILTER_TYPE_DEFAULT);
|
| + png_write_info(png_ptr, info_ptr);
|
| +
|
| + if (!converter) {
|
| + // No conversion needed, give the data directly to libpng.
|
| + for (int y = 0; y < h; y ++)
|
| + png_write_row(png_ptr,
|
| + const_cast<unsigned char*>(&input[y * row_byte_width]));
|
| + } else {
|
| + // Needs conversion using a separate buffer.
|
| + unsigned char* row = new unsigned char[w * output_color_components];
|
| + for (int y = 0; y < h; y ++) {
|
| + converter(&input[y * row_byte_width], w, row);
|
| + png_write_row(png_ptr, row);
|
| + }
|
| + delete[] row;
|
| + }
|
| +
|
| + png_write_end(png_ptr, info_ptr);
|
| + return true;
|
| +}
|
| +
|
| +// static
|
| +bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input,
|
| + bool discard_transparency,
|
| + std::vector<unsigned char>* output) {
|
| + static const int bbp = 4;
|
| +
|
| + SkAutoLockPixels lock_input(input);
|
| + DCHECK(input.empty() || input.bytesPerPixel() == bbp);
|
| +
|
| + // SkBitmaps are premultiplied, we need to unpremultiply them.
|
| + scoped_array<unsigned char> divided(
|
| + new unsigned char[input.width() * input.height() * bbp]);
|
| +
|
| + int i = 0;
|
| + for (int y = 0; y < input.height(); y++) {
|
| + for (int x = 0; x < input.width(); x++) {
|
| + uint32 pixel = input.getAddr32(0, y)[x];
|
| +
|
| + int alpha = SkColorGetA(pixel);
|
| + if (alpha != 0 && alpha != 255) {
|
| + SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel);
|
| + divided[i + 0] = SkColorGetR(unmultiplied);
|
| + divided[i + 1] = SkColorGetG(unmultiplied);
|
| + divided[i + 2] = SkColorGetB(unmultiplied);
|
| + divided[i + 3] = alpha;
|
| + } else {
|
| + divided[i + 0] = SkColorGetR(pixel);
|
| + divided[i + 1] = SkColorGetG(pixel);
|
| + divided[i + 2] = SkColorGetB(pixel);
|
| + divided[i + 3] = alpha;
|
| + }
|
| + i += bbp;
|
| + }
|
| + }
|
| +
|
| + return Encode(divided.get(),
|
| + PNGCodec::FORMAT_RGBA, input.width(), input.height(),
|
| + input.width() * bbp, discard_transparency, output);
|
| +}
|
| +
|
| +} // namespace gfx
|
|
|
| Property changes on: app/gfx/codec/png_codec.cc
|
| ___________________________________________________________________
|
| Added: svn:mergeinfo
|
| Merged /branches/chrome_webkit_merge_branch/base/gfx/png_decoder.cc:r69-2775
|
|
|
|
|