1 | # ---------------------------------------------------------------------- |
---|
2 | # UTILITY: color |
---|
3 | # |
---|
4 | # This file contains various utility functions for manipulating |
---|
5 | # color values. |
---|
6 | # ====================================================================== |
---|
7 | # AUTHOR: Michael McLennan, Purdue University |
---|
8 | # Copyright (c) 2004-2005 |
---|
9 | # Purdue Research Foundation, West Lafayette, IN |
---|
10 | # ====================================================================== |
---|
11 | |
---|
12 | namespace eval Rappture::color { # forward declaration } |
---|
13 | |
---|
14 | # --------------------------------------------------------------------- |
---|
15 | # USAGE: brightness <color> <fraction> |
---|
16 | # |
---|
17 | # Used to brighten or dim a Tk <color> value by some +/- <fraction> in |
---|
18 | # the range 0-1. Returns another color in the same hue, but with |
---|
19 | # different brighness. |
---|
20 | # ---------------------------------------------------------------------- |
---|
21 | proc Rappture::color::brightness {color frac} { |
---|
22 | foreach {h s v} [Rappture::color::RGBtoHSV $color] { break } |
---|
23 | set v [expr {$v+$frac}] |
---|
24 | |
---|
25 | # if frac overflows the value, pass changes along to saturation |
---|
26 | if {$v < 0} { |
---|
27 | set s [expr {$s+$v}] |
---|
28 | if {$s < 0} { set s 0 } |
---|
29 | set v 0 |
---|
30 | } |
---|
31 | if {$v > 1} { |
---|
32 | set s [expr {$s-($v-1)}] |
---|
33 | if {$s < 0} { set s 0 } |
---|
34 | set v 1 |
---|
35 | } |
---|
36 | |
---|
37 | return [Rappture::color::HSVtoRGB $h $s $v] |
---|
38 | } |
---|
39 | |
---|
40 | # --------------------------------------------------------------------- |
---|
41 | # USAGE: brightness_min <color> <min> |
---|
42 | # |
---|
43 | # Used to make sure a color is not too dim. If the value is less |
---|
44 | # than the <min>, then it is capped at that value. That way, the |
---|
45 | # return color shows up against black. |
---|
46 | # ---------------------------------------------------------------------- |
---|
47 | proc Rappture::color::brightness_min {color min} { |
---|
48 | foreach {h s v} [Rappture::color::RGBtoHSV $color] { break } |
---|
49 | if {$v < $min} { |
---|
50 | set v $min |
---|
51 | } |
---|
52 | return [Rappture::color::HSVtoRGB $h $s $v] |
---|
53 | } |
---|
54 | |
---|
55 | # --------------------------------------------------------------------- |
---|
56 | # USAGE: brightness_max <color> <max> |
---|
57 | # |
---|
58 | # Used to make sure a color is not too dim. If the value is less |
---|
59 | # than the <min>, then it is capped at that value. That way, the |
---|
60 | # return color shows up against black. |
---|
61 | # ---------------------------------------------------------------------- |
---|
62 | proc Rappture::color::brightness_max {color max} { |
---|
63 | foreach {h s v} [Rappture::color::RGBtoHSV $color] { break } |
---|
64 | if {$v > $max} { |
---|
65 | set v $max |
---|
66 | } |
---|
67 | return [Rappture::color::HSVtoRGB $h $s $v] |
---|
68 | } |
---|
69 | |
---|
70 | # --------------------------------------------------------------------- |
---|
71 | # USAGE: RGBtoHSV <color> |
---|
72 | # |
---|
73 | # Used to convert a Tk <color> value to hue, saturation, value |
---|
74 | # components. Returns a list of the form {h s v}. |
---|
75 | # ---------------------------------------------------------------------- |
---|
76 | proc Rappture::color::RGBtoHSV {color} { |
---|
77 | # |
---|
78 | # If the colors are exhausted sometimes winfo can fail with a |
---|
79 | # division by zero. Catch it to avoid problems. |
---|
80 | # |
---|
81 | if { [catch {winfo rgb . $color} status] != 0 } { |
---|
82 | set s 0 |
---|
83 | set v 0 |
---|
84 | set h 0 |
---|
85 | return [list $h $s $v] |
---|
86 | } |
---|
87 | foreach {r g b} $status {} |
---|
88 | set min [expr {($r < $g) ? $r : $g}] |
---|
89 | set min [expr {($b < $min) ? $b : $min}] |
---|
90 | set max [expr {($r > $g) ? $r : $g}] |
---|
91 | set max [expr {($b > $max) ? $b : $max}] |
---|
92 | |
---|
93 | set v [expr {$max/65535.0}] |
---|
94 | |
---|
95 | set delta [expr {$max-$min}] |
---|
96 | |
---|
97 | if { $delta == 0 } { |
---|
98 | # delta=0 => gray color |
---|
99 | set s 0 |
---|
100 | set v [expr {$r/65535.0}] |
---|
101 | set h 0 |
---|
102 | return [list $h $s $v] |
---|
103 | } |
---|
104 | |
---|
105 | if {$max > 0} { |
---|
106 | set s [expr {$delta/double($max)}] |
---|
107 | } else { |
---|
108 | # r=g=b=0 => s=0, v undefined |
---|
109 | set s 0 |
---|
110 | set v 0 |
---|
111 | set h 0 |
---|
112 | return [list $h $s $v] |
---|
113 | } |
---|
114 | |
---|
115 | if {$r == $max} { |
---|
116 | set h [expr {($g - $b)/double($delta)}] |
---|
117 | } elseif {$g == $max} { |
---|
118 | set h [expr {2 + ($b - $r)/double($delta)}] |
---|
119 | } else { |
---|
120 | set h [expr {4 + ($r - $g)/double($delta)}] |
---|
121 | } |
---|
122 | set h [expr {$h*1.04719756667}] ;# *60 degrees |
---|
123 | if {$h < 0} { |
---|
124 | set h [expr {$h+6.2831854}] |
---|
125 | } |
---|
126 | return [list $h $s $v] |
---|
127 | } |
---|
128 | |
---|
129 | # --------------------------------------------------------------------- |
---|
130 | # USAGE: HSVtoRGB <color> |
---|
131 | # |
---|
132 | # Used to convert hue, saturation, value for a color to its |
---|
133 | # equivalent RGB form. Returns a prompt Tk color of the form |
---|
134 | # #RRGGBB. |
---|
135 | # ---------------------------------------------------------------------- |
---|
136 | proc Rappture::color::HSVtoRGB {h s v} { |
---|
137 | if {$s == 0} { |
---|
138 | set v [expr round(255*$v)] |
---|
139 | set r $v |
---|
140 | set g $v |
---|
141 | set b $v |
---|
142 | } else { |
---|
143 | if {$h >= 6.28318} {set h [expr $h-6.28318]} |
---|
144 | set h [expr $h/1.0472] |
---|
145 | set f [expr $h-floor($h)] |
---|
146 | set p [expr round(255*$v*(1.0-$s))] |
---|
147 | set q [expr round(255*$v*(1.0-$s*$f))] |
---|
148 | set t [expr round(255*$v*(1.0-$s*(1.0-$f)))] |
---|
149 | set v [expr round(255*$v)] |
---|
150 | |
---|
151 | switch [expr int($h)] { |
---|
152 | 0 {set r $v; set g $t; set b $p} |
---|
153 | 1 {set r $q; set g $v; set b $p} |
---|
154 | 2 {set r $p; set g $v; set b $t} |
---|
155 | 3 {set r $p; set g $q; set b $v} |
---|
156 | 4 {set r $t; set g $p; set b $v} |
---|
157 | 5 {set r $v; set g $p; set b $q} |
---|
158 | } |
---|
159 | } |
---|
160 | return [format "#%.2x%.2x%.2x" $r $g $b] |
---|
161 | } |
---|