Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

to generate a set of well contrasted colors

by pg (Canon)
on Nov 07, 2003 at 00:22 UTC ( [id://305198]=perlquestion: print w/replies, xml ) Need Help??

pg has asked for the wisdom of the Perl Monks concerning the following question:

I run a chat room on my web site. To make the content more attractive, and also to visually confirm to the user that the content has refreshed when they click "listen", I change the background color each time randomly.

Now if the foreground color stays the same all the time, it could be too close to the background color, and the user will not be able to read. So I come up with this piece of code to generate two colors that (I believe) are well contrasted to each other:

sub random_color { my ($r, $g, $b) = (int(rand(256)), int(rand(256)), int(rand(256))) +; my $color1 = sprintf("#%02x%02x%02x", $r, $g, $b); my $color2 = sprintf("#%02x%02x%02x", ($r + 128) % 256, ($g + 128) + % 256, ($b + 128) % 256); return ($color1, $color2); }
and I use it in this way:
my ($c1, $c2) = random_color(); $msg .= $cgi->table({-border => 1, bgcolor => $c1, sty +le => "Color: $c2;"}, $cgi->Tr($table_data));

So far, it seems to me work very well, but I am not sure whether this really gurantees the well-contrastness. Maybe some one can enlighten me, or come up with some other interesting way to generate the colors, and give a different look and feel.

Replies are listed 'Best First'.
Re: to generate a set of well contrasted colors
by blokhead (Monsignor) on Nov 07, 2003 at 00:47 UTC
    Although colors chosen by your method may contrast, they might still be unreadable. Have you ever seen a webpage with a pure blue background and pure yellow text? Perhaps a more eye-friendly method is to always use black or white foreground text, which would hardly clash with anything

    To determine whether white or black would contrast more with your random background color, you can use the luminosity (brightness) of the background color. The luminosity is the value the color would become when converted to grayscale. What's nice is that human perception is built in -- the formula for luminosity takes into account the differences in how red, green, and blue contribute to the perception of "brightness". If the luminosity is brighter than 50% gray, use black text, otherwise use white text. The results are very readable.

    sub random_colors { my ($r, $g, $b) = map { int rand 256 } 1 .. 3; my $lum = ($r * 0.3) + ($g * 0.59) + ($b * 0.11); my $bg = sprintf("#%02x%02x%02x", $r, $g, $b); my $fg = $lum < 128 ? "white" : "black"; return ($bg, $fg); } for (1 .. 10) { my ($bg, $fg) = random_colors(); print qq{ <table><tr><td bgcolor=$bg> <font color=$fg>THIS IS A TEST</font> </td></tr></table> }; }
    THIS IS A TEST
    THIS IS A TEST
    THIS IS A TEST
    THIS IS A TEST
    THIS IS A TEST
    THIS IS A TEST
    THIS IS A TEST
    THIS IS A TEST
    THIS IS A TEST
    THIS IS A TEST
    Update: (This is for my own reference in the future as much as anything, so I can find these links when I need to.) To be nitpicky, choosing a "random" color by uniformly choosing random RGB components is not as random as one would think. RGB is not a perceptually uniform color space. A better method to generate colors that are perceptually random instead of numerically random in their RGB components would be to use a different color space like L*a*b* or L*u*v*, where the three color dimensions are closer to perceptually uniform. Uniformly select the three components in this color space, then convert to RGB. For more info, see the Color Space FAQ, questions C-35 and C-39.

    But for the purposes of pg's app, uniformly choosing in RGB-space is probably quite sufficient, as we only need the color to be noticably different than the previous.

    blokhead

      Quite a few interesting replies came up for this thread!

      I come up below piece of code to demon different solutions together. It displays a table that:

      • The background color of each row is randomly generated, and keep the same for all cells in the row;
      • The foreground color is generated by different solutions, identified by author's name.

      To run it, just type:

      perl -w blah.pl > result.html

      And then use your browser to view result.html.

      You will see that each siolution has its merit, and a different look and feel. I think, if you love fish, then take fish; if you love meat, then take meat, all delicious.

      sub random_colors { my ($r, $g, $b) = map { int rand 256 } 1 .. 3; my $lum = ($r * 0.3) + ($g * 0.59) + ($b * 0.11); my $bg = sprintf("#%02x%02x%02x", $r, $g, $b); my $fg1 = sprintf("#%02x%02x%02x", ($r + 128) % 256, ($g + 128) % +256, ($b + 128) % 256); my $fg2 = $lum < 128 ? "white" : "black"; return ($bg, $fg1, $fg2); } for (1 .. 100) { my ($bg, $fg1, $fg2) = random_colors(); print qq{ <table> <tr> <td bgcolor=$bg><font size=5 color=$fg1>pg</font></td> <td bgcolor=$bg><font size=5 color=$fg2>blokhead</font></t +d> </tr> </table> }; }

      Here is just a piece of it:

      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      pg blokhead
      I second the colored background black or white text plan. Pretty much any scheme for creating contrast will either fail for grey (as the 255-r,255-g,255-b method does), produce eye-destroying combinations, or have at least one of the colors so close to white/black that it's not worth the effort to calculate it (like my idea, using HSB to create a complimentary pair, one color with high brightness and low saturation and the other vice-versa, aka a pastel and and an earthtone).

      I do, however have to take issue with your luminance function. Those coeffiecients are for NTSC, and despite the fact that it would likely never make a difference, for the sake of argument

      Y = 0.212671 * R + 0.715160 * G + 0.072169 * B

      is more apropriate for a computer monitor.

      Having worked off and on with L*a*b* and L*u*v* transforms for several months now, I whole heartedly agree that it's not in any way worth pursuing them. 'Uniformly distributed' in either is easier said than done, as neither a* and b* nor u* and v* have well defined maximums. Now call me crazy, but color spaces that let you specify colors outside the gamut of *light* bother me.


      'The fickle fascination of and Everlasting God' - Billy Corgan, The Smashing Pumpkins
        Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
        ...but those are for the sRGB primaries in linear space; css/HTML codes are in gamma space.
      Hey, there's nowt wrong with yellow on blue. It was NASA, I think, who found that to be the most readable. At least, that was the reason that Amstrad gave for making their CPC 464 colour scheme yellow on blue.

      Still doesn't make it any less ugly ...

      --
      bowling trophy thieves, die!

Re: to generate a set of well contrasted colors
by jweed (Chaplain) on Nov 07, 2003 at 00:41 UTC

    Though it might be very difficult to implement, I would suggest that you take into accound the needs of color deficient users. What looks contrasting to me may look very similar to someone else. Safe Web Colours is a good website with design tips regarding color-deficiency.

    Because of this difficulty, I would suggest that you either a) compile a data set of colors that are contrasting for any user or b) scrap the bg changing shenanegins. In general, I would suggest the latter because even without color deficiency, some combinations are too harsh to be of any use.

    Hope this helps!

      I guess this is why one should come to perlmonk often.

      I have never thought of this before, and this is definitely a reply I didn't expect. One's thinking is always narrowed, and that's why one need talk to people, ask for wisedom!

      I will look into it more, and see whether can turn this into a picture transformation module. I feel that it is a bit of waste to use it only for text, considering the thinking and implementation might take. If I come up with anything, I will post it in cool use of Perl and credit you on the post.

      To add to the above comment, Cal Henderson has a module on CPAN called Graphics::ColorDeficiency. It allows you to simulate color deficiencies. You can even get the resulting color as hex for html use.

      See also, this page on his site.

      --
      "To err is human, but to really foul things up you need a computer." --Paul Ehrlich

