Support parametric transfer functions in SkImage_Raster::onMakeColorSpace()

BUG=skia:6456
Change-Id: Ib94bba9db669562a9b2b64fff56ebe40a2bc0096
Reviewed-on: https://skia-review.googlesource.com/11122
Commit-Queue: Matt Sarett <msarett@google.com>
Reviewed-by: Mike Klein <mtklein@chromium.org>
This commit is contained in:
Matt Sarett 2017-04-03 11:42:52 -04:00 committed by Skia Commit-Bot
parent 887cdf1128
commit 5b1dba8451
2 changed files with 57 additions and 3 deletions

View File

@ -9,12 +9,15 @@
#include "SkBitmap.h" #include "SkBitmap.h"
#include "SkBitmapProcShader.h" #include "SkBitmapProcShader.h"
#include "SkCanvas.h" #include "SkCanvas.h"
#include "SkColorSpaceXform_Base.h"
#include "SkColorSpaceXformPriv.h"
#include "SkColorTable.h" #include "SkColorTable.h"
#include "SkData.h" #include "SkData.h"
#include "SkImagePriv.h" #include "SkImagePriv.h"
#include "SkPixelRef.h" #include "SkPixelRef.h"
#include "SkSurface.h" #include "SkSurface.h"
#include "SkTLazy.h" #include "SkTLazy.h"
#include "SkUnPreMultiplyPriv.h"
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
#include "GrContext.h" #include "GrContext.h"
@ -350,6 +353,47 @@ bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) c
return this->INHERITED::onAsLegacyBitmap(bitmap, mode); return this->INHERITED::onAsLegacyBitmap(bitmap, mode);
} }
///////////////////////////////////////////////////////////////////////////////
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 { sk_sp<SkImage> SkImage_Raster::onMakeColorSpace(sk_sp<SkColorSpace> target) const {
// Force the color type of the new image to be kN32_SkColorType. // 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 // (1) This means we lose precision on F16 images. This is necessary while this function is
@ -374,9 +418,7 @@ sk_sp<SkImage> SkImage_Raster::onMakeColorSpace(sk_sp<SkColorSpace> target) cons
src.setColorSpace(SkColorSpace::MakeSRGB()); src.setColorSpace(SkColorSpace::MakeSRGB());
} }
// Use kIgnore for transfer function behavior. This is used by the SkColorSpaceXformCanvas, do_color_xform_non_linear_blending(&dst, src);
// which wants to pre-xform the inputs but ignore the transfer function on blends.
SkAssertResult(dst.writePixels(src, 0, 0, SkTransferFunctionBehavior::kIgnore));
dst.setImmutable(); dst.setImmutable();
return SkImage::MakeFromBitmap(dst); return SkImage::MakeFromBitmap(dst);
} }

View File

@ -1054,6 +1054,9 @@ DEF_TEST(Image_ColorSpace, r) {
DEF_TEST(Image_makeColorSpace, r) { DEF_TEST(Image_makeColorSpace, r) {
sk_sp<SkColorSpace> p3 = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, sk_sp<SkColorSpace> p3 = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
SkColorSpace::kDCIP3_D65_Gamut); SkColorSpace::kDCIP3_D65_Gamut);
SkColorSpaceTransferFn fn;
fn.fA = 1.f; fn.fB = 0.f; fn.fC = 0.f; fn.fD = 0.f; fn.fE = 0.f; fn.fF = 0.f; fn.fG = 1.8f;
sk_sp<SkColorSpace> adobeGamut = SkColorSpace::MakeRGB(fn, SkColorSpace::kAdobeRGB_Gamut);
SkBitmap srgbBitmap; SkBitmap srgbBitmap;
srgbBitmap.allocPixels(SkImageInfo::MakeS32(1, 1, kOpaque_SkAlphaType)); srgbBitmap.allocPixels(SkImageInfo::MakeS32(1, 1, kOpaque_SkAlphaType));
@ -1069,6 +1072,15 @@ DEF_TEST(Image_makeColorSpace, r) {
REPORTER_ASSERT(r, almost_equal(0x40, SkGetPackedG32(*p3Bitmap.getAddr32(0, 0)))); REPORTER_ASSERT(r, almost_equal(0x40, SkGetPackedG32(*p3Bitmap.getAddr32(0, 0))));
REPORTER_ASSERT(r, almost_equal(0x5E, SkGetPackedB32(*p3Bitmap.getAddr32(0, 0)))); REPORTER_ASSERT(r, almost_equal(0x5E, SkGetPackedB32(*p3Bitmap.getAddr32(0, 0))));
sk_sp<SkImage> adobeImage = as_IB(srgbImage)->makeColorSpace(adobeGamut);
SkBitmap adobeBitmap;
success = adobeImage->asLegacyBitmap(&adobeBitmap, SkImage::kRO_LegacyBitmapMode);
REPORTER_ASSERT(r, success);
adobeBitmap.lockPixels();
REPORTER_ASSERT(r, almost_equal(0x21, SkGetPackedR32(*adobeBitmap.getAddr32(0, 0))));
REPORTER_ASSERT(r, almost_equal(0x31, SkGetPackedG32(*adobeBitmap.getAddr32(0, 0))));
REPORTER_ASSERT(r, almost_equal(0x4C, SkGetPackedB32(*adobeBitmap.getAddr32(0, 0))));
srgbImage = GetResourceAsImage("1x1.png"); srgbImage = GetResourceAsImage("1x1.png");
p3Image = as_IB(srgbImage)->makeColorSpace(p3); p3Image = as_IB(srgbImage)->makeColorSpace(p3);
success = p3Image->asLegacyBitmap(&p3Bitmap, SkImage::kRO_LegacyBitmapMode); success = p3Image->asLegacyBitmap(&p3Bitmap, SkImage::kRO_LegacyBitmapMode);