From cb87423cffb22467033a9e4f932399fb970faab6 Mon Sep 17 00:00:00 2001 From: Matt Sarett Date: Wed, 5 Apr 2017 11:41:27 -0400 Subject: [PATCH] Add SkImage::makeColorSpace() to public API Gives Chrome the flexibility to xform and cache SkImages before they reach the SkColorSpaceXformCanvas. Bug: skia: Change-Id: I1f188f385b953b5a958c15578ea66deffb4dc6c5 Reviewed-on: https://skia-review.googlesource.com/11290 Commit-Queue: Matt Sarett Reviewed-by: Mike Klein Reviewed-by: Mike Reed --- include/core/SkImage.h | 16 ++++++++++++++++ src/core/SkColorSpaceXformer.cpp | 4 ++-- src/image/SkImage.cpp | 15 +++++++++++---- src/image/SkImage_Base.h | 9 +-------- tests/ImageTest.cpp | 7 ++++--- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/include/core/SkImage.h b/include/core/SkImage.h index f504897..ace4fe7 100644 --- a/include/core/SkImage.h +++ b/include/core/SkImage.h @@ -437,6 +437,22 @@ public: */ bool isLazyGenerated() const; + /** + * If |target| is supported, returns an SkImage in the |target| color space. + * Otherwise, returns nullptr. + * + * This will leave the image as is if it already in the |target| color space. + * Otherwise, it will convert the pixels from the src color space to the |target| + * color space. If this->colorSpace() is nullptr, the src color space will be + * treated as sRGB. + * + * If |premulBehavior| is kIgnore, any premultiplication or unpremultiplication will + * be performed in the gamma encoded space. If it is kRespect, premultiplication is + * assumed to be linear. + */ + sk_sp makeColorSpace(sk_sp target, + SkTransferFunctionBehavior premulBehavior) const; + protected: SkImage(int width, int height, uint32_t uniqueID); diff --git a/src/core/SkColorSpaceXformer.cpp b/src/core/SkColorSpaceXformer.cpp index 4d93fae..8a83dbc 100644 --- a/src/core/SkColorSpaceXformer.cpp +++ b/src/core/SkColorSpaceXformer.cpp @@ -28,7 +28,7 @@ std::unique_ptr SkColorSpaceXformer::Make(sk_sp SkColorSpaceXformer::apply(const SkImage* src) { - return as_IB(src)->makeColorSpace(fDst); + return src->makeColorSpace(fDst, SkTransferFunctionBehavior::kIgnore); } sk_sp SkColorSpaceXformer::apply(const SkBitmap& src) { @@ -37,7 +37,7 @@ sk_sp SkColorSpaceXformer::apply(const SkBitmap& src) { return nullptr; } - sk_sp xformed = as_IB(image)->makeColorSpace(fDst); + sk_sp xformed = image->makeColorSpace(fDst, SkTransferFunctionBehavior::kIgnore); // We want to be sure we don't let the kNever_SkCopyPixelsMode image escape this stack frame. SkASSERT(xformed != image); return xformed; diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp index e45bbd7..0847eb1 100644 --- a/src/image/SkImage.cpp +++ b/src/image/SkImage.cpp @@ -302,7 +302,13 @@ bool SkImage::isAlphaOnly() const { return as_IB(this)->onImageInfo().colorType() == kAlpha_8_SkColorType; } -sk_sp SkImage_Base::makeColorSpace(sk_sp target) const { +sk_sp SkImage::makeColorSpace(sk_sp target, + SkTransferFunctionBehavior premulBehavior) const { + if (SkTransferFunctionBehavior::kRespect == premulBehavior) { + // TODO (msarett, brianosman): Implement this. + return nullptr; + } + SkColorSpaceTransferFn fn; if (!target || !target->isNumericalTransferFn(&fn)) { return nullptr; @@ -313,11 +319,12 @@ sk_sp SkImage_Base::makeColorSpace(sk_sp target) const { // (2) The color type is kAlpha8. if ((!this->colorSpace() && target->isSRGB()) || SkColorSpace::Equals(this->colorSpace(), target.get()) || - kAlpha_8_SkColorType == this->onImageInfo().colorType()) { - return sk_ref_sp(const_cast(this)); + kAlpha_8_SkColorType == as_IB(this)->onImageInfo().colorType()) { + return sk_ref_sp(const_cast(this)); } - return this->onMakeColorSpace(std::move(target)); + // TODO: We might consider making this a deferred conversion? + return as_IB(this)->onMakeColorSpace(std::move(target)); } ////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h index 5bdf940..062d785 100644 --- a/src/image/SkImage_Base.h +++ b/src/image/SkImage_Base.h @@ -86,17 +86,10 @@ public: fAddedToCache.store(true); } - // Transforms image into the input color space. - sk_sp makeColorSpace(sk_sp target) const; - virtual bool onPinAsTexture(GrContext*) const { return false; } virtual void onUnpinAsTexture(GrContext*) const {} -protected: - virtual sk_sp onMakeColorSpace(sk_sp) const { - // TODO: Make this pure virtual. - return sk_ref_sp(const_cast(this)); - } + virtual sk_sp onMakeColorSpace(sk_sp) const = 0; private: // Set true by caches when they cache content that's derived from the current pixels. diff --git a/tests/ImageTest.cpp b/tests/ImageTest.cpp index 9916ed3..22004a0 100644 --- a/tests/ImageTest.cpp +++ b/tests/ImageTest.cpp @@ -1061,7 +1061,7 @@ DEF_TEST(Image_makeColorSpace, r) { *srgbBitmap.getAddr32(0, 0) = SkSwizzle_RGBA_to_PMColor(0xFF604020); srgbBitmap.setImmutable(); sk_sp srgbImage = SkImage::MakeFromBitmap(srgbBitmap); - sk_sp p3Image = as_IB(srgbImage)->makeColorSpace(p3); + sk_sp p3Image = srgbImage->makeColorSpace(p3, SkTransferFunctionBehavior::kIgnore); SkBitmap p3Bitmap; bool success = p3Image->asLegacyBitmap(&p3Bitmap, SkImage::kRO_LegacyBitmapMode); REPORTER_ASSERT(r, success); @@ -1070,7 +1070,8 @@ DEF_TEST(Image_makeColorSpace, r) { REPORTER_ASSERT(r, almost_equal(0x40, SkGetPackedG32(*p3Bitmap.getAddr32(0, 0)))); REPORTER_ASSERT(r, almost_equal(0x5E, SkGetPackedB32(*p3Bitmap.getAddr32(0, 0)))); - sk_sp adobeImage = as_IB(srgbImage)->makeColorSpace(adobeGamut); + sk_sp adobeImage = srgbImage->makeColorSpace(adobeGamut, + SkTransferFunctionBehavior::kIgnore); SkBitmap adobeBitmap; success = adobeImage->asLegacyBitmap(&adobeBitmap, SkImage::kRO_LegacyBitmapMode); REPORTER_ASSERT(r, success); @@ -1080,7 +1081,7 @@ DEF_TEST(Image_makeColorSpace, r) { REPORTER_ASSERT(r, almost_equal(0x4C, SkGetPackedB32(*adobeBitmap.getAddr32(0, 0)))); srgbImage = GetResourceAsImage("1x1.png"); - p3Image = as_IB(srgbImage)->makeColorSpace(p3); + p3Image = srgbImage->makeColorSpace(p3, SkTransferFunctionBehavior::kIgnore); success = p3Image->asLegacyBitmap(&p3Bitmap, SkImage::kRO_LegacyBitmapMode); REPORTER_ASSERT(r, success); p3Bitmap.lockPixels(); -- 2.7.4