Re: to generate a set of well contrasted colors
by vacant (Pilgrim) on Nov 07, 2003 at 01:37 UTC
    This might be of some help. It is a subroutine I wrote to generate randomly-colored backgrounds for text-on-colored-background pages. The two simple subroutines bg_text() and bg_page() at the bottom illustrate how to use it. I used this method to create the background colors for areas containing text (tables) and areas elsewhere (page background). Pick a contrasting color for the text, or experiment with a different brightness and saturation for randomly-colored text. Some experimentation will be required.
    # Subroutine bg_color() creates colors of random hue and fairly # consistent brightness and saturation. The highest and lowest of the # three color channel values are fixed, and the third is given # a random value between the highest and lowest. The three values are # then assigned in random order to red, green, and blue. The highest # value will control the brightness of the resulting color, and the # distance between the highest and lowest will control the saturation. # Hue is randomly set by the value of the random third parameter toget +her # with the random assignment of the three values to red, green, and bl +ue. sub bg_color { my $highest = shift; # lightness my $lowest = shift; # saturation my $middle = int(rand($highest - $lowest) + $lowest); my @c = ($highest, $lowest, $middle); # randomize the order of the three values with the Fisher-Yates shuf +fle my ($i, $j); for ($i = 3; --$i; ) { $j = int rand ($i+1); next if $i == $j; @c[$i,$j] = @c[$j,$i]; } # convert to hex in the form: #RRGGBB my $cs = sprintf "\#%0.2X%0.2X%0.2X", @c; return $cs; } sub bg_text {bg_color(215, 153)}; # light colors, low saturation sub bg_page {bg_color(204, 102)};
Re: to generate a set of well contrasted colors
by Anonymous Monk on Nov 07, 2003 at 01:40 UTC
    You may want to check out: http://www.pixy.cz/apps/barvy/index-en.html particularly to test for readability for those who are color blind
Re: to generate a set of well contrasted colors
by zengargoyle (Deacon) on Nov 07, 2003 at 02:04 UTC

    warning: only tangentally relevant

    the first few sections of chapter 5 of Grokking the GIMP have a pretty good explanation of RGB vs HSV vs CMYK with some pictures to help.

    i can't seem to help linking Visibone and EasyRGB. both are handy when looking for any sort of color information. (or just looking at the pretty colors)

Re: to generate a set of well contrasted colors
by inman (Curate) on Nov 07, 2003 at 09:28 UTC
    It might be useful to look at a color wheel of web safe colours. You could use the colour values from opposite sides of the wheel to display text.

    There is a rather nice colour wheel on this website: http://www.visibone.com/colorlab/big.html. The wheel is interactive and demonstrates both the luminosity aspect (choosing black or white text) and the use of opposing colours in the table on the right hand side.

    A nice question.

    inman

Re: to generate a set of well contrasted colors
by Anonymous Monk on Nov 07, 2003 at 21:42 UTC
    I'll agree with most of the previous posters; doing both the random selection and the contrast in a psychologically relevant color model, any one, would be better. Myself, I've always used HSV space, but any of several mentioned works.

    The +128%256 operation will not achieve maximal contrast in some cases (it results in Grey on White or Black), but at least it avoids the inverse-video transform trap in which neutral gray transforms to itself.

    -- Bill / N1VUX

Re: to generate a set of well contrasted colors
by Anonymous Monk on Nov 07, 2003 at 21:53 UTC
    A module to consider for easy color-space work: Graphics::RGBManipulate "HSV adjustment tool for RGB colours". Haven't tried it myself, but it sounds right. -- Bill N1VUX

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://305198]
Approved by blokhead
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (4)
As of 2024-04-19 02:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found