aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/codec/SkAndroidCodec.h3
-rw-r--r--src/codec/SkAndroidCodec.cpp48
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();