@@ -4,6 +4,7 @@ import { ColorNotation } from './color-notation';
44import type { TokenNumber } from '@csstools/css-tokenizer' ;
55import { NumberType , TokenType } from '@csstools/css-tokenizer' ;
66import { HSL_to_XYZ_D50 , HSL_to_XYZ_D65 , HWB_to_XYZ_D50 , HWB_to_XYZ_D65 , LCH_to_XYZ_D50 , LCH_to_XYZ_D65 , Lab_to_XYZ_D50 , Lab_to_XYZ_D65 , OKLCH_to_XYZ_D50 , OKLCH_to_XYZ_D65 , OKLab_to_XYZ_D50 , OKLab_to_XYZ_D65 , P3_to_XYZ_D50 , P3_to_XYZ_D65 , ProPhoto_RGB_to_XYZ_D50 , ProPhoto_RGB_to_XYZ_D65 , XYZ_D50_to_LCH , XYZ_D50_to_Lab , XYZ_D50_to_ProPhoto , XYZ_D50_to_XYZ_D50 , XYZ_D50_to_XYZ_D65 , XYZ_D65_to_HSL , XYZ_D65_to_HWB , XYZ_D65_to_OKLCH , XYZ_D65_to_OKLab , XYZ_D65_to_P3 , XYZ_D65_to_XYZ_D50 , XYZ_D65_to_XYZ_D65 , XYZ_D65_to_a98_RGB , XYZ_D65_to_lin_P3 , XYZ_D65_to_lin_sRGB , XYZ_D65_to_rec_2020 , XYZ_D65_to_sRGB , a98_RGB_to_XYZ_D50 , a98_RGB_to_XYZ_D65 , lin_P3_to_XYZ_D50 , lin_P3_to_XYZ_D65 , lin_sRGB_to_XYZ_D50 , lin_sRGB_to_XYZ_D65 , rec_2020_to_XYZ_D50 , rec_2020_to_XYZ_D65 , sRGB_to_XYZ_D50 , sRGB_to_XYZ_D65 } from '@csstools/color-helpers' ;
7+ import { normalize } from './functions/normalize' ;
78
89/**
910 * A color data object.
@@ -413,55 +414,64 @@ function convertToDestination(colorData: ColorData, toNotation: ColorNotation):
413414 // 9. If dest-rect is not the same as dest, in other words dest is a cylindrical polar color representation, convert from dest-rect to dest, and let this be col2.
414415 colorData . channels = XYZ_D65_to_sRGB ( xyzColorData . channels ) ;
415416 colorData . channels = colorData . channels . map ( ( x ) => reducePrecisionOrNaN ( x , 8 ) ) as Color ;
417+ colorData . channels = normalizeAfterColorConversion ( colorData . channels ) ;
416418 break ;
417419 }
418420 case ColorNotation . sRGB : {
419421 const xyzColorData = colorData_to_XYZ_D65 ( colorData ) ;
420422 colorData . colorNotation = ColorNotation . sRGB ;
421423 colorData . channels = XYZ_D65_to_sRGB ( xyzColorData . channels ) ;
424+ colorData . channels = normalizeAfterColorConversion ( colorData . channels ) ;
422425 break ;
423426 }
424427 case ColorNotation . Linear_sRGB : {
425428 const xyzColorData = colorData_to_XYZ_D65 ( colorData ) ;
426429 colorData . colorNotation = ColorNotation . Linear_sRGB ;
427430 colorData . channels = XYZ_D65_to_lin_sRGB ( xyzColorData . channels ) ;
431+ colorData . channels = normalizeAfterColorConversion ( colorData . channels ) ;
428432 break ;
429433 }
430434 case ColorNotation . Display_P3 : {
431435 const xyzColorData = colorData_to_XYZ_D65 ( colorData ) ;
432436 colorData . colorNotation = ColorNotation . Display_P3 ;
433437 colorData . channels = XYZ_D65_to_P3 ( xyzColorData . channels ) ;
438+ colorData . channels = normalizeAfterColorConversion ( colorData . channels ) ;
434439 break ;
435440 }
436441 case ColorNotation . Linear_Display_P3 : {
437442 const xyzColorData = colorData_to_XYZ_D65 ( colorData ) ;
438443 colorData . colorNotation = ColorNotation . Linear_Display_P3 ;
439444 colorData . channels = XYZ_D65_to_lin_P3 ( xyzColorData . channels ) ;
445+ colorData . channels = normalizeAfterColorConversion ( colorData . channels ) ;
440446 break ;
441447 }
442448 case ColorNotation . Rec2020 : {
443449 const xyzColorData = colorData_to_XYZ_D65 ( colorData ) ;
444450 colorData . colorNotation = ColorNotation . Rec2020 ;
445451 colorData . channels = XYZ_D65_to_rec_2020 ( xyzColorData . channels ) ;
452+ colorData . channels = normalizeAfterColorConversion ( colorData . channels ) ;
446453 break ;
447454 }
448455 case ColorNotation . ProPhoto_RGB : {
449456 const xyzColorData = colorData_to_XYZ_D50 ( colorData ) ;
450457 colorData . colorNotation = ColorNotation . ProPhoto_RGB ;
451458 colorData . channels = XYZ_D50_to_ProPhoto ( xyzColorData . channels ) ;
459+ colorData . channels = normalizeAfterColorConversion ( colorData . channels ) ;
452460 break ;
453461 }
454462 case ColorNotation . A98_RGB : {
455463 const xyzColorData = colorData_to_XYZ_D65 ( colorData ) ;
456464 colorData . colorNotation = ColorNotation . A98_RGB ;
457465 colorData . channels = XYZ_D65_to_a98_RGB ( xyzColorData . channels ) ;
466+ colorData . channels = normalizeAfterColorConversion ( colorData . channels ) ;
458467 break ;
459468 }
460469 case ColorNotation . HSL : {
461470 const xyzColorData = colorData_to_XYZ_D65 ( colorData ) ;
462471 colorData . colorNotation = ColorNotation . HSL ;
463472 colorData . channels = XYZ_D65_to_HSL ( xyzColorData . channels ) ;
464473 colorData . channels = colorData . channels . map ( ( x ) => reducePrecisionOrNaN ( x , 8 ) ) as Color ;
474+ colorData . channels = normalizeAfterColorConversion ( colorData . channels , 0 ) ;
465475
466476 // https://drafts.csswg.org/css-color-4/#color-conversion
467477 // 9. This may produce missing components.
@@ -473,6 +483,7 @@ function convertToDestination(colorData: ColorData, toNotation: ColorNotation):
473483 colorData . colorNotation = ColorNotation . HWB ;
474484 colorData . channels = XYZ_D65_to_HWB ( xyzColorData . channels ) ;
475485 colorData . channels = colorData . channels . map ( ( x ) => reducePrecisionOrNaN ( x , 8 ) ) as Color ;
486+ colorData . channels = normalizeAfterColorConversion ( colorData . channels , 0 ) ;
476487
477488 // https://drafts.csswg.org/css-color-4/#color-conversion
478489 // 9. This may produce missing components.
@@ -483,12 +494,14 @@ function convertToDestination(colorData: ColorData, toNotation: ColorNotation):
483494 const xyzColorData = colorData_to_XYZ_D50 ( colorData ) ;
484495 colorData . colorNotation = ColorNotation . Lab ;
485496 colorData . channels = XYZ_D50_to_Lab ( xyzColorData . channels ) ;
497+ colorData . channels = normalizeAfterColorConversion ( colorData . channels ) ;
486498 break ;
487499 }
488500 case ColorNotation . LCH : {
489501 const xyzColorData = colorData_to_XYZ_D50 ( colorData ) ;
490502 colorData . colorNotation = ColorNotation . LCH ;
491503 colorData . channels = XYZ_D50_to_LCH ( xyzColorData . channels ) ;
504+ colorData . channels = normalizeAfterColorConversion ( colorData . channels , 2 ) ;
492505
493506 // https://drafts.csswg.org/css-color-4/#color-conversion
494507 // 9. This may produce missing components.
@@ -499,6 +512,7 @@ function convertToDestination(colorData: ColorData, toNotation: ColorNotation):
499512 const xyzColorData = colorData_to_XYZ_D65 ( colorData ) ;
500513 colorData . colorNotation = ColorNotation . OKLCH ;
501514 colorData . channels = XYZ_D65_to_OKLCH ( xyzColorData . channels ) ;
515+ colorData . channels = normalizeAfterColorConversion ( colorData . channels , 2 ) ;
502516
503517 // https://drafts.csswg.org/css-color-4/#color-conversion
504518 // 9. This may produce missing components.
@@ -509,18 +523,21 @@ function convertToDestination(colorData: ColorData, toNotation: ColorNotation):
509523 const xyzColorData = colorData_to_XYZ_D65 ( colorData ) ;
510524 colorData . colorNotation = ColorNotation . OKLab ;
511525 colorData . channels = XYZ_D65_to_OKLab ( xyzColorData . channels ) ;
526+ colorData . channels = normalizeAfterColorConversion ( colorData . channels ) ;
512527 break ;
513528 }
514529 case ColorNotation . XYZ_D50 : {
515530 const xyzColorData = colorData_to_XYZ_D50 ( colorData ) ;
516531 colorData . colorNotation = ColorNotation . XYZ_D50 ;
517532 colorData . channels = XYZ_D50_to_XYZ_D50 ( xyzColorData . channels ) ;
533+ colorData . channels = normalizeAfterColorConversion ( colorData . channels ) ;
518534 break ;
519535 }
520536 case ColorNotation . XYZ_D65 : {
521537 const xyzColorData = colorData_to_XYZ_D65 ( colorData ) ;
522538 colorData . colorNotation = ColorNotation . XYZ_D65 ;
523539 colorData . channels = XYZ_D65_to_XYZ_D65 ( xyzColorData . channels ) ;
540+ colorData . channels = normalizeAfterColorConversion ( colorData . channels ) ;
524541 break ;
525542 }
526543 default :
@@ -915,6 +932,21 @@ export function noneToZeroInRelativeColorDataChannels(x: Map<string, TokenNumber
915932 return globals ;
916933}
917934
935+ function normalizeAfterColorConversion ( a : Color , hueIndex : number = - 1 ) : Color {
936+ a = convertNaNToZero ( a ) ;
937+ a = [
938+ hueIndex === 0 ? a [ 0 ] : normalize ( a [ 0 ] , 1 , - 2_147_483_647 , 2_147_483_647 ) ,
939+ hueIndex === 1 ? a [ 1 ] : normalize ( a [ 1 ] , 1 , - 2_147_483_647 , 2_147_483_647 ) ,
940+ hueIndex === 2 ? a [ 2 ] : normalize ( a [ 2 ] , 1 , - 2_147_483_647 , 2_147_483_647 ) ,
941+ ] ;
942+
943+ if ( ! Number . isNaN ( a [ hueIndex ] ) && ! Number . isFinite ( a [ hueIndex ] ) ) {
944+ a [ hueIndex ] = 0 ;
945+ }
946+
947+ return a ;
948+ }
949+
918950function dummyNumberToken ( x : number ) : TokenNumber {
919951 if ( Number . isNaN ( x ) ) {
920952 return [ TokenType . Number , 'none' , - 1 , - 1 , { value : Number . NaN , type : NumberType . Number } ] ;
0 commit comments