| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gfx/skia_color_space_util.h" | 5 #include "ui/gfx/skia_color_space_util.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <vector> |
| 9 | 10 |
| 10 #include "base/logging.h" | 11 #include "base/logging.h" |
| 11 | 12 |
| 12 namespace gfx { | 13 namespace gfx { |
| 13 | 14 |
| 14 namespace { | 15 namespace { |
| 15 | 16 |
| 16 // Solve for the parameter fC, given the parameter fD, assuming fF is zero. | 17 // Solve for the parameter fC, given the parameter fD, assuming fF is zero. |
| 17 void SkTransferFnSolveLinear(SkColorSpaceTransferFn* fn, | 18 void SkTransferFnSolveLinear(SkColorSpaceTransferFn* fn, |
| 18 const float* x, | 19 const float* x, |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 if (std::abs(fn->fG - 1.f) < kRoundEpsilon) | 214 if (std::abs(fn->fG - 1.f) < kRoundEpsilon) |
| 214 fn->fG = 1.f; | 215 fn->fG = 1.f; |
| 215 return true; | 216 return true; |
| 216 } | 217 } |
| 217 | 218 |
| 218 bool SkApproximateTransferFnInternal(const float* x, | 219 bool SkApproximateTransferFnInternal(const float* x, |
| 219 const float* t, | 220 const float* t, |
| 220 size_t n, | 221 size_t n, |
| 221 SkColorSpaceTransferFn* fn) { | 222 SkColorSpaceTransferFn* fn) { |
| 222 // First, guess at a value of fD. Assume that the nonlinear segment applies | 223 // First, guess at a value of fD. Assume that the nonlinear segment applies |
| 223 // to all x >= 0.1. This is generally a safe assumption (fD is usually less | 224 // to all x >= 0.25. This is generally a safe assumption (fD is usually less |
| 224 // than 0.1). | 225 // than 0.1). |
| 225 fn->fD = 0.1f; | 226 fn->fD = 0.25f; |
| 226 | 227 |
| 227 // Do a nonlinear regression on the nonlinear segment. Use a number of guesses | 228 // Do a nonlinear regression on the nonlinear segment. Use a number of guesses |
| 228 // for the initial value of fG, because not all values will converge. | 229 // for the initial value of fG, because not all values will converge. |
| 229 bool nonlinear_fit_converged = false; | 230 bool nonlinear_fit_converged = false; |
| 230 { | 231 { |
| 231 const size_t kNumInitialGammas = 4; | 232 const size_t kNumInitialGammas = 4; |
| 232 float initial_gammas[kNumInitialGammas] = {2.f, 1.f, 3.f, 0.5f}; | 233 float initial_gammas[kNumInitialGammas] = {2.f, 1.f, 3.f, 0.5f}; |
| 233 for (size_t i = 0; i < kNumInitialGammas; ++i) { | 234 for (size_t i = 0; i < kNumInitialGammas; ++i) { |
| 234 fn->fG = initial_gammas[i]; | 235 fn->fG = initial_gammas[i]; |
| 235 fn->fA = 1; | 236 fn->fA = 1; |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 fn->fA = 1; | 356 fn->fA = 1; |
| 356 fn->fB = 0; | 357 fn->fB = 0; |
| 357 fn->fC = 1; | 358 fn->fC = 1; |
| 358 fn->fD = 0; | 359 fn->fD = 0; |
| 359 fn->fE = 0; | 360 fn->fE = 0; |
| 360 fn->fF = 0; | 361 fn->fF = 0; |
| 361 fn->fG = 1; | 362 fn->fG = 1; |
| 362 return false; | 363 return false; |
| 363 } | 364 } |
| 364 | 365 |
| 366 bool GFX_EXPORT SkApproximateTransferFn(sk_sp<SkICC> sk_icc, |
| 367 float* max_error, |
| 368 SkColorSpaceTransferFn* fn) { |
| 369 SkICC::Tables tables; |
| 370 bool got_tables = sk_icc->rawTransferFnData(&tables); |
| 371 if (!got_tables) |
| 372 return false; |
| 373 |
| 374 // Merge all channels' tables into a single array. |
| 375 std::vector<float> x; |
| 376 std::vector<float> t; |
| 377 for (size_t c = 0; c < 3; ++c) { |
| 378 SkICC::Channel* channels[3] = {&tables.fRed, &tables.fGreen, &tables.fBlue}; |
| 379 SkICC::Channel* channel = channels[c]; |
| 380 const float* data = reinterpret_cast<const float*>( |
| 381 tables.fStorage->bytes() + channel->fOffset); |
| 382 for (int i = 0; i < channel->fCount; ++i) { |
| 383 float xi = i / (channel->fCount - 1.f); |
| 384 float ti = data[i]; |
| 385 x.push_back(xi); |
| 386 t.push_back(ti); |
| 387 } |
| 388 } |
| 389 |
| 390 // Approximate and evalaute. |
| 391 bool converged = |
| 392 SkApproximateTransferFnInternal(x.data(), t.data(), x.size(), fn); |
| 393 if (!converged) |
| 394 return false; |
| 395 *max_error = 0; |
| 396 for (size_t i = 0; i < x.size(); ++i) { |
| 397 float fn_of_xi = gfx::SkTransferFnEval(*fn, x[i]); |
| 398 float error_at_xi = std::abs(t[i] - fn_of_xi); |
| 399 *max_error = std::max(*max_error, error_at_xi); |
| 400 } |
| 401 return true; |
| 402 } |
| 403 |
| 365 bool SkMatrixIsApproximatelyIdentity(const SkMatrix44& m) { | 404 bool SkMatrixIsApproximatelyIdentity(const SkMatrix44& m) { |
| 366 const float kEpsilon = 1.f / 256.f; | 405 const float kEpsilon = 1.f / 256.f; |
| 367 for (int i = 0; i < 4; ++i) { | 406 for (int i = 0; i < 4; ++i) { |
| 368 for (int j = 0; j < 4; ++j) { | 407 for (int j = 0; j < 4; ++j) { |
| 369 float identity_value = i == j ? 1 : 0; | 408 float identity_value = i == j ? 1 : 0; |
| 370 float value = m.get(i, j); | 409 float value = m.get(i, j); |
| 371 if (std::abs(identity_value - value) > kEpsilon) | 410 if (std::abs(identity_value - value) > kEpsilon) |
| 372 return false; | 411 return false; |
| 373 } | 412 } |
| 374 } | 413 } |
| 375 return true; | 414 return true; |
| 376 } | 415 } |
| 377 | 416 |
| 378 } // namespace gfx | 417 } // namespace gfx |
| OLD | NEW |