SkMaskGamma.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /*
  2. * Copyright 2012 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "src/core/SkMaskGamma.h"
  8. #include "include/core/SkColor.h"
  9. #include "include/core/SkTypes.h"
  10. #include "include/private/SkFloatingPoint.h"
  11. #include "include/private/SkTo.h"
  12. class SkLinearColorSpaceLuminance : public SkColorSpaceLuminance {
  13. SkScalar toLuma(SkScalar SkDEBUGCODE(gamma), SkScalar luminance) const override {
  14. SkASSERT(SK_Scalar1 == gamma);
  15. return luminance;
  16. }
  17. SkScalar fromLuma(SkScalar SkDEBUGCODE(gamma), SkScalar luma) const override {
  18. SkASSERT(SK_Scalar1 == gamma);
  19. return luma;
  20. }
  21. };
  22. class SkGammaColorSpaceLuminance : public SkColorSpaceLuminance {
  23. SkScalar toLuma(SkScalar gamma, SkScalar luminance) const override {
  24. return SkScalarPow(luminance, gamma);
  25. }
  26. SkScalar fromLuma(SkScalar gamma, SkScalar luma) const override {
  27. return SkScalarPow(luma, SkScalarInvert(gamma));
  28. }
  29. };
  30. class SkSRGBColorSpaceLuminance : public SkColorSpaceLuminance {
  31. SkScalar toLuma(SkScalar SkDEBUGCODE(gamma), SkScalar luminance) const override {
  32. SkASSERT(0 == gamma);
  33. //The magic numbers are derived from the sRGB specification.
  34. //See http://www.color.org/chardata/rgb/srgb.xalter .
  35. if (luminance <= 0.04045f) {
  36. return luminance / 12.92f;
  37. }
  38. return SkScalarPow((luminance + 0.055f) / 1.055f,
  39. 2.4f);
  40. }
  41. SkScalar fromLuma(SkScalar SkDEBUGCODE(gamma), SkScalar luma) const override {
  42. SkASSERT(0 == gamma);
  43. //The magic numbers are derived from the sRGB specification.
  44. //See http://www.color.org/chardata/rgb/srgb.xalter .
  45. if (luma <= 0.0031308f) {
  46. return luma * 12.92f;
  47. }
  48. return 1.055f * SkScalarPow(luma, SkScalarInvert(2.4f))
  49. - 0.055f;
  50. }
  51. };
  52. /*static*/ const SkColorSpaceLuminance& SkColorSpaceLuminance::Fetch(SkScalar gamma) {
  53. static SkLinearColorSpaceLuminance gSkLinearColorSpaceLuminance;
  54. static SkGammaColorSpaceLuminance gSkGammaColorSpaceLuminance;
  55. static SkSRGBColorSpaceLuminance gSkSRGBColorSpaceLuminance;
  56. if (0 == gamma) {
  57. return gSkSRGBColorSpaceLuminance;
  58. } else if (SK_Scalar1 == gamma) {
  59. return gSkLinearColorSpaceLuminance;
  60. } else {
  61. return gSkGammaColorSpaceLuminance;
  62. }
  63. }
  64. static float apply_contrast(float srca, float contrast) {
  65. return srca + ((1.0f - srca) * contrast * srca);
  66. }
  67. void SkTMaskGamma_build_correcting_lut(uint8_t table[256], U8CPU srcI, SkScalar contrast,
  68. const SkColorSpaceLuminance& srcConvert, SkScalar srcGamma,
  69. const SkColorSpaceLuminance& dstConvert, SkScalar dstGamma) {
  70. const float src = (float)srcI / 255.0f;
  71. const float linSrc = srcConvert.toLuma(srcGamma, src);
  72. //Guess at the dst. The perceptual inverse provides smaller visual
  73. //discontinuities when slight changes to desaturated colors cause a channel
  74. //to map to a different correcting lut with neighboring srcI.
  75. //See https://code.google.com/p/chromium/issues/detail?id=141425#c59 .
  76. const float dst = 1.0f - src;
  77. const float linDst = dstConvert.toLuma(dstGamma, dst);
  78. //Contrast value tapers off to 0 as the src luminance becomes white
  79. const float adjustedContrast = SkScalarToFloat(contrast) * linDst;
  80. //Remove discontinuity and instability when src is close to dst.
  81. //The value 1/256 is arbitrary and appears to contain the instability.
  82. if (fabs(src - dst) < (1.0f / 256.0f)) {
  83. float ii = 0.0f;
  84. for (int i = 0; i < 256; ++i, ii += 1.0f) {
  85. float rawSrca = ii / 255.0f;
  86. float srca = apply_contrast(rawSrca, adjustedContrast);
  87. table[i] = SkToU8(sk_float_round2int(255.0f * srca));
  88. }
  89. } else {
  90. // Avoid slow int to float conversion.
  91. float ii = 0.0f;
  92. for (int i = 0; i < 256; ++i, ii += 1.0f) {
  93. // 'rawSrca += 1.0f / 255.0f' and even
  94. // 'rawSrca = i * (1.0f / 255.0f)' can add up to more than 1.0f.
  95. // When this happens the table[255] == 0x0 instead of 0xff.
  96. // See http://code.google.com/p/chromium/issues/detail?id=146466
  97. float rawSrca = ii / 255.0f;
  98. float srca = apply_contrast(rawSrca, adjustedContrast);
  99. SkASSERT(srca <= 1.0f);
  100. float dsta = 1.0f - srca;
  101. //Calculate the output we want.
  102. float linOut = (linSrc * srca + dsta * linDst);
  103. SkASSERT(linOut <= 1.0f);
  104. float out = dstConvert.fromLuma(dstGamma, linOut);
  105. //Undo what the blit blend will do.
  106. float result = (out - dst) / (src - dst);
  107. SkASSERT(sk_float_round2int(255.0f * result) <= 255);
  108. table[i] = SkToU8(sk_float_round2int(255.0f * result));
  109. }
  110. }
  111. }