| 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_Base.h" | 9 #include "SkColorSpace_Base.h" |
| 10 #include "SkColorSpaceXform.h" | 10 #include "SkColorSpaceXform.h" |
| 11 #include "SkOpts.h" |
| 11 | 12 |
| 12 static inline bool compute_gamut_xform(SkMatrix44* srcToDst, const SkMatrix44& s
rcToXYZ, | 13 static inline bool compute_gamut_xform(SkMatrix44* srcToDst, const SkMatrix44& s
rcToXYZ, |
| 13 const SkMatrix44& dstToXYZ) { | 14 const SkMatrix44& dstToXYZ) { |
| 14 if (!dstToXYZ.invert(srcToDst)) { | 15 if (!dstToXYZ.invert(srcToDst)) { |
| 15 return false; | 16 return false; |
| 16 } | 17 } |
| 17 | 18 |
| 18 srcToDst->postConcat(srcToXYZ); | 19 srcToDst->postConcat(srcToXYZ); |
| 19 return true; | 20 return true; |
| 20 } | 21 } |
| 21 | 22 |
| 22 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
ce>& srcSpace, | 23 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
ce>& srcSpace, |
| 23 const sk_sp<SkColorSpa
ce>& dstSpace) { | 24 const sk_sp<SkColorSpa
ce>& dstSpace) { |
| 24 if (!srcSpace || !dstSpace) { | 25 if (!srcSpace || !dstSpace) { |
| 25 // Invalid input | 26 // Invalid input |
| 26 return nullptr; | 27 return nullptr; |
| 27 } | 28 } |
| 28 | 29 |
| 29 if (as_CSB(srcSpace)->colorLUT() || as_CSB(dstSpace)->colorLUT()) { | 30 if (as_CSB(srcSpace)->colorLUT() || as_CSB(dstSpace)->colorLUT()) { |
| 30 // Unimplemented | 31 // Unimplemented |
| 31 return nullptr; | 32 return nullptr; |
| 32 } | 33 } |
| 33 | 34 |
| 34 SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); | 35 SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); |
| 35 if (!compute_gamut_xform(&srcToDst, srcSpace->xyz(), dstSpace->xyz())) { | 36 if (!compute_gamut_xform(&srcToDst, srcSpace->xyz(), dstSpace->xyz())) { |
| 36 return nullptr; | 37 return nullptr; |
| 37 } | 38 } |
| 38 | 39 |
| 39 if (as_CSB(srcSpace)->gammas()->isValues() && as_CSB(dstSpace)->gammas()->is
Values()) { | 40 if (SkColorSpace::k2Dot2Curve_GammaNamed == srcSpace->gammaNamed() && |
| 40 float srcGammas[3]; | 41 SkColorSpace::k2Dot2Curve_GammaNamed == dstSpace->gammaNamed()) |
| 41 float dstGammas[3]; | 42 { |
| 42 srcGammas[0] = as_CSB(srcSpace)->gammas()->fRed.fValue; | 43 return std::unique_ptr<SkColorSpaceXform>(new Sk2Dot2Xform(srcToDst)); |
| 43 srcGammas[1] = as_CSB(srcSpace)->gammas()->fGreen.fValue; | |
| 44 srcGammas[2] = as_CSB(srcSpace)->gammas()->fBlue.fValue; | |
| 45 dstGammas[0] = 1.0f / as_CSB(dstSpace)->gammas()->fRed.fValue; | |
| 46 dstGammas[1] = 1.0f / as_CSB(dstSpace)->gammas()->fGreen.fValue; | |
| 47 dstGammas[2] = 1.0f / as_CSB(dstSpace)->gammas()->fBlue.fValue; | |
| 48 | |
| 49 return std::unique_ptr<SkColorSpaceXform>( | |
| 50 new SkGammaByValueXform(srcGammas, srcToDst, dstGammas)); | |
| 51 } | 44 } |
| 52 | 45 |
| 53 return std::unique_ptr<SkColorSpaceXform>( | 46 return std::unique_ptr<SkColorSpaceXform>( |
| 54 new SkDefaultXform(as_CSB(srcSpace)->gammas(), srcToDst, as_CSB(dstS
pace)->gammas())); | 47 new SkDefaultXform(as_CSB(srcSpace)->gammas(), srcToDst, as_CSB(dstS
pace)->gammas())); |
| 55 } | 48 } |
| 56 | 49 |
| 57 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 50 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 58 | 51 |
| 52 Sk2Dot2Xform::Sk2Dot2Xform(const SkMatrix44& srcToDst) |
| 53 { |
| 54 // Build row major 4x4 matrix: |
| 55 // rX gX bX 0 |
| 56 // rY gY bY 0 |
| 57 // rZ gZ bZ 0 |
| 58 // rQ gQ bQ 0 |
| 59 fSrcToDst[0] = srcToDst.getFloat(0, 0); |
| 60 fSrcToDst[1] = srcToDst.getFloat(0, 1); |
| 61 fSrcToDst[2] = srcToDst.getFloat(0, 2); |
| 62 fSrcToDst[3] = 0.0f; |
| 63 fSrcToDst[4] = srcToDst.getFloat(1, 0); |
| 64 fSrcToDst[5] = srcToDst.getFloat(1, 1); |
| 65 fSrcToDst[6] = srcToDst.getFloat(1, 2); |
| 66 fSrcToDst[7] = 0.0f; |
| 67 fSrcToDst[8] = srcToDst.getFloat(2, 0); |
| 68 fSrcToDst[9] = srcToDst.getFloat(2, 1); |
| 69 fSrcToDst[10] = srcToDst.getFloat(2, 2); |
| 70 fSrcToDst[11] = 0.0f; |
| 71 fSrcToDst[12] = srcToDst.getFloat(3, 0); |
| 72 fSrcToDst[13] = srcToDst.getFloat(3, 1); |
| 73 fSrcToDst[14] = srcToDst.getFloat(3, 2); |
| 74 fSrcToDst[15] = 0.0f; |
| 75 } |
| 76 |
| 77 void Sk2Dot2Xform::xform_RGBA_8888(uint32_t* dst, const uint32_t* src, uint32_t
len) const { |
| 78 SkOpts::color_xform_2Dot2_RGBA_to_8888(dst, src, len, fSrcToDst); |
| 79 } |
| 80 |
| 81 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 82 |
| 59 static inline float byte_to_float(uint8_t v) { | 83 static inline float byte_to_float(uint8_t v) { |
| 60 return ((float) v) * (1.0f / 255.0f); | 84 return ((float) v) * (1.0f / 255.0f); |
| 61 } | 85 } |
| 62 | 86 |
| 63 static inline uint8_t clamp_float_to_byte(float v) { | 87 // Expand range from 0-1 to 0-255, then convert. |
| 88 static inline uint8_t clamp_normalized_float_to_byte(float v) { |
| 64 v = v * 255.0f; | 89 v = v * 255.0f; |
| 65 if (v > 255.0f) { | 90 if (v >= 254.5f) { |
| 66 return 255; | 91 return 255; |
| 67 } else if (v <= 0.0f) { | 92 } else if (v < 0.5f) { |
| 68 return 0; | 93 return 0; |
| 69 } else { | 94 } else { |
| 70 return (uint8_t) (v + 0.5f); | 95 return (uint8_t) (v + 0.5f); |
| 71 } | 96 } |
| 72 } | 97 } |
| 73 | 98 |
| 74 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
| 75 | |
| 76 SkGammaByValueXform::SkGammaByValueXform(float srcGammas[3], const SkMatrix44& s
rcToDst, | |
| 77 float dstGammas[3]) | |
| 78 : fSrcToDst(srcToDst) | |
| 79 { | |
| 80 memcpy(fSrcGammas, srcGammas, 3 * sizeof(float)); | |
| 81 memcpy(fDstGammas, dstGammas, 3 * sizeof(float)); | |
| 82 } | |
| 83 | |
| 84 void SkGammaByValueXform::xform_RGBA_8888(uint32_t* dst, const uint32_t* src, ui
nt32_t len) const { | |
| 85 while (len-- > 0) { | |
| 86 float srcFloats[3]; | |
| 87 srcFloats[0] = byte_to_float((*src >> 0) & 0xFF); | |
| 88 srcFloats[1] = byte_to_float((*src >> 8) & 0xFF); | |
| 89 srcFloats[2] = byte_to_float((*src >> 16) & 0xFF); | |
| 90 | |
| 91 // Convert to linear. | |
| 92 srcFloats[0] = pow(srcFloats[0], fSrcGammas[0]); | |
| 93 srcFloats[1] = pow(srcFloats[1], fSrcGammas[1]); | |
| 94 srcFloats[2] = pow(srcFloats[2], fSrcGammas[2]); | |
| 95 | |
| 96 // Convert to dst gamut. | |
| 97 float dstFloats[3]; | |
| 98 dstFloats[0] = srcFloats[0] * fSrcToDst.getFloat(0, 0) + | |
| 99 srcFloats[1] * fSrcToDst.getFloat(1, 0) + | |
| 100 srcFloats[2] * fSrcToDst.getFloat(2, 0) + fSrcToDst.getFl
oat(3, 0); | |
| 101 dstFloats[1] = srcFloats[0] * fSrcToDst.getFloat(0, 1) + | |
| 102 srcFloats[1] * fSrcToDst.getFloat(1, 1) + | |
| 103 srcFloats[2] * fSrcToDst.getFloat(2, 1) + fSrcToDst.getFl
oat(3, 1); | |
| 104 dstFloats[2] = srcFloats[0] * fSrcToDst.getFloat(0, 2) + | |
| 105 srcFloats[1] * fSrcToDst.getFloat(1, 2) + | |
| 106 srcFloats[2] * fSrcToDst.getFloat(2, 2) + fSrcToDst.getFl
oat(3, 2); | |
| 107 | |
| 108 // Convert to dst gamma. | |
| 109 dstFloats[0] = pow(dstFloats[0], fDstGammas[0]); | |
| 110 dstFloats[1] = pow(dstFloats[1], fDstGammas[1]); | |
| 111 dstFloats[2] = pow(dstFloats[2], fDstGammas[2]); | |
| 112 | |
| 113 *dst = SkPackARGB32NoCheck(((*src >> 24) & 0xFF), | |
| 114 clamp_float_to_byte(dstFloats[0]), | |
| 115 clamp_float_to_byte(dstFloats[1]), | |
| 116 clamp_float_to_byte(dstFloats[2])); | |
| 117 | |
| 118 dst++; | |
| 119 src++; | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
| 124 | |
| 125 // Interpolating lookup in a variably sized table. | 99 // Interpolating lookup in a variably sized table. |
| 126 static inline float interp_lut(uint8_t byte, float* table, size_t tableSize) { | 100 static inline float interp_lut(uint8_t byte, float* table, size_t tableSize) { |
| 127 float index = byte_to_float(byte) * (tableSize - 1); | 101 float index = byte_to_float(byte) * (tableSize - 1); |
| 128 float diff = index - sk_float_floor2int(index); | 102 float diff = index - sk_float_floor2int(index); |
| 129 return table[(int) sk_float_floor2int(index)] * (1.0f - diff) + | 103 return table[(int) sk_float_floor2int(index)] * (1.0f - diff) + |
| 130 table[(int) sk_float_ceil2int(index)] * diff; | 104 table[(int) sk_float_ceil2int(index)] * diff; |
| 131 } | 105 } |
| 132 | 106 |
| 133 // Inverse table lookup. Ex: what index corresponds to the input value? This w
ill | 107 // Inverse table lookup. Ex: what index corresponds to the input value? This w
ill |
| 134 // have strange results when the table is non-increasing. But any sane gamma | 108 // have strange results when the table is non-increasing. But any sane gamma |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 dstFloats[i] = 0.0f; | 228 dstFloats[i] = 0.0f; |
| 255 } else { | 229 } else { |
| 256 dstFloats[i] = (pow(dstFloats[i] - gamma.fC, 1.0f / gamm
a.fG) - gamma.fB) | 230 dstFloats[i] = (pow(dstFloats[i] - gamma.fC, 1.0f / gamm
a.fG) - gamma.fB) |
| 257 / gamma.fA; | 231 / gamma.fA; |
| 258 } | 232 } |
| 259 } | 233 } |
| 260 } | 234 } |
| 261 } | 235 } |
| 262 | 236 |
| 263 *dst = SkPackARGB32NoCheck(((*src >> 24) & 0xFF), | 237 *dst = SkPackARGB32NoCheck(((*src >> 24) & 0xFF), |
| 264 clamp_float_to_byte(dstFloats[0]), | 238 clamp_normalized_float_to_byte(dstFloats[0]), |
| 265 clamp_float_to_byte(dstFloats[1]), | 239 clamp_normalized_float_to_byte(dstFloats[1]), |
| 266 clamp_float_to_byte(dstFloats[2])); | 240 clamp_normalized_float_to_byte(dstFloats[2]))
; |
| 267 | 241 |
| 268 dst++; | 242 dst++; |
| 269 src++; | 243 src++; |
| 270 } | 244 } |
| 271 } | 245 } |
| OLD | NEW |