Index: base/gfx/png_encoder.cc |
=================================================================== |
--- base/gfx/png_encoder.cc (revision 27832) |
+++ base/gfx/png_encoder.cc (working copy) |
@@ -1,240 +0,0 @@ |
-// Copyright (c) 2006-2008 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/basictypes.h" |
-#include "base/gfx/png_encoder.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) |
-#include <png.h> |
-#else |
-#include "third_party/libpng/png.h" |
-#endif |
-} |
- |
-namespace { |
- |
-// Converts BGRA->RGBA and RGBA->BGRA. |
-void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width, |
- unsigned char* output) { |
- 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) { |
- for (int x = 0; x < pixel_width; x++) { |
- const unsigned char* pixel_in = &rgba[x * 4]; |
- unsigned char* pixel_out = &rgb[x * 3]; |
- pixel_out[0] = pixel_in[0]; |
- pixel_out[1] = pixel_in[1]; |
- pixel_out[2] = pixel_in[2]; |
- } |
-} |
- |
-} // namespace |
- |
-// 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 PNGEncoder::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 PNGEncoder::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(), |
- PNGEncoder::FORMAT_RGBA, input.width(), input.height(), |
- input.width() * bbp, discard_transparency, output); |
-} |