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:
parent
887cdf1128
commit
5b1dba8451
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user