diff options
Diffstat (limited to 'WebCore/platform/image-encoders')
4 files changed, 251 insertions, 160 deletions
diff --git a/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp b/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp new file mode 100644 index 0000000..d4e1481 --- /dev/null +++ b/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp @@ -0,0 +1,153 @@ +/* + * 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 + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * 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 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JPEGImageEncoder.h" + +#include "IntSize.h" +#include "SkBitmap.h" +#include "SkUnPreMultiply.h" +#include "SkColorPriv.h" +extern "C" { +#include <stdio.h> // jpeglib.h needs stdio.h FILE +#include "jpeglib.h" +#include <setjmp.h> +} + +namespace WebCore { + +struct JPEGOutputBuffer : public jpeg_destination_mgr { + Vector<unsigned char>* output; + Vector<unsigned char> buffer; +}; + +static void prepareOutput(j_compress_ptr cinfo) +{ + JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest); + const size_t internalBufferSize = 8192; + out->buffer.resize(internalBufferSize); + out->next_output_byte = out->buffer.data(); + out->free_in_buffer = out->buffer.size(); +} + +static boolean writeOutput(j_compress_ptr cinfo) +{ + JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest); + out->output->append(out->buffer.data(), out->buffer.size()); + out->next_output_byte = out->buffer.data(); + out->free_in_buffer = out->buffer.size(); + return TRUE; +} + +static void finishOutput(j_compress_ptr cinfo) +{ + JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest); + const size_t size = out->buffer.size() - out->free_in_buffer; + out->output->append(out->buffer.data(), size); +} + +static void handleError(j_common_ptr common) +{ + jmp_buf* jumpBufferPtr = static_cast<jmp_buf*>(common->client_data); + longjmp(*jumpBufferPtr, -1); +} + +// FIXME: is alpha unpremultiplication correct, or should the alpha channel +// be ignored? See bug http://webkit.org/b/40147. +void preMultipliedBGRAtoRGB(const SkPMColor* input, unsigned int pixels, unsigned char* output) +{ + static const SkUnPreMultiply::Scale* scale = SkUnPreMultiply::GetScaleTable(); + + for (; pixels-- > 0; ++input) { + const unsigned alpha = SkGetPackedA32(*input); + if ((alpha != 0) && (alpha != 255)) { + *output++ = SkUnPreMultiply::ApplyScale(scale[alpha], SkGetPackedR32(*input)); + *output++ = SkUnPreMultiply::ApplyScale(scale[alpha], SkGetPackedG32(*input)); + *output++ = SkUnPreMultiply::ApplyScale(scale[alpha], SkGetPackedB32(*input)); + } else { + *output++ = SkGetPackedR32(*input); + *output++ = SkGetPackedG32(*input); + *output++ = SkGetPackedB32(*input); + } + } +} + +bool JPEGImageEncoder::encode(const SkBitmap& bitmap, int quality, Vector<unsigned char>* output) +{ + if (bitmap.config() != SkBitmap::kARGB_8888_Config) + return false; // Only support ARGB 32 bpp skia bitmaps. + + SkAutoLockPixels bitmapLock(bitmap); + IntSize imageSize(bitmap.width(), bitmap.height()); + imageSize.clampNegativeToZero(); + JPEGOutputBuffer destination; + destination.output = output; + Vector<JSAMPLE> row; + + jpeg_compress_struct cinfo; + jpeg_error_mgr error; + cinfo.err = jpeg_std_error(&error); + error.error_exit = handleError; + jmp_buf jumpBuffer; + cinfo.client_data = &jumpBuffer; + + if (setjmp(jumpBuffer)) { + jpeg_destroy_compress(&cinfo); + return false; + } + + jpeg_create_compress(&cinfo); + cinfo.dest = &destination; + cinfo.dest->init_destination = prepareOutput; + cinfo.dest->empty_output_buffer = writeOutput; + cinfo.dest->term_destination = finishOutput; + cinfo.image_height = imageSize.height(); + cinfo.image_width = imageSize.width(); + cinfo.in_color_space = JCS_RGB; + cinfo.input_components = 3; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + jpeg_start_compress(&cinfo, TRUE); + + const SkPMColor* pixels = static_cast<SkPMColor*>(bitmap.getPixels()); + row.resize(cinfo.image_width * cinfo.input_components); + while (cinfo.next_scanline < cinfo.image_height) { + preMultipliedBGRAtoRGB(pixels, cinfo.image_width, row.data()); + jpeg_write_scanlines(&cinfo, row.dataSlot(), 1); + pixels += cinfo.image_width; + } + + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + return true; +} + +} // namespace WebCore diff --git a/WebCore/platform/image-encoders/skia/JPEGImageEncoder.h b/WebCore/platform/image-encoders/skia/JPEGImageEncoder.h new file mode 100644 index 0000000..f2ac52d --- /dev/null +++ b/WebCore/platform/image-encoders/skia/JPEGImageEncoder.h @@ -0,0 +1,51 @@ +/* + * 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 + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * 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 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JPEGImageEncoder_h +#define JPEGImageEncoder_h + +#include "Vector.h" + +class SkBitmap; + +namespace WebCore { + +class JPEGImageEncoder { +public: + // Encode the input bitmap with a compression quality in [0-100]. + static bool encode(const SkBitmap&, int quality, Vector<unsigned char>*); + + // For callers: provide a reasonable compression quality default. + enum Quality { DefaultCompressionQuality = 92 }; +}; + +} // namespace WebCore + +#endif 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 diff --git a/WebCore/platform/image-encoders/skia/PNGImageEncoder.h b/WebCore/platform/image-encoders/skia/PNGImageEncoder.h index b5865d2..b8dfec3 100644 --- a/WebCore/platform/image-encoders/skia/PNGImageEncoder.h +++ b/WebCore/platform/image-encoders/skia/PNGImageEncoder.h @@ -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 @@ -33,23 +33,16 @@ #include "Vector.h" -class IntSize; class SkBitmap; namespace WebCore { - // Interface for encoding PNG data. This is a wrapper around libpng. - class PNGImageEncoder { - public: - // Encodes the specific SkBitmap into the supplied vector. - static bool encode(const SkBitmap&, WTF::Vector<unsigned char>* output); - - // Encodes the specified image data into the supplied vector. - // w, h give the size of the image and bytes_per_row gives the bytes - // per row. - static bool encode(const unsigned char* input, const IntSize& size, int bytesPerRow, WTF::Vector<unsigned char>* output); - }; +// Interface for encoding PNG data. This is a wrapper around libpng. +class PNGImageEncoder { +public: + static bool encode(const SkBitmap&, Vector<unsigned char>* output); +}; -} // namespace WebCore +} // namespace WebCore #endif |