xref: /plan9/sys/src/cmd/unix/drawterm/libdraw/rgb.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 
5 /*
6  * This original version, although fast and a true inverse of
7  * cmap2rgb, in the sense that rgb2cmap(cmap2rgb(c))
8  * returned the original color, does a terrible job for RGB
9  * triples that do not appear in the color map, so it has been
10  * replaced by the much slower version below, that loops
11  * over the color map looking for the nearest point in RGB
12  * space.  There is no visual psychology reason for that
13  * criterion, but it's easy to implement and the results are
14  * far more pleasing.
15  *
16 int
17 rgb2cmap(int cr, int cg, int cb)
18 {
19 	int r, g, b, v, cv;
20 
21 	if(cr < 0)
22 		cr = 0;
23 	else if(cr > 255)
24 		cr = 255;
25 	if(cg < 0)
26 		cg = 0;
27 	else if(cg > 255)
28 		cg = 255;
29 	if(cb < 0)
30 		cb = 0;
31 	else if(cb > 255)
32 		cb = 255;
33 	r = cr>>6;
34 	g = cg>>6;
35 	b = cb>>6;
36 	cv = cr;
37 	if(cg > cv)
38 		cv = cg;
39 	if(cb > cv)
40 		cv = cb;
41 	v = (cv>>4)&3;
42 	return ((((r<<2)+v)<<4)+(((g<<2)+b+v-r)&15));
43 }
44 */
45 
46 int
rgb2cmap(int cr,int cg,int cb)47 rgb2cmap(int cr, int cg, int cb)
48 {
49 	int i, r, g, b, sq;
50 	ulong rgb;
51 	int best, bestsq;
52 
53 	best = 0;
54 	bestsq = 0x7FFFFFFF;
55 	for(i=0; i<256; i++){
56 		rgb = cmap2rgb(i);
57 		r = (rgb>>16) & 0xFF;
58 		g = (rgb>>8) & 0xFF;
59 		b = (rgb>>0) & 0xFF;
60 		sq = (r-cr)*(r-cr)+(g-cg)*(g-cg)+(b-cb)*(b-cb);
61 		if(sq < bestsq){
62 			bestsq = sq;
63 			best = i;
64 		}
65 	}
66 	return best;
67 }
68 
69 int
cmap2rgb(int c)70 cmap2rgb(int c)
71 {
72 	int j, num, den, r, g, b, v, rgb;
73 
74 	r = c>>6;
75 	v = (c>>4)&3;
76 	j = (c-v+r)&15;
77 	g = j>>2;
78 	b = j&3;
79 	den=r;
80 	if(g>den)
81 		den=g;
82 	if(b>den)
83 		den=b;
84 	if(den==0) {
85 		v *= 17;
86 		rgb = (v<<16)|(v<<8)|v;
87 	}
88 	else{
89 		num=17*(4*den+v);
90 		rgb = ((r*num/den)<<16)|((g*num/den)<<8)|(b*num/den);
91 	}
92 	return rgb;
93 }
94 
95 int
cmap2rgba(int c)96 cmap2rgba(int c)
97 {
98 	return (cmap2rgb(c)<<8)|0xFF;
99 }
100