aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/images/SkImageDecoder.cpp11
-rw-r--r--src/images/SkImageDecoder_libjpeg.cpp83
-rw-r--r--src/images/SkImageDecoder_libpng.cpp43
-rw-r--r--src/images/SkImageDecoder_libwebp.cpp78
4 files changed, 140 insertions, 75 deletions
diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp
index 23dec76..c4eac9c 100644
--- a/src/images/SkImageDecoder.cpp
+++ b/src/images/SkImageDecoder.cpp
@@ -195,19 +195,8 @@ void SkImageDecoder::cropBitmap(SkBitmap *dest, SkBitmap *src,
int width, int height, int srcX, int srcY) {
int w = width / sampleSize;
int h = height / sampleSize;
- if (w == src->width() && h == src->height() &&
- (srcX - destX) / sampleSize == 0 &&
- (srcY - destY) / sampleSize == 0 &&
- dest->isNull()
- ) {
- // The output rect is the same as the decode result
- dest->swap(*src);
- return;
- }
-
// if the destination has no pixels then we must allocate them.
if (dest->isNull()) {
- // The output rect is smaller than the decode result
dest->setConfig(src->getConfig(), w, h);
dest->setIsOpaque(src->isOpaque());
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index b191848..fbb6887 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -77,6 +77,8 @@ protected:
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
private:
SkJPEGImageIndex *index;
+ int imageWidth;
+ int imageHeight;
};
//////////////////////////////////////////////////////////////////////////
@@ -528,7 +530,8 @@ bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream,
index->cinfo = cinfo;
*height = cinfo->output_height;
*width = cinfo->output_width;
-
+ this->imageWidth = *width;
+ this->imageHeight = *height;
this->index = index;
return true;
}
@@ -537,11 +540,14 @@ bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) {
if (index == NULL) {
return false;
}
- int startX = region.fLeft;
- int startY = region.fTop;
- int width = region.width();
- int height = region.height();
jpeg_decompress_struct *cinfo = index->cinfo;
+
+ SkIRect rect = SkIRect::MakeWH(this->imageWidth, this->imageHeight);
+ if (!rect.intersect(region)) {
+ // If the requested region is entirely outsides the image, just
+ // returns false
+ return false;
+ }
SkAutoMalloc srcStorage;
skjpeg_error_mgr sk_err;
cinfo->err = jpeg_std_error(&sk_err);
@@ -579,11 +585,11 @@ bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) {
}
}
#endif
+ int startX = rect.fLeft;
+ int startY = rect.fTop;
+ int width = rect.width();
+ int height = rect.height();
- int oriStartX = startX;
- int oriStartY = startY;
- int oriWidth = width;
- int oriHeight = height;
jpeg_init_read_tile_scanline(cinfo, index->index,
&startX, &startY, &width, &height);
int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
@@ -604,22 +610,25 @@ bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) {
{
bitmap->setConfig(config, cinfo->output_width, height);
bitmap->setIsOpaque(true);
- // Check ahead of time if the swap(dest, src) is possible in crop or
- // not. If yes, then we will stick to AllocPixelRef since it's cheaper
+
+ // Check ahead of time if the swap(dest, src) is possible or not.
+ // If yes, then we will stick to AllocPixelRef since it's cheaper
// with the swap happening. If no, then we will use alloc to allocate
// pixels to prevent garbage collection.
- int w = oriWidth / actualSampleSize;
- int h = oriHeight / actualSampleSize;
- if (w == bitmap->width() && h == bitmap->height() &&
- (startX - oriStartX) / actualSampleSize == 0 &&
- (startY - oriStartY) / actualSampleSize == 0 && bm->isNull()) {
- // Not using a recycled-bitmap and the output rect is same as the
- // decoded region.
+ //
+ // Not using a recycled-bitmap and the output rect is same as the
+ // decoded region.
+ int w = rect.width() / actualSampleSize;
+ int h = rect.height() / actualSampleSize;
+ bool swapOnly = (rect == region) && bm->isNull() &&
+ (w == bitmap->width()) && (h == bitmap->height()) &&
+ ((startX - rect.x()) / actualSampleSize == 0) &&
+ ((startY - rect.y()) / actualSampleSize == 0);
+ if (swapOnly) {
if (!this->allocPixelRef(bitmap, NULL)) {
return return_false(*cinfo, *bitmap, "allocPixelRef");
}
- }
- else {
+ } else {
if (!bitmap->allocPixels()) {
return return_false(*cinfo, *bitmap, "allocPixels");
}
@@ -644,8 +653,13 @@ bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) {
row_total_count += row_count;
rowptr += bpr;
}
- cropBitmap(bm, bitmap, actualSampleSize, oriStartX, oriStartY,
- oriWidth, oriHeight, startX, startY);
+
+ if (swapOnly) {
+ bm->swap(*bitmap);
+ } else {
+ cropBitmap(bm, bitmap, actualSampleSize, region.x(), region.y(),
+ region.width(), region.height(), startX, startY);
+ }
return true;
}
#endif
@@ -671,20 +685,21 @@ bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) {
bitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
bitmap->setIsOpaque(true);
- // Check ahead of time if the swap(dest, src) is possible in crop or not.
+ // Check ahead of time if the swap(dest, src) is possible or not.
// If yes, then we will stick to AllocPixelRef since it's cheaper with the
// swap happening. If no, then we will use alloc to allocate pixels to
// prevent garbage collection.
- int w = oriWidth / actualSampleSize;
- int h = oriHeight / actualSampleSize;
- if (w == bitmap->width() && h == bitmap->height() &&
- (startX - oriStartX) / actualSampleSize == 0 &&
- (startY - oriStartY) / actualSampleSize == 0 && bm->isNull()) {
+ int w = rect.width() / actualSampleSize;
+ int h = rect.height() / actualSampleSize;
+ bool swapOnly = (rect == region) && bm->isNull() &&
+ (w == bitmap->width()) && (h == bitmap->height()) &&
+ ((startX - rect.x()) / actualSampleSize == 0) &&
+ ((startY - rect.y()) / actualSampleSize == 0);
+ if (swapOnly) {
if (!this->allocPixelRef(bitmap, NULL)) {
return return_false(*cinfo, *bitmap, "allocPixelRef");
}
- }
- else {
+ } else {
if (!bitmap->allocPixels()) {
return return_false(*cinfo, *bitmap, "allocPixels");
}
@@ -724,8 +739,12 @@ bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) {
return return_false(*cinfo, *bitmap, "skip rows");
}
}
- cropBitmap(bm, bitmap, actualSampleSize, oriStartX, oriStartY,
- oriWidth, oriHeight, startX, startY);
+ if (swapOnly) {
+ bm->swap(*bitmap);
+ } else {
+ cropBitmap(bm, bitmap, actualSampleSize, region.x(), region.y(),
+ region.width(), region.height(), startX, startY);
+ }
return true;
}
diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp
index bb31806..fa35239 100644
--- a/src/images/SkImageDecoder_libpng.cpp
+++ b/src/images/SkImageDecoder_libpng.cpp
@@ -58,7 +58,7 @@ public:
protected:
virtual bool onBuildTileIndex(SkStream *stream,
int *width, int *height);
- virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect rect);
+ virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect region);
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
private:
@@ -616,7 +616,7 @@ bool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr,
return true;
}
-bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect rect) {
+bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) {
int i;
png_structp png_ptr = this->index->png_ptr;
png_infop info_ptr = this->index->info_ptr;
@@ -624,14 +624,19 @@ bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect rect) {
return false;
}
- int requestedHeight = rect.fBottom - rect.fTop;
- int requestedWidth = rect.fRight - rect.fLeft;
-
png_uint_32 origWidth, origHeight;
int bit_depth, color_type, interlace_type;
png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth,
&color_type, &interlace_type, int_p_NULL, int_p_NULL);
+ SkIRect rect = SkIRect::MakeWH(origWidth, origHeight);
+
+ if (!rect.intersect(region)) {
+ // If the requested region is entirely outsides the image, just
+ // returns false
+ return false;
+ }
+
SkBitmap::Config config;
bool hasAlpha = false;
bool doDither = this->getDitherImage();
@@ -643,7 +648,7 @@ bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect rect) {
}
const int sampleSize = this->getSampleSize();
- SkScaledBitmapSampler sampler(origWidth, requestedHeight, sampleSize);
+ SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize);
SkBitmap *decodedBitmap = new SkBitmap;
SkAutoTDelete<SkBitmap> adb(decodedBitmap);
@@ -669,17 +674,17 @@ bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect rect) {
// Check ahead of time if the swap(dest, src) is possible in crop or not.
// If yes, then we will stick to AllocPixelRef since it's cheaper with the swap happening.
// If no, then we will use alloc to allocate pixels to prevent garbage collection.
- int w = requestedWidth / sampleSize;
- int h = requestedHeight / sampleSize;
- if (w == decodedBitmap->width() && h == decodedBitmap->height() &&
- (0 - rect.fLeft / sampleSize) == 0 && (rect.fTop - rect.fTop) / sampleSize == 0 &&
- bm->isNull()) {
+ int w = rect.width() / sampleSize;
+ int h = rect.height() / sampleSize;
+ bool swapOnly = (rect == region) && (w == decodedBitmap->width()) &&
+ (h == decodedBitmap->height()) &&
+ ((0 - rect.x()) / sampleSize == 0) && bm->isNull();
+ if (swapOnly) {
if (!this->allocPixelRef(decodedBitmap,
SkBitmap::kIndex8_Config == config ? colorTable : NULL)) {
return false;
}
- }
- else {
+ } else {
if (!decodedBitmap->allocPixels(
NULL, SkBitmap::kIndex8_Config == config ? colorTable : NULL)) {
return false;
@@ -706,8 +711,6 @@ bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect rect) {
png_ptr->pass = 0;
png_read_update_info(png_ptr, info_ptr);
- // SkDebugf("Request size %d %d\n", requestedWidth, requestedHeight);
-
int actualTop = rect.fTop;
if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
@@ -757,7 +760,7 @@ bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect rect) {
png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
}
uint8_t* row = base;
- for (png_uint_32 y = 0; y < requestedHeight; y++) {
+ for (png_uint_32 y = 0; y < rect.height(); y++) {
uint8_t* bmRow = row;
png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
row += rb;
@@ -790,8 +793,12 @@ bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect rect) {
}
}
}
- cropBitmap(bm, decodedBitmap, sampleSize, rect.fLeft, rect.fTop,
- requestedWidth, requestedHeight, 0, rect.fTop);
+ if (swapOnly) {
+ bm->swap(*decodedBitmap);
+ } else {
+ cropBitmap(bm, decodedBitmap, sampleSize, region.x(), region.y(),
+ region.width(), region.height(), 0, rect.y());
+ }
if (0 != theTranspColor) {
reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp
index c2fce45..3e416cc 100644
--- a/src/images/SkImageDecoder_libwebp.cpp
+++ b/src/images/SkImageDecoder_libwebp.cpp
@@ -21,6 +21,7 @@
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkUtils.h"
+#include "SkTScopedPtr.h"
// A WebP decoder only, on top of (subset of) libwebp
// For more information on WebP image format, and libwebp library, see:
@@ -151,7 +152,7 @@ static WEBP_CSP_MODE webp_decode_mode(SkBitmap* decodedBitmap) {
// 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);
+ WebPIDecoder* idec = WebPIDecode(NULL, 0, &config);
if (idec == NULL) {
WebPFreeDecBuffer(&config.output);
return false;
@@ -309,33 +310,82 @@ bool SkWEBPImageDecoder::onBuildTileIndex(SkStream* stream,
return true;
}
+static bool isConfigCompatiable(SkBitmap* bitmap) {
+ SkBitmap::Config config = bitmap->config();
+ return config == SkBitmap::kARGB_4444_Config ||
+ config == SkBitmap::kRGB_565_Config ||
+ config == SkBitmap::kARGB_8888_Config;
+}
+
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);
+ SkIRect rect = SkIRect::MakeWH(origWidth, origHeight);
- if (!setDecodeConfig(decodedBitmap, sampler.scaledWidth(),
- sampler.scaledHeight())) {
+ if (!rect.intersect(region)) {
+ // If the requested region is entirely outsides the image, just
+ // returns false
return false;
}
- if (!this->allocPixelRef(decodedBitmap, NULL)) {
- return return_false(*decodedBitmap, "allocPixelRef");
+ const int sampleSize = this->getSampleSize();
+ SkScaledBitmapSampler sampler(rect.width(), rect.height(), sampleSize);
+ const int width = sampler.scaledWidth();
+ const int height = sampler.scaledHeight();
+
+ // The image can be decoded directly to decodedBitmap if
+ // 1. the region is within the image range
+ // 2. bitmap's config is compatible
+ // 3. bitmap's size is same as the required region (after sampled)
+ bool directDecode = (rect == region) &&
+ (decodedBitmap->isNull() ||
+ isConfigCompatiable(decodedBitmap) &&
+ (decodedBitmap->width() == width) &&
+ (decodedBitmap->height() == height));
+ SkTScopedPtr<SkBitmap> adb;
+ SkBitmap *bitmap = decodedBitmap;
+
+ if (!directDecode) {
+ // allocates a temp bitmap
+ bitmap = new SkBitmap;
+ adb.reset(bitmap);
+ }
+
+ if (bitmap->isNull()) {
+ if (!setDecodeConfig(bitmap, width, height)) {
+ return false;
+ }
+ // alloc from native heap if it is a temp bitmap. (prevent GC)
+ bool allocResult = (bitmap == decodedBitmap)
+ ? allocPixelRef(bitmap, NULL)
+ : bitmap->allocPixels();
+ if (!allocResult) {
+ return return_false(*decodedBitmap, "allocPixelRef");
+ }
+ } else {
+ // This is also called in setDecodeConfig in above block.
+ // i.e., when bitmap->isNull() is true.
+ if (!chooseFromOneChoice(bitmap->config(), width, height)) {
+ return false;
+ }
}
- SkAutoLockPixels alp(*decodedBitmap);
-
+ SkAutoLockPixels alp(*bitmap);
WebPDecoderConfig config;
- if (!webp_get_config_resize_crop(config, decodedBitmap, region)) {
+ if (!webp_get_config_resize_crop(config, bitmap, rect)) {
return false;
}
// Decode the WebP image data stream using WebP incremental decoding for
// the specified cropped image-region.
- return webp_idecode(this->inputStream, config);
+ if (!webp_idecode(this->inputStream, config)) {
+ return false;
+ }
+
+ if (!directDecode) {
+ cropBitmap(decodedBitmap, bitmap, sampleSize, region.x(), region.y(),
+ region.width(), region.height(), rect.x(), rect.y());
+ }
+ return true;
}
bool SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,