aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVikas Arora <vikasa@google.com>2011-07-19 18:17:09 +0530
committerVikas Arora <vikasa@google.com>2011-07-21 17:59:13 +0530
commit8c52c218e8b00b33f837ac4891fcde3a08817169 (patch)
tree0699cc0696168ed772fb5ff4b6205c2b11438abe
parentc5013e3870ecf5a7798c1857a3060d880a7bf2c3 (diff)
downloadskia-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.cpp174
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);
}
///////////////////////////////////////////////////////////////////////////////