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:
parent
1608a1dd17
commit
3928ff8e0b
48
gm/xform_image_gen.cpp
Normal file
48
gm/xform_image_gen.cpp
Normal 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(); )
|
@ -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",
|
||||
]
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
96
src/core/SkColorSpaceXformImageGenerator.cpp
Normal file
96
src/core/SkColorSpaceXformImageGenerator.cpp
Normal 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 = ©
|
||||
}
|
||||
|
||||
|
||||
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
|
40
src/core/SkColorSpaceXformImageGenerator.h
Normal file
40
src/core/SkColorSpaceXformImageGenerator.h
Normal 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
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user