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