aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/image
diff options
context:
space:
mode:
authorGravatar Matt Sarett <msarett@google.com>2017-05-03 19:09:46 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-05-03 23:45:55 +0000
commit9ad0531a18f854e5a2c8034880140dd6cd3ea3c1 (patch)
treebfa2ca0ef23438b70159a5d2eb5a8a1a3b477094 /src/image
parent1478f74aa2233a7ae40351764d37fde679d2c561 (diff)
Add SkImage::makeColorSpace() with correct transfer fn behavior
Completes implementation for lazy and raster images. gpu is still a TODO. Bug: skia:6553 Change-Id: I04eea5c4fb53c50c0406c2e6b6778b0e21fd85f8 Reviewed-on: https://skia-review.googlesource.com/14403 Commit-Queue: Matt Sarett <msarett@google.com> Reviewed-by: Mike Reed <reed@google.com>
Diffstat (limited to 'src/image')
-rw-r--r--src/image/SkImage.cpp12
-rw-r--r--src/image/SkImage_Base.h3
-rw-r--r--src/image/SkImage_Gpu.cpp8
-rw-r--r--src/image/SkImage_Gpu.h3
-rw-r--r--src/image/SkImage_Lazy.cpp19
-rw-r--r--src/image/SkImage_Raster.cpp62
6 files changed, 32 insertions, 75 deletions
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 5debe48b00..cbb9a621db 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -288,11 +288,6 @@ bool SkImage::isAlphaOnly() const {
sk_sp<SkImage> SkImage::makeColorSpace(sk_sp<SkColorSpace> target,
SkTransferFunctionBehavior premulBehavior) const {
- if (SkTransferFunctionBehavior::kRespect == premulBehavior) {
- // TODO (msarett, brianosman): Implement this.
- return nullptr;
- }
-
SkColorSpaceTransferFn fn;
if (!target || !target->isNumericalTransferFn(&fn)) {
return nullptr;
@@ -307,8 +302,13 @@ sk_sp<SkImage> SkImage::makeColorSpace(sk_sp<SkColorSpace> target,
return sk_ref_sp(const_cast<SkImage*>(this));
}
+ SkColorType targetColorType = kN32_SkColorType;
+ if (SkTransferFunctionBehavior::kRespect == premulBehavior && target->gammaIsLinear()) {
+ targetColorType = kRGBA_F16_SkColorType;
+ }
+
// TODO: We might consider making this a deferred conversion?
- return as_IB(this)->onMakeColorSpace(std::move(target));
+ return as_IB(this)->onMakeColorSpace(std::move(target), targetColorType, premulBehavior);
}
//////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h
index ce9c5cde52..34f194b61a 100644
--- a/src/image/SkImage_Base.h
+++ b/src/image/SkImage_Base.h
@@ -85,7 +85,8 @@ public:
virtual bool onPinAsTexture(GrContext*) const { return false; }
virtual void onUnpinAsTexture(GrContext*) const {}
- virtual sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>) const = 0;
+ virtual sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>, SkColorType,
+ SkTransferFunctionBehavior) const = 0;
private:
// Set true by caches when they cache content that's derived from the current pixels.
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 2c7a194444..581841b1d5 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -905,7 +905,13 @@ sk_sp<SkImage> SkImage::MakeTextureFromMipMap(GrContext* ctx, const SkImageInfo&
info.refColorSpace(), budgeted);
}
-sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> colorSpace) const {
+sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> colorSpace, SkColorType,
+ SkTransferFunctionBehavior premulBehavior) const {
+ if (SkTransferFunctionBehavior::kRespect == premulBehavior) {
+ // TODO: Implement this.
+ return nullptr;
+ }
+
sk_sp<SkColorSpace> srcSpace = fColorSpace ? fColorSpace : SkColorSpace::MakeSRGB();
auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), colorSpace.get());
if (!xform) {
diff --git a/src/image/SkImage_Gpu.h b/src/image/SkImage_Gpu.h
index b477acc7b5..a644ee25be 100644
--- a/src/image/SkImage_Gpu.h
+++ b/src/image/SkImage_Gpu.h
@@ -59,7 +59,8 @@ public:
GrContext* context() { return fContext; }
sk_sp<SkColorSpace> refColorSpace() { return fColorSpace; }
- sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>) const override;
+ sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>, SkColorType,
+ SkTransferFunctionBehavior) const override;
private:
GrContext* fContext;
diff --git a/src/image/SkImage_Lazy.cpp b/src/image/SkImage_Lazy.cpp
index 215f4c284c..3ee18de9db 100644
--- a/src/image/SkImage_Lazy.cpp
+++ b/src/image/SkImage_Lazy.cpp
@@ -82,7 +82,8 @@ public:
sk_sp<SkImage> onMakeSubset(const SkIRect&) const override;
bool getROPixels(SkBitmap*, SkColorSpace* dstColorSpace, CachingHint) const override;
bool onIsLazyGenerated() const override { return true; }
- sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>) const override;
+ sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>, SkColorType,
+ SkTransferFunctionBehavior) const override;
SkImageCacherator* peekCacherator() const override {
return const_cast<SkImage_Lazy*>(this);
@@ -574,20 +575,14 @@ sk_sp<SkImage> SkImage_Lazy::onMakeSubset(const SkIRect& subset) const {
return validator ? sk_sp<SkImage>(new SkImage_Lazy(&validator)) : nullptr;
}
-sk_sp<SkImage> SkImage_Lazy::onMakeColorSpace(sk_sp<SkColorSpace> target) const {
+sk_sp<SkImage> SkImage_Lazy::onMakeColorSpace(sk_sp<SkColorSpace> target,
+ SkColorType targetColorType,
+ SkTransferFunctionBehavior premulBehavior) const {
SkBitmap dst;
- SkImageInfo dstInfo = fInfo.makeColorSpace(target);
- if (kIndex_8_SkColorType == dstInfo.colorType() ||
- kGray_8_SkColorType == dstInfo.colorType() ||
- kRGB_565_SkColorType == dstInfo.colorType()) {
- dstInfo = dstInfo.makeColorType(kN32_SkColorType);
- }
+ SkImageInfo dstInfo = fInfo.makeColorType(targetColorType).makeColorSpace(target);
dst.allocPixels(dstInfo);
-
- // Use kIgnore for transfer function behavior. This is used by the SkColorSpaceXformCanvas,
- // which wants to pre-xform the inputs but ignore the transfer function on blends.
if (!this->directGeneratePixels(dstInfo, dst.getPixels(), dst.rowBytes(), 0, 0,
- SkTransferFunctionBehavior::kIgnore)) {
+ premulBehavior)) {
return nullptr;
}
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index 88847551d1..1c3c515a60 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -112,7 +112,8 @@ public:
SkASSERT(bitmapMayBeMutable || fBitmap.isImmutable());
}
- sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>) const override;
+ sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>, SkColorType,
+ SkTransferFunctionBehavior) const override;
#if SK_SUPPORT_GPU
sk_sp<GrTextureProxy> refPinnedTextureProxy(uint32_t* uniqueID) const override;
@@ -342,69 +343,22 @@ bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) c
///////////////////////////////////////////////////////////////////////////////
-static inline void do_color_xform_non_linear_blending(SkBitmap* dst, const SkPixmap& src) {
- SkDEBUGCODE(SkColorSpaceTransferFn fn;);
- SkASSERT(dst->colorSpace()->isNumericalTransferFn(&fn) &&
- src.colorSpace()->isNumericalTransferFn(&fn));
-
- void* dstPixels = dst->getPixels();
- const void* srcPixels = src.addr();
- size_t dstRowBytes = dst->rowBytes();
- size_t srcRowBytes = src.rowBytes();
- if (kN32_SkColorType != src.colorType()) {
- SkAssertResult(src.readPixels(src.info().makeColorType(kN32_SkColorType), dstPixels,
- dstRowBytes, 0, 0));
-
- srcPixels = dstPixels;
- srcRowBytes = dstRowBytes;
- }
-
- std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform_Base::New(
- src.colorSpace(), dst->colorSpace(), SkTransferFunctionBehavior::kIgnore);
-
- void* dstRow = dstPixels;
- const void* srcRow = srcPixels;
- for (int y = 0; y < dst->height(); y++) {
- // This function assumes non-linear blending. Which means that we must start by
- // unpremultiplying in the gamma encoded space.
- const void* tmpRow = srcRow;
- if (kPremul_SkAlphaType == src.alphaType()) {
- SkUnpremultiplyRow<false>((uint32_t*) dstRow, (const uint32_t*) srcRow, dst->width());
- tmpRow = dstRow;
- }
-
- SkColorSpaceXform::ColorFormat fmt = select_xform_format(kN32_SkColorType);
- SkAssertResult(xform->apply(fmt, dstRow, fmt, tmpRow, dst->width(), dst->alphaType()));
-
- dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
- srcRow = SkTAddOffset<const void>(srcRow, srcRowBytes);
- }
-}
-
-sk_sp<SkImage> SkImage_Raster::onMakeColorSpace(sk_sp<SkColorSpace> target) const {
- // Force the color type of the new image to be kN32_SkColorType.
- // (1) This means we lose precision on F16 images. This is necessary while this function is
- // used to pre-transform inputs to a legacy canvas. Legacy canvases do not handle F16.
- // (2) kIndex8 and kGray8 must be expanded in order perform a color space transformation.
- // (3) Seems reasonable to expand k565 and k4444. It's nice to avoid these color types for
- // clients who opt into color space support.
- SkImageInfo dstInfo = fBitmap.info().makeColorType(kN32_SkColorType).makeColorSpace(target);
+sk_sp<SkImage> SkImage_Raster::onMakeColorSpace(sk_sp<SkColorSpace> target,
+ SkColorType targetColorType,
+ SkTransferFunctionBehavior premulBehavior) const {
+ SkImageInfo dstInfo = fBitmap.info().makeColorType(targetColorType).makeColorSpace(target);
SkBitmap dst;
dst.allocPixels(dstInfo);
SkPixmap src;
- SkTLazy<SkBitmap> tmp;
- if (!fBitmap.peekPixels(&src)) {
- tmp.init(fBitmap);
- SkAssertResult(tmp.get()->peekPixels(&src));
- }
+ SkAssertResult(fBitmap.peekPixels(&src));
// Treat nullptr srcs as sRGB.
if (!src.colorSpace()) {
src.setColorSpace(SkColorSpace::MakeSRGB());
}
- do_color_xform_non_linear_blending(&dst, src);
+ SkAssertResult(dst.writePixels(src));
dst.setImmutable();
return SkImage::MakeFromBitmap(dst);
}