Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <memdraw.h>
5 #include <bio.h>
6 #include "imagefile.h"
8 /* Convert image to a single channel, one byte per pixel */
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 }
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 }
39 /*
40 * Convert to one byte per pixel, RGBV or grey, depending
41 */
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;
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);
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 }
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;
104 ri.chandesc = CRGB;
106 p = data;
107 q0 = ri.chans[0];
108 q1 = ri.chans[1];
109 q2 = ri.chans[2];
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);
125 break;
126 case RGB24:
127 for(i=0; i<ri.chanlen; i++){
128 *q2++ = *p++;
129 *q1++ = *p++;
130 *q0++ = *p++;
132 break;
133 case RGBA32:
134 for(i=0; i<ri.chanlen; i++){
135 *q2++ = *p++;
136 *q1++ = *p++;
137 *q0++ = *p++;
138 p++;
140 break;
141 case ARGB32:
142 for(i=0; i<ri.chanlen; i++){
143 p++;
144 *q2++ = *p++;
145 *q1++ = *p++;
146 *q0++ = *p++;
148 break;
151 rgbv = nil;
152 nri = torgbv(&ri, 1);
153 if(nri != nil){
154 rgbv = nri->chans[0];
155 free(nri);
158 free(ri.chans[0]);
159 free(ri.chans[1]);
160 free(ri.chans[2]);
161 free(data);
162 return rgbv;
165 Image*
166 onechan(Image *i)
168 uchar *data;
169 Image *ni;
171 if(notrans(i->chan))
172 return i;
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);
185 if(data == nil)
186 return nil;
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;
194 free(data);
195 return ni;
198 Memimage*
199 memonechan(Memimage *i)
201 uchar *data;
202 Memimage *ni;
204 if(notrans(i->chan))
205 return i;
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);
218 if(data == nil)
219 return nil;
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;
227 free(data);
228 return ni;