Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(283)

Unified Diff: ui/gfx/color_transform.cc

Issue 2203663002: ColorTransform, transforms colors from one color space to another (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/gfx/color_transform.h ('k') | ui/gfx/color_transform_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/gfx/color_transform.cc
diff --git a/ui/gfx/color_transform.cc b/ui/gfx/color_transform.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fdf4a2926af36ea997be107532494a1e9efadc67
--- /dev/null
+++ b/ui/gfx/color_transform.cc
@@ -0,0 +1,609 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/color_transform.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/transform.h"
+
+namespace gfx {
+
+Transform Invert(const Transform& t) {
+ Transform ret = t;
+ if (!t.GetInverse(&ret)) {
+ LOG(ERROR) << "Inverse should alsways be possible.";
+ }
+ return ret;
+}
+
+ColorTransform::TriStim Map(const Transform& t, ColorTransform::TriStim color) {
+ t.TransformPoint(&color);
+ return color;
+}
+
+// XY color coordinate
+typedef std::pair<float, float> XY;
ccameron 2016/08/02 02:47:38 use gfx::PointF instead of std::pair<float,float>
hubbe 2016/08/02 08:10:57 Gone.
+
+std::vector<XY> GetPrimaries(ColorSpace::PrimaryID id) {
ccameron 2016/08/02 02:47:38 Don't return a std::vector here -- pass the return
hubbe 2016/08/02 08:10:57 Calling the arguments red/green/blue is somewhat m
ccameron 2016/08/02 17:12:57 Yeah, I was wondering about that ... in particular
+ std::vector<XY> ret(4);
+ switch (id) {
+ default:
+ // If we don't know, assume BT709
+
+ case ColorSpace::PrimaryID::BT709:
+ // Red
+ ret[0].first = 0.640;
+ ret[0].second = 0.330;
+ // Green
+ ret[1].first = 0.300;
+ ret[1].second = 0.600;
+ // Blue
+ ret[2].first = 0.150;
+ ret[2].second = 0.060;
+ // Whitepoint (D65)
+ ret[3].first = 0.3127;
+ ret[3].second = 0.3290;
+ break;
+
+ case ColorSpace::PrimaryID::BT470M:
+ // Red
+ ret[0].first = 0.67;
+ ret[0].second = 0.33;
+ // Green
+ ret[1].first = 0.21;
+ ret[1].second = 0.71;
+ // Blue
+ ret[2].first = 0.14;
+ ret[2].second = 0.08;
+ // Whitepoint
+ ret[3].first = 0.31;
+ ret[3].second = 0.316;
+ break;
+
+ case ColorSpace::PrimaryID::BT470BG:
+ // Red
+ ret[0].first = 0.64;
+ ret[0].second = 0.33;
+ // Green
+ ret[1].first = 0.29;
+ ret[1].second = 0.60;
+ // Blue
+ ret[2].first = 0.15;
+ ret[2].second = 0.06;
+ // Whitepoint (D65)
+ ret[3].first = 0.3127;
+ ret[3].second = 0.3290;
+ break;
+
+ case ColorSpace::PrimaryID::SMPTE170M:
+ case ColorSpace::PrimaryID::SMPTE240M:
+ // Red
+ ret[0].first = 0.630;
+ ret[0].second = 0.340;
+ // Green
+ ret[1].first = 0.310;
+ ret[1].second = 0.595;
+ // Blue
+ ret[2].first = 0.155;
+ ret[2].second = 0.070;
+ // Whitepoint (D65)
+ ret[3].first = 0.3127;
+ ret[3].second = 0.3290;
+ break;
+
+ case ColorSpace::PrimaryID::FILM:
+ // Red
+ ret[0].first = 0.681;
+ ret[0].second = 0.319;
+ // Green
+ ret[1].first = 0.243;
+ ret[1].second = 0.692;
+ // Blue
+ ret[2].first = 0.145;
+ ret[2].second = 0.049;
+ // Whitepoint (C)
+ ret[3].first = 0.310;
+ ret[3].second = 0.136;
+ break;
+
+ case ColorSpace::PrimaryID::BT2020:
+ // Red
+ ret[0].first = 0.708;
+ ret[0].second = 0.292;
+ // Green
+ ret[1].first = 0.170;
+ ret[1].second = 0.797;
+ // Blue
+ ret[2].first = 0.131;
+ ret[2].second = 0.046;
+ // Whitepoint (D65)
+ ret[3].first = 0.3127;
+ ret[3].second = 0.3290;
+ break;
+
+ case ColorSpace::PrimaryID::SMPTEST428_1:
+ // X
+ ret[0].first = 1.0;
+ ret[0].second = 0.0;
+ // Y
+ ret[1].first = 0.0;
+ ret[1].second = 1.0;
+ // Z
+ ret[2].first = 0.0;
+ ret[2].second = 0.0;
+ // Whitepoint (E)
+ ret[3].first = 1.0f / 3.0f;
+ ret[3].second = 1.0f / 3.0f;
+ break;
+
+ case ColorSpace::PrimaryID::SMPTEST431_2:
+ // Red
+ ret[0].first = 0.680;
+ ret[0].second = 0.320;
+ // Green
+ ret[1].first = 0.265;
+ ret[1].second = 0.690;
+ // Blue
+ ret[2].first = 0.150;
+ ret[2].second = 0.060;
+ // Whitepoint
+ ret[3].first = 0.314;
+ ret[3].second = 0.351;
+ break;
+
+ case ColorSpace::PrimaryID::SMPTEST432_1:
+ // Red
+ ret[0].first = 0.680;
+ ret[0].second = 0.320;
+ // Green
+ ret[1].first = 0.265;
+ ret[1].second = 0.690;
+ // Blue
+ ret[2].first = 0.150;
+ ret[2].second = 0.060;
+ // Whitepoint (D65)
+ ret[3].first = 0.3127;
+ ret[3].second = 0.3290;
+ break;
+
+ case ColorSpace::PrimaryID::XYZ_D50:
+ // X
+ ret[0].first = 1.0;
+ ret[0].second = 0.0;
+ // Y
+ ret[1].first = 0.0;
+ ret[1].second = 1.0;
+ // Z
+ ret[2].first = 0.0;
+ ret[2].second = 0.0;
+ // D50
+ ret[3].first = 0.34567;
+ ret[3].second = 0.35850;
+ break;
+ }
+ return ret;
+}
+
+ColorTransform::TriStim xy2xyz(const XY& xy) {
ccameron 2016/08/02 02:47:39 naming nit: rename to XYToTriStim Function names
hubbe 2016/08/02 08:10:57 That doesn't specify what color space the tristim
+ return ColorTransform::TriStim(xy.first, xy.second,
+ 1.0f - xy.first - xy.second);
+}
+
+GFX_EXPORT Transform GetPrimaryMatrix(ColorSpace::PrimaryID id) {
ccameron 2016/08/02 02:47:38 This can be made simpler by using the existing mat
hubbe 2016/08/02 08:10:57 I like Scale3d, but I think the order in your func
ccameron 2016/08/02 17:12:57 Makes sense.
+ std::vector<XY> primaries = GetPrimaries(id);
+ ColorTransform::TriStim Rxyz = xy2xyz(primaries[0]);
+ ColorTransform::TriStim Gxyz = xy2xyz(primaries[1]);
+ ColorTransform::TriStim Bxyz = xy2xyz(primaries[2]);
+ ColorTransform::TriStim Wxyz = xy2xyz(primaries[3]);
ccameron 2016/08/02 17:12:57 Y was wondering why we didn't call them just "prim
+ ColorTransform::TriStim WXYZ(Wxyz.x() / Wxyz.y(), 1.0f, Wxyz.z() / Wxyz.y());
+
+ Transform tmp(Rxyz.x(), Gxyz.x(), Bxyz.x(), 0.0f, Rxyz.y(), Gxyz.y(),
+ Bxyz.y(), 0.0f, Rxyz.z(), Gxyz.z(), Bxyz.z(), 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f);
+
+ ColorTransform::TriStim conv = Map(Invert(tmp), WXYZ);
+ Transform ret(
+ conv.x() * tmp.matrix().get(0, 0), conv.y() * tmp.matrix().get(0, 1),
+ conv.z() * tmp.matrix().get(0, 2), 0.0f,
+ conv.x() * tmp.matrix().get(1, 0), conv.y() * tmp.matrix().get(1, 1),
+ conv.z() * tmp.matrix().get(1, 2), 0.0f,
+ conv.x() * tmp.matrix().get(2, 0), conv.y() * tmp.matrix().get(2, 1),
+ conv.z() * tmp.matrix().get(2, 2), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+
+ // Chromatic adaptation.
+ Transform bradford(0.8951000f, 0.2664000f, -0.1614000f, 0.0f, -0.7502000f,
+ 1.7135000f, 0.0367000f, 0.0f, 0.0389000f, -0.0685000f,
+ 1.0296000f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+
+ Transform bradford_inv = Invert(bradford);
+
+ ColorTransform::TriStim D50(0.9642, 1.0000, 0.8249);
+ ColorTransform::TriStim source_response = Map(bradford, WXYZ);
+ ColorTransform::TriStim dest_response = Map(bradford, D50);
+
+ Transform adapter(dest_response.x() / source_response.x(), 0.0f, 0.0f, 0.0f,
+ 0.0f, dest_response.y() / source_response.y(), 0.0f, 0.0f,
+ 0.0f, 0.0f, dest_response.z() / source_response.z(), 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f);
+
+ return bradford * adapter * bradford_inv * ret;
+}
+
+GFX_EXPORT float fromLinear(ColorSpace::TransferID id, float v) {
ccameron 2016/08/02 02:47:39 Nit: capitalization: FromLinear.
hubbe 2016/08/02 08:10:57 Done.
+ switch (id) {
+ default:
+ case ColorSpace::TransferID::BT709:
+ case ColorSpace::TransferID::SMPTE170M:
+ case ColorSpace::TransferID::BT2020_10:
+ case ColorSpace::TransferID::BT2020_12: {
+ v = fmax(0.0f, v);
+ float a = 1.099296826809442f;
+ float b = 0.018053968510807;
+ if (v <= b) {
+ return 4.5f * v;
+ } else {
+ return a * pow(v, 0.45f) - (a - 1.0f);
+ }
+ }
+
+ case ColorSpace::TransferID::GAMMA22:
+ v = fmax(0.0f, v);
+ return pow(v, 1.0f / 2.2f);
+
+ case ColorSpace::TransferID::GAMMA28:
+ v = fmax(0.0f, v);
+ return pow(v, 1.0f / 2.8f);
+
+ case ColorSpace::TransferID::SMPTE240M: {
+ v = fmax(0.0f, v);
+ float a = 1.11157219592173128753f;
+ float b = 0.02282158552944503135f;
+ if (v <= b) {
+ return 4.0f * v;
+ } else {
+ return a * pow(v, 0.45f) - (a - 1.0f);
+ }
+ }
+
+ case ColorSpace::TransferID::LINEAR:
+ return v;
+
+ case ColorSpace::TransferID::LOG:
+ if (v < 0.01)
+ return 0.0;
+ return 1.0 + log(v) / log(10.0f) / 2.0f;
+
+ case ColorSpace::TransferID::LOG_SQRT:
+ if (v < sqrt(10.0f) / 1000.0)
+ return 0.0;
+ return 1.0 + log(v) / log(10.0f) / 2.5f;
+
+ case ColorSpace::TransferID::IEC61966_2_4: {
+ float a = 1.099296826809442f;
+ float b = 0.018053968510807f;
+ if (v < -b) {
+ return -a * pow(-v, 0.45) + (a - 1.0f);
+ } else if (v <= b) {
+ return 4.5 * v;
+ } else {
+ return a * pow(v, 0.45) - (a - 1.0f);
+ }
+ }
+
+ case ColorSpace::TransferID::BT1361_ECG: {
+ float a = 1.099;
+ float b = 0.018;
+ float l = 0.0045;
+ if (v < -l) {
+ return -(a * pow(-4.0f * v, 0.45) + (a - 1.0f)) / 4.0f;
+ } else if (v <= b) {
+ return 4.5 * v;
+ } else {
+ return a * pow(v, 0.45) - (a - 1.0f);
+ }
+ }
+
+ case ColorSpace::TransferID::IEC61966_2_1: { // SRGB
+ v = fmax(0.0f, v);
+ float a = 1.055f;
+ float b = 0.0031308f;
+ if (v < b) {
+ return 12.92f * v;
+ } else {
+ return a * pow(v, 1.0f / 2.4f) - (a - 1.0f);
+ }
+ }
+ case ColorSpace::TransferID::SMPTEST2084: {
+ v = fmax(0.0f, v);
+ float m1 = (2610.0 / 4096.0) / 4.0;
+ float m2 = (2523.0 / 4096.0) * 128.0;
+ float c1 = 3424.0 / 4096.0;
+ float c2 = (2413.0 / 4096.0) * 32.0;
+ float c3 = (2392.0 / 4096.0) * 32.0;
+ return pow((c1 + c2 * pow(v, m1)) / (1.0f + c3 * pow(v, m1)), m2);
+ }
+
+ case ColorSpace::TransferID::SMPTEST428_1:
+ v = fmax(0.0f, v);
+ return pow(48.0f * v + 52.37f, 1.0f / 2.6f);
+
+ // Chrome-specific values below
+ case ColorSpace::TransferID::GAMMA24:
+ v = fmax(0.0f, v);
+ return pow(v, 1.0f / 2.4f);
+ }
+}
+
+GFX_EXPORT float toLinear(ColorSpace::TransferID id, float v) {
ccameron 2016/08/02 02:47:38 nit: ToLinear
hubbe 2016/08/02 08:10:57 Done.
+ switch (id) {
+ default:
+ case ColorSpace::TransferID::BT709:
+ case ColorSpace::TransferID::SMPTE170M:
+ case ColorSpace::TransferID::BT2020_10:
+ case ColorSpace::TransferID::BT2020_12: {
+ v = fmax(0.0f, v);
+ float a = 1.099296826809442f;
+ float b = 0.018053968510807;
+ if (v < fromLinear(ColorSpace::TransferID::BT709, b)) {
+ return v / 4.5f;
+ } else {
+ return pow((v + a - 1.0f) / a, 1.0f / 0.45f);
+ }
+ }
+
+ case ColorSpace::TransferID::GAMMA22:
+ v = fmax(0.0f, v);
+ return pow(v, 2.2f);
+
+ case ColorSpace::TransferID::GAMMA28:
+ v = fmax(0.0f, v);
+ return pow(v, 2.8f);
+
+ case ColorSpace::TransferID::SMPTE240M: {
+ v = fmax(0.0f, v);
+ float a = 1.11157219592173128753f;
+ float b = 0.02282158552944503135f;
+ if (v <= fromLinear(ColorSpace::TransferID::SMPTE240M, b)) {
+ return v / 4.0f;
+ } else {
+ return pow((v + a - 1.0f) / a, 1.0f / 0.45f);
+ }
+ }
+
+ case ColorSpace::TransferID::LINEAR:
+ return v;
+
+ case ColorSpace::TransferID::LOG:
+ if (v < 0.0)
+ return 0.0;
+ return pow(10.0, (v - 1.0f) * 2.0f);
+
+ case ColorSpace::TransferID::LOG_SQRT:
+ if (v < 0.0)
+ return 0.0;
+ return pow(10.0, (v - 1.0f) * 2.5f);
+
+ case ColorSpace::TransferID::IEC61966_2_4: {
+ float a = 1.099296826809442f;
+ float b = 0.018053968510807f;
+ if (v < fromLinear(ColorSpace::TransferID::IEC61966_2_4, -a)) {
+ return -pow((a - 1.0f - v) / a, 1.0f / 0.45f);
+ } else if (v <= fromLinear(ColorSpace::TransferID::IEC61966_2_4, b)) {
+ return v / 4.5f;
+ } else {
+ return pow((v + a - 1.0f) / a, 1.0f / 0.45f);
+ }
+ }
+
+ case ColorSpace::TransferID::BT1361_ECG: {
+ float a = 1.099;
+ float b = 0.018;
+ float l = 0.0045;
+ if (v < fromLinear(ColorSpace::TransferID::BT1361_ECG, -l)) {
+ return -pow((1.0f - a - v * 4.0) / a, 1.0f / 0.45f) / 4.0f;
+ } else if (v <= fromLinear(ColorSpace::TransferID::BT1361_ECG, b)) {
+ return v / 4.5f;
+ } else {
+ return pow((v + a - 1.0f) / a, 1.0f / 0.45f);
+ }
+ }
+
+ case ColorSpace::TransferID::IEC61966_2_1: { // SRGB
+ v = fmax(0.0f, v);
+ float a = 1.055f;
+ float b = 0.0031308f;
+ if (v < fromLinear(ColorSpace::TransferID::IEC61966_2_1, b)) {
+ return v / 12.92f;
+ } else {
+ return pow((v + a - 1.0f) / a, 2.4f);
+ }
+ }
+
+ case ColorSpace::TransferID::SMPTEST2084: {
+ v = fmax(0.0f, v);
+ float m1 = (2610.0f / 4096.0f) / 4.0f;
+ float m2 = (2523.0f / 4096.0f) * 128.0f;
+ float c1 = 3424.0f / 4096.0f;
+ float c2 = (2413.0f / 4096.0f) * 32.0f;
+ float c3 = (2392.0f / 4096.0f) * 32.0f;
+ return pow(fmax(pow(v, 1.0 / m2) - c1, 0) / (c2 - c3 * pow(v, 1.0 / m2)),
+ 1.0f / m1);
+ }
+
+ case ColorSpace::TransferID::SMPTEST428_1:
+ return (pow(v, 2.6f) - 52.37f) / 48.0f;
+
+ // Chrome-specific values below
+ case ColorSpace::TransferID::GAMMA24:
+ v = fmax(0.0f, v);
+ return pow(v, 2.4f);
+ }
+}
+
+GFX_EXPORT Transform GetTransferMatrix(ColorSpace::MatrixID id) {
+ float Kr, Kb;
+ switch (id) {
+ case ColorSpace::MatrixID::RGB:
+ return Transform();
+
+ case ColorSpace::MatrixID::BT709:
+ case ColorSpace::MatrixID::UNSPECIFIED:
+ case ColorSpace::MatrixID::RESERVED:
+ Kr = 0.2126f;
+ Kb = 0.0722f;
+ break;
+
+ case ColorSpace::MatrixID::FCC:
+ Kr = 0.30f;
+ Kb = 0.11f;
+ break;
+
+ case ColorSpace::MatrixID::BT470BG:
+ case ColorSpace::MatrixID::SMPTE170M:
+ Kr = 0.299f;
+ Kb = 0.144f;
+ break;
+
+ case ColorSpace::MatrixID::SMPTE240M:
+ Kr = 0.212f;
+ Kb = 0.087f;
+ break;
+
+ case ColorSpace::MatrixID::YCOCG:
+ return Transform(0.25f, 0.5f, 0.25f, 0.5, // 1
+ -0.25f, 0.5f, -0.25f, 0.5, // 2
+ 0.5f, 0.0f, -0.5f, 0.0, // 3
+ 0.0f, 0.0f, 0.0f, 1.0f); // 4
+
+ // TODO(hubbe): Check if the CL equation is right.
+ case ColorSpace::MatrixID::BT2020_NCL:
+ case ColorSpace::MatrixID::BT2020_CL:
+ Kr = 0.2627f;
+ Kb = 0.0593f;
+ break;
+
+ case ColorSpace::MatrixID::YDZDX:
+ return Transform(0.0f, 1.0f, 0.0, 0.0f, // 1
+ 0.0f, -0.5f, 0.986566f / 2.0f, 0.5f, // 2
+ 0.5f, -0.991902f / 2.0f, 0.0f, 0.5f, // 3
+ 0.0f, 0.0f, 0.0f, 1.0f); // 4
+ }
+ float u_m = 0.5f / (1.0f - Kb);
+ float v_m = 0.5f / (1.0f - Kr);
+ return Transform(
+ Kr, 1.0f - Kr - Kb, Kb, 0.0f, // 1
+ u_m * -Kr, u_m * -(1.0f - Kr - Kb), u_m * (1.0f - Kb), 0.5f, // 2
+ v_m * (1.0f - Kr), v_m * -(1.0f - Kr - Kb), v_m * -Kb, 0.5f, // 3
+ 0.0f, 0.0f, 0.0f, 1.0f); // 4
+}
+
+Transform GetRangeAdjustMatrix(ColorSpace::RangeID range,
+ ColorSpace::MatrixID matrix) {
+ switch (range) {
+ case ColorSpace::RangeID::FULL:
+ return Transform();
+
+ case ColorSpace::RangeID::LIMITED:
+ break;
+ }
+ switch (matrix) {
+ case ColorSpace::MatrixID::RGB:
+ case ColorSpace::MatrixID::YCOCG:
+ return Transform(255.0f / 219.0f, 0.0f, 0.0f, -16.0f / 219.0f, // 1
+ 0.0f, 255.0f / 219.0f, 0.0f, -16.0f / 219.0f, // 2
+ 0.0f, 0.0f, 255.0f / 219.0f, -16.0f / 219.0f, // 3
+ 0.0f, 0.0f, 0.0f, 1.0f); // 4
+
+ case ColorSpace::MatrixID::BT709:
+ case ColorSpace::MatrixID::UNSPECIFIED:
+ case ColorSpace::MatrixID::RESERVED:
+ case ColorSpace::MatrixID::FCC:
+ case ColorSpace::MatrixID::BT470BG:
+ case ColorSpace::MatrixID::SMPTE170M:
+ case ColorSpace::MatrixID::SMPTE240M:
+ case ColorSpace::MatrixID::BT2020_NCL:
+ case ColorSpace::MatrixID::BT2020_CL:
+ case ColorSpace::MatrixID::YDZDX:
+ return Transform(255.0f / 219.0f, 0.0f, 0.0f, -16.0f / 219.0f, // 1
+ 0.0f, 255.0f / 224.0f, 0.0f, -15.5f / 224.0f, // 2
+ 0.0f, 0.0f, 255.0f / 224.0f, -15.5f / 224.0f, // 3
+ 0.0f, 0.0f, 0.0f, 1.0f); // 4
+ }
+}
+
+class ColorSpaceToColorSpaceTransform : public ColorTransform {
+ public:
+ ColorSpaceToColorSpaceTransform(const ColorSpace& from,
+ const ColorSpace& to,
+ Intent intent)
+ : from_(from), to_(to) {
+ if (intent == Intent::PERCEPTUAL) {
+ switch (from_.transfer_) {
+ case ColorSpace::TransferID::UNSPECIFIED:
+ case ColorSpace::TransferID::BT709:
+ case ColorSpace::TransferID::SMPTE170M:
+ // See SMPTE 1886
+ from_.transfer_ = ColorSpace::TransferID::GAMMA24;
+ break;
+
+ default: // Do nothing
+ break;
+ }
+
+ // TODO(hubbe): shrink gamuts here (never stretch gamuts)
+ }
+
+ Transform* from_transfer_matrix =
+ from_.matrix_ == ColorSpace::MatrixID::BT2020_CL ? &b_ : &a_;
+ Transform* to_transfer_matrix =
+ to_.matrix_ == ColorSpace::MatrixID::BT2020_CL ? &b_ : &c_;
+
+ c_ *= Invert(GetRangeAdjustMatrix(to_.range_, to_.matrix_));
+ *to_transfer_matrix *= GetTransferMatrix(to_.matrix_);
+ b_ *= Invert(GetPrimaryMatrix(to_.primaries_));
+ b_ *= GetPrimaryMatrix(from_.primaries_);
+ *from_transfer_matrix *= Invert(GetTransferMatrix(from_.matrix_));
+ a_ *= GetRangeAdjustMatrix(from_.range_, from_.matrix_);
+ }
+
+ void transform(TriStim* colors, size_t num) override {
+ for (size_t i = 0; i < num; i++) {
+ TriStim c = colors[i];
+ a_.TransformPoint(&c);
+ c.set_x(toLinear(from_.transfer_, c.x()));
+ c.set_y(toLinear(from_.transfer_, c.y()));
+ c.set_z(toLinear(from_.transfer_, c.z()));
+ b_.TransformPoint(&c);
+ c.set_x(fromLinear(to_.transfer_, c.x()));
+ c.set_y(fromLinear(to_.transfer_, c.y()));
+ c.set_z(fromLinear(to_.transfer_, c.z()));
+ c_.TransformPoint(&c);
+ colors[i] = c;
+ }
+ }
+
+ private:
+ ColorSpace from_;
+ ColorSpace to_;
+
+ // a_ -> tolinear -> b_ -> fromlinear -> c_;
+ Transform a_;
+ Transform b_;
+ Transform c_;
+};
+
+std::unique_ptr<ColorTransform> ColorTransform::NewColorTransform(
+ const ColorSpace& from,
+ const ColorSpace& to,
+ Intent intent) {
+ // TODO(Hubbe): Check if from and/or to can be mapped to ICC profiles and
+ // provide better transforms in those cases.
+ return std::unique_ptr<ColorTransform>(
+ new ColorSpaceToColorSpaceTransform(from, to, intent));
+}
+
+} // namespace gfx
« no previous file with comments | « ui/gfx/color_transform.h ('k') | ui/gfx/color_transform_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698