2005. április 3., vasárnap

Convert between RGB and HSB color spaces and back


Problem/Question/Abstract:

Is there any way to convert a set of colors that look good on a random background, and have them look "complimentary" and have good contrast with the background? What I have is a chart with an arbitrary background color. What I want to do is to automatically come up with a set of colors for channels that will look good on that arbitarary background color.

Answer:

I found some C++ functions to convert between RGB and HSB, and converted them to Pascal (hopefully correctly):

procedure TForm1.RGBtoHSB(const r, g, b: Integer; var h, s, br: Double);
var
  largestColor: Integer; {holds the largest color (RGB) at the start}
  lowestColor: Integer; {opposite of above}
  hue: Double; {it puts the "H" in "HSB"}
  saturation: Double; {S}
  brightness: Double; {and the B}
  redRatio: Double;
  greenRatio: Double;
  blueRatio: Double;
begin
  {assign largestColor to the greater of the red or green}
  if (r <= g) then
    largestColor := g
  else
    largestColor := r;
  {now see if blue is bigger}
  if (b > largestColor) then
    largestColor := b;
  {set lowestColor = to the smallest value}
  if (g < r) then
    lowestColor := g
  else
    lowestColor := r;
  if (b < lowestColor) then
    lowestColor := b;
  {brightness is calculated like so:}
  brightness := largestColor / 255.0;
  {if the largestColor isn't zero (so we don't divide by zero) set the variable to
  the difference of the two as a percentage of the largest}
  if (largestColor <> 0) then
    saturation := (largestColor - lowestColor) / largestColor
  else
    saturation := 0.0;
  if (saturation = 0.0) then
    hue := 0.0
  else
  begin
    {some temporary variables to figure out the hue}
    redRatio := (largestColor - r) / (largestColor - lowestColor);
    greenRatio := (largestColor - g) / (largestColor - lowestColor);
    blueRatio := (largestColor - b) / (largestColor - lowestColor);
    {depending on which of the 3 was the highest, we calculate our hue}
    if (r = largestColor) then
      hue := blueRatio - greenRatio
    else if (g = largestColor) then
      hue := (2.0 + redRatio) - blueRatio
    else {blue is largest}
      hue := (4.0 + greenRatio) - redRatio;
    {divide it by 6}
    hue := hue / 6.0;
    {I don't know if this prevents us from being negative
                (as in theworst outcome from the above operations is -1, or if this does
    something different)
    if (hue < 0.0) then
      hue := hue + 1;
    end;
{pass back values}
    h := hue;
    s := saturation;
    br := brightness;
  end;

procedure TForm1.HSBtoRGB(const hue, saturation, brightness: Double; var r, g, b:
  Integer);
const
  max = 255;
var
  h: Double;
  f: Double;
  p: Double;
  q: Double;
  t: Double;
begin
  if (saturation = 0) then
  begin
    r := trunc(brightness * 255);
    g := trunc(brightness * 255);
    b := trunc(brightness * 255);
  end
  else
  begin
    h := (hue - floor(hue)) * 6.0;
    f := h - floor(h);
    p := brightness * (1.0 - saturation);
    q := brightness * (1.0 - saturation * f);
    t := brightness * (1.0 - (saturation * (1.0 - f)));
    case trunc(h) of
      0:
        begin
          r := trunc(brightness * 255);
          g := trunc(t * max);
          b := trunc(p * max);
        end;
      1:
        begin
          r := trunc(q * max);
          g := trunc(brightness * max);
          b := trunc(p * max);
        end;
      2:
        begin
          r := trunc(p * max);
          g := trunc(brightness * max);
          b := trunc(t * max);
        end;
      3:
        begin
          r := trunc(p * max);
          g := trunc(q * max);
          b := trunc(brightness * max);
        end;
      4:
        begin
          r := trunc(t * max);
          g := trunc(p * max);
          b := trunc(brightness * max);
        end;
      5:
        begin
          r := trunc(brightness * max);
          g := trunc(p * max);
          b := trunc(q * max);
        end;
    end;
  end;
end;

I then convert each color and the background to HSB, add the Hues of both colors, and then convert the color back to RGB. It works most of the time, but generally the brightness of some of the colors are too bright when the background is too bright, or too dark when the background is too dark.

Nincsenek megjegyzések:

Megjegyzés küldése