(* Copyright (C) 1992, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* Created by Jorge Stolfi on Fri Oct 6 22:07:13 PDT 1989 *) (* Last modified on Tue Feb 11 21:39:47 PST 1992 by muller *) (* modified on Mon Nov 11 16:06:07 PST 1991 by steveg *) (* modified on Thu Oct 25 8:53:50 PDT 1990 by stolfi *) MODULE HSV; IMPORT RGB, Math, YPQ, Intensity; PROCEDURE HSVFromRGB (READONLY rgb: RGB.T): T = VAR pure: RGB.T; t, lo, hi: REAL; hsv: T; BEGIN IF rgb = RGB.Undefined THEN RETURN Undefined END; lo := MIN(MIN(rgb[0], rgb[1]), rgb[2]); hi := MAX(MAX(rgb[0], rgb[1]), rgb[2]); IF hi <= 0.0 THEN hsv := T{0.0, 0.0, 0.0} ELSE hsv[2] := (hi + lo) / 2.0; t := hi - lo; IF (t > 0.0005) THEN (* Compute purest color with same hue *) pure[0] := (rgb[0] - lo) / t; pure[1] := (rgb[1] - lo) / t; pure[2] := (rgb[2] - lo) / t; hsv[0] := HueFromRGB(pure); IF (hsv[2] <= 0.5) THEN hsv[1] := t * 0.5 / hsv[2]; ELSE hsv[1] := t * 0.5 / (MAX(1.0, hi) - hsv[2]); END; ELSE hsv[0] := 0.0; hsv[1] := 0.0; END; END; RETURN hsv END HSVFromRGB; PROCEDURE RGBFromHSV (READONLY hsv: T): RGB.T = (* Updates rgb to match hsl. *) VAR pure, rgb: RGB.T; sat, lum: REAL; BEGIN IF hsv = Undefined THEN RETURN Undefined END; pure := RGBFromHue(hsv[0]); sat := MIN(1.0, MAX(0.0, hsv[1])); rgb := RGB.Mix(pure, sat, RGB.Grey(0.5), 1.0 - sat); lum := MIN(1.0, MAX(0.0, hsv[2])); IF (lum > 0.5) THEN rgb := RGB.Mix( RGB.White, (lum - 0.5) / 0.5, rgb, (1.0 - lum) / 0.5 ) ELSIF (lum < 0.5) THEN rgb := RGB.Mix( RGB.Black, (0.5 - lum) / 0.5, rgb, (lum - 0.0) / 0.5 ) END; RETURN rgb END RGBFromHSV; PROCEDURE HueFromRGB (READONLY rgb: RGB.T): REAL = CONST TwoPi = 6.28318530718; VAR p, q, h, t: REAL; BEGIN IF rgb = Undefined THEN RETURN Intensity.Undefined END; p := rgb[0] * YPQ.rP + rgb[1] * YPQ.gP + rgb[2] * YPQ.bP; q := rgb[0] * YPQ.rQ + rgb[1] * YPQ.gQ + rgb[2] * YPQ.bQ; (* Convert argument angle of (p, q) to fraction of turn: *) (* To be improved *) h := 0.0; IF q < 0.0 THEN p := -p; q := -q; h := h + 0.5 END; IF p < 0.0 THEN t := p; p := q; q := -t; h := h + 0.25; END; IF p <= q THEN t := p; p := p + q; q := q - t; h := h + 0.125 END; IF (p < 0.0001) AND (q < 0.0001) THEN RETURN 0.0 END; RETURN h + FLOAT(Math.atan(FLOAT(q / p, LONGREAL))) / TwoPi; END HueFromRGB; PROCEDURE RGBFromHue (h: REAL): RGB.T = CONST TwoPi = 6.28318530718; VAR p, q, ma, mi: REAL; c: T; BEGIN IF h = Intensity.Undefined THEN RETURN Undefined END; (* To be improved *) p := FLOAT(Math.cos(FLOAT(h * TwoPi, LONGREAL))); q := FLOAT(Math.sin(FLOAT(h * TwoPi, LONGREAL))); c[0] := p * YPQ.Pr + q * YPQ.Qr; c[1] := p * YPQ.Pg + q * YPQ.Qg; c[2] := p * YPQ.Pb + q * YPQ.Qb; mi := MIN(c[0], MIN(c[1], c[2])); c[0] := c[0] - mi; c[1] := c[1] - mi; c[2] := c[2] - mi; ma := MAX(c[0], MAX(c[1], c[2])); c[0] := c[0] / ma; c[1] := c[1] / ma; c[2] := c[2] / ma; RETURN c END RGBFromHue; BEGIN END HSV.