add SkImage::NewFromBitmap

BUG=skia:

Review URL: https://codereview.chromium.org/1217053003
This commit is contained in:
reed 2015-07-07 06:11:19 -07:00 committed by Commit bot
parent 6f29a3c92c
commit 5617900063
10 changed files with 162 additions and 107 deletions

View File

@ -8,60 +8,40 @@
#include "gm.h"
#include "SkColorMatrixFilter.h"
#include "SkGradientShader.h"
#include "SkImage.h"
#define WIDTH 500
#define HEIGHT 500
class SkDoOnce {
public:
SkDoOnce() : fOnce(false) {};
bool once() const {
if (fOnce) {
return false;
}
fOnce = true;
return true;
}
private:
mutable bool fOnce;
};
static void setColorMatrix(SkPaint* paint, const SkColorMatrix& matrix) {
static void set_color_matrix(SkPaint* paint, const SkColorMatrix& matrix) {
paint->setColorFilter(SkColorMatrixFilter::Create(matrix))->unref();
}
static void setArray(SkPaint* paint, const SkScalar array[]) {
static void set_array(SkPaint* paint, const SkScalar array[]) {
paint->setColorFilter(SkColorMatrixFilter::Create(array))->unref();
}
namespace skiagm {
class ColorMatrixGM : public GM {
SkDoOnce fOnce;
void init() {
if (fOnce.once()) {
fSolidBitmap = this->createSolidBitmap(64, 64);
fTransparentBitmap = this->createTransparentBitmap(64, 64);
}
}
class ColorMatrixGM : public skiagm::GM {
public:
ColorMatrixGM() {
this->setBGColor(sk_tool_utils::color_to_565(0xFF808080));
}
protected:
virtual SkString onShortName() {
SkString onShortName() override {
return SkString("colormatrix");
}
virtual SkISize onISize() {
SkISize onISize() override {
return SkISize::Make(WIDTH, HEIGHT);
}
void onOnceBeforeDraw() override {
fSolidImg.reset(CreateSolidBitmap(64, 64));
fTransparentImg.reset(CreateTransparentBitmap(64, 64));
}
SkBitmap createSolidBitmap(int width, int height) {
static SkImage* CreateSolidBitmap(int width, int height) {
SkBitmap bm;
bm.allocN32Pixels(width, height);
SkCanvas canvas(bm);
@ -74,11 +54,11 @@ protected:
SkIntToScalar(y), SK_Scalar1, SK_Scalar1), paint);
}
}
return bm;
return SkImage::NewFromBitmap(bm);
}
// creates a bitmap with shades of transparent gray.
SkBitmap createTransparentBitmap(int width, int height) {
static SkImage* CreateTransparentBitmap(int width, int height) {
SkBitmap bm;
bm.allocN32Pixels(width, height);
SkCanvas canvas(bm);
@ -90,58 +70,56 @@ protected:
paint.setShader(SkGradientShader::CreateLinear(pts, colors, NULL, 2,
SkShader::kClamp_TileMode))->unref();
canvas.drawRect(SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)), paint);
return bm;
return SkImage::NewFromBitmap(bm);
}
virtual void onDraw(SkCanvas* canvas) {
this->init();
void onDraw(SkCanvas* canvas) override {
SkPaint paint;
SkColorMatrix matrix;
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
const SkBitmap bmps[] = { fSolidBitmap, fTransparentBitmap };
const SkImage* bmps[] = { fSolidImg, fTransparentImg };
for (size_t i = 0; i < SK_ARRAY_COUNT(bmps); ++i) {
matrix.setIdentity();
setColorMatrix(&paint, matrix);
canvas->drawBitmap(bmps[i], 0, 0, &paint);
set_color_matrix(&paint, matrix);
canvas->drawImage(bmps[i], 0, 0, &paint);
matrix.setRotate(SkColorMatrix::kR_Axis, 90);
setColorMatrix(&paint, matrix);
canvas->drawBitmap(bmps[i], 80, 0, &paint);
set_color_matrix(&paint, matrix);
canvas->drawImage(bmps[i], 80, 0, &paint);
matrix.setRotate(SkColorMatrix::kG_Axis, 90);
setColorMatrix(&paint, matrix);
canvas->drawBitmap(bmps[i], 160, 0, &paint);
set_color_matrix(&paint, matrix);
canvas->drawImage(bmps[i], 160, 0, &paint);
matrix.setRotate(SkColorMatrix::kB_Axis, 90);
setColorMatrix(&paint, matrix);
canvas->drawBitmap(bmps[i], 240, 0, &paint);
set_color_matrix(&paint, matrix);
canvas->drawImage(bmps[i], 240, 0, &paint);
///////////////////////////////////////////////
matrix.setSaturation(0.0f);
setColorMatrix(&paint, matrix);
canvas->drawBitmap(bmps[i], 0, 80, &paint);
set_color_matrix(&paint, matrix);
canvas->drawImage(bmps[i], 0, 80, &paint);
matrix.setSaturation(0.5f);
setColorMatrix(&paint, matrix);
canvas->drawBitmap(bmps[i], 80, 80, &paint);
set_color_matrix(&paint, matrix);
canvas->drawImage(bmps[i], 80, 80, &paint);
matrix.setSaturation(1.0f);
setColorMatrix(&paint, matrix);
canvas->drawBitmap(bmps[i], 160, 80, &paint);
set_color_matrix(&paint, matrix);
canvas->drawImage(bmps[i], 160, 80, &paint);
matrix.setSaturation(2.0f);
setColorMatrix(&paint, matrix);
canvas->drawBitmap(bmps[i], 240, 80, &paint);
set_color_matrix(&paint, matrix);
canvas->drawImage(bmps[i], 240, 80, &paint);
///////////////////////////////////////////////
matrix.setRGB2YUV();
setColorMatrix(&paint, matrix);
canvas->drawBitmap(bmps[i], 0, 160, &paint);
set_color_matrix(&paint, matrix);
canvas->drawImage(bmps[i], 0, 160, &paint);
matrix.setYUV2RGB();
setColorMatrix(&paint, matrix);
canvas->drawBitmap(bmps[i], 80, 160, &paint);
set_color_matrix(&paint, matrix);
canvas->drawImage(bmps[i], 80, 160, &paint);
SkScalar s1 = SK_Scalar1;
SkScalar s255 = SkIntToScalar(255);
@ -153,22 +131,18 @@ protected:
s1, 0, 0, 0, 0,
};
setArray(&paint, data);
canvas->drawBitmap(bmps[i], 160, 160, &paint);
set_array(&paint, data);
canvas->drawImage(bmps[i], 160, 160, &paint);
///////////////////////////////////////////////
canvas->translate(0, 240);
}
}
private:
SkBitmap fSolidBitmap;
SkBitmap fTransparentBitmap;
typedef GM INHERITED;
SkAutoTUnref<SkImage> fSolidImg;
SkAutoTUnref<SkImage> fTransparentImg;
typedef skiagm::GM INHERITED;
};
DEF_GM( return new ColorMatrixGM; )
//////////////////////////////////////////////////////////////////////////////
static GM* MyFactory(void*) { return new ColorMatrixGM; }
static GMRegistry reg(MyFactory);
}

View File

@ -61,6 +61,12 @@ public:
static SkImage* NewFromRaster(const Info&, const void* pixels, size_t rowBytes,
RasterReleaseProc, ReleaseContext);
/**
* Construct a new image from the specified bitmap. If the bitmap is marked immutable, and
* its pixel memory is shareable, it may be shared instead of copied.
*/
static SkImage* NewFromBitmap(const SkBitmap&);
/**
* Construct a new SkImage based on the given ImageGenerator.
* This function will always take ownership of the passed

View File

@ -12,6 +12,8 @@
#include "SkPictureUtils.h"
#include "SkRecorder.h"
//#define WRAP_BITMAP_AS_IMAGE
SkDrawableList::~SkDrawableList() {
fArray.unrefAll();
}
@ -170,7 +172,14 @@ void SkRecorder::onDrawBitmap(const SkBitmap& bitmap,
SkScalar left,
SkScalar top,
const SkPaint* paint) {
#ifdef WRAP_BITMAP_AS_IMAGE
SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bitmap));
if (image) {
this->onDrawImage(image, left, top, paint);
}
#else
APPEND(DrawBitmap, this->copy(paint), bitmap, left, top);
#endif
}
void SkRecorder::onDrawBitmapRect(const SkBitmap& bitmap,
@ -178,6 +187,13 @@ void SkRecorder::onDrawBitmapRect(const SkBitmap& bitmap,
const SkRect& dst,
const SkPaint* paint,
DrawBitmapRectFlags flags) {
#ifdef WRAP_BITMAP_AS_IMAGE
// TODO: need a way to support the flags for images...
SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bitmap));
if (image) {
this->onDrawImageRect(image, src, dst, paint);
}
#else
TRY_MINIRECORDER(drawBitmapRectToRect, bitmap, src, dst, paint, flags);
if (kBleed_DrawBitmapRectFlag == flags) {
APPEND(DrawBitmapRectToRectBleed,
@ -187,13 +203,21 @@ void SkRecorder::onDrawBitmapRect(const SkBitmap& bitmap,
SkASSERT(kNone_DrawBitmapRectFlag == flags);
APPEND(DrawBitmapRectToRect,
this->copy(paint), bitmap, this->copy(src), dst);
#endif
}
void SkRecorder::onDrawBitmapNine(const SkBitmap& bitmap,
const SkIRect& center,
const SkRect& dst,
const SkPaint* paint) {
#ifdef WRAP_BITMAP_AS_IMAGE
SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bitmap));
if (image) {
this->onDrawImageNine(image, center, dst, paint);
}
#else
APPEND(DrawBitmapNine, this->copy(paint), bitmap, center, dst);
#endif
}
void SkRecorder::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,

View File

@ -11,12 +11,15 @@
#include "SkImageGenerator.h"
#include "SkImagePriv.h"
#include "SkImage_Base.h"
#include "SkPixelRef.h"
#include "SkReadPixelsRec.h"
#include "SkString.h"
#include "SkSurface.h"
#if SK_SUPPORT_GPU
#include "GrTexture.h"
#include "GrContext.h"
#include "SkImage_Gpu.h"
#endif
uint32_t SkImage::NextUniqueID() {
@ -227,6 +230,41 @@ bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY) const {
///////////////////////////////////////////////////////////////////////////////////////////////////
SkImage* SkImage::NewFromBitmap(const SkBitmap& bm) {
SkPixelRef* pr = bm.pixelRef();
if (NULL == pr) {
return NULL;
}
#if SK_SUPPORT_GPU
if (GrTexture* tex = pr->getTexture()) {
SkAutoTUnref<GrTexture> unrefCopy;
if (!bm.isImmutable()) {
const bool notBudgeted = false;
tex = GrDeepCopyTexture(tex, notBudgeted);
if (NULL == tex) {
return NULL;
}
unrefCopy.reset(tex);
}
const SkImageInfo info = bm.info();
return SkNEW_ARGS(SkImage_Gpu, (info.width(), info.height(), info.alphaType(),
tex, 0, SkSurface::kNo_Budgeted));
}
#endif
// Encoded version?
if (SkData* encoded = pr->refEncodedData()) {
SkAutoTUnref<SkData> data(encoded);
return SkImage::NewFromEncoded(encoded); // todo: add origin/subset/etc?
}
// This will check for immutable (share or copy)
return SkNewImageFromRasterBitmap(bm, false, NULL);
}
//////////////////////////////////////////////////////////////////////////////////////
#if !SK_SUPPORT_GPU
SkImage* SkImage::NewFromTexture(GrContext*, const GrBackendTextureDesc&, SkAlphaType,

View File

@ -23,11 +23,14 @@ extern SkImage* SkNewImageFromPixelRef(const SkImageInfo&, SkPixelRef*,
* be shared if either the bitmap is marked as immutable, or canSharePixelRef
* is true.
*
* It is illegal to call this with a texture-backed bitmap.
*
* If the bitmap's colortype cannot be converted into a corresponding
* SkImageInfo, or the bitmap's pixels cannot be accessed, this will return
* NULL.
*/
extern SkImage* SkNewImageFromBitmap(const SkBitmap&, bool canSharePixelRef, const SkSurfaceProps*);
extern SkImage* SkNewImageFromRasterBitmap(const SkBitmap&, bool forceSharePixelRef,
const SkSurfaceProps*);
static inline size_t SkImageMinRowBytes(const SkImageInfo& info) {
size_t minRB = info.minRowBytes();
@ -53,4 +56,6 @@ extern void SkTextureImageApplyBudgetedDecision(SkImage* textureImage);
// surface needs to perform a copy-on-write
extern void SkTextureImageSetTexture(SkImage* image, GrTexture* texture);
GrTexture* GrDeepCopyTexture(GrTexture* src, bool isBudgeted);
#endif

View File

@ -144,42 +144,27 @@ SkImage* SkImage::NewFromAdoptedTexture(GrContext* ctx, const GrBackendTextureDe
return new_wrapped_texture_common(ctx, desc, at, kAdopt_GrWrapOwnership, NULL, NULL);
}
SkImage* SkImage::NewFromTextureCopy(GrContext* ctx, const GrBackendTextureDesc& srcDesc,
SkImage* SkImage::NewFromTextureCopy(GrContext* ctx, const GrBackendTextureDesc& desc,
SkAlphaType at) {
const bool isBudgeted = true;
const SkSurface::Budgeted budgeted = SkSurface::kYes_Budgeted;
if (srcDesc.fWidth <= 0 || srcDesc.fHeight <= 0) {
if (desc.fWidth <= 0 || desc.fHeight <= 0) {
return NULL;
}
SkAutoTUnref<GrTexture> src(ctx->textureProvider()->wrapBackendTexture(
srcDesc, kBorrow_GrWrapOwnership));
desc, kBorrow_GrWrapOwnership));
if (!src) {
return NULL;
}
GrSurfaceDesc dstDesc;
// need to be a rendertarget for readpixels to work, instead of kNone_GrSurfaceFlags
dstDesc.fFlags = kRenderTarget_GrSurfaceFlag;
dstDesc.fOrigin = srcDesc.fOrigin;
dstDesc.fWidth = srcDesc.fWidth;
dstDesc.fHeight = srcDesc.fHeight;
dstDesc.fConfig = srcDesc.fConfig;
dstDesc.fSampleCnt = srcDesc.fSampleCnt;
SkAutoTUnref<GrTexture> dst(ctx->textureProvider()->createTexture(
dstDesc, isBudgeted, NULL, 0));
const bool isBudgeted = true;
SkAutoTUnref<GrTexture> dst(GrDeepCopyTexture(src, isBudgeted));
if (!dst) {
return NULL;
}
const SkIRect srcR = SkIRect::MakeWH(dstDesc.fWidth, dstDesc.fHeight);
const SkIPoint dstP = SkIPoint::Make(0, 0);
ctx->copySurface(dst, src, srcR, dstP, GrContext::kFlushWrites_PixelOp);
const SkSurface::Budgeted budgeted = SkSurface::kYes_Budgeted;
const int sampleCount = 0; // todo: make this an explicit parameter to newSurface()?
return SkNEW_ARGS(SkImage_Gpu, (dstDesc.fWidth, dstDesc.fHeight, at, dst, sampleCount,
budgeted));
return SkNEW_ARGS(SkImage_Gpu, (desc.fWidth, desc.fHeight, at, dst, sampleCount, budgeted));
}
SkImage* SkImage::NewFromYUVTexturesCopy(GrContext* ctx , SkYUVColorSpace colorSpace,
@ -256,3 +241,23 @@ SkImage* SkImage::NewFromYUVTexturesCopy(GrContext* ctx , SkYUVColorSpace colorS
return SkNEW_ARGS(SkImage_Gpu, (dstDesc.fWidth, dstDesc.fHeight, kOpaque_SkAlphaType, dst, 0,
budgeted));
}
///////////////////////////////////////////////////////////////////////////////////////////////////
GrTexture* GrDeepCopyTexture(GrTexture* src, bool budgeted) {
GrContext* ctx = src->getContext();
GrSurfaceDesc desc = src->desc();
// need to be a rendertarget for readpixels to work, instead of kNone_GrSurfaceFlags
desc.fFlags = kRenderTarget_GrSurfaceFlag;
GrTexture* dst = ctx->textureProvider()->createTexture(desc, budgeted, NULL, 0);
if (!dst) {
return NULL;
}
const SkIRect srcR = SkIRect::MakeWH(desc.fWidth, desc.fHeight);
const SkIPoint dstP = SkIPoint::Make(0, 0);
ctx->copySurface(dst, src, srcR, dstP, GrContext::kFlushWrites_PixelOp);
return dst;
}

View File

@ -227,21 +227,24 @@ SkImage* SkNewImageFromPixelRef(const SkImageInfo& info, SkPixelRef* pr,
return SkNEW_ARGS(SkImage_Raster, (info, pr, pixelRefOrigin, rowBytes, props));
}
SkImage* SkNewImageFromBitmap(const SkBitmap& bm, bool canSharePixelRef,
const SkSurfaceProps* props) {
SkImage* SkNewImageFromRasterBitmap(const SkBitmap& bm, bool forceSharePixelRef,
const SkSurfaceProps* props) {
SkASSERT(NULL == bm.getTexture());
if (!SkImage_Raster::ValidArgs(bm.info(), bm.rowBytes(), NULL, NULL)) {
return NULL;
}
SkImage* image = NULL;
if (canSharePixelRef || bm.isImmutable()) {
if (forceSharePixelRef || bm.isImmutable()) {
image = SkNEW_ARGS(SkImage_Raster, (bm, props));
} else {
bm.lockPixels();
if (bm.getPixels()) {
image = SkImage::NewRasterCopy(bm.info(), bm.getPixels(), bm.rowBytes());
SkBitmap tmp(bm);
tmp.lockPixels();
if (tmp.getPixels()) {
image = SkImage::NewRasterCopy(tmp.info(), tmp.getPixels(), tmp.rowBytes(),
tmp.getColorTable());
}
bm.unlockPixels();
// we don't expose props to NewRasterCopy (need a private vers) so post-init it here
if (image && props) {

View File

@ -118,7 +118,7 @@ void SkSurface_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
}
SkImage* SkSurface_Raster::onNewImageSnapshot(Budgeted) {
return SkNewImageFromBitmap(fBitmap, fWeOwnThePixels, &this->props());
return SkNewImageFromRasterBitmap(fBitmap, fWeOwnThePixels, &this->props());
}
void SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) {

View File

@ -64,7 +64,7 @@ public:
}
SkImage* onNewImageSnapshot(Budgeted) override {
return SkNewImageFromBitmap(fBitmap, true, &this->props());
return SkNewImageFromRasterBitmap(fBitmap, true, &this->props());
}
void onCopyOnWrite(ContentChangeMode mode) override {

View File

@ -26,7 +26,7 @@ DEF_TEST(SkImageFromBitmap_extractSubset, reporter) {
canvas.drawIRect(r, p);
SkBitmap dstBitmap;
srcBitmap.extractSubset(&dstBitmap, r);
image.reset(SkNewImageFromBitmap(dstBitmap, true, NULL));
image.reset(SkNewImageFromRasterBitmap(dstBitmap, true, NULL));
}
SkBitmap tgt;