blob: ea1c489bec696fabcf1c1b03393488953743a7fb [file] [log] [blame]
rsc28994502004-04-21 22:19:33 +00001#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
10static
11int
12notrans(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
25static
26int
27easycase(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
43static
44uchar*
45load(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
165Image*
166onechan(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
198Memimage*
199memonechan(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}