diff options
author | 2017-06-06 10:11:34 -0400 | |
---|---|---|
committer | 2017-06-06 14:34:03 +0000 | |
commit | 3928ff8e0b617c3a00eee1963bc31ce5470fba6d (patch) | |
tree | 98bbe9e51b3316c175a8b1ffe1063877ca84eb55 | |
parent | 1608a1dd17187aeeada376e710ecfafb1e229af2 (diff) |
Create an SkColorSpaceXform image generator
This should be immediately useful in the Skia-Android
rendering pipeline.
Possible future uses include creating a "renderable"
SkImage from a bitmap with a funny color space.
Inspired by:
https://skia-review.googlesource.com/c/13981/
Bug: b/62347704
Change-Id: I388c7af1fc43834b8ad22022d0caf3ac90b734c8
Reviewed-on: https://skia-review.googlesource.com/18598
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Matt Sarett <msarett@google.com>
-rw-r--r-- | gm/xform_image_gen.cpp | 48 | ||||
-rw-r--r-- | gn/core.gni | 2 | ||||
-rw-r--r-- | gn/gm.gni | 1 | ||||
-rw-r--r-- | include/core/SkBitmap.h | 11 | ||||
-rw-r--r-- | include/core/SkPixmap.h | 7 | ||||
-rw-r--r-- | src/core/SkBitmap.cpp | 4 | ||||
-rw-r--r-- | src/core/SkColorSpaceXformImageGenerator.cpp | 96 | ||||
-rw-r--r-- | src/core/SkColorSpaceXformImageGenerator.h | 40 | ||||
-rw-r--r-- | src/core/SkPixmap.cpp | 6 |
9 files changed, 205 insertions, 10 deletions
diff --git a/gm/xform_image_gen.cpp b/gm/xform_image_gen.cpp new file mode 100644 index 0000000000..69a1ce173f --- /dev/null +++ b/gm/xform_image_gen.cpp @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gm.h" +#include "SkColorSpaceXformImageGenerator.h" + +class ColorXformImageGenGM : public skiagm::GM { +public: + ColorXformImageGenGM() {} + +protected: + + SkString onShortName() override { + return SkString("color_xform_image_gen"); + } + + SkISize onISize() override { + return SkISize::Make(100, 100); + } + + void onDraw(SkCanvas* canvas) override { + SkBitmap bitmap; + SkImageInfo info = + SkImageInfo::MakeN32(100, 100, kOpaque_SkAlphaType, SkColorSpace::MakeSRGB()); + bitmap.allocPixels(info); + bitmap.eraseColor(SK_ColorRED); + bitmap.eraseArea(SkIRect::MakeWH(25, 25), SK_ColorBLUE); // We should not see any blue. + + std::unique_ptr<SkImageGenerator> gen = SkColorSpaceXformImageGenerator::Make( + bitmap, + SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, + SkColorSpace::kRec2020_Gamut), + kNever_SkCopyPixelsMode); + + SkIRect subset = SkIRect::MakeXYWH(25, 25, 50, 50); + sk_sp<SkImage> image = SkImage::MakeFromGenerator(std::move(gen), &subset); + canvas->drawImage(image, 25, 25); + } + +private: + typedef GM INHERITED; +}; + +DEF_GM( return new ColorXformImageGenGM(); ) diff --git a/gn/core.gni b/gn/core.gni index 21f3c207be..0ffff84a2e 100644 --- a/gn/core.gni +++ b/gn/core.gni @@ -84,6 +84,8 @@ skia_core_sources = [ "$_src/core/SkColorSpaceXformCanvas.cpp", "$_src/core/SkColorSpaceXformer.cpp", "$_src/core/SkColorSpaceXformer.h", + "$_src/core/SkColorSpaceXformImageGenerator.cpp", + "$_src/core/SkColorSpaceXformImageGenerator.h", "$_src/core/SkColorSpaceXform_A2B.cpp", "$_src/core/SkColorSpaceXform_A2B.h", "$_src/core/SkColorTable.cpp", @@ -319,5 +319,6 @@ gm_sources = [ "$_gm/xfermodes.cpp", "$_gm/xfermodes2.cpp", "$_gm/xfermodes3.cpp", + "$_gm/xform_image_gen.cpp", "$_gm/yuvtorgbeffect.cpp", ] diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h index 764139b3a6..8b8942f194 100644 --- a/include/core/SkBitmap.h +++ b/include/core/SkBitmap.h @@ -571,7 +571,12 @@ public: * - If the src pixels are not available. */ bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, - int srcX, int srcY) const; + int srcX, int srcY, SkTransferFunctionBehavior behavior) const; + bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, + int srcX, int srcY) const { + return this->readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY, + SkTransferFunctionBehavior::kRespect); + } bool readPixels(const SkPixmap& dst, int srcX, int srcY) const; bool readPixels(const SkPixmap& dst) const { return this->readPixels(dst, 0, 0); @@ -589,6 +594,7 @@ public: bool writePixels(const SkPixmap& src) { return this->writePixels(src, 0, 0); } + bool writePixels(const SkPixmap& src, int x, int y, SkTransferFunctionBehavior behavior); #ifdef SK_BUILD_FOR_ANDROID bool hasHardwareMipMap() const { @@ -684,9 +690,6 @@ private: uint32_t fRowBytes; uint8_t fFlags; - friend class SkImage_Raster; - bool writePixels(const SkPixmap& src, int x, int y, SkTransferFunctionBehavior behavior); - /* Unreference any pixelrefs or colortables */ void freePixels(); diff --git a/include/core/SkPixmap.h b/include/core/SkPixmap.h index af8618b4de..1e79bba225 100644 --- a/include/core/SkPixmap.h +++ b/include/core/SkPixmap.h @@ -183,10 +183,15 @@ public: // copy methods bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, - int srcX, int srcY) const; + int srcX, int srcY, SkTransferFunctionBehavior behavior) const; bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes) const { return this->readPixels(dstInfo, dstPixels, dstRowBytes, 0, 0); } + bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, + int srcY) const { + return this->readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY, + SkTransferFunctionBehavior::kRespect); + } bool readPixels(const SkPixmap& dst, int srcX, int srcY) const { return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY); } diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index 72cac7cc9c..e88fa5ec57 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -512,12 +512,12 @@ bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { /////////////////////////////////////////////////////////////////////////////// bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB, - int x, int y) const { + int x, int y, SkTransferFunctionBehavior behavior) const { SkPixmap src; if (!this->peekPixels(&src)) { return false; } - return src.readPixels(requestedDstInfo, dstPixels, dstRB, x, y); + return src.readPixels(requestedDstInfo, dstPixels, dstRB, x, y, behavior); } bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const { diff --git a/src/core/SkColorSpaceXformImageGenerator.cpp b/src/core/SkColorSpaceXformImageGenerator.cpp new file mode 100644 index 0000000000..d9bec78035 --- /dev/null +++ b/src/core/SkColorSpaceXformImageGenerator.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorSpaceXformImageGenerator.h" + +std::unique_ptr<SkImageGenerator> SkColorSpaceXformImageGenerator::Make( + const SkBitmap& src, sk_sp<SkColorSpace> dst, SkCopyPixelsMode mode) { + if (!dst) { + return nullptr; + } + + const SkBitmap* srcPtr = &src; + SkBitmap copy; + if (kAlways_SkCopyPixelsMode == mode || + (kNever_SkCopyPixelsMode != mode && !src.isImmutable())) { + if (!copy.tryAllocPixels(src.info())) { + return nullptr; + } + + SkAssertResult(src.readPixels(copy.info(), copy.getPixels(), copy.rowBytes(), 0, 0)); + copy.setImmutable(); + srcPtr = © + } + + + return std::unique_ptr<SkImageGenerator>( + new SkColorSpaceXformImageGenerator(*srcPtr, std::move(dst))); +} + +SkColorSpaceXformImageGenerator::SkColorSpaceXformImageGenerator(const SkBitmap& src, + sk_sp<SkColorSpace> dst) + : INHERITED(src.info().makeColorSpace(dst), kNeedNewImageUniqueID) + , fSrc(src) + , fDst(dst) +{} + +bool SkColorSpaceXformImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, + size_t rowBytes, const Options& opts) { + SkImageInfo dstInfo = info; + if (!info.colorSpace()) { + dstInfo = dstInfo.makeColorSpace(fDst); + } + return fSrc.readPixels(dstInfo, pixels, rowBytes, 0, 0, opts.fBehavior); +} + +#if SK_SUPPORT_GPU + +#include "GrClip.h" +#include "GrContext.h" +#include "GrPaint.h" +#include "GrRenderTargetContext.h" +#include "GrTextureProxy.h" +#include "SkGr.h" +#include "effects/GrNonlinearColorSpaceXformEffect.h" + +sk_sp<GrTextureProxy> SkColorSpaceXformImageGenerator::onGenerateTexture(GrContext* ctx, + const SkImageInfo& info, + const SkIPoint& origin) { + // FIXME: + // This always operates as if SkTranferFunctionBehavior is kIgnore. Should we add + // options so that caller can also request kRespect? + + SkASSERT(ctx); + + sk_sp<GrTextureProxy> proxy = + GrUploadBitmapToTextureProxy(ctx->resourceProvider(), fSrc, nullptr); + + sk_sp<SkColorSpace> srcSpace = + fSrc.colorSpace() ? sk_ref_sp(fSrc.colorSpace()) : SkColorSpace::MakeSRGB(); + auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), fDst.get()); + if (!xform) { + return nullptr; + } + + sk_sp<GrRenderTargetContext> renderTargetContext = ctx->makeDeferredRenderTargetContext( + SkBackingFit::kExact, fSrc.width(), fSrc.height(), kRGBA_8888_GrPixelConfig, nullptr); + if (!renderTargetContext) { + return nullptr; + } + + GrPaint paint; + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + paint.addColorTextureProcessor(ctx->resourceProvider(), proxy, nullptr, + SkMatrix::MakeTrans(origin.fX, origin.fY)); + paint.addColorFragmentProcessor(std::move(xform)); + + const SkRect rect = SkRect::MakeWH(info.width(), info.height()); + renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect); + return sk_ref_sp(renderTargetContext->asTextureProxy()); +} + +#endif diff --git a/src/core/SkColorSpaceXformImageGenerator.h b/src/core/SkColorSpaceXformImageGenerator.h new file mode 100644 index 0000000000..29bf85bff9 --- /dev/null +++ b/src/core/SkColorSpaceXformImageGenerator.h @@ -0,0 +1,40 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorSpaceXformImageGenerator_DEFINED +#define SkColorSpaceXformImageGenerator_DEFINED + +#include "SkImageGenerator.h" +#include "SkImagePriv.h" + +class SkColorSpaceXformImageGenerator : public SkImageGenerator { +public: + + static std::unique_ptr<SkImageGenerator> Make( + const SkBitmap& src, sk_sp<SkColorSpace> dst, SkCopyPixelsMode); + +protected: + bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, + const Options& opts) override; + +#if SK_SUPPORT_GPU + sk_sp<GrTextureProxy> onGenerateTexture(GrContext*, const SkImageInfo&, + const SkIPoint&) override; +#endif + +private: + SkBitmap fSrc; + sk_sp<SkColorSpace> fDst; + + SkColorSpaceXformImageGenerator(const SkBitmap& src, sk_sp<SkColorSpace> dst); + + friend class SkImageGenerator; + + typedef SkImageGenerator INHERITED; +}; + +#endif // SkColorSpaceXformImageGenerator_DEFINED diff --git a/src/core/SkPixmap.cpp b/src/core/SkPixmap.cpp index 02090b77c6..6425b29f92 100644 --- a/src/core/SkPixmap.cpp +++ b/src/core/SkPixmap.cpp @@ -74,8 +74,8 @@ bool SkPixmap::extractSubset(SkPixmap* result, const SkIRect& subset) const { return true; } -bool SkPixmap::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, int x, int y) -const { +bool SkPixmap::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, int x, int y, + SkTransferFunctionBehavior behavior) const { if (!SkImageInfoValidConversion(dstInfo, fInfo)) { return false; } @@ -88,7 +88,7 @@ const { const void* srcPixels = this->addr(rec.fX, rec.fY); const SkImageInfo srcInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height()); SkConvertPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, srcInfo, srcPixels, this->rowBytes(), - this->ctable(), SkTransferFunctionBehavior::kRespect); + this->ctable(), behavior); return true; } |