| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkColorPriv.h" | 8 #include "SkColorPriv.h" |
| 9 #include "SkColorSpace_A2B.h" |
| 9 #include "SkColorSpace_Base.h" | 10 #include "SkColorSpace_Base.h" |
| 11 #include "SkColorSpace_XYZ.h" |
| 10 #include "SkColorSpacePriv.h" | 12 #include "SkColorSpacePriv.h" |
| 11 #include "SkColorSpaceXform_Base.h" | 13 #include "SkColorSpaceXform_Base.h" |
| 12 #include "SkHalf.h" | 14 #include "SkHalf.h" |
| 13 #include "SkOpts.h" | 15 #include "SkOpts.h" |
| 14 #include "SkSRGB.h" | 16 #include "SkSRGB.h" |
| 15 | 17 |
| 16 static constexpr float sk_linear_from_2dot2[256] = { | 18 static constexpr float sk_linear_from_2dot2[256] = { |
| 17 0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.0
00056921765712193f, | 19 0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.0
00056921765712193f, |
| 18 0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.0
00367136269815943f, | 20 0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.0
00367136269815943f, |
| 19 0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.0
00992374304074325f, | 21 0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.0
00992374304074325f, |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 nullptr, | 249 nullptr, |
| 248 nullptr, | 250 nullptr, |
| 249 &build_table_linear_to_gamma, | 251 &build_table_linear_to_gamma, |
| 250 &build_table_linear_to_gamma, | 252 &build_table_linear_to_gamma, |
| 251 &build_table_linear_to_gamma, | 253 &build_table_linear_to_gamma, |
| 252 }; | 254 }; |
| 253 | 255 |
| 254 // Build tables to transform src gamma to linear. | 256 // Build tables to transform src gamma to linear. |
| 255 template <typename T> | 257 template <typename T> |
| 256 static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage,
int gammaTableSize, | 258 static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage,
int gammaTableSize, |
| 257 const SkColorSpace* space, const GammaFns<T>& fns
, | 259 const SkColorSpace_XYZ* space, const GammaFns<T>&
fns, |
| 258 bool gammasAreMatching) | 260 bool gammasAreMatching) |
| 259 { | 261 { |
| 260 switch (as_CSB(space)->gammaNamed()) { | 262 switch (space->gammaNamed()) { |
| 261 case kSRGB_SkGammaNamed: | 263 case kSRGB_SkGammaNamed: |
| 262 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRG
BTable; | 264 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRG
BTable; |
| 263 break; | 265 break; |
| 264 case k2Dot2Curve_SkGammaNamed: | 266 case k2Dot2Curve_SkGammaNamed: |
| 265 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Do
t2Table; | 267 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Do
t2Table; |
| 266 break; | 268 break; |
| 267 case kLinear_SkGammaNamed: | 269 case kLinear_SkGammaNamed: |
| 268 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = nullptr; | 270 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = nullptr; |
| 269 break; | 271 break; |
| 270 default: { | 272 default: { |
| 271 const SkGammas* gammas = as_CSB(space)->gammas(); | 273 const SkGammas* gammas = space->gammas(); |
| 272 SkASSERT(gammas); | 274 SkASSERT(gammas); |
| 273 | 275 |
| 274 auto build_table = [=](int i) { | 276 auto build_table = [=](int i) { |
| 275 if (gammas->isNamed(i)) { | 277 if (gammas->isNamed(i)) { |
| 276 switch (gammas->data(i).fNamed) { | 278 switch (gammas->data(i).fNamed) { |
| 277 case kSRGB_SkGammaNamed: | 279 case kSRGB_SkGammaNamed: |
| 278 (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaT
ableSize], 2.4f, | 280 (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaT
ableSize], 2.4f, |
| 279 (1.0f / 1.055f), (0.055f / 1.
055f), 0.0f, | 281 (1.0f / 1.055f), (0.055f / 1.
055f), 0.0f, |
| 280 0.04045f, (1.0f / 12.92f), 0.
0f); | 282 0.04045f, (1.0f / 12.92f), 0.
0f); |
| 281 outGammaTables[i] = &gammaTableStorage[i * gammaTabl
eSize]; | 283 outGammaTables[i] = &gammaTableStorage[i * gammaTabl
eSize]; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 build_table(1); | 321 build_table(1); |
| 320 build_table(2); | 322 build_table(2); |
| 321 } | 323 } |
| 322 | 324 |
| 323 break; | 325 break; |
| 324 } | 326 } |
| 325 } | 327 } |
| 326 } | 328 } |
| 327 | 329 |
| 328 void SkColorSpaceXform_Base::BuildDstGammaTables(const uint8_t* dstGammaTables[3
], | 330 void SkColorSpaceXform_Base::BuildDstGammaTables(const uint8_t* dstGammaTables[3
], |
| 329 uint8_t* dstStorage, const SkCo
lorSpace* space, | 331 uint8_t* dstStorage, |
| 332 const SkColorSpace_XYZ* space, |
| 330 bool gammasAreMatching) { | 333 bool gammasAreMatching) { |
| 331 build_gamma_tables(dstGammaTables, dstStorage, kDstGammaTableSize, space, kF
romLinear, | 334 build_gamma_tables(dstGammaTables, dstStorage, kDstGammaTableSize, space, kF
romLinear, |
| 332 gammasAreMatching); | 335 gammasAreMatching); |
| 333 } | 336 } |
| 334 | 337 |
| 335 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 338 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 336 | 339 |
| 337 static inline bool is_almost_identity(const SkMatrix44& srcToDst) { | 340 static inline bool is_almost_identity(const SkMatrix44& srcToDst) { |
| 338 for (int i = 0; i < 4; i++) { | 341 for (int i = 0; i < 4; i++) { |
| 339 for (int j = 0; j < 4; j++) { | 342 for (int j = 0; j < 4; j++) { |
| 340 float expected = (i == j) ? 1.0f : 0.0f; | 343 float expected = (i == j) ? 1.0f : 0.0f; |
| 341 if (!color_space_almost_equal(srcToDst.getFloat(i,j), expected)) { | 344 if (!color_space_almost_equal(srcToDst.getFloat(i,j), expected)) { |
| 342 return false; | 345 return false; |
| 343 } | 346 } |
| 344 } | 347 } |
| 345 } | 348 } |
| 346 return true; | 349 return true; |
| 347 } | 350 } |
| 348 | 351 |
| 349 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 352 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 350 | 353 |
| 351 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* srcSpace
, | 354 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* srcSpace
, |
| 352 SkColorSpace* dstSpace
) { | 355 SkColorSpace* dstSpace
) { |
| 353 if (!srcSpace || !dstSpace) { | 356 if (!srcSpace || !dstSpace) { |
| 354 // Invalid input | 357 // Invalid input |
| 355 return nullptr; | 358 return nullptr; |
| 356 } | 359 } |
| 357 | 360 |
| 361 if (SkColorSpace_Base::Type::kA2B == as_CSB(dstSpace)->type()) { |
| 362 SkColorSpacePrintf("A2B destinations not supported\n"); |
| 363 return nullptr; |
| 364 } |
| 365 |
| 366 if (SkColorSpace_Base::Type::kA2B == as_CSB(srcSpace)->type()) { |
| 367 // TODO (raftias): return an A2B-supporting SkColorSpaceXform here once
the xform. |
| 368 // is implemented. SkColorSpaceXform_Base only supports XYZ+TRC based Sk
ColorSpaces |
| 369 //SkColorSpace_A2B* src = static_cast<SkColorSpace_A2B*>(srcSpace); |
| 370 //SkColorSpace_XYZ* dst = static_cast<SkColorSpace_XYZ*>(dstSpace); |
| 371 //return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_A2B(sr
c, dst)); |
| 372 SkColorSpacePrintf("A2B sources not supported (yet)\n"); |
| 373 return nullptr; |
| 374 } |
| 375 SkColorSpace_XYZ* srcSpaceXYZ = static_cast<SkColorSpace_XYZ*>(srcSpace); |
| 376 SkColorSpace_XYZ* dstSpaceXYZ = static_cast<SkColorSpace_XYZ*>(dstSpace); |
| 377 |
| 358 ColorSpaceMatch csm = kNone_ColorSpaceMatch; | 378 ColorSpaceMatch csm = kNone_ColorSpaceMatch; |
| 359 SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); | 379 SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); |
| 360 if (SkColorSpace::Equals(srcSpace, dstSpace)) { | 380 if (SkColorSpace::Equals(srcSpace, dstSpace)) { |
| 361 srcToDst.setIdentity(); | 381 srcToDst.setIdentity(); |
| 362 csm = kFull_ColorSpaceMatch; | 382 csm = kFull_ColorSpaceMatch; |
| 363 } else { | 383 } else { |
| 364 srcToDst.setConcat(as_CSB(dstSpace)->fromXYZD50(), as_CSB(srcSpace)->toX
YZD50()); | 384 srcToDst.setConcat(*dstSpaceXYZ->fromXYZD50(), *srcSpaceXYZ->toXYZD50())
; |
| 365 | 385 |
| 366 if (is_almost_identity(srcToDst)) { | 386 if (is_almost_identity(srcToDst)) { |
| 367 srcToDst.setIdentity(); | 387 srcToDst.setIdentity(); |
| 368 csm = kGamut_ColorSpaceMatch; | 388 csm = kGamut_ColorSpaceMatch; |
| 369 } | 389 } |
| 370 } | 390 } |
| 371 | 391 |
| 372 switch (csm) { | 392 switch (csm) { |
| 373 case kNone_ColorSpaceMatch: | 393 case kNone_ColorSpaceMatch: |
| 374 switch (as_CSB(dstSpace)->gammaNamed()) { | 394 switch (dstSpaceXYZ->gammaNamed()) { |
| 375 case kSRGB_SkGammaNamed: | 395 case kSRGB_SkGammaNamed: |
| 376 if (srcSpace->gammaIsLinear()) { | 396 if (srcSpaceXYZ->gammaIsLinear()) { |
| 377 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 397 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 378 <kLinear_SrcGamma, kSRGB_DstGamma, kNone_ColorSp
aceMatch> | 398 <kLinear_SrcGamma, kSRGB_DstGamma, kNone_ColorSp
aceMatch> |
| 379 (srcSpace, srcToDst, dstSpace)); | 399 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 380 } else { | 400 } else { |
| 381 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 401 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 382 <kTable_SrcGamma, kSRGB_DstGamma, kNone_ColorSpa
ceMatch> | 402 <kTable_SrcGamma, kSRGB_DstGamma, kNone_ColorSpa
ceMatch> |
| 383 (srcSpace, srcToDst, dstSpace)); | 403 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 384 } | 404 } |
| 385 case k2Dot2Curve_SkGammaNamed: | 405 case k2Dot2Curve_SkGammaNamed: |
| 386 if (srcSpace->gammaIsLinear()) { | 406 if (srcSpaceXYZ->gammaIsLinear()) { |
| 387 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 407 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 388 <kLinear_SrcGamma, k2Dot2_DstGamma, kNone_ColorS
paceMatch> | 408 <kLinear_SrcGamma, k2Dot2_DstGamma, kNone_ColorS
paceMatch> |
| 389 (srcSpace, srcToDst, dstSpace)); | 409 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 390 } else { | 410 } else { |
| 391 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 411 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 392 <kTable_SrcGamma, k2Dot2_DstGamma, kNone_ColorSp
aceMatch> | 412 <kTable_SrcGamma, k2Dot2_DstGamma, kNone_ColorSp
aceMatch> |
| 393 (srcSpace, srcToDst, dstSpace)); | 413 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 394 } | 414 } |
| 395 case kLinear_SkGammaNamed: | 415 case kLinear_SkGammaNamed: |
| 396 if (srcSpace->gammaIsLinear()) { | 416 if (srcSpaceXYZ->gammaIsLinear()) { |
| 397 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 417 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 398 <kLinear_SrcGamma, kLinear_DstGamma, kNone_Color
SpaceMatch> | 418 <kLinear_SrcGamma, kLinear_DstGamma, kNone_Color
SpaceMatch> |
| 399 (srcSpace, srcToDst, dstSpace)); | 419 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 400 } else { | 420 } else { |
| 401 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 421 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 402 <kTable_SrcGamma, kLinear_DstGamma, kNone_ColorS
paceMatch> | 422 <kTable_SrcGamma, kLinear_DstGamma, kNone_ColorS
paceMatch> |
| 403 (srcSpace, srcToDst, dstSpace)); | 423 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 404 } | 424 } |
| 405 default: | 425 default: |
| 406 if (srcSpace->gammaIsLinear()) { | 426 if (srcSpaceXYZ->gammaIsLinear()) { |
| 407 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 427 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 408 <kLinear_SrcGamma, kTable_DstGamma, kNone_ColorS
paceMatch> | 428 <kLinear_SrcGamma, kTable_DstGamma, kNone_ColorS
paceMatch> |
| 409 (srcSpace, srcToDst, dstSpace)); | 429 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 410 } else { | 430 } else { |
| 411 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 431 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 412 <kTable_SrcGamma, kTable_DstGamma, kNone_ColorSp
aceMatch> | 432 <kTable_SrcGamma, kTable_DstGamma, kNone_ColorSp
aceMatch> |
| 413 (srcSpace, srcToDst, dstSpace)); | 433 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 414 } | 434 } |
| 415 } | 435 } |
| 416 case kGamut_ColorSpaceMatch: | 436 case kGamut_ColorSpaceMatch: |
| 417 switch (as_CSB(dstSpace)->gammaNamed()) { | 437 switch (dstSpaceXYZ->gammaNamed()) { |
| 418 case kSRGB_SkGammaNamed: | 438 case kSRGB_SkGammaNamed: |
| 419 if (srcSpace->gammaIsLinear()) { | 439 if (srcSpaceXYZ->gammaIsLinear()) { |
| 420 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 440 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 421 <kLinear_SrcGamma, kSRGB_DstGamma, kGamut_ColorS
paceMatch> | 441 <kLinear_SrcGamma, kSRGB_DstGamma, kGamut_ColorS
paceMatch> |
| 422 (srcSpace, srcToDst, dstSpace)); | 442 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 423 } else { | 443 } else { |
| 424 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 444 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 425 <kTable_SrcGamma, kSRGB_DstGamma, kGamut_ColorSp
aceMatch> | 445 <kTable_SrcGamma, kSRGB_DstGamma, kGamut_ColorSp
aceMatch> |
| 426 (srcSpace, srcToDst, dstSpace)); | 446 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 427 } | 447 } |
| 428 case k2Dot2Curve_SkGammaNamed: | 448 case k2Dot2Curve_SkGammaNamed: |
| 429 if (srcSpace->gammaIsLinear()) { | 449 if (srcSpaceXYZ->gammaIsLinear()) { |
| 430 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 450 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 431 <kLinear_SrcGamma, k2Dot2_DstGamma, kGamut_Color
SpaceMatch> | 451 <kLinear_SrcGamma, k2Dot2_DstGamma, kGamut_Color
SpaceMatch> |
| 432 (srcSpace, srcToDst, dstSpace)); | 452 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 433 } else { | 453 } else { |
| 434 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 454 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 435 <kTable_SrcGamma, k2Dot2_DstGamma, kGamut_ColorS
paceMatch> | 455 <kTable_SrcGamma, k2Dot2_DstGamma, kGamut_ColorS
paceMatch> |
| 436 (srcSpace, srcToDst, dstSpace)); | 456 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 437 } | 457 } |
| 438 case kLinear_SkGammaNamed: | 458 case kLinear_SkGammaNamed: |
| 439 if (srcSpace->gammaIsLinear()) { | 459 if (srcSpaceXYZ->gammaIsLinear()) { |
| 440 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 460 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 441 <kLinear_SrcGamma, kLinear_DstGamma, kGamut_Colo
rSpaceMatch> | 461 <kLinear_SrcGamma, kLinear_DstGamma, kGamut_Colo
rSpaceMatch> |
| 442 (srcSpace, srcToDst, dstSpace)); | 462 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 443 } else { | 463 } else { |
| 444 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 464 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 445 <kTable_SrcGamma, kLinear_DstGamma, kGamut_Color
SpaceMatch> | 465 <kTable_SrcGamma, kLinear_DstGamma, kGamut_Color
SpaceMatch> |
| 446 (srcSpace, srcToDst, dstSpace)); | 466 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 447 } | 467 } |
| 448 default: | 468 default: |
| 449 if (srcSpace->gammaIsLinear()) { | 469 if (srcSpaceXYZ->gammaIsLinear()) { |
| 450 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 470 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 451 <kLinear_SrcGamma, kTable_DstGamma, kGamut_Color
SpaceMatch> | 471 <kLinear_SrcGamma, kTable_DstGamma, kGamut_Color
SpaceMatch> |
| 452 (srcSpace, srcToDst, dstSpace)); | 472 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 453 } else { | 473 } else { |
| 454 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ | 474 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpa
ceXform_XYZ |
| 455 <kTable_SrcGamma, kTable_DstGamma, kGamut_ColorS
paceMatch> | 475 <kTable_SrcGamma, kTable_DstGamma, kGamut_ColorS
paceMatch> |
| 456 (srcSpace, srcToDst, dstSpace)); | 476 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 457 } | 477 } |
| 458 } | 478 } |
| 459 case kFull_ColorSpaceMatch: | 479 case kFull_ColorSpaceMatch: |
| 460 switch (as_CSB(dstSpace)->gammaNamed()) { | 480 switch (dstSpaceXYZ->gammaNamed()) { |
| 461 case kSRGB_SkGammaNamed: | 481 case kSRGB_SkGammaNamed: |
| 462 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_XYZ | 482 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_XYZ |
| 463 <kTable_SrcGamma, kSRGB_DstGamma, kFull_ColorSpaceMa
tch> | 483 <kTable_SrcGamma, kSRGB_DstGamma, kFull_ColorSpaceMa
tch> |
| 464 (srcSpace, srcToDst, dstSpace)); | 484 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 465 case k2Dot2Curve_SkGammaNamed: | 485 case k2Dot2Curve_SkGammaNamed: |
| 466 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_XYZ | 486 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_XYZ |
| 467 <kTable_SrcGamma, k2Dot2_DstGamma, kFull_ColorSpaceM
atch> | 487 <kTable_SrcGamma, k2Dot2_DstGamma, kFull_ColorSpaceM
atch> |
| 468 (srcSpace, srcToDst, dstSpace)); | 488 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 469 case kLinear_SkGammaNamed: | 489 case kLinear_SkGammaNamed: |
| 470 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_XYZ | 490 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_XYZ |
| 471 <kLinear_SrcGamma, kLinear_DstGamma, kFull_ColorSpac
eMatch> | 491 <kLinear_SrcGamma, kLinear_DstGamma, kFull_ColorSpac
eMatch> |
| 472 (srcSpace, srcToDst, dstSpace)); | 492 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 473 default: | 493 default: |
| 474 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_XYZ | 494 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_XYZ |
| 475 <kTable_SrcGamma, kTable_DstGamma, kFull_ColorSpaceM
atch> | 495 <kTable_SrcGamma, kTable_DstGamma, kFull_ColorSpaceM
atch> |
| 476 (srcSpace, srcToDst, dstSpace)); | 496 (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
| 477 } | 497 } |
| 478 default: | 498 default: |
| 479 SkASSERT(false); | 499 SkASSERT(false); |
| 480 return nullptr; | 500 return nullptr; |
| 481 } | 501 } |
| 482 } | 502 } |
| 483 | 503 |
| 484 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 504 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 485 | 505 |
| 486 static float byte_to_float(uint8_t byte) { | |
| 487 return ((float) byte) * (1.0f / 255.0f); | |
| 488 } | |
| 489 | |
| 490 // Clamp to the 0-1 range. | |
| 491 static float clamp_normalized_float(float v) { | |
| 492 if (v > 1.0f) { | |
| 493 return 1.0f; | |
| 494 } else if ((v < 0.0f) || (v != v)) { | |
| 495 return 0.0f; | |
| 496 } else { | |
| 497 return v; | |
| 498 } | |
| 499 } | |
| 500 | |
| 501 static void interp_3d_clut(float dst[3], float src[3], const SkColorLookUpTable*
colorLUT) { | |
| 502 // Call the src components x, y, and z. | |
| 503 uint8_t maxX = colorLUT->fGridPoints[0] - 1; | |
| 504 uint8_t maxY = colorLUT->fGridPoints[1] - 1; | |
| 505 uint8_t maxZ = colorLUT->fGridPoints[2] - 1; | |
| 506 | |
| 507 // An approximate index into each of the three dimensions of the table. | |
| 508 float x = src[0] * maxX; | |
| 509 float y = src[1] * maxY; | |
| 510 float z = src[2] * maxZ; | |
| 511 | |
| 512 // This gives us the low index for our interpolation. | |
| 513 int ix = sk_float_floor2int(x); | |
| 514 int iy = sk_float_floor2int(y); | |
| 515 int iz = sk_float_floor2int(z); | |
| 516 | |
| 517 // Make sure the low index is not also the max index. | |
| 518 ix = (maxX == ix) ? ix - 1 : ix; | |
| 519 iy = (maxY == iy) ? iy - 1 : iy; | |
| 520 iz = (maxZ == iz) ? iz - 1 : iz; | |
| 521 | |
| 522 // Weighting factors for the interpolation. | |
| 523 float diffX = x - ix; | |
| 524 float diffY = y - iy; | |
| 525 float diffZ = z - iz; | |
| 526 | |
| 527 // Constants to help us navigate the 3D table. | |
| 528 // Ex: Assume x = a, y = b, z = c. | |
| 529 // table[a * n001 + b * n010 + c * n100] logically equals table[a][b][c]
. | |
| 530 const int n000 = 0; | |
| 531 const int n001 = 3 * colorLUT->fGridPoints[1] * colorLUT->fGridPoints[2]; | |
| 532 const int n010 = 3 * colorLUT->fGridPoints[2]; | |
| 533 const int n011 = n001 + n010; | |
| 534 const int n100 = 3; | |
| 535 const int n101 = n100 + n001; | |
| 536 const int n110 = n100 + n010; | |
| 537 const int n111 = n110 + n001; | |
| 538 | |
| 539 // Base ptr into the table. | |
| 540 const float* ptr = &(colorLUT->table()[ix*n001 + iy*n010 + iz*n100]); | |
| 541 | |
| 542 // The code below performs a tetrahedral interpolation for each of the three | |
| 543 // dst components. Once the tetrahedron containing the interpolation point
is | |
| 544 // identified, the interpolation is a weighted sum of grid values at the | |
| 545 // vertices of the tetrahedron. The claim is that tetrahedral interpolation | |
| 546 // provides a more accurate color conversion. | |
| 547 // blogs.mathworks.com/steve/2006/11/24/tetrahedral-interpolation-for-colors
pace-conversion/ | |
| 548 // | |
| 549 // I have one test image, and visually I can't tell the difference between | |
| 550 // tetrahedral and trilinear interpolation. In terms of computation, the | |
| 551 // tetrahedral code requires more branches but less computation. The | |
| 552 // SampleICC library provides an option for the client to choose either | |
| 553 // tetrahedral or trilinear. | |
| 554 for (int i = 0; i < 3; i++) { | |
| 555 if (diffZ < diffY) { | |
| 556 if (diffZ < diffX) { | |
| 557 dst[i] = (ptr[n000] + diffZ * (ptr[n110] - ptr[n010]) + | |
| 558 diffY * (ptr[n010] - ptr[n000]) + | |
| 559 diffX * (ptr[n111] - ptr[n110])); | |
| 560 } else if (diffY < diffX) { | |
| 561 dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) + | |
| 562 diffY * (ptr[n011] - ptr[n001]) + | |
| 563 diffX * (ptr[n001] - ptr[n000])); | |
| 564 } else { | |
| 565 dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) + | |
| 566 diffY * (ptr[n010] - ptr[n000]) + | |
| 567 diffX * (ptr[n011] - ptr[n010])); | |
| 568 } | |
| 569 } else { | |
| 570 if (diffZ < diffX) { | |
| 571 dst[i] = (ptr[n000] + diffZ * (ptr[n101] - ptr[n001]) + | |
| 572 diffY * (ptr[n111] - ptr[n101]) + | |
| 573 diffX * (ptr[n001] - ptr[n000])); | |
| 574 } else if (diffY < diffX) { | |
| 575 dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) + | |
| 576 diffY * (ptr[n111] - ptr[n101]) + | |
| 577 diffX * (ptr[n101] - ptr[n100])); | |
| 578 } else { | |
| 579 dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) + | |
| 580 diffY * (ptr[n110] - ptr[n100]) + | |
| 581 diffX * (ptr[n111] - ptr[n110])); | |
| 582 } | |
| 583 } | |
| 584 | |
| 585 // Increment the table ptr in order to handle the next component. | |
| 586 // Note that this is the how table is designed: all of nXXX | |
| 587 // variables are multiples of 3 because there are 3 output | |
| 588 // components. | |
| 589 ptr++; | |
| 590 } | |
| 591 } | |
| 592 | |
| 593 static void handle_color_lut(uint32_t* dst, const void* vsrc, int len, | |
| 594 SkColorLookUpTable* colorLUT) { | |
| 595 const uint32_t* src = (const uint32_t*) vsrc; | |
| 596 while (len-- > 0) { | |
| 597 uint8_t r = (*src >> 0) & 0xFF, | |
| 598 g = (*src >> 8) & 0xFF, | |
| 599 b = (*src >> 16) & 0xFF; | |
| 600 | |
| 601 float in[3]; | |
| 602 float out[3]; | |
| 603 in[0] = byte_to_float(r); | |
| 604 in[1] = byte_to_float(g); | |
| 605 in[2] = byte_to_float(b); | |
| 606 interp_3d_clut(out, in, colorLUT); | |
| 607 | |
| 608 r = sk_float_round2int(255.0f * clamp_normalized_float(out[0])); | |
| 609 g = sk_float_round2int(255.0f * clamp_normalized_float(out[1])); | |
| 610 b = sk_float_round2int(255.0f * clamp_normalized_float(out[2])); | |
| 611 *dst = SkPackARGB_as_RGBA(0xFF, r, g, b); | |
| 612 | |
| 613 src++; | |
| 614 dst++; | |
| 615 } | |
| 616 } | |
| 617 | |
| 618 static inline void load_matrix(const float matrix[16], | 506 static inline void load_matrix(const float matrix[16], |
| 619 Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& r
TgTbT) { | 507 Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& r
TgTbT) { |
| 620 rXgXbX = Sk4f::Load(matrix + 0); | 508 rXgXbX = Sk4f::Load(matrix + 0); |
| 621 rYgYbY = Sk4f::Load(matrix + 4); | 509 rYgYbY = Sk4f::Load(matrix + 4); |
| 622 rZgZbZ = Sk4f::Load(matrix + 8); | 510 rZgZbZ = Sk4f::Load(matrix + 8); |
| 623 rTgTbT = Sk4f::Load(matrix + 12); | 511 rTgTbT = Sk4f::Load(matrix + 12); |
| 624 } | 512 } |
| 625 | 513 |
| 626 enum Order { | 514 enum Order { |
| 627 kRGBA_Order, | 515 kRGBA_Order, |
| (...skipping 591 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1219 store_1(dst, src, rgba, a, dstTables); | 1107 store_1(dst, src, rgba, a, dstTables); |
| 1220 | 1108 |
| 1221 src += 1; | 1109 src += 1; |
| 1222 len -= 1; | 1110 len -= 1; |
| 1223 dst = SkTAddOffset<void>(dst, sizeOfDstPixel); | 1111 dst = SkTAddOffset<void>(dst, sizeOfDstPixel); |
| 1224 } | 1112 } |
| 1225 } | 1113 } |
| 1226 | 1114 |
| 1227 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 1115 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 1228 | 1116 |
| 1229 static inline int num_tables(SkColorSpace* space) { | 1117 static inline int num_tables(SkColorSpace_XYZ* space) { |
| 1230 switch (as_CSB(space)->gammaNamed()) { | 1118 switch (space->gammaNamed()) { |
| 1231 case kSRGB_SkGammaNamed: | 1119 case kSRGB_SkGammaNamed: |
| 1232 case k2Dot2Curve_SkGammaNamed: | 1120 case k2Dot2Curve_SkGammaNamed: |
| 1233 case kLinear_SkGammaNamed: | 1121 case kLinear_SkGammaNamed: |
| 1234 return 0; | 1122 return 0; |
| 1235 default: { | 1123 default: { |
| 1236 const SkGammas* gammas = as_CSB(space)->gammas(); | 1124 const SkGammas* gammas = space->gammas(); |
| 1237 SkASSERT(gammas); | 1125 SkASSERT(gammas); |
| 1238 | 1126 |
| 1239 bool gammasAreMatching = (gammas->type(0) == gammas->type(1)) && | 1127 bool gammasAreMatching = (gammas->type(0) == gammas->type(1)) && |
| 1240 (gammas->data(0) == gammas->data(1)) && | 1128 (gammas->data(0) == gammas->data(1)) && |
| 1241 (gammas->type(0) == gammas->type(2)) && | 1129 (gammas->type(0) == gammas->type(2)) && |
| 1242 (gammas->data(0) == gammas->data(2)); | 1130 (gammas->data(0) == gammas->data(2)); |
| 1243 | 1131 |
| 1244 // It's likely that each component will have the same gamma. In thi
s case, | 1132 // It's likely that each component will have the same gamma. In thi
s case, |
| 1245 // we only need to build one table. | 1133 // we only need to build one table. |
| 1246 return gammasAreMatching ? 1 : 3; | 1134 return gammasAreMatching ? 1 : 3; |
| 1247 } | 1135 } |
| 1248 } | 1136 } |
| 1249 } | 1137 } |
| 1250 | 1138 |
| 1251 template <SrcGamma kSrc, DstGamma kDst, ColorSpaceMatch kCSM> | 1139 template <SrcGamma kSrc, DstGamma kDst, ColorSpaceMatch kCSM> |
| 1252 SkColorSpaceXform_XYZ<kSrc, kDst, kCSM> | 1140 SkColorSpaceXform_XYZ<kSrc, kDst, kCSM> |
| 1253 ::SkColorSpaceXform_XYZ(SkColorSpace* srcSpace, const SkMatrix44& srcToDst, SkCo
lorSpace* dstSpace) | 1141 ::SkColorSpaceXform_XYZ(SkColorSpace_XYZ* srcSpace, const SkMatrix44& srcToDst, |
| 1254 : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT())) | 1142 SkColorSpace_XYZ* dstSpace) |
| 1255 { | 1143 { |
| 1256 srcToDst.asColMajorf(fSrcToDst); | 1144 srcToDst.asColMajorf(fSrcToDst); |
| 1257 | 1145 |
| 1258 const int numSrcTables = num_tables(srcSpace); | 1146 const int numSrcTables = num_tables(srcSpace); |
| 1259 const size_t srcEntries = numSrcTables * 256; | 1147 const size_t srcEntries = numSrcTables * 256; |
| 1260 const bool srcGammasAreMatching = (1 >= numSrcTables); | 1148 const bool srcGammasAreMatching = (1 >= numSrcTables); |
| 1261 fSrcStorage.reset(srcEntries); | 1149 fSrcStorage.reset(srcEntries); |
| 1262 build_gamma_tables(fSrcGammaTables, fSrcStorage.get(), 256, srcSpace, kToLin
ear, | 1150 build_gamma_tables(fSrcGammaTables, fSrcStorage.get(), 256, srcSpace, kToLin
ear, |
| 1263 srcGammasAreMatching); | 1151 srcGammasAreMatching); |
| 1264 | 1152 |
| 1265 const int numDstTables = num_tables(dstSpace); | 1153 const int numDstTables = num_tables(dstSpace); |
| 1266 as_CSB(dstSpace)->toDstGammaTables(fDstGammaTables, &fDstStorage, numDstTabl
es); | 1154 dstSpace->toDstGammaTables(fDstGammaTables, &fDstStorage, numDstTables); |
| 1267 } | 1155 } |
| 1268 | 1156 |
| 1269 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 1157 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 1270 | 1158 |
| 1271 template <SrcFormat kSrc, DstFormat kDst, ColorSpaceMatch kCSM> | 1159 template <SrcFormat kSrc, DstFormat kDst, ColorSpaceMatch kCSM> |
| 1272 static inline bool apply_set_alpha(void* dst, const void* src, int len, SkAlphaT
ype alphaType, | 1160 static inline bool apply_set_alpha(void* dst, const void* src, int len, SkAlphaT
ype alphaType, |
| 1273 const float* const srcTables[3], const float
matrix[16], | 1161 const float* const srcTables[3], const float
matrix[16], |
| 1274 const uint8_t* const dstTables[3]) { | 1162 const uint8_t* const dstTables[3]) { |
| 1275 switch (alphaType) { | 1163 switch (alphaType) { |
| 1276 case kOpaque_SkAlphaType: | 1164 case kOpaque_SkAlphaType: |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1341 case kRGBA_F16_ColorFormat: | 1229 case kRGBA_F16_ColorFormat: |
| 1342 case kRGBA_F32_ColorFormat: | 1230 case kRGBA_F32_ColorFormat: |
| 1343 // There's still work to do to xform to linear floats. | 1231 // There's still work to do to xform to linear floats. |
| 1344 break; | 1232 break; |
| 1345 default: | 1233 default: |
| 1346 return false; | 1234 return false; |
| 1347 } | 1235 } |
| 1348 } | 1236 } |
| 1349 } | 1237 } |
| 1350 | 1238 |
| 1351 #if defined(GOOGLE3) | |
| 1352 // Stack frame size is limited in GOOGLE3. | |
| 1353 SkAutoSMalloc<256 * sizeof(uint32_t)> storage; | |
| 1354 #else | |
| 1355 SkAutoSMalloc<1024 * sizeof(uint32_t)> storage; | |
| 1356 #endif | |
| 1357 if (fColorLUT) { | |
| 1358 size_t storageBytes = len * sizeof(uint32_t); | |
| 1359 storage.reset(storageBytes); | |
| 1360 handle_color_lut((uint32_t*) storage.get(), src, len, fColorLUT.get()); | |
| 1361 src = (const uint32_t*) storage.get(); | |
| 1362 } | |
| 1363 | |
| 1364 switch (dstColorFormat) { | 1239 switch (dstColorFormat) { |
| 1365 case kRGBA_8888_ColorFormat: | 1240 case kRGBA_8888_ColorFormat: |
| 1366 switch (kDst) { | 1241 switch (kDst) { |
| 1367 case kLinear_DstGamma: | 1242 case kLinear_DstGamma: |
| 1368 return apply_set_src<kSrc, kRGBA_8888_Linear_DstFormat, kCSM
> | 1243 return apply_set_src<kSrc, kRGBA_8888_Linear_DstFormat, kCSM
> |
| 1369 (dst, src, len, alphaType, fSrcGammaTables, fSrcToDs
t, nullptr, | 1244 (dst, src, len, alphaType, fSrcGammaTables, fSrcToDs
t, nullptr, |
| 1370 srcColorFormat); | 1245 srcColorFormat); |
| 1371 case kSRGB_DstGamma: | 1246 case kSRGB_DstGamma: |
| 1372 return apply_set_src<kSrc, kRGBA_8888_SRGB_DstFormat, kCSM> | 1247 return apply_set_src<kSrc, kRGBA_8888_SRGB_DstFormat, kCSM> |
| 1373 (dst, src, len, alphaType, fSrcGammaTables, fSrcToDs
t, nullptr, | 1248 (dst, src, len, alphaType, fSrcGammaTables, fSrcToDs
t, nullptr, |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1424 } | 1299 } |
| 1425 | 1300 |
| 1426 bool SkColorSpaceXform::apply(ColorFormat dstColorFormat, void* dst, ColorFormat
srcColorFormat, | 1301 bool SkColorSpaceXform::apply(ColorFormat dstColorFormat, void* dst, ColorFormat
srcColorFormat, |
| 1427 const void* src, int len, SkAlphaType alphaType) c
onst { | 1302 const void* src, int len, SkAlphaType alphaType) c
onst { |
| 1428 return ((SkColorSpaceXform_Base*) this)->onApply(dstColorFormat, dst, srcCol
orFormat, src, len, | 1303 return ((SkColorSpaceXform_Base*) this)->onApply(dstColorFormat, dst, srcCol
orFormat, src, len, |
| 1429 alphaType); | 1304 alphaType); |
| 1430 } | 1305 } |
| 1431 | 1306 |
| 1432 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 1307 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 1433 | 1308 |
| 1434 std::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace* space) { | 1309 std::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace_XYZ* space) { |
| 1435 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ | 1310 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
| 1436 <kTable_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch> | 1311 <kTable_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch> |
| 1437 (space, SkMatrix::I(), space)); | 1312 (space, SkMatrix::I(), space)); |
| 1438 } | 1313 } |
| OLD | NEW |