diff options
Diffstat (limited to 'WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp')
-rw-r--r-- | WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp | 182 |
1 files changed, 38 insertions, 144 deletions
diff --git a/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp b/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp index a2e8760..9fc82c4 100644 --- a/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp +++ b/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2006-2009, Google Inc. All rights reserved. - * + * Copyright (c) 2010, Google Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above @@ -14,7 +14,7 @@ * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -29,172 +29,66 @@ */ #include "config.h" - -#include "IntSize.h" -#include "OwnArrayPtr.h" #include "PNGImageEncoder.h" -#include "Vector.h" +#include "IntSize.h" #include "SkBitmap.h" #include "SkUnPreMultiply.h" - extern "C" { #include "png.h" } namespace WebCore { -// Converts BGRA->RGBA and RGBA->BGRA. -static void convertBetweenBGRAandRGBA(const unsigned char* input, int numberOfPixels, - unsigned char* output) +static void writeOutput(png_structp png, png_bytep data, png_size_t size) { - for (int x = 0; x < numberOfPixels; x++) { - const unsigned char* pixelIn = &input[x * 4]; - unsigned char* pixelOut = &output[x * 4]; - pixelOut[0] = pixelIn[2]; - pixelOut[1] = pixelIn[1]; - pixelOut[2] = pixelIn[0]; - pixelOut[3] = pixelIn[3]; - } + static_cast<Vector<unsigned char>*>(png->io_ptr)->append(data, size); } -// Converts BGRA->RGBA and RGBA->BGRA and undoes alpha premultiplication. -static void preMultipliedBGRAtoRGBA(const unsigned char* input, int numberOfPixels, - unsigned char* output) +static void preMultipliedBGRAtoRGBA(const SkPMColor* input, int pixels, unsigned char* output) { - SkBitmap inputBitmap; - inputBitmap.setConfig(SkBitmap::kARGB_8888_Config, numberOfPixels, 1); - inputBitmap.setPixels(const_cast<unsigned char*>(input)); - for (int x = 0; x < numberOfPixels; x++) { - uint32_t srcPixel = *inputBitmap.getAddr32(x, 0); - SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(srcPixel); - unsigned char* pixelOut = &output[x * 4]; - pixelOut[0] = SkColorGetR(unmultiplied); - pixelOut[1] = SkColorGetG(unmultiplied); - pixelOut[2] = SkColorGetB(unmultiplied); - pixelOut[3] = SkColorGetA(unmultiplied); + while (pixels-- > 0) { + SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(*input++); + *output++ = SkColorGetR(unmultiplied); + *output++ = SkColorGetG(unmultiplied); + *output++ = SkColorGetB(unmultiplied); + *output++ = SkColorGetA(unmultiplied); } } - -// Encoder -------------------------------------------------------------------- -// -// This section of the code is based on nsPNGEncoder.cpp in Mozilla -// (Copyright 2005 Google Inc.) - -// Passed around as the io_ptr in the png structs so our callbacks know where -// to write data. -struct PNGEncoderState { - PNGEncoderState(Vector<unsigned char>* o) : m_out(o) {} - Vector<unsigned char>* m_out; -}; - -// Called by libpng to flush its internal buffer to ours. -void encoderWriteCallback(png_structp png, png_bytep data, png_size_t size) +bool PNGImageEncoder::encode(const SkBitmap& bitmap, Vector<unsigned char>* output) { - PNGEncoderState* state = static_cast<PNGEncoderState*>(png_get_io_ptr(png)); - ASSERT(state->m_out); + if (bitmap.config() != SkBitmap::kARGB_8888_Config) + return false; // Only support ARGB 32 bpp skia bitmaps. - size_t oldSize = state->m_out->size(); - state->m_out->resize(oldSize + size); - memcpy(&(*state->m_out)[oldSize], data, size); -} - -// 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) - : m_pngStruct(ps) - , m_pngInfo(pi) { - } - - ~PNGWriteStructDestroyer() { - png_destroy_write_struct(m_pngStruct, m_pngInfo); - } - -private: - png_struct** m_pngStruct; - png_info** m_pngInfo; -}; - -static bool encodeImpl(const unsigned char* input, - const IntSize& size, - int bytesPerRow, - Vector<unsigned char>* output, - void (*conversionFunc)(const unsigned char*, int, unsigned char*) - ) -{ - int inputColorComponents = 4; - int outputColorComponents = 4; - int pngOutputColorType = PNG_COLOR_TYPE_RGB_ALPHA; - IntSize imageSize(size); + SkAutoLockPixels bitmapLock(bitmap); + IntSize imageSize(bitmap.width(), bitmap.height()); imageSize.clampNegativeToZero(); + Vector<unsigned char> row; - // Row stride should be at least as long as the length of the data. - if (inputColorComponents * imageSize.width() > bytesPerRow) { - ASSERT(false); - return false; - } - - png_struct* pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (!pngPtr) - return false; - - png_info* infoPtr = png_create_info_struct(pngPtr); - if (!infoPtr) { - png_destroy_write_struct(&pngPtr, NULL); + png_struct* png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + png_info* info = png_create_info_struct(png); + if (!png || !info || setjmp(png_jmpbuf(png))) { + png_destroy_write_struct(png ? &png : 0, info ? &info : 0); return false; } - PNGWriteStructDestroyer destroyer(&pngPtr, &infoPtr); - - if (setjmp(png_jmpbuf(pngPtr))) { - // 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(pngPtr, &state, encoderWriteCallback, NULL); - - png_set_IHDR(pngPtr, infoPtr, imageSize.width(), imageSize.height(), 8, pngOutputColorType, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - png_write_info(pngPtr, infoPtr); - OwnArrayPtr<unsigned char> rowPixels(new unsigned char[imageSize.width() * outputColorComponents]); - for (int y = 0; y < imageSize.height(); y ++) { - conversionFunc(&input[y * bytesPerRow], imageSize.width(), rowPixels.get()); - png_write_row(pngPtr, rowPixels.get()); + png_set_write_fn(png, output, writeOutput, 0); + png_set_IHDR(png, info, imageSize.width(), imageSize.height(), + 8, PNG_COLOR_TYPE_RGB_ALPHA, 0, 0, 0); + png_write_info(png, info); + + const SkPMColor* pixels = static_cast<SkPMColor*>(bitmap.getPixels()); + row.resize(imageSize.width() * bitmap.bytesPerPixel()); + for (int y = 0; y < imageSize.height(); ++y) { + preMultipliedBGRAtoRGBA(pixels, imageSize.width(), row.data()); + png_write_row(png, row.data()); + pixels += imageSize.width(); } - png_write_end(pngPtr, infoPtr); + png_write_end(png, info); + png_destroy_write_struct(&png, &info); return true; } - -// static -bool PNGImageEncoder::encode(const SkBitmap& image, Vector<unsigned char>* output) -{ - if (image.config() != SkBitmap::kARGB_8888_Config) - return false; // Only support ARGB at 8 bpp now. - - image.lockPixels(); - bool result = encodeImpl(static_cast<unsigned char*>( - image.getPixels()), IntSize(image.width(), image.height()), - image.rowBytes(), output, preMultipliedBGRAtoRGBA); - image.unlockPixels(); - return result; -} - -// static -bool PNGImageEncoder::encode(const unsigned char* input, const IntSize& size, - int bytesPerRow, - Vector<unsigned char>* output) -{ - return encodeImpl(input, size, bytesPerRow, output, convertBetweenBGRAandRGBA); -} - -} // namespace WebCore +} // namespace WebCore |