]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/jpg/totruecolor.c
Libflac: Tell it that we have stdint.h so it finds SIZE_MAX
[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[4*256];
21         int r, g, b, Y, Cr, Cb, psize;
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         case CRGBV:
71                 psize = (i->chandesc == CRGB1) ? 3 : 4;
72                 if(cmap == nil)
73                         return _remaperror("remap: image has no color map");
74                 if(i->nchans != 1)
75                         return _remaperror("remap: can't handle nchans %d", i->nchans);
76                 if(i->cmaplen > psize*256)
77                         return _remaperror("remap: can't do colormap size %d*%d", psize, i->cmaplen/psize);
78                 if(i->cmaplen != psize*256){
79                         /* to avoid a range check in loop below, make a full-size cmap */
80                         memmove(cmap1, cmap, i->cmaplen);
81                         cmap = cmap1;
82                 }
83                 inp = i->chans[0];
84                 if(chandesc == CY){
85                         for(j=0; j<i->chanlen; j++){
86                                 k = psize*(*inp++);
87                                 r = cmap[k+2];
88                                 g = cmap[k+1];
89                                 b = cmap[k+0];
90                                 r = (2125*r + 7154*g + 721*b)/10000;    /* Poynton page 84 */
91                                 *outp++ = r;
92                         }
93                 }else{
94                         for(j=0; j<i->chanlen; j++){
95                                 k = psize*(*inp++);
96                                 *outp++ = cmap[k+2];
97                                 *outp++ = cmap[k+1];
98                                 *outp++ = cmap[k+0];
99                         }
100                 }
101                 break;
102
103         case CRGB:
104                 if(i->nchans != 3)
105                         return _remaperror("remap: can't handle nchans %d", i->nchans);
106                 rp = i->chans[0];
107                 gp = i->chans[1];
108                 bp = i->chans[2];
109                 if(chandesc == CY){
110                         for(j=0; j<i->chanlen; j++){
111                                 r = *bp++;
112                                 g = *gp++;
113                                 b = *rp++;
114                                 r = (2125*r + 7154*g + 721*b)/10000;    /* Poynton page 84 */
115                                 *outp++ = r;
116                         }
117                 }else
118                         for(j=0; j<i->chanlen; j++){
119                                 *outp++ = *bp++;
120                                 *outp++ = *gp++;
121                                 *outp++ = *rp++;
122                         }
123                 break;
124
125         case CYCbCr:
126                 if(i->nchans != 3)
127                         return _remaperror("remap: can't handle nchans %d", i->nchans);
128                 rp = i->chans[0];
129                 gp = i->chans[1];
130                 bp = i->chans[2];
131                 for(j=0; j<i->chanlen; j++){
132                         Y = *rp++ << 11;
133                         Cb = *gp++ - 128;
134                         Cr = *bp++ - 128;
135                         r = (Y+c1*Cr) >> 11;
136                         g = (Y-c2*Cb-c3*Cr) >> 11;
137                         b = (Y+c4*Cb) >> 11;
138                         if(r < 0)
139                                 r = 0;
140                         if(r > 255)
141                                 r = 255;
142                         if(g < 0)
143                                 g = 0;
144                         if(g > 255)
145                                 g = 255;
146                         if(b < 0)
147                                 b = 0;
148                         if(b > 255)
149                                 b = 255;
150                         if(chandesc == CY){
151                                 r = (2125*r + 7154*g + 721*b)/10000;
152                                 *outp++ = r;
153                         }else{
154                                 *outp++ = b;
155                                 *outp++ = g;
156                                 *outp++ = r;
157                         }
158                 }
159                 break;
160         }
161         return im;
162 }