]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/jpg/onechan.c
cwfs: back to previous version
[plan9front.git] / sys / src / cmd / jpg / onechan.c
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <memdraw.h>
5 #include <bio.h>
6 #include "imagefile.h"
7
8 /* Convert image to a single channel, one byte per pixel */
9
10 static
11 int
12 notrans(ulong chan)
13 {
14         switch(chan){
15         case GREY1:
16         case GREY2:
17         case GREY4:
18         case    CMAP8:
19         case GREY8:
20                 return 1;
21         }
22         return 0;
23 }
24
25 static
26 int
27 easycase(ulong chan)
28 {
29         switch(chan){
30         case RGB16:
31         case RGB24:
32         case RGBA32:
33         case ARGB32:
34                 return 1;
35         }
36         return 0;
37 }
38
39 /*
40  * Convert to one byte per pixel, RGBV or grey, depending
41  */
42
43 static
44 uchar*
45 load(Image *image, Memimage *memimage)
46 {
47         uchar *data, *p, *q0, *q1, *q2;
48         uchar *rgbv;
49         int depth, ndata, dx, dy, i, v;
50         ulong chan, pixel;
51         Rectangle r;
52         Rawimage ri, *nri;
53
54         if(memimage == nil){
55                 r = image->r;
56                 depth = image->depth;
57                 chan = image->chan;
58         }else{
59                 r = memimage->r;
60                 depth = memimage->depth;
61                 chan = memimage->chan;
62         }
63         dx = Dx(r);
64         dy = Dy(r);
65
66         /* 
67          * Read image data into memory
68          * potentially one extra byte on each end of each scan line.
69          */
70         ndata = dy*(2+bytesperline(r, depth));
71         data = malloc(ndata);
72         if(data == nil)
73                 return nil;
74         if(memimage != nil)
75                 ndata = unloadmemimage(memimage, r, data, ndata);
76         else
77                 ndata = unloadimage(image, r, data, ndata);
78         if(ndata < 0){
79                 werrstr("onechan: %r");
80                 free(data);
81                 return nil;
82         }
83
84         /*
85          * Repack
86          */
87         memset(&ri, 0, sizeof(ri));
88         ri.r = r;
89         ri.cmap = nil;
90         ri.cmaplen = 0;
91         ri.nchans = 3;
92         ri.chanlen = dx*dy;
93         ri.chans[0] = malloc(ri.chanlen);
94         ri.chans[1] = malloc(ri.chanlen);
95         ri.chans[2] = malloc(ri.chanlen);
96         if(ri.chans[0]==nil || ri.chans[1]==nil || ri.chans[2]==nil){
97     Err:
98                 free(ri.chans[0]);
99                 free(ri.chans[1]);
100                 free(ri.chans[2]);
101                 free(data);
102                 return nil;
103         }
104         ri.chandesc = CRGB;
105
106         p = data;
107         q0 = ri.chans[0];
108         q1 = ri.chans[1];
109         q2 = ri.chans[2];
110
111         switch(chan){
112         default:
113                 werrstr("can't handle image type 0x%lux", chan);
114                 goto Err;
115         case RGB16:
116                 for(i=0; i<ri.chanlen; i++, p+=2){
117                         pixel = (p[1]<<8)|p[0]; /* rrrrrggg gggbbbbb */
118                         v = (pixel & 0xF800) >> 8;
119                         *q0++ = v | (v>>5);
120                         v = (pixel & 0x07E0) >> 3;
121                         *q1++ = v | (v>>6);
122                         v = (pixel & 0x001F) << 3;
123                         *q2++ = v | (v>>5);
124                 }
125                 break;
126         case RGB24:
127                 for(i=0; i<ri.chanlen; i++){
128                         *q2++ = *p++;
129                         *q1++ = *p++;
130                         *q0++ = *p++;
131                 }
132                 break;
133         case RGBA32:
134                 for(i=0; i<ri.chanlen; i++){
135                         *q2++ = *p++;
136                         *q1++ = *p++;
137                         *q0++ = *p++;
138                         p++;
139                 }
140                 break;
141         case ARGB32:
142                 for(i=0; i<ri.chanlen; i++){
143                         p++;
144                         *q2++ = *p++;
145                         *q1++ = *p++;
146                         *q0++ = *p++;
147                 }
148                 break;
149         }
150
151         rgbv = nil;
152         nri = torgbv(&ri, 1);
153         if(nri != nil){
154                 rgbv = nri->chans[0];
155                 free(nri);
156         }
157
158         free(ri.chans[0]);
159         free(ri.chans[1]);
160         free(ri.chans[2]);
161         free(data);
162         return rgbv;
163 }
164
165 Image*
166 onechan(Image *i)
167 {
168         uchar *data;
169         Image *ni;
170
171         if(notrans(i->chan))
172                 return i;
173
174         if(easycase(i->chan))
175                 data = load(i, nil);
176         else{
177                 ni = allocimage(display, i->r, RGB24, 0, DNofill);
178                 if(ni == nil)
179                         return ni;
180                 draw(ni, ni->r, i, nil, i->r.min);
181                 data = load(ni, nil);
182                 freeimage(ni);
183         }
184
185         if(data == nil)
186                 return nil;
187
188         ni = allocimage(display, i->r, CMAP8, 0, DNofill);
189         if(ni != nil)
190                 if(loadimage(ni, ni->r, data, Dx(ni->r)*Dy(ni->r)) < 0){
191                         freeimage(ni);
192                         ni = nil;
193                 }
194         free(data);
195         return ni;
196 }
197
198 Memimage*
199 memonechan(Memimage *i)
200 {
201         uchar *data;
202         Memimage *ni;
203
204         if(notrans(i->chan))
205                 return i;
206
207         if(easycase(i->chan))
208                 data = load(nil, i);
209         else{
210                 ni = allocmemimage(i->r, RGB24);
211                 if(ni == nil)
212                         return ni;
213                 memimagedraw(ni, ni->r, i, i->r.min, nil, ZP, S);
214                 data = load(nil, ni);
215                 freememimage(ni);
216         }
217
218         if(data == nil)
219                 return nil;
220
221         ni = allocmemimage(i->r, CMAP8);
222         if(ni != nil)
223                 if(loadmemimage(ni, ni->r, data, Dx(ni->r)*Dy(ni->r)) < 0){
224                         freememimage(ni);
225                         ni = nil;
226                 }
227         free(data);
228         return ni;
229 }