1 /*
2  * $Id: color.i,v 1.1 2005-09-18 22:05:54 dhmunro Exp $
3  * Hue-Saturation-Value color representation routines and other
4  * color and palette construction tools.
5  */
6 /* Copyright (c) 2005, The Regents of the University of California.
7  * All rights reserved.
8  * This file is part of yorick (http://yorick.sourceforge.net).
9  * Read the accompanying LICENSE file for details.
10  */
11 
12 local palette_directory;
13 /* DOCUMENT palette_directory= "~/Gist/"
14      holds the default directory for the dump_palette command.
15      The directory name *must* end with "/"; the default is shown.
16    SEE ALSO: dump_palette
17  */
18 palette_directory= "~/Gist/";
19 
dump_palette(name)20 func dump_palette(name)
21 /* DOCUMENT dump_palette, name
22      dump the current palette under the NAME.  If NAME contains no
23      slash characters, the palette_directory will be prepended to the
24      name.  The name can be fed back to the palette command in order
25      to reload the cumped palette.
26    SEE ALSO: brighten, palette, palette_directory
27  */
28 {
29   if (!strmatch(name,"/")) name= palette_directory+name;
30   local r, g, b;
31   palette, query=1, r, g, b;
32   f= create(name);
33   write,f, format="%s\n", "ncolors= "+pr1(numberof(r));
34   write,f, format="%s\n", "ntsc= 1";
35   write,f, format="%s\n", "#  r   g   b";
36   write,f, format="%4d%4d%4d\n", r, g, b;
37 }
38 
brighten(factor)39 func brighten(factor)
40 /* DOCUMENT brighten, factor
41          or brighten
42      brighten the current palette by the specified FACTOR.
43      The FACTOR is the slope of the transfer function for the color value
44      (see to_hsv for a description of the hsv color system); a value of
45      1.0 always remains 1.0, but values near 0.0 change by FACTOR.
46      FACTOR= 1.0 is a no-op.  The default factor is 4.0.
47    SEE ALSO: dump_palette
48  */
49 {
50   if (is_void(factor)) factor= 4.0;
51   local r, g, b;
52   palette, query=1, r, g, b;
53   hsv= to_hsv([r,g,b]);
54   v= hsv(,3);
55   /* this function is a symmetric parabolic mapping from [0,1] to [0,1] */
56   fv= 0.5*(factor-1.0)*v;
57   n= (2.*factor-fv)*v;
58   d= 1.+fv+sqrt(max(1.+(factor^2-1.)*v,0.));
59   hsv(,3)= n/d;
60   /* here is an alternative which has the property that applying the
61      function twice is the same as applying with the product of the
62      two factors - however, this nice property is spoiled by the
63      quantization of the byte scaling of the rgb values */
64   /* hsv(,3)= 1.-(1.-v)^factor; */
65   rgb= to_rgb(hsv);
66   palette, rgb(,1),rgb(,2),rgb(,3);
67 }
68 
to_rgb(hsv)69 func to_rgb(hsv)
70 /* DOCUMENT rgb= to_rgb(hsv)
71          or rgb= to_rgb([h,s,v])
72      return the RGB representation of the n-by-3 array of HSV colors
73      rgb: red, green, blue from 0 to 255
74      hsv: h= hue in degrees, red=0, green=120, blue=240
75           s= saturation from 0 (gray) to 1 (full hue)
76           v= value from 0 (black) to 1 (full intensity)
77           s= 1 - min(r,g,b)/max(r,g,b)
78           v= max(r,g,b)/255
79    SEE ALSO: to_hsv
80  */
81 {
82   hsv= double(hsv);
83   h= hsv(*,1);
84   s= hsv(*,2);
85   v= hsv(*,3);
86 
87   /* normalize hue to lie in 0<=h<360 */
88   h= h % 360.0;
89   h+= (h<0.0)*360.0;
90 
91   /* divide hue into 60 degree sectors */
92   i= long(h/60.0);
93   f= h/60.0 - i;
94 
95   p= 1.0 - s;
96   q= 1.0 - s*f;
97   t= 1.0 - s*(1.-f);
98   /* each hue sector will be represented by rgb values taken
99    * from one of v, p, q, or t */
100   r= ((i==0|i==5) + (i==2|i==3)*p + (i==1)*q + (i==4)*t) * v;
101   g= ((i==1|i==2) + (i==4|i==5)*p + (i==3)*q + (i==0)*t) * v;
102   b= ((i==3|i==4) + (i==0|i==1)*p + (i==5)*q + (i==2)*t) * v;
103 
104   /* return array same shape as input */
105   rgb= hsv;
106   rgb(*,1)= r;
107   rgb(*,2)= g;
108   rgb(*,3)= b;
109   return bytscl(rgb,top=255,cmin=0.0,cmax=1.0);
110 }
111 
to_hsv(rgb)112 func to_hsv(rgb)
113 /* DOCUMENT hsv= to_hsv(rgb)
114          or hsv= to_hsv([r,g,b])
115      return the HSV representation of the n-by-3 array of RGB colors
116      rgb: red, green, blue from 0 to 255
117      hsv: h= hue in degrees, red=0, green=120, blue=240
118           s= saturation from 0 (gray) to 1 (full hue)
119           v= value from 0 (black) to 1 (full intensity)
120           s= 1 - min(r,g,b)/max(r,g,b)
121           v= max(r,g,b)
122    SEE ALSO: to_rgb
123  */
124 {
125   rgb/= 255.0;
126   hsv= rgb;
127   rgb= rgb(*,);
128   r= rgb(,1);
129   g= rgb(,2);
130   b= rgb(,3);
131 
132   /* compute and normalize hue angle */
133   h= atan((g-b)*sqrt(0.75), r-0.5*(g+b)+1.e-30)/pi * 180.;
134   h+= (h<0.0)*360.;
135 
136   /* any given hue is adjacent to one primary, opposite a second primary,
137    * and neutral for the third
138    * value is adjacent, which is always maximum
139    * the ratio of opposite to adjacent is 1-saturation */
140   v= max(r,g,b);
141   s= 1.0 - (min(r,g,b)+1.e-30)/(v+1.e-30);
142 
143   hsv(*,1)= h;
144   hsv(*,2)= s;
145   hsv(*,3)= v;
146   return hsv;
147 }
148