Prepare Skia-Webp decoder for Alpha and lossless.
Change the webp_parse_header to read appropriate header bytes (required
for Alpha & lossless bit-stream);
Replaced call WebPGetInfo with WebPGetFeatures to get hasAlpha
information;
Replaced hard-coded setIsOpaque(true) with setIsOpaque(!hasAlpha);
Refactored code for setting decoder config;
Change-Id: I8208233d1aaa0a213a35dd996a72e43f78901c89
diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp
index 3e416cc..b2aea24 100644
--- a/src/images/SkImageDecoder_libwebp.cpp
+++ b/src/images/SkImageDecoder_libwebp.cpp
@@ -56,20 +56,29 @@
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-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 +111,7 @@
SkStream *inputStream;
int origWidth;
int origHeight;
+ int hasAlpha;
};
//////////////////////////////////////////////////////////////////////////
@@ -160,10 +170,8 @@
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 +183,8 @@
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,9 +209,9 @@
}
}
-static bool webp_get_config_resize_crop(WebPDecoderConfig& config,
- SkBitmap* decodedBitmap,
- SkIRect region) {
+static bool webp_get_config_resize(WebPDecoderConfig& config,
+ SkBitmap* decodedBitmap,
+ int width, int height) {
WEBP_CSP_MODE mode = webp_decode_mode(decodedBitmap);
if (mode == MODE_LAST) {
return false;
@@ -219,53 +227,34 @@
config.output.u.RGBA.size = decodedBitmap->getSize();
config.output.is_external_memory = 1;
+ if (width != decodedBitmap->width() ||
+ 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_crop(WebPDecoderConfig& config,
+ SkBitmap* decodedBitmap,
+ SkIRect region) {
+
+ if (!webp_get_config_resize(config, decodedBitmap,
+ region.width(), region.height())) return false;
+
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);
// YUV converter supports output in RGB565, RGBA4444 and RGBA8888 formats.
@@ -286,16 +275,15 @@
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 +294,12 @@
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 +327,9 @@
// 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;
@@ -394,10 +383,11 @@
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);
@@ -568,8 +558,8 @@
#include "SkTRegistry.h"
static SkImageDecoder* DFactory(SkStream* stream) {
- int width, height;
- if (!webp_parse_header(stream, &width, &height)) {
+ int width, height, hasAlpha;
+ if (!webp_parse_header(stream, &width, &height, &hasAlpha)) {
return false;
}