diff options
-rw-r--r-- | include/codec/SkAndroidCodec.h | 3 | ||||
-rw-r--r-- | src/codec/SkAndroidCodec.cpp | 48 |
2 files changed, 48 insertions, 3 deletions
diff --git a/include/codec/SkAndroidCodec.h b/include/codec/SkAndroidCodec.h index e30a2aa0b3..8e9ad4e2d3 100644 --- a/include/codec/SkAndroidCodec.h +++ b/include/codec/SkAndroidCodec.h @@ -79,9 +79,6 @@ public: * @param outputColorType Color type that the client will 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); 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<SkColorSpace> 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(); |