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

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

Issue 243076: Move the JPEG and PNG codecs from base/gfx to app/gfx/codec. Move the classes... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 3 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
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

Powered by Google App Engine
This is Rietveld 408576698