diff options
author | Vikas Arora <vikasa@google.com> | 2011-07-19 18:17:09 +0530 |
---|---|---|
committer | Vikas Arora <vikasa@google.com> | 2011-07-21 17:59:13 +0530 |
commit | 8c52c218e8b00b33f837ac4891fcde3a08817169 (patch) | |
tree | 0699cc0696168ed772fb5ff4b6205c2b11438abe | |
parent | c5013e3870ecf5a7798c1857a3060d880a7bf2c3 (diff) | |
download | skia-8c52c218e8b00b33f837ac4891fcde3a08817169.tar.gz |
Add image cropping support in Skia-WebP decoder.
Implement virtual methods 'onBuildTileIndex' & 'onDecodeRegion' for
supporting image cropping for Skia-WebP image Decoder.
Utilize the native rescaling+Cropping capability of WebP-Decoder to
implement image cropping.
- Incorporated code comments from Pascal.
- Found one bug w.r.t setting SampleSize. Rectifying that in this patch.
Change-Id: Ib7b04129a65ed17f845d0600f3553b9b24846838
-rw-r--r-- | src/images/SkImageDecoder_libwebp.cpp | 174 |
1 files changed, 135 insertions, 39 deletions
diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp index 7b4a39f0f0..984331c6e8 100644 --- a/src/images/SkImageDecoder_libwebp.cpp +++ b/src/images/SkImageDecoder_libwebp.cpp @@ -30,8 +30,8 @@ #include <stdio.h> extern "C" { -// If moving libwebp out of skia source tree, path for webp headers must be updated accordingly. -// Here, we enforce using local copy in webp sub-directory. +// If moving libwebp out of skia source tree, path for webp headers must be +// updated accordingly. Here, we enforce using local copy in webp sub-directory. #include "webp/decode.h" #include "webp/decode_vp8.h" #include "webp/encode.h" @@ -92,10 +92,15 @@ public: } protected: + virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height); + virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect rect); virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode); private: bool setDecodeConfig(SkBitmap* decodedBitmap, int width, int height); + SkStream *inputStream; + int origWidth; + int origHeight; }; ////////////////////////////////////////////////////////////////////////// @@ -130,15 +135,7 @@ static bool return_false(const SkBitmap& bm, const char msg[]) { return false; // must always return false } -// Incremental WebP image decoding. Reads input buffer of 64K size iteratively -// and decodes this block to appropriate color-space as per config object. -static bool webp_idecode(SkStream* stream, SkBitmap* decodedBitmap, - int origWidth, int origHeight) { - SkAutoLockPixels alp(*decodedBitmap); - - stream->rewind(); - const uint32_t contentSize = stream->getLength(); - +static WEBP_CSP_MODE webp_decode_mode(SkBitmap* decodedBitmap) { WEBP_CSP_MODE mode = MODE_LAST; SkBitmap::Config config = decodedBitmap->config(); if (config == SkBitmap::kARGB_8888_Config) { @@ -147,33 +144,21 @@ static bool webp_idecode(SkStream* stream, SkBitmap* decodedBitmap, mode = MODE_RGBA_4444; } else if (config == SkBitmap::kRGB_565_Config) { mode = MODE_RGB_565; - } else { - return false; - } - - WebPDecoderConfig decode_config; - if (WebPInitDecoderConfig(&decode_config) == 0) { - return false; - } - - decode_config.output.colorspace = mode; - decode_config.output.u.RGBA.rgba = (uint8_t*)decodedBitmap->getPixels(); - decode_config.output.u.RGBA.stride = decodedBitmap->rowBytes(); - decode_config.output.u.RGBA.size = decodedBitmap->getSize(); - decode_config.output.is_external_memory = 1; - if (origWidth != decodedBitmap->width() || - origHeight != decodedBitmap->height()) { - decode_config.options.use_scaling = 1; - decode_config.options.scaled_width = decodedBitmap->width(); - decode_config.options.scaled_height = decodedBitmap->height(); } + return mode; +} - WebPIDecoder* idec = WebPIDecode(NULL, NULL, &decode_config); +// Incremental WebP image decoding. Reads input buffer of 64K size iteratively +// and decodes this block to appropriate color-space as per config object. +static bool webp_idecode(SkStream* stream, WebPDecoderConfig& config) { + WebPIDecoder* idec = WebPIDecode(NULL, NULL, &config); if (idec == NULL) { - WebPFreeDecBuffer(&decode_config.output); + WebPFreeDecBuffer(&config.output); return false; } + stream->rewind(); + const uint32_t contentSize = stream->getLength(); uint32_t read_buffer_size = contentSize; if (read_buffer_size > WEBP_IDECODE_BUFFER_SZ) { read_buffer_size = WEBP_IDECODE_BUFFER_SZ; @@ -182,7 +167,7 @@ static bool webp_idecode(SkStream* stream, SkBitmap* decodedBitmap, unsigned char* input = (uint8_t*)srcStorage.get(); if (input == NULL) { WebPIDelete(idec); - WebPFreeDecBuffer(&decode_config.output); + WebPFreeDecBuffer(&config.output); return false; } @@ -206,7 +191,7 @@ static bool webp_idecode(SkStream* stream, SkBitmap* decodedBitmap, } srcStorage.free(); WebPIDelete(idec); - WebPFreeDecBuffer(&decode_config.output); + WebPFreeDecBuffer(&config.output); if (bytes_remaining > 0) { return false; @@ -215,13 +200,74 @@ static bool webp_idecode(SkStream* stream, SkBitmap* decodedBitmap, } } +static bool webp_get_config_resize_crop(WebPDecoderConfig& config, + SkBitmap* decodedBitmap, + SkIRect region) { + WEBP_CSP_MODE mode = webp_decode_mode(decodedBitmap); + if (mode == MODE_LAST) { + return false; + } + + if (WebPInitDecoderConfig(&config) == 0) { + return false; + } + + config.output.colorspace = mode; + config.output.u.RGBA.rgba = (uint8_t*)decodedBitmap->getPixels(); + config.output.u.RGBA.stride = decodedBitmap->rowBytes(); + config.output.u.RGBA.size = decodedBitmap->getSize(); + config.output.is_external_memory = 1; + + config.options.use_cropping = 1; + config.options.crop_left = region.fLeft; + config.options.crop_top = region.fTop; + config.options.crop_width = region.width(); + config.options.crop_height = region.height(); + + if (region.width() != decodedBitmap->width() || + region.height() != decodedBitmap->height()) { + config.options.use_scaling = 1; + config.options.scaled_width = decodedBitmap->width(); + config.options.scaled_height = decodedBitmap->height(); + } + + return true; +} + +static bool webp_get_config_resize(WebPDecoderConfig& config, + SkBitmap* decodedBitmap, int origWidth, + int origHeight) { + WEBP_CSP_MODE mode = webp_decode_mode(decodedBitmap); + if (mode == MODE_LAST) { + return false; + } + + if (WebPInitDecoderConfig(&config) == 0) { + return false; + } + + config.output.colorspace = mode; + config.output.u.RGBA.rgba = (uint8_t*)decodedBitmap->getPixels(); + config.output.u.RGBA.stride = decodedBitmap->rowBytes(); + config.output.u.RGBA.size = decodedBitmap->getSize(); + config.output.is_external_memory = 1; + + if (origWidth != decodedBitmap->width() || + origHeight != decodedBitmap->height()) { + config.options.use_scaling = 1; + config.options.scaled_width = decodedBitmap->width(); + config.options.scaled_height = decodedBitmap->height(); + } + + return true; +} + bool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap, int width, int height) { bool hasAlpha = false; SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, hasAlpha); - // only accept prefConfig if it makes sense for us. YUV converter - // supports output in RGB565, RGBA4444 and RGBA8888 formats. + // YUV converter supports output in RGB565, RGBA4444 and RGBA8888 formats. if (hasAlpha) { if (config != SkBitmap::kARGB_4444_Config) { config = SkBitmap::kARGB_8888_Config; @@ -245,6 +291,53 @@ bool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap, return true; } +bool SkWEBPImageDecoder::onBuildTileIndex(SkStream* stream, + int *width, int *height) { + int origWidth, origHeight; + if (!webp_parse_header(stream, &origWidth, &origHeight)) { + return false; + } + + stream->rewind(); + *width = origWidth; + *height = origHeight; + + this->inputStream = stream; + this->origWidth = origWidth; + this->origHeight = origHeight; + + return true; +} + +bool SkWEBPImageDecoder::onDecodeRegion(SkBitmap* decodedBitmap, + SkIRect region) { + const int width = region.width(); + const int height = region.height(); + + const int sampleSize = this->getSampleSize(); + SkScaledBitmapSampler sampler(width, height, sampleSize); + + if (!setDecodeConfig(decodedBitmap, sampler.scaledWidth(), + sampler.scaledHeight())) { + return false; + } + + if (!this->allocPixelRef(decodedBitmap, NULL)) { + return return_false(*decodedBitmap, "allocPixelRef"); + } + + SkAutoLockPixels alp(*decodedBitmap); + + WebPDecoderConfig config; + if (!webp_get_config_resize_crop(config, decodedBitmap, region)) { + return false; + } + + // Decode the WebP image data stream using WebP incremental decoding for + // the specified cropped image-region. + return webp_idecode(this->inputStream, config); +} + bool SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap, Mode mode) { #ifdef TIME_DECODE @@ -273,12 +366,15 @@ bool SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap, return return_false(*decodedBitmap, "allocPixelRef"); } - // Decode the WebP image data stream using WebP incremental decoding. - if (!webp_idecode(stream, decodedBitmap, origWidth, origHeight)) { + SkAutoLockPixels alp(*decodedBitmap); + + WebPDecoderConfig config; + if (!webp_get_config_resize(config, decodedBitmap, origWidth, origHeight)) { return false; } - return true; + // Decode the WebP image data stream using WebP incremental decoding. + return webp_idecode(stream, config); } /////////////////////////////////////////////////////////////////////////////// |