aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkImage.h44
-rw-r--r--include/core/SkSurface.h14
-rw-r--r--src/core/SkCanvas.cpp38
-rw-r--r--src/core/SkImageInfo.cpp44
-rw-r--r--src/image/SkImage.cpp58
-rw-r--r--src/image/SkImage_Base.h7
-rw-r--r--src/image/SkImage_Raster.cpp15
-rw-r--r--src/image/SkReadPixelsRec.h41
-rw-r--r--src/image/SkSurface.cpp9
-rw-r--r--tests/SurfaceTest.cpp59
10 files changed, 197 insertions, 132 deletions
diff --git a/include/core/SkImage.h b/include/core/SkImage.h
index 63fa41b4e7..6070b6bf6b 100644
--- a/include/core/SkImage.h
+++ b/include/core/SkImage.h
@@ -85,6 +85,27 @@ public:
const void* peekPixels(SkImageInfo* info, size_t* rowBytes) const;
/**
+ * Copy the pixels from the image into the specified buffer (pixels + rowBytes),
+ * converting them into the requested format (dstInfo). The image pixels are read
+ * starting at the specified (srcX,srcY) location.
+ *
+ * The specified ImageInfo and (srcX,srcY) offset specifies a source rectangle
+ *
+ * srcR.setXYWH(srcX, srcY, dstInfo.width(), dstInfo.height());
+ *
+ * srcR is intersected with the bounds of the image. If this intersection is not empty,
+ * then we have two sets of pixels (of equal size). Replace the dst pixels with the
+ * corresponding src pixels, performing any colortype/alphatype transformations needed
+ * (in the case where the src and dst have different colortypes or alphatypes).
+ *
+ * This call can fail, returning false, for several reasons:
+ * - If srcR does not intersect the image bounds.
+ * - If the requested colortype/alphatype cannot be converted from the image's types.
+ */
+ bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
+ int srcX, int srcY) const;
+
+ /**
* Encode the image's pixels and return the result as a new SkData, which
* the caller must manage (i.e. call unref() when they are done).
*
@@ -134,29 +155,6 @@ private:
* See SkCanvas::drawBitmapRectToRect for similar behavior.
*/
void drawRect(SkCanvas*, const SkRect* src, const SkRect& dst, const SkPaint*) const;
-
- /**
- * Return a copy of the image's pixels, limiting them to the subset
- * rectangle's intersection wit the image bounds. If subset is NULL, then
- * the entire image will be considered.
- *
- * If the bitmap's pixels have already been allocated, then readPixels()
- * will succeed only if it can support converting the image's pixels into
- * the bitmap's ColorType/AlphaType. Any pixels in the bitmap that do not
- * intersect with the image's bounds and the subset (if not null) will be
- * left untouched.
- *
- * If the bitmap is initially empty/unallocated, then it will be allocated
- * using the default allocator, and the ColorType/AlphaType will be chosen
- * to most closely fit the image's configuration.
- *
- * On failure, false will be returned, and bitmap will unmodified.
- */
- // On ice for now:
- // - should it respect the particular colortype/alphatype of the src
- // - should it have separate entrypoints for preallocated and not bitmaps?
- // - isn't it enough to allow the caller to draw() the image into a canvas?
- bool readPixels(SkBitmap* bitmap, const SkIRect* subset = NULL) const;
};
#endif
diff --git a/include/core/SkSurface.h b/include/core/SkSurface.h
index 8b36314360..74c54e8d68 100644
--- a/include/core/SkSurface.h
+++ b/include/core/SkSurface.h
@@ -219,8 +219,8 @@ public:
/**
* Copy the pixels from the surface into the specified buffer (pixels + rowBytes),
- * converting them into the requested format (dstInfo). The base-layer pixels are read
- * starting at the specified (srcX,srcY) location in the coordinate system of the base-layer.
+ * converting them into the requested format (dstInfo). The surface pixels are read
+ * starting at the specified (srcX,srcY) location.
*
* The specified ImageInfo and (srcX,srcY) offset specifies a source rectangle
*
@@ -233,19 +233,11 @@ public:
*
* This call can fail, returning false, for several reasons:
* - If srcR does not intersect the surface bounds.
- * - If the requested colortype/alphatype cannot be converted from the base-layer's types.
+ * - If the requested colortype/alphatype cannot be converted from the surface's types.
*/
bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
int srcX, int srcY);
- /**
- * Helper for allocating pixels and then calling readPixels(info, ...). The bitmap is resized
- * to the intersection of srcRect and the surface bounds (if srcRect is non-null).
- * On success, pixels will be allocated in bitmap and true returned. On failure,
- * false is returned and bitmap will be set to empty.
- */
- bool readPixels(SkBitmap* dst, const SkIRect* srcRect = NULL);
-
const SkSurfaceProps& props() const { return fProps; }
protected:
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index bf86005315..083a8ed7e8 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -19,6 +19,7 @@
#include "SkPatchUtils.h"
#include "SkPicture.h"
#include "SkRasterClip.h"
+#include "SkReadPixelsRec.h"
#include "SkRRect.h"
#include "SkSmallAllocator.h"
#include "SkSurface_Base.h"
@@ -686,47 +687,20 @@ bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
return true;
}
-bool SkCanvas::readPixels(const SkImageInfo& origInfo, void* dstP, size_t rowBytes, int x, int y) {
- switch (origInfo.colorType()) {
- case kUnknown_SkColorType:
- case kIndex_8_SkColorType:
- return false;
- default:
- break;
- }
- if (NULL == dstP || rowBytes < origInfo.minRowBytes()) {
- return false;
- }
- if (0 == origInfo.width() || 0 == origInfo.height()) {
- return false;
- }
-
+bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
SkBaseDevice* device = this->getDevice();
if (!device) {
return false;
}
-
const SkISize size = this->getBaseLayerSize();
- SkIRect srcR = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
- if (!srcR.intersect(0, 0, size.width(), size.height())) {
+
+ SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
+ if (!rec.trim(size.width(), size.height())) {
return false;
}
- // the intersect may have shrunk info's logical size
- const SkImageInfo info = origInfo.makeWH(srcR.width(), srcR.height());
-
- // if x or y are negative, then we have to adjust pixels
- if (x > 0) {
- x = 0;
- }
- if (y > 0) {
- y = 0;
- }
- // here x,y are either 0 or negative
- dstP = ((char*)dstP - y * rowBytes - x * info.bytesPerPixel());
-
// The device can assert that the requested area is always contained in its bounds
- return device->readPixels(info, dstP, rowBytes, srcR.x(), srcR.y());
+ return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
}
bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
diff --git a/src/core/SkImageInfo.cpp b/src/core/SkImageInfo.cpp
index 7931358d82..146a3aeed8 100644
--- a/src/core/SkImageInfo.cpp
+++ b/src/core/SkImageInfo.cpp
@@ -76,3 +76,47 @@ bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType,
}
return true;
}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkReadPixelsRec.h"
+
+bool SkReadPixelsRec::trim(int srcWidth, int srcHeight) {
+ switch (fInfo.colorType()) {
+ case kUnknown_SkColorType:
+ case kIndex_8_SkColorType:
+ return false;
+ default:
+ break;
+ }
+ if (NULL == fPixels || fRowBytes < fInfo.minRowBytes()) {
+ return false;
+ }
+ if (0 == fInfo.width() || 0 == fInfo.height()) {
+ return false;
+ }
+
+ int x = fX;
+ int y = fY;
+ SkIRect srcR = SkIRect::MakeXYWH(x, y, fInfo.width(), fInfo.height());
+ if (!srcR.intersect(0, 0, srcWidth, srcHeight)) {
+ return false;
+ }
+
+ // if x or y are negative, then we have to adjust pixels
+ if (x > 0) {
+ x = 0;
+ }
+ if (y > 0) {
+ y = 0;
+ }
+ // here x,y are either 0 or negative
+ fPixels = ((char*)fPixels - y * fRowBytes - x * fInfo.bytesPerPixel());
+ // the intersect may have shrunk info's logical size
+ fInfo = fInfo.makeWH(srcR.width(), srcR.height());
+ fX = srcR.x();
+ fY = srcR.y();
+
+ return true;
+}
+
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index cbde961b78..1acff3e4ed 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -9,6 +9,7 @@
#include "SkCanvas.h"
#include "SkImagePriv.h"
#include "SkImage_Base.h"
+#include "SkReadPixelsRec.h"
#include "SkSurface.h"
uint32_t SkImage::NextUniqueID() {
@@ -43,27 +44,13 @@ const void* SkImage::peekPixels(SkImageInfo* info, size_t* rowBytes) const {
return as_IB(this)->onPeekPixels(info, rowBytes);
}
-bool SkImage::readPixels(SkBitmap* bitmap, const SkIRect* subset) const {
- if (NULL == bitmap) {
+bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
+ int srcX, int srcY) const {
+ SkReadPixelsRec rec(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
+ if (!rec.trim(this->width(), this->height())) {
return false;
}
-
- SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
-
- // trim against the bitmap, if its already been allocated
- if (bitmap->pixelRef()) {
- bounds.fRight = SkMin32(bounds.fRight, bitmap->width());
- bounds.fBottom = SkMin32(bounds.fBottom, bitmap->height());
- if (bounds.isEmpty()) {
- return false;
- }
- }
-
- if (subset && !bounds.intersect(*subset)) {
- // perhaps we could return true + empty-bitmap?
- return false;
- }
- return as_IB(this)->onReadPixels(bitmap, bounds);
+ return as_IB(this)->onReadPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
}
GrTexture* SkImage::getTexture() {
@@ -107,34 +94,19 @@ static bool raster_canvas_supports(const SkImageInfo& info) {
return false;
}
-bool SkImage_Base::onReadPixels(SkBitmap* bitmap, const SkIRect& subset) const {
- if (bitmap->pixelRef()) {
- const SkImageInfo info = bitmap->info();
- if (kUnknown_SkColorType == info.colorType()) {
- return false;
- }
- if (!raster_canvas_supports(info)) {
- return false;
- }
- } else {
- SkBitmap tmp;
- if (!tmp.tryAllocN32Pixels(subset.width(), subset.height())) {
- return false;
- }
- *bitmap = tmp;
+bool SkImage_Base::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
+ int srcX, int srcY) const {
+ if (!raster_canvas_supports(dstInfo)) {
+ return false;
}
- SkRect srcR, dstR;
- srcR.set(subset);
- dstR = srcR;
- dstR.offset(-dstR.left(), -dstR.top());
-
- SkCanvas canvas(*bitmap);
+ SkBitmap bm;
+ bm.installPixels(dstInfo, dstPixels, dstRowBytes);
+ SkCanvas canvas(bm);
SkPaint paint;
- paint.setXfermodeMode(SkXfermode::kClear_Mode);
- canvas.drawRect(dstR, paint);
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas.drawImage(this, -SkIntToScalar(srcX), -SkIntToScalar(srcY), &paint);
- canvas.drawImageRect(this, &srcR, dstR);
return true;
}
diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h
index 8f0fefe4f8..8c1dfada63 100644
--- a/src/image/SkImage_Base.h
+++ b/src/image/SkImage_Base.h
@@ -41,13 +41,14 @@ public:
const SkRect& dst, const SkPaint*) const = 0;
virtual SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) const = 0;
- // Default impl calls onDraw
- virtual bool onReadPixels(SkBitmap*, const SkIRect& subset) const;
-
virtual const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const {
return NULL;
}
+ // Default impl calls onDraw
+ virtual bool onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
+ int srcX, int srcY) const;
+
virtual GrTexture* onGetTexture() const { return NULL; }
// return a read-only copy of the pixels. We promise to not modify them,
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index 9ae3d36426..24b971ad84 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -57,7 +57,7 @@ public:
void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) const SK_OVERRIDE;
void onDrawRect(SkCanvas*, const SkRect*, const SkRect&, const SkPaint*) const SK_OVERRIDE;
SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) const SK_OVERRIDE;
- bool onReadPixels(SkBitmap*, const SkIRect&) const SK_OVERRIDE;
+ bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY) const SK_OVERRIDE;
const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const SK_OVERRIDE;
bool getROPixels(SkBitmap*) const SK_OVERRIDE;
@@ -143,16 +143,9 @@ SkSurface* SkImage_Raster::onNewSurface(const SkImageInfo& info, const SkSurface
return SkSurface::NewRaster(info, &props);
}
-bool SkImage_Raster::onReadPixels(SkBitmap* dst, const SkIRect& subset) const {
- if (dst->pixelRef()) {
- return this->INHERITED::onReadPixels(dst, subset);
- } else {
- SkBitmap src;
- if (!fBitmap.extractSubset(&src, subset)) {
- return false;
- }
- return src.copyTo(dst, src.colorType());
- }
+bool SkImage_Raster::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
+ int srcX, int srcY) const {
+ return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
}
const void* SkImage_Raster::onPeekPixels(SkImageInfo* infoPtr, size_t* rowBytesPtr) const {
diff --git a/src/image/SkReadPixelsRec.h b/src/image/SkReadPixelsRec.h
new file mode 100644
index 0000000000..ed93b74b0f
--- /dev/null
+++ b/src/image/SkReadPixelsRec.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkReadPixelsRec_DEFINED
+#define SkReadPixelsRec_DEFINED
+
+#include "SkImageInfo.h"
+
+/**
+ * Helper class to package and trim the parameters passed to readPixels()
+ */
+struct SkReadPixelsRec {
+ SkReadPixelsRec(const SkImageInfo& info, void* pixels, size_t rowBytes, int x, int y)
+ : fPixels(pixels)
+ , fRowBytes(rowBytes)
+ , fInfo(info)
+ , fX(x)
+ , fY(y)
+ {}
+
+ void* fPixels;
+ size_t fRowBytes;
+ SkImageInfo fInfo;
+ int fX;
+ int fY;
+
+ /*
+ * On true, may have modified its fields (except fRowBytes) to make it a legal subset
+ * of the specified src width/height.
+ *
+ * On false, leaves self unchanged, but indicates that it does not overlap src, or
+ * is not valid (e.g. bad fInfo) for readPixels().
+ */
+ bool trim(int srcWidth, int srcHeight);
+};
+
+#endif
diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp
index 13b7d65546..7587f25284 100644
--- a/src/image/SkSurface.cpp
+++ b/src/image/SkSurface.cpp
@@ -175,15 +175,6 @@ bool SkSurface::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t d
return this->getCanvas()->readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
}
-bool SkSurface::readPixels(SkBitmap* dst, const SkIRect* srcRect) {
- SkIRect storage;
- if (NULL == srcRect) {
- storage.set(0, 0, this->width(), this->height());
- srcRect = &storage;
- }
- return this->getCanvas()->readPixels(*srcRect, dst);
-}
-
//////////////////////////////////////////////////////////////////////////////////////
#ifdef SK_SUPPORT_LEGACY_TEXTRENDERMODE
diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp
index 1f0db67c5c..28abf9804c 100644
--- a/tests/SurfaceTest.cpp
+++ b/tests/SurfaceTest.cpp
@@ -118,6 +118,63 @@ static SkImage* createImage(ImageType imageType, GrContext* context, SkColor col
return NULL;
}
+static void set_pixels(SkPMColor pixels[], int count, SkPMColor color) {
+ sk_memset32(pixels, color, count);
+}
+static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected) {
+ for (int i = 0; i < count; ++i) {
+ if (pixels[i] != expected) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void test_image_readpixels(skiatest::Reporter* reporter, SkImage* image,
+ SkPMColor expected) {
+ const SkPMColor notExpected = ~expected;
+
+ const int w = 2, h = 2;
+ const size_t rowBytes = w * sizeof(SkPMColor);
+ SkPMColor pixels[w*h];
+
+ SkImageInfo info;
+
+ info = SkImageInfo::MakeUnknown(w, h);
+ REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, 0));
+
+ // out-of-bounds should fail
+ info = SkImageInfo::MakeN32Premul(w, h);
+ REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, -w, 0));
+ REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, -h));
+ REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, image->width(), 0));
+ REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, image->height()));
+
+ // top-left should succeed
+ set_pixels(pixels, w*h, notExpected);
+ REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 0, 0));
+ REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
+
+ // bottom-right should succeed
+ set_pixels(pixels, w*h, notExpected);
+ REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
+ image->width() - w, image->height() - h));
+ REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
+
+ // partial top-left should succeed
+ set_pixels(pixels, w*h, notExpected);
+ REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, -1, -1));
+ REPORTER_ASSERT(reporter, pixels[3] == expected);
+ REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected));
+
+ // partial bottom-right should succeed
+ set_pixels(pixels, w*h, notExpected);
+ REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
+ image->width() - 1, image->height() - 1));
+ REPORTER_ASSERT(reporter, pixels[0] == expected);
+ REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected));
+}
+
static void test_imagepeek(skiatest::Reporter* reporter, GrContextFactory* factory) {
static const struct {
ImageType fType;
@@ -159,6 +216,8 @@ static void test_imagepeek(skiatest::Reporter* reporter, GrContextFactory* facto
REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes);
REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr);
}
+
+ test_image_readpixels(reporter, image, pmcolor);
}
}