ColorManagement.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import { SRGBColorSpace, LinearSRGBColorSpace, SRGBTransfer, LinearTransfer, NoColorSpace } from '../constants.js';
  2. import { Matrix3 } from './Matrix3.js';
  3. const LINEAR_REC709_TO_XYZ = /*@__PURE__*/ new Matrix3().set(
  4. 0.4123908, 0.3575843, 0.1804808,
  5. 0.2126390, 0.7151687, 0.0721923,
  6. 0.0193308, 0.1191948, 0.9505322
  7. );
  8. const XYZ_TO_LINEAR_REC709 = /*@__PURE__*/ new Matrix3().set(
  9. 3.2409699, - 1.5373832, - 0.4986108,
  10. - 0.9692436, 1.8759675, 0.0415551,
  11. 0.0556301, - 0.2039770, 1.0569715
  12. );
  13. function createColorManagement() {
  14. const ColorManagement = {
  15. enabled: true,
  16. workingColorSpace: LinearSRGBColorSpace,
  17. /**
  18. * Implementations of supported color spaces.
  19. *
  20. * Required:
  21. * - primaries: chromaticity coordinates [ rx ry gx gy bx by ]
  22. * - whitePoint: reference white [ x y ]
  23. * - transfer: transfer function (pre-defined)
  24. * - toXYZ: Matrix3 RGB to XYZ transform
  25. * - fromXYZ: Matrix3 XYZ to RGB transform
  26. * - luminanceCoefficients: RGB luminance coefficients
  27. *
  28. * Optional:
  29. * - outputColorSpaceConfig: { drawingBufferColorSpace: ColorSpace }
  30. * - workingColorSpaceConfig: { unpackColorSpace: ColorSpace }
  31. *
  32. * Reference:
  33. * - https://www.russellcottrell.com/photo/matrixCalculator.htm
  34. */
  35. spaces: {},
  36. convert: function ( color, sourceColorSpace, targetColorSpace ) {
  37. if ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) {
  38. return color;
  39. }
  40. if ( this.spaces[ sourceColorSpace ].transfer === SRGBTransfer ) {
  41. color.r = SRGBToLinear( color.r );
  42. color.g = SRGBToLinear( color.g );
  43. color.b = SRGBToLinear( color.b );
  44. }
  45. if ( this.spaces[ sourceColorSpace ].primaries !== this.spaces[ targetColorSpace ].primaries ) {
  46. color.applyMatrix3( this.spaces[ sourceColorSpace ].toXYZ );
  47. color.applyMatrix3( this.spaces[ targetColorSpace ].fromXYZ );
  48. }
  49. if ( this.spaces[ targetColorSpace ].transfer === SRGBTransfer ) {
  50. color.r = LinearToSRGB( color.r );
  51. color.g = LinearToSRGB( color.g );
  52. color.b = LinearToSRGB( color.b );
  53. }
  54. return color;
  55. },
  56. fromWorkingColorSpace: function ( color, targetColorSpace ) {
  57. return this.convert( color, this.workingColorSpace, targetColorSpace );
  58. },
  59. toWorkingColorSpace: function ( color, sourceColorSpace ) {
  60. return this.convert( color, sourceColorSpace, this.workingColorSpace );
  61. },
  62. getPrimaries: function ( colorSpace ) {
  63. return this.spaces[ colorSpace ].primaries;
  64. },
  65. getTransfer: function ( colorSpace ) {
  66. if ( colorSpace === NoColorSpace ) return LinearTransfer;
  67. return this.spaces[ colorSpace ].transfer;
  68. },
  69. getLuminanceCoefficients: function ( target, colorSpace = this.workingColorSpace ) {
  70. return target.fromArray( this.spaces[ colorSpace ].luminanceCoefficients );
  71. },
  72. define: function ( colorSpaces ) {
  73. Object.assign( this.spaces, colorSpaces );
  74. },
  75. // Internal APIs
  76. _getMatrix: function ( targetMatrix, sourceColorSpace, targetColorSpace ) {
  77. return targetMatrix
  78. .copy( this.spaces[ sourceColorSpace ].toXYZ )
  79. .multiply( this.spaces[ targetColorSpace ].fromXYZ );
  80. },
  81. _getDrawingBufferColorSpace: function ( colorSpace ) {
  82. return this.spaces[ colorSpace ].outputColorSpaceConfig.drawingBufferColorSpace;
  83. },
  84. _getUnpackColorSpace: function ( colorSpace = this.workingColorSpace ) {
  85. return this.spaces[ colorSpace ].workingColorSpaceConfig.unpackColorSpace;
  86. }
  87. };
  88. /******************************************************************************
  89. * sRGB definitions
  90. */
  91. const REC709_PRIMARIES = [ 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 ];
  92. const REC709_LUMINANCE_COEFFICIENTS = [ 0.2126, 0.7152, 0.0722 ];
  93. const D65 = [ 0.3127, 0.3290 ];
  94. ColorManagement.define( {
  95. [ LinearSRGBColorSpace ]: {
  96. primaries: REC709_PRIMARIES,
  97. whitePoint: D65,
  98. transfer: LinearTransfer,
  99. toXYZ: LINEAR_REC709_TO_XYZ,
  100. fromXYZ: XYZ_TO_LINEAR_REC709,
  101. luminanceCoefficients: REC709_LUMINANCE_COEFFICIENTS,
  102. workingColorSpaceConfig: { unpackColorSpace: SRGBColorSpace },
  103. outputColorSpaceConfig: { drawingBufferColorSpace: SRGBColorSpace }
  104. },
  105. [ SRGBColorSpace ]: {
  106. primaries: REC709_PRIMARIES,
  107. whitePoint: D65,
  108. transfer: SRGBTransfer,
  109. toXYZ: LINEAR_REC709_TO_XYZ,
  110. fromXYZ: XYZ_TO_LINEAR_REC709,
  111. luminanceCoefficients: REC709_LUMINANCE_COEFFICIENTS,
  112. outputColorSpaceConfig: { drawingBufferColorSpace: SRGBColorSpace }
  113. },
  114. } );
  115. return ColorManagement;
  116. }
  117. export const ColorManagement = /*@__PURE__*/ createColorManagement();
  118. export function SRGBToLinear( c ) {
  119. return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );
  120. }
  121. export function LinearToSRGB( c ) {
  122. return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;
  123. }
粤ICP备19079148号