aboutsummaryrefslogtreecommitdiffstats
path: root/src/images/SkImageDecoder_libwebp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/images/SkImageDecoder_libwebp.cpp')
-rw-r--r--src/images/SkImageDecoder_libwebp.cpp120
1 files changed, 58 insertions, 62 deletions
diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp
index 3e416cc..3ca1254 100644
--- a/src/images/SkImageDecoder_libwebp.cpp
+++ b/src/images/SkImageDecoder_libwebp.cpp
@@ -34,7 +34,6 @@ 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.
#include "webp/decode.h"
-#include "webp/decode_vp8.h"
#include "webp/encode.h"
}
@@ -56,20 +55,29 @@ static const char KEY_MEM_CAP[] = "ro.media.dec.webp.memcap";
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-static const size_t WEBP_VP8_HEADER_SIZE = 30;
+static const size_t WEBP_VP8_HEADER_SIZE = 64;
static const size_t WEBP_IDECODE_BUFFER_SZ = (1 << 16);
// Parse headers of RIFF container, and check for valid Webp (VP8) content.
-static bool webp_parse_header(SkStream* stream, int* width, int* height) {
+static bool webp_parse_header(SkStream* stream, int* width, int* height,
+ int* alpha) {
unsigned char buffer[WEBP_VP8_HEADER_SIZE];
+ const uint32_t contentSize = stream->getLength();
const size_t len = stream->read(buffer, WEBP_VP8_HEADER_SIZE);
- if (len != WEBP_VP8_HEADER_SIZE) {
+ const uint32_t read_bytes = (contentSize < WEBP_VP8_HEADER_SIZE) ?
+ contentSize : WEBP_VP8_HEADER_SIZE;
+ if (len != read_bytes) {
return false; // can't read enough
}
- if (WebPGetInfo(buffer, WEBP_VP8_HEADER_SIZE, width, height) == 0) {
+ WebPBitstreamFeatures features;
+ VP8StatusCode status = WebPGetFeatures(buffer, read_bytes, &features);
+ if (status != VP8_STATUS_OK) {
return false; // Invalid WebP file.
}
+ *width = features.width;
+ *height = features.height;
+ *alpha = features.has_alpha;
// sanity check for image size that's about to be decoded.
{
@@ -102,6 +110,7 @@ private:
SkStream *inputStream;
int origWidth;
int origHeight;
+ int hasAlpha;
};
//////////////////////////////////////////////////////////////////////////
@@ -136,16 +145,20 @@ static bool return_false(const SkBitmap& bm, const char msg[]) {
return false; // must always return false
}
-static WEBP_CSP_MODE webp_decode_mode(SkBitmap* decodedBitmap) {
+static WEBP_CSP_MODE webp_decode_mode(SkBitmap* decodedBitmap, int hasAlpha) {
WEBP_CSP_MODE mode = MODE_LAST;
SkBitmap::Config config = decodedBitmap->config();
+ // For images that have alpha, choose appropriate color mode (MODE_rgbA,
+ // MODE_rgbA_4444) that pre-multiplies RGB pixel values with transparency
+ // factor (alpha).
if (config == SkBitmap::kARGB_8888_Config) {
- mode = MODE_RGBA;
+ mode = hasAlpha ? MODE_rgbA : MODE_RGBA;
} else if (config == SkBitmap::kARGB_4444_Config) {
- mode = MODE_RGBA_4444;
+ mode = hasAlpha ? MODE_rgbA_4444 : MODE_RGBA_4444;
} else if (config == SkBitmap::kRGB_565_Config) {
mode = MODE_RGB_565;
}
+ SkASSERT(mode != MODE_LAST);
return mode;
}
@@ -160,10 +173,8 @@ static bool webp_idecode(SkStream* stream, WebPDecoderConfig& config) {
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;
- }
+ const uint32_t read_buffer_size = (contentSize < WEBP_IDECODE_BUFFER_SZ) ?
+ contentSize : WEBP_IDECODE_BUFFER_SZ;
SkAutoMalloc srcStorage(read_buffer_size);
unsigned char* input = (uint8_t*)srcStorage.get();
if (input == NULL) {
@@ -175,8 +186,8 @@ static bool webp_idecode(SkStream* stream, WebPDecoderConfig& config) {
uint32_t bytes_remaining = contentSize;
while (bytes_remaining > 0) {
const uint32_t bytes_to_read =
- (bytes_remaining > WEBP_IDECODE_BUFFER_SZ) ?
- WEBP_IDECODE_BUFFER_SZ : bytes_remaining;
+ (bytes_remaining < WEBP_IDECODE_BUFFER_SZ) ?
+ bytes_remaining : WEBP_IDECODE_BUFFER_SZ;
const size_t bytes_read = stream->read(input, bytes_to_read);
if (bytes_read == 0) {
@@ -201,10 +212,10 @@ static bool webp_idecode(SkStream* stream, WebPDecoderConfig& config) {
}
}
-static bool webp_get_config_resize_crop(WebPDecoderConfig& config,
- SkBitmap* decodedBitmap,
- SkIRect region) {
- WEBP_CSP_MODE mode = webp_decode_mode(decodedBitmap);
+static bool webp_get_config_resize(WebPDecoderConfig& config,
+ SkBitmap* decodedBitmap,
+ int width, int height, int hasAlpha) {
+ WEBP_CSP_MODE mode = webp_decode_mode(decodedBitmap, hasAlpha);
if (mode == MODE_LAST) {
return false;
}
@@ -219,14 +230,8 @@ static bool webp_get_config_resize_crop(WebPDecoderConfig& config,
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()) {
+ if (width != decodedBitmap->width() ||
+ height != decodedBitmap->height()) {
config.options.use_scaling = 1;
config.options.scaled_width = decodedBitmap->width();
config.options.scaled_height = decodedBitmap->height();
@@ -235,37 +240,26 @@ static bool webp_get_config_resize_crop(WebPDecoderConfig& config,
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;
- }
+static bool webp_get_config_resize_crop(WebPDecoderConfig& config,
+ SkBitmap* decodedBitmap,
+ SkIRect region, int hasAlpha) {
- if (WebPInitDecoderConfig(&config) == 0) {
- return false;
+ if (!webp_get_config_resize(
+ config, decodedBitmap, region.width(), region.height(), hasAlpha)) {
+ 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();
- }
+ 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();
return true;
}
bool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap,
int width, int height) {
- bool hasAlpha = false;
SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, hasAlpha);
// YUV converter supports output in RGB565, RGBA4444 and RGBA8888 formats.
@@ -286,16 +280,15 @@ bool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap,
decodedBitmap->setConfig(config, width, height, 0);
- // Current WEBP specification has no support for alpha layer.
- decodedBitmap->setIsOpaque(true);
+ decodedBitmap->setIsOpaque(!hasAlpha);
return true;
}
bool SkWEBPImageDecoder::onBuildTileIndex(SkStream* stream,
int *width, int *height) {
- int origWidth, origHeight;
- if (!webp_parse_header(stream, &origWidth, &origHeight)) {
+ int origWidth, origHeight, hasAlpha;
+ if (!webp_parse_header(stream, &origWidth, &origHeight, &hasAlpha)) {
return false;
}
@@ -306,11 +299,12 @@ bool SkWEBPImageDecoder::onBuildTileIndex(SkStream* stream,
this->inputStream = stream;
this->origWidth = origWidth;
this->origHeight = origHeight;
+ this->hasAlpha = hasAlpha;
return true;
}
-static bool isConfigCompatiable(SkBitmap* bitmap) {
+static bool isConfigCompatible(SkBitmap* bitmap) {
SkBitmap::Config config = bitmap->config();
return config == SkBitmap::kARGB_4444_Config ||
config == SkBitmap::kRGB_565_Config ||
@@ -338,9 +332,9 @@ bool SkWEBPImageDecoder::onDecodeRegion(SkBitmap* decodedBitmap,
// 3. bitmap's size is same as the required region (after sampled)
bool directDecode = (rect == region) &&
(decodedBitmap->isNull() ||
- isConfigCompatiable(decodedBitmap) &&
+ (isConfigCompatible(decodedBitmap) &&
(decodedBitmap->width() == width) &&
- (decodedBitmap->height() == height));
+ (decodedBitmap->height() == height)));
SkTScopedPtr<SkBitmap> adb;
SkBitmap *bitmap = decodedBitmap;
@@ -371,7 +365,7 @@ bool SkWEBPImageDecoder::onDecodeRegion(SkBitmap* decodedBitmap,
SkAutoLockPixels alp(*bitmap);
WebPDecoderConfig config;
- if (!webp_get_config_resize_crop(config, bitmap, rect)) {
+ if (!webp_get_config_resize_crop(config, bitmap, rect, hasAlpha)) {
return false;
}
@@ -394,10 +388,11 @@ bool SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
AutoTimeMillis atm("WEBP Decode");
#endif
- int origWidth, origHeight;
- if (!webp_parse_header(stream, &origWidth, &origHeight)) {
+ int origWidth, origHeight, hasAlpha;
+ if (!webp_parse_header(stream, &origWidth, &origHeight, &hasAlpha)) {
return false;
}
+ this->hasAlpha = hasAlpha;
const int sampleSize = this->getSampleSize();
SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
@@ -428,7 +423,8 @@ bool SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
SkAutoLockPixels alp(*decodedBitmap);
WebPDecoderConfig config;
- if (!webp_get_config_resize(config, decodedBitmap, origWidth, origHeight)) {
+ if (!webp_get_config_resize(config, decodedBitmap, origWidth, origHeight,
+ hasAlpha)) {
return false;
}
@@ -568,9 +564,9 @@ bool SkWEBPImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bm,
#include "SkTRegistry.h"
static SkImageDecoder* DFactory(SkStream* stream) {
- int width, height;
- if (!webp_parse_header(stream, &width, &height)) {
- return false;
+ int width, height, hasAlpha;
+ if (!webp_parse_header(stream, &width, &height, &hasAlpha)) {
+ return NULL;
}
// Magic matches, call decoder