]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/jpg/totruecolor.c
cwfs: back to previous version
[plan9front.git] / sys / src / cmd / jpg / totruecolor.c
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*
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 }