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 gen = SkColorSpaceXformImageGenerator::Make( + bitmap, + SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, + SkColorSpace::kRec2020_Gamut), + kNever_SkCopyPixelsMode); + + SkIRect subset = SkIRect::MakeXYWH(25, 25, 50, 50); + sk_sp 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", diff --git a/gn/gm.gni b/gn/gm.gni index cd7985a020..c28504e14c 100644 --- a/gn/gm.gni +++ b/gn/gm.gni @@ -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 SkColorSpaceXformImageGenerator::Make( + const SkBitmap& src, sk_sp 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( + new SkColorSpaceXformImageGenerator(*srcPtr, std::move(dst))); +} + +SkColorSpaceXformImageGenerator::SkColorSpaceXformImageGenerator(const SkBitmap& src, + sk_sp 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 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 proxy = + GrUploadBitmapToTextureProxy(ctx->resourceProvider(), fSrc, nullptr); + + sk_sp srcSpace = + fSrc.colorSpace() ? sk_ref_sp(fSrc.colorSpace()) : SkColorSpace::MakeSRGB(); + auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), fDst.get()); + if (!xform) { + return nullptr; + } + + sk_sp 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 Make( + const SkBitmap& src, sk_sp dst, SkCopyPixelsMode); + +protected: + bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, + const Options& opts) override; + +#if SK_SUPPORT_GPU + sk_sp onGenerateTexture(GrContext*, const SkImageInfo&, + const SkIPoint&) override; +#endif + +private: + SkBitmap fSrc; + sk_sp fDst; + + SkColorSpaceXformImageGenerator(const SkBitmap& src, sk_sp 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; }