<> <> <> <> <<>> DIRECTORY ColorFns, ImagerColor USING [CIEFromChromaticity], RealFns USING [Power, Log, SqRt]; <<>> ColorFnsImpl: CEDAR PROGRAM IMPORTS RealFns, ImagerColor EXPORTS ColorFns ~ BEGIN OPEN ColorFns; <> <> LStarFromLuminance: PUBLIC PROC [Y: REAL, whiteY: REAL] RETURNS[lStar: REAL] = { < 0.008856>> <> rel: REAL _ Y/whiteY; IF rel > 0.008856 THEN lStar _ 116.0*RealFns.Power[base: rel, exponent: 1.0/3.0] -16.0 ELSE lStar _ 903.29*rel; }; LuminanceFromLStar: PUBLIC PROC [lStar: REAL, whiteY: REAL] RETURNS[Y: REAL] = { < 0.008856>> <> rel: REAL _ Y/whiteY; IF lStar > 8.0 THEN Y _ whiteY*RealFns.Power[base: ((lStar+16)/116.0), exponent: 3.0] ELSE Y _ whiteY*lStar/903.29; }; <<>> <<>> <> <> MetricChrFromXYZ: PUBLIC PROC[xyz: CIE] RETURNS[uv: MetricChromaticity] = { <> <> <> den: REAL _ xyz.X+15*xyz.Y+3*xyz.Z; RETURN[[uPrime: 4*xyz.X/den, vPrime: 9*xyz.Y/den]]; }; MetricChrFromChr: PUBLIC PROC[xy: CIEChromaticity] RETURNS[uv: MetricChromaticity] = { <> den: REAL _ -2*xy.x+12*xy.y+3; RETURN[[uPrime: 4*xy.x/den, vPrime: 9*xy.y/den]]; }; ChrFromMetricChr: PUBLIC PROC[uv: MetricChromaticity] RETURNS[xy: CIEChromaticity] = { <> den: REAL _ 18*uv.uPrime-48*uv.vPrime+36; RETURN[[x: 27*uv.uPrime/den, y: 12*uv.vPrime/den]]; }; <> CIELABFromXYZ: PUBLIC PROC [xyz: CIE, white: CIE] RETURNS[lab: CIELAB] = { <> <> <> <> cubeRootY: REAL _ RealFns.Power[base: xyz.Y/white.Y, exponent: 1.0/3.0]; lab.lStar _ LStarFromLuminance[xyz.Y, white.Y]; lab.aStar _ 500*(RealFns.Power[base: xyz.X/white.X, exponent: 1.0/3.0]-cubeRootY); lab.bStar _ 200*(cubeRootY-RealFns.Power[base: xyz.Z/white.Z, exponent: 1.0/3.0]); }; XYZFromCIELAB: PUBLIC PROC [lab: CIELAB, white: CIE] RETURNS[xyz: CIE] = { val: REAL _ (lab.lStar+16)/116.0; xyz.Y _ LuminanceFromLStar[lab.lStar, white.Y]; xyz.X _ white.X*RealFns.Power[base: (val+lab.aStar/500.0), exponent: 3]; xyz.Z _ white.Z*RealFns.Power[base: (val-lab.bStar/200.0), exponent: 3]; }; CIELUVFromXYZ: PUBLIC PROC [xyz: CIE, white: CIE] RETURNS[luv: CIELUV] = { <> <> <> <> <> <> uvWhite: MetricChromaticity _ MetricChrFromXYZ[white]; luv.lStar _ LStarFromLuminance[xyz.Y, white.Y]; IF luv.lStar > 10E-8 THEN { uv: MetricChromaticity _ MetricChrFromXYZ[xyz]; luv.uStar _ 13*luv.lStar*(uv.uPrime-uvWhite.uPrime); luv.vStar _ 13*luv.lStar*(uv.vPrime-uvWhite.vPrime); } ELSE {luv.uStar _ luv.vStar _ 13*luv.lStar}; }; XYZFromCIELUV: PUBLIC PROC [luv: CIELUV, white: CIE] RETURNS[xyz: CIE] = { <> <> <> <> <> uvWhite: MetricChromaticity _ MetricChrFromXYZ[white]; uv: MetricChromaticity _ [ uPrime: luv.uStar/(13*luv.lStar)+uvWhite.uPrime, vPrime: luv.vStar/(13*luv.lStar)+uvWhite.vPrime]; xy: CIEChromaticity _ ChrFromMetricChr[uv]; Y: REAL _ LuminanceFromLStar[luv.lStar, white.Y]; xyz _ ImagerColor.CIEFromChromaticity[xy,Y]; }; DifferenceCIELAB: PUBLIC PROC [color1, color2: CIELAB] RETURNS [difference: REAL] = { delL: REAL _ color2.lStar-color1.lStar; delA: REAL _ color2.aStar-color1.aStar; delB: REAL _ color2.bStar-color1.bStar; RETURN[RealFns.SqRt[delL*delL+delA*delA+delB*delB]]; }; DifferenceCIELUV: PUBLIC PROC [color1, color2: CIELUV] RETURNS [difference: REAL] = { delL: REAL _ color2.lStar-color1.lStar; delU: REAL _ color2.uStar-color1.uStar; delV: REAL _ color2.vStar-color1.vStar; RETURN[RealFns.SqRt[delL*delL+delU*delU+delV*delV]]; }; <> <> DensityFromReflectance: PUBLIC PROC[r: REAL] RETURNS[REAL] = { <> <> RETURN[IF r=0 THEN 5.0 ELSE RealFns.Log[base: 10, arg: (100.0/r)]]; }; ReflectanceFromDensity: PUBLIC PROC[d: REAL] RETURNS[REAL] = { <> RETURN[100.0/RealFns.Power[base: 10, exponent: d]]; }; <> <> DensityFromDotArea: PUBLIC PROC[area: REAL, solidD: REAL _ 1.5, n: REAL _ 1.4] RETURNS[density: REAL] = { <> <> density _ -n*RealFns.Log[ base: 10, arg: (1-area*(1-RealFns.Power[base: 10, exponent: -solidD/n])/100.0)]; RETURN[density]; }; <> <> DotAreaFromDensity: PUBLIC PROC[density: REAL, solidD: REAL _ 1.5, n: REAL _ 1.4] RETURNS[area: REAL] = { <> area _ 100.0*(1-RealFns.Power[base: 10, exponent: -density/n])/ (1-RealFns.Power[base: 10, exponent: -solidD/n]); RETURN[area]; }; <> END.