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 <msarett@google.com>
Reviewed-by: Leon Scroggins <scroggo@google.com>
This commit is contained in:
Matt Sarett 2017-02-15 08:48:02 -05:00 committed by Skia Commit-Bot
parent 3f405985be
commit 2ae3a2ec29
2 changed files with 48 additions and 3 deletions

View File

@ -79,9 +79,6 @@ public:
* @param outputColorType Color type that the client will decode to * @param outputColorType Color type that the client will decode to
* *
* Returns the appropriate color space to decode to. * Returns the appropriate color space to decode to.
*
* For now, this just returns a default. This could be updated to take
* requests for wide gamut modes or specific output spaces.
*/ */
sk_sp<SkColorSpace> computeOutputColorSpace(SkColorType outputColorType); sk_sp<SkColorSpace> computeOutputColorSpace(SkColorType outputColorType);

View File

@ -17,6 +17,49 @@ static bool is_valid_sample_size(int sampleSize) {
return sampleSize > 0; 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) SkAndroidCodec::SkAndroidCodec(SkCodec* codec)
: fInfo(codec->getInfo()) : fInfo(codec->getInfo())
, fCodec(codec) , fCodec(codec)
@ -131,6 +174,11 @@ sk_sp<SkColorSpace> SkAndroidCodec::computeOutputColorSpace(SkColorType outputCo
case kRGBA_8888_SkColorType: case kRGBA_8888_SkColorType:
case kBGRA_8888_SkColorType: case kBGRA_8888_SkColorType:
case kIndex_8_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(); return SkColorSpace::MakeSRGB();
case kRGBA_F16_SkColorType: case kRGBA_F16_SkColorType:
return SkColorSpace::MakeSRGBLinear(); return SkColorSpace::MakeSRGBLinear();