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>
This commit is contained in:
Matt Sarett 2017-06-06 10:11:34 -04:00 committed by Skia Commit-Bot
parent 1608a1dd17
commit 3928ff8e0b
9 changed files with 205 additions and 10 deletions

48
gm/xform_image_gen.cpp Normal file
View File

@ -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(); )

View File

@ -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",

View File

@ -319,5 +319,6 @@ gm_sources = [
"$_gm/xfermodes.cpp",
"$_gm/xfermodes2.cpp",
"$_gm/xfermodes3.cpp",
"$_gm/xform_image_gen.cpp",
"$_gm/yuvtorgbeffect.cpp",
]

View File

@ -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();

View File

@ -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);
}

View File

@ -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 {

View File

@ -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 = &copy;
}
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

View File

@ -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

View File

@ -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;
}