aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-05-03 20:14:28 +0000
committerGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-05-03 20:14:28 +0000
commit7e6fceeffd250d99eff9f1dbb459a916ae4a754e (patch)
tree12bd9ee920cd58a8a31b9aff4abde0429a95a372 /src
parentdc9cdf8d49ecfe174c408845b7f2de6f5a756b1d (diff)
Test region decoding in skimage, plus fixes.
Add tests in skimage to perform region decoding. Write out a PNG of the region as well as a bitmap obtained with extractSubset for comparison. Rename decodeRegion to decodeSubset, so it will not be confused with SkRegion. (Leave a function called decodeRegion which calls decodeSubset.) Clean up some comments. Use png_set_interlaced_pass instead of modifying pass directly. Make some changes to region decoding to fix problems I discovered during testing: Only call getAddr within a valid range. Check for a NULL fInputStream. Return a boolean for whether cropBitmap succeeded. In cropBitmap, do not attempt to draw to a bitmap to an Index8 bitmap, which crashes. Use extractSubset instead. Remove an assert. R=djsollen@google.com Review URL: https://codereview.chromium.org/14567011 git-svn-id: http://skia.googlecode.com/svn/trunk@8996 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r--src/images/SkImageDecoder.cpp44
-rw-r--r--src/images/SkImageDecoder_libjpeg.cpp4
-rw-r--r--src/images/SkImageDecoder_libpng.cpp25
-rw-r--r--src/images/SkImageDecoder_libwebp.cpp4
4 files changed, 51 insertions, 26 deletions
diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp
index de0bc14c90..9ffae5f0e7 100644
--- a/src/images/SkImageDecoder.cpp
+++ b/src/images/SkImageDecoder.cpp
@@ -33,9 +33,14 @@ void SkImageDecoder::SetDeviceConfig(SkBitmap::Config config)
///////////////////////////////////////////////////////////////////////////////
SkImageDecoder::SkImageDecoder()
- : fPeeker(NULL), fChooser(NULL), fAllocator(NULL), fSampleSize(1),
- fDefaultPref(SkBitmap::kNo_Config), fDitherImage(true),
- fUsePrefTable(false),fPreferQualityOverSpeed(false) {
+ : fPeeker(NULL)
+ , fChooser(NULL)
+ , fAllocator(NULL)
+ , fSampleSize(1)
+ , fDefaultPref(SkBitmap::kNo_Config)
+ , fDitherImage(true)
+ , fUsePrefTable(false)
+ , fPreferQualityOverSpeed(false) {
}
SkImageDecoder::~SkImageDecoder() {
@@ -177,14 +182,14 @@ bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm,
return true;
}
-bool SkImageDecoder::decodeRegion(SkBitmap* bm, const SkIRect& rect,
+bool SkImageDecoder::decodeSubset(SkBitmap* bm, const SkIRect& rect,
SkBitmap::Config pref) {
- // we reset this to false before calling onDecodeRegion
+ // we reset this to false before calling onDecodeSubset
fShouldCancelDecode = false;
// assign this, for use by getPrefConfig(), in case fUsePrefTable is false
fDefaultPref = pref;
- return this->onDecodeRegion(bm, rect);
+ return this->onDecodeSubset(bm, rect);
}
bool SkImageDecoder::buildTileIndex(SkStream* stream,
@@ -195,11 +200,25 @@ bool SkImageDecoder::buildTileIndex(SkStream* stream,
return this->onBuildTileIndex(stream, width, height);
}
-void SkImageDecoder::cropBitmap(SkBitmap *dst, SkBitmap *src, int sampleSize,
- int dstX, int dstY, int width, int height,
- int srcX, int srcY) {
+bool SkImageDecoder::cropBitmap(SkBitmap *dst, SkBitmap *src, int sampleSize,
+ int dstX, int dstY, int width, int height,
+ int srcX, int srcY) {
int w = width / sampleSize;
int h = height / sampleSize;
+ if (src->getConfig() == SkBitmap::kIndex8_Config) {
+ // kIndex8 does not allow drawing via an SkCanvas, as is done below.
+ // Instead, use extractSubset. Note that this shares the SkPixelRef and
+ // SkColorTable.
+ // FIXME: Since src is discarded in practice, this holds on to more
+ // pixels than is strictly necessary. Switch to a copy if memory
+ // savings are more important than speed here. This also means
+ // that the pixels in dst can not be reused (though there is no
+ // allocation, which was already done on src).
+ int x = (dstX - srcX) / sampleSize;
+ int y = (dstY - srcY) / sampleSize;
+ SkIRect subset = SkIRect::MakeXYWH(x, y, w, h);
+ return src->extractSubset(dst, subset);
+ }
// if the destination has no pixels then we must allocate them.
if (dst->isNull()) {
dst->setConfig(src->getConfig(), w, h);
@@ -207,13 +226,15 @@ void SkImageDecoder::cropBitmap(SkBitmap *dst, SkBitmap *src, int sampleSize,
if (!this->allocPixelRef(dst, NULL)) {
SkDEBUGF(("failed to allocate pixels needed to crop the bitmap"));
- return;
+ return false;
}
}
// check to see if the destination is large enough to decode the desired
// region. If this assert fails we will just draw as much of the source
// into the destination that we can.
- SkASSERT(dst->width() >= w && dst->height() >= h);
+ if (dst->width() < w || dst->height() < h) {
+ SkDEBUGF(("SkImageDecoder::cropBitmap does not have a large enough bitmap.\n"));
+ }
// Set the Src_Mode for the paint to prevent transparency issue in the
// dest in the event that the dest was being re-used.
@@ -224,6 +245,7 @@ void SkImageDecoder::cropBitmap(SkBitmap *dst, SkBitmap *src, int sampleSize,
canvas.drawSprite(*src, (srcX - dstX) / sampleSize,
(srcY - dstY) / sampleSize,
&paint);
+ return true;
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index c55f4c4123..3ed3806543 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -118,7 +118,7 @@ public:
protected:
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_OVERRIDE;
- virtual bool onDecodeRegion(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE;
+ virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE;
#endif
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
@@ -556,7 +556,7 @@ bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *hei
return true;
}
-bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, const SkIRect& region) {
+bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
if (NULL == fImageIndex) {
return false;
}
diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp
index 0e02ccf08d..d967a69e84 100644
--- a/src/images/SkImageDecoder_libpng.cpp
+++ b/src/images/SkImageDecoder_libpng.cpp
@@ -72,7 +72,7 @@ public:
protected:
#ifdef SK_BUILD_FOR_ANDROID
virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_OVERRIDE;
- virtual bool onDecodeRegion(SkBitmap* bitmap, const SkIRect& region) SK_OVERRIDE;
+ virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& region) SK_OVERRIDE;
#endif
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
@@ -642,7 +642,11 @@ bool SkPNGImageDecoder::onBuildTileIndex(SkStream* sk_stream, int *width, int *h
return true;
}
-bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, const SkIRect& region) {
+bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
+ if (NULL == fImageIndex) {
+ return false;
+ }
+
png_structp png_ptr = fImageIndex->png_ptr;
png_infop info_ptr = fImageIndex->info_ptr;
if (setjmp(png_jmpbuf(png_ptr))) {
@@ -657,7 +661,7 @@ bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, const SkIRect& region) {
SkIRect rect = SkIRect::MakeWH(origWidth, origHeight);
if (!rect.intersect(region)) {
- // If the requested region is entirely outsides the image, just
+ // If the requested region is entirely outside the image, just
// returns false
return false;
}
@@ -731,8 +735,8 @@ bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, const SkIRect& region) {
#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
png_ptr->pass = 0;
#else
- // FIXME: Figure out what (if anything) to do when Android moves to
- // libpng > 1.2.
+ // FIXME: This sets pass as desired, but also sets iwidth. Is that ok?
+ png_set_interlaced_pass(png_ptr, 0);
#endif
png_read_update_info(png_ptr, info_ptr);
@@ -745,7 +749,8 @@ bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, const SkIRect& region) {
uint8_t* bmRow = decodedBitmap.getAddr8(0, 0);
png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
}
- for (png_uint_32 y = 0; y < origHeight; y++) {
+ png_uint_32 bitmapHeight = (png_uint_32) decodedBitmap.height();
+ for (png_uint_32 y = 0; y < bitmapHeight; y++) {
uint8_t* bmRow = decodedBitmap.getAddr8(0, y);
png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
}
@@ -826,12 +831,10 @@ bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, const SkIRect& region) {
if (swapOnly) {
bm->swap(decodedBitmap);
- } else {
- cropBitmap(bm, &decodedBitmap, sampleSize, region.x(), region.y(),
- region.width(), region.height(), 0, rect.y());
+ return true;
}
-
- return true;
+ return this->cropBitmap(bm, &decodedBitmap, sampleSize, region.x(), region.y(),
+ region.width(), region.height(), 0, rect.y());
}
#endif
diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp
index a33d0f9b2f..e623f376d7 100644
--- a/src/images/SkImageDecoder_libwebp.cpp
+++ b/src/images/SkImageDecoder_libwebp.cpp
@@ -111,7 +111,7 @@ public:
protected:
virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_OVERRIDE;
- virtual bool onDecodeRegion(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE;
+ virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE;
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
private:
@@ -321,7 +321,7 @@ static bool is_config_compatible(const SkBitmap& bitmap) {
config == SkBitmap::kARGB_8888_Config;
}
-bool SkWEBPImageDecoder::onDecodeRegion(SkBitmap* decodedBitmap,
+bool SkWEBPImageDecoder::onDecodeSubset(SkBitmap* decodedBitmap,
const SkIRect& region) {
SkIRect rect = SkIRect::MakeWH(fOrigWidth, fOrigHeight);