xref: /plan9-contrib/sys/src/cmd/jpg/totruecolor.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <draw.h>
5 #include "imagefile.h"
6 
7 enum {
8 	c1 = 2871,	/* 1.402 * 2048 */
9 	c2 = 705,		/* 0.34414 * 2048 */
10 	c3 = 1463,	/* 0.71414 * 2048 */
11 	c4 = 3629,	/* 1.772 * 2048 */
12 };
13 
14 Rawimage*
totruecolor(Rawimage * i,int chandesc)15 totruecolor(Rawimage *i, int chandesc)
16 {
17 	int j, k;
18 	Rawimage *im;
19 	char err[ERRMAX];
20 	uchar *rp, *gp, *bp, *cmap, *inp, *outp, cmap1[3*256];
21 	int r, g, b, Y, Cr, Cb;
22 
23 	if(chandesc!=CY && chandesc!=CRGB24)
24 		return _remaperror("remap: can't convert to chandesc %d", chandesc);
25 
26 	err[0] = '\0';
27 	errstr(err, sizeof err);	/* throw it away */
28 	im = malloc(sizeof(Rawimage));
29 	if(im == nil)
30 		return nil;
31 	memset(im, 0, sizeof(Rawimage));
32 	if(chandesc == CY)
33 		im->chanlen = i->chanlen;
34 	else
35 		im->chanlen = 3*i->chanlen;
36 	im->chandesc = chandesc;
37 	im->chans[0] = malloc(im->chanlen);
38 	if(im->chans[0] == nil){
39 		free(im);
40 		return nil;
41 	}
42 	im->r = i->r;
43 	im->nchans = 1;
44 
45 	cmap = i->cmap;
46 
47 	outp = im->chans[0];
48 
49 	switch(i->chandesc){
50 	default:
51 		return _remaperror("remap: can't recognize channel type %d", i->chandesc);
52 	case CY:
53 		if(i->nchans != 1)
54 			return _remaperror("remap: Y image has %d chans", i->nchans);
55 		if(chandesc == CY){
56 			memmove(im->chans[0], i->chans[0], i->chanlen);
57 			break;
58 		}
59 		/* convert to three color */
60 		inp = i->chans[0];
61 		for(j=0; j<i->chanlen; j++){
62 			k = *inp++;
63 			*outp++ = k;
64 			*outp++ = k;
65 			*outp++ = k;
66 		}
67 		break;
68 
69 	case CRGB1:
70 		if(cmap == nil)
71 			return _remaperror("remap: image has no color map");
72 		if(i->nchans != 1)
73 			return _remaperror("remap: can't handle nchans %d", i->nchans);
74 		for(j=1; j<=8; j++)
75 			if(i->cmaplen == 3*(1<<j))
76 				break;
77 		if(j > 8)
78 			return _remaperror("remap: can't do colormap size 3*%d", i->cmaplen/3);
79 		if(i->cmaplen != 3*256){
80 			/* to avoid a range check in loop below, make a full-size cmap */
81 			memmove(cmap1, cmap, i->cmaplen);
82 			cmap = cmap1;
83 		}
84 		inp = i->chans[0];
85 		if(chandesc == CY){
86 			for(j=0; j<i->chanlen; j++){
87 				k = *inp++;
88 				r = cmap[3*k+2];
89 				g = cmap[3*k+1];
90 				b = cmap[3*k+0];
91 				r = (2125*r + 7154*g + 721*b)/10000;	/* Poynton page 84 */
92 				*outp++ = r;
93 			}
94 		}else{
95 			for(j=0; j<i->chanlen; j++){
96 				k = *inp++;
97 				*outp++ = cmap[3*k+2];
98 				*outp++ = cmap[3*k+1];
99 				*outp++ = cmap[3*k+0];
100 			}
101 		}
102 		break;
103 
104 	case CRGB:
105 		if(i->nchans != 3)
106 			return _remaperror("remap: can't handle nchans %d", i->nchans);
107 		rp = i->chans[0];
108 		gp = i->chans[1];
109 		bp = i->chans[2];
110 		if(chandesc == CY){
111 			for(j=0; j<i->chanlen; j++){
112 				r = *bp++;
113 				g = *gp++;
114 				b = *rp++;
115 				r = (2125*r + 7154*g + 721*b)/10000;	/* Poynton page 84 */
116 				*outp++ = r;
117 			}
118 		}else
119 			for(j=0; j<i->chanlen; j++){
120 				*outp++ = *bp++;
121 				*outp++ = *gp++;
122 				*outp++ = *rp++;
123 			}
124 		break;
125 
126 	case CYCbCr:
127 		if(i->nchans != 3)
128 			return _remaperror("remap: can't handle nchans %d", i->nchans);
129 		rp = i->chans[0];
130 		gp = i->chans[1];
131 		bp = i->chans[2];
132 		for(j=0; j<i->chanlen; j++){
133 			Y = *rp++ << 11;
134 			Cb = *gp++ - 128;
135 			Cr = *bp++ - 128;
136 			r = (Y+c1*Cr) >> 11;
137 			g = (Y-c2*Cb-c3*Cr) >> 11;
138 			b = (Y+c4*Cb) >> 11;
139 			if(r < 0)
140 				r = 0;
141 			if(r > 255)
142 				r = 255;
143 			if(g < 0)
144 				g = 0;
145 			if(g > 255)
146 				g = 255;
147 			if(b < 0)
148 				b = 0;
149 			if(b > 255)
150 				b = 255;
151 			if(chandesc == CY){
152 				r = (2125*r + 7154*g + 721*b)/10000;
153 				*outp++ = r;
154 			}else{
155 				*outp++ = b;
156 				*outp++ = g;
157 				*outp++ = r;
158 			}
159 		}
160 		break;
161 	}
162 	return im;
163 }
164