From 2ae3a2ec299b9b529496bbd06b8276263c8df9b0 Mon Sep 17 00:00:00 2001 From: Matt Sarett Date: Wed, 15 Feb 2017 08:48:02 -0500 Subject: Suggest P3 for wide gamut images in SkAndroidCodec This will prevent us from clipping the gamut to sRGB. BUG=skia: Change-Id: Ifc34369d96aa9dd92ae2af72aac1cfa17fdc4b94 Reviewed-on: https://skia-review.googlesource.com/8025 Commit-Queue: Matt Sarett Reviewed-by: Leon Scroggins --- src/codec/SkAndroidCodec.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'src') diff --git a/src/codec/SkAndroidCodec.cpp b/src/codec/SkAndroidCodec.cpp index 5fc7bfc585..c1f12fa591 100644 --- a/src/codec/SkAndroidCodec.cpp +++ b/src/codec/SkAndroidCodec.cpp @@ -17,6 +17,49 @@ static bool is_valid_sample_size(int sampleSize) { return sampleSize > 0; } +/** + * Loads the gamut as a set of three points (triangle). + */ +static void load_gamut(SkPoint rgb[], const SkMatrix44& xyz) { + // rx = rX / (rX + rY + rZ) + // ry = rY / (rX + rY + rZ) + // gx, gy, bx, and gy are calulcated similarly. + float rSum = xyz.get(0, 0) + xyz.get(1, 0) + xyz.get(2, 0); + float gSum = xyz.get(0, 1) + xyz.get(1, 1) + xyz.get(2, 1); + float bSum = xyz.get(0, 2) + xyz.get(1, 2) + xyz.get(2, 2); + rgb[0].fX = xyz.get(0, 0) / rSum; + rgb[0].fY = xyz.get(1, 0) / rSum; + rgb[1].fX = xyz.get(0, 1) / gSum; + rgb[1].fY = xyz.get(1, 1) / gSum; + rgb[2].fX = xyz.get(0, 2) / bSum; + rgb[2].fY = xyz.get(1, 2) / bSum; +} + +/** + * Calculates the area of the triangular gamut. + */ +static float calculate_area(SkPoint abc[]) { + SkPoint a = abc[0]; + SkPoint b = abc[1]; + SkPoint c = abc[2]; + return 0.5f * SkTAbs(a.fX*b.fY + b.fX*c.fY - a.fX*c.fY - c.fX*b.fY - b.fX*a.fY); +} + +static const float kSRGB_D50_GamutArea = 0.084f; + +static bool is_wide_gamut(const SkColorSpace* colorSpace) { + // Determine if the source image has a gamut that is wider than sRGB. If so, we + // will use P3 as the output color space to avoid clipping the gamut. + const SkMatrix44* toXYZD50 = as_CSB(colorSpace)->toXYZD50(); + if (toXYZD50) { + SkPoint rgb[3]; + load_gamut(rgb, *toXYZD50); + return calculate_area(rgb) > kSRGB_D50_GamutArea; + } + + return false; +} + SkAndroidCodec::SkAndroidCodec(SkCodec* codec) : fInfo(codec->getInfo()) , fCodec(codec) @@ -131,6 +174,11 @@ sk_sp SkAndroidCodec::computeOutputColorSpace(SkColorType outputCo case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: case kIndex_8_SkColorType: + if (is_wide_gamut(fCodec->getInfo().colorSpace())) { + return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, + SkColorSpace::kDCIP3_D65_Gamut); + } + return SkColorSpace::MakeSRGB(); case kRGBA_F16_SkColorType: return SkColorSpace::MakeSRGBLinear(); -- cgit v1.2.3