1*8fa2b2a7SDavid du Colombier #include <u.h>
2*8fa2b2a7SDavid du Colombier #include <libc.h>
3*8fa2b2a7SDavid du Colombier #include <bio.h>
4*8fa2b2a7SDavid du Colombier #include <draw.h>
5*8fa2b2a7SDavid du Colombier
6*8fa2b2a7SDavid du Colombier enum
7*8fa2b2a7SDavid du Colombier {
8*8fa2b2a7SDavid du Colombier FileHdrLen= 6,
9*8fa2b2a7SDavid du Colombier IconDescrLen= 16,
10*8fa2b2a7SDavid du Colombier IconHdrLen= 40,
11*8fa2b2a7SDavid du Colombier };
12*8fa2b2a7SDavid du Colombier
13*8fa2b2a7SDavid du Colombier typedef struct Icon Icon;
14*8fa2b2a7SDavid du Colombier struct Icon
15*8fa2b2a7SDavid du Colombier {
16*8fa2b2a7SDavid du Colombier Icon *next;
17*8fa2b2a7SDavid du Colombier char *file;
18*8fa2b2a7SDavid du Colombier
19*8fa2b2a7SDavid du Colombier uchar w; /* icon width */
20*8fa2b2a7SDavid du Colombier uchar h; /* icon height */
21*8fa2b2a7SDavid du Colombier ushort ncolor; /* number of colors */
22*8fa2b2a7SDavid du Colombier ushort nplane; /* number of bit planes */
23*8fa2b2a7SDavid du Colombier ushort bits; /* bits per pixel */
24*8fa2b2a7SDavid du Colombier ulong len; /* length of data */
25*8fa2b2a7SDavid du Colombier ulong offset; /* file offset to data */
26*8fa2b2a7SDavid du Colombier uchar map[4*256]; /* color map */
27*8fa2b2a7SDavid du Colombier
28*8fa2b2a7SDavid du Colombier Image *img;
29*8fa2b2a7SDavid du Colombier
30*8fa2b2a7SDavid du Colombier uchar *xor;
31*8fa2b2a7SDavid du Colombier int xorlen;
32*8fa2b2a7SDavid du Colombier uchar *and;
33*8fa2b2a7SDavid du Colombier int andlen;
34*8fa2b2a7SDavid du Colombier };
35*8fa2b2a7SDavid du Colombier
36*8fa2b2a7SDavid du Colombier typedef struct Header Header;
37*8fa2b2a7SDavid du Colombier struct Header
38*8fa2b2a7SDavid du Colombier {
39*8fa2b2a7SDavid du Colombier uint n;
40*8fa2b2a7SDavid du Colombier Icon *first;
41*8fa2b2a7SDavid du Colombier Icon *last;
42*8fa2b2a7SDavid du Colombier };
43*8fa2b2a7SDavid du Colombier
44*8fa2b2a7SDavid du Colombier void
Bputs(Biobuf * b,ushort x)45*8fa2b2a7SDavid du Colombier Bputs(Biobuf *b, ushort x)
46*8fa2b2a7SDavid du Colombier {
47*8fa2b2a7SDavid du Colombier Bputc(b, x&0xff);
48*8fa2b2a7SDavid du Colombier Bputc(b, x>>8);
49*8fa2b2a7SDavid du Colombier }
50*8fa2b2a7SDavid du Colombier
51*8fa2b2a7SDavid du Colombier void
Bputl(Biobuf * b,ulong x)52*8fa2b2a7SDavid du Colombier Bputl(Biobuf *b, ulong x)
53*8fa2b2a7SDavid du Colombier {
54*8fa2b2a7SDavid du Colombier Bputs(b, x&0xffff);
55*8fa2b2a7SDavid du Colombier Bputs(b, x>>16);
56*8fa2b2a7SDavid du Colombier }
57*8fa2b2a7SDavid du Colombier
58*8fa2b2a7SDavid du Colombier Header h;
59*8fa2b2a7SDavid du Colombier
60*8fa2b2a7SDavid du Colombier void* emalloc(int);
61*8fa2b2a7SDavid du Colombier void mk8bit(Icon*, int);
62*8fa2b2a7SDavid du Colombier void mkxorand(Icon*, int);
63*8fa2b2a7SDavid du Colombier void readicon(char*);
64*8fa2b2a7SDavid du Colombier
65*8fa2b2a7SDavid du Colombier void
main(int argc,char ** argv)66*8fa2b2a7SDavid du Colombier main(int argc, char **argv)
67*8fa2b2a7SDavid du Colombier {
68*8fa2b2a7SDavid du Colombier int i;
69*8fa2b2a7SDavid du Colombier Biobuf *b, out;
70*8fa2b2a7SDavid du Colombier Icon *icon;
71*8fa2b2a7SDavid du Colombier ulong offset;
72*8fa2b2a7SDavid du Colombier ulong len;
73*8fa2b2a7SDavid du Colombier
74*8fa2b2a7SDavid du Colombier ARGBEGIN{
75*8fa2b2a7SDavid du Colombier }ARGEND;
76*8fa2b2a7SDavid du Colombier
77*8fa2b2a7SDavid du Colombier /* read in all the images */
78*8fa2b2a7SDavid du Colombier display = initdisplay(nil, nil, nil);
79*8fa2b2a7SDavid du Colombier if(argc < 1){
80*8fa2b2a7SDavid du Colombier readicon("/fd/0");
81*8fa2b2a7SDavid du Colombier } else {
82*8fa2b2a7SDavid du Colombier for(i = 0; i < argc; i++)
83*8fa2b2a7SDavid du Colombier readicon(argv[i]);
84*8fa2b2a7SDavid du Colombier }
85*8fa2b2a7SDavid du Colombier
86*8fa2b2a7SDavid du Colombier /* create the .ico file */
87*8fa2b2a7SDavid du Colombier b = &out;
88*8fa2b2a7SDavid du Colombier Binit(b, 1, OWRITE);
89*8fa2b2a7SDavid du Colombier
90*8fa2b2a7SDavid du Colombier /* offset to first icon */
91*8fa2b2a7SDavid du Colombier offset = FileHdrLen + h.n*IconDescrLen;
92*8fa2b2a7SDavid du Colombier
93*8fa2b2a7SDavid du Colombier /* file header is */
94*8fa2b2a7SDavid du Colombier Bputs(b, 0);
95*8fa2b2a7SDavid du Colombier Bputs(b, 1);
96*8fa2b2a7SDavid du Colombier Bputs(b, h.n);
97*8fa2b2a7SDavid du Colombier
98*8fa2b2a7SDavid du Colombier /* icon description */
99*8fa2b2a7SDavid du Colombier for(icon = h.first; icon != nil; icon = icon->next){
100*8fa2b2a7SDavid du Colombier Bputc(b, icon->w);
101*8fa2b2a7SDavid du Colombier Bputc(b, icon->h);
102*8fa2b2a7SDavid du Colombier Bputc(b, icon->ncolor);
103*8fa2b2a7SDavid du Colombier Bputc(b, 0);
104*8fa2b2a7SDavid du Colombier Bputs(b, icon->nplane);
105*8fa2b2a7SDavid du Colombier Bputs(b, icon->bits);
106*8fa2b2a7SDavid du Colombier len = IconHdrLen + icon->ncolor*4 + icon->xorlen + icon->andlen;
107*8fa2b2a7SDavid du Colombier Bputl(b, len);
108*8fa2b2a7SDavid du Colombier Bputl(b, offset);
109*8fa2b2a7SDavid du Colombier offset += len;
110*8fa2b2a7SDavid du Colombier }
111*8fa2b2a7SDavid du Colombier
112*8fa2b2a7SDavid du Colombier /* icons */
113*8fa2b2a7SDavid du Colombier for(icon = h.first; icon != nil; icon = icon->next){
114*8fa2b2a7SDavid du Colombier /* icon header (BMP like) */
115*8fa2b2a7SDavid du Colombier Bputl(b, IconHdrLen);
116*8fa2b2a7SDavid du Colombier Bputl(b, icon->w);
117*8fa2b2a7SDavid du Colombier Bputl(b, 2*icon->h);
118*8fa2b2a7SDavid du Colombier Bputs(b, icon->nplane);
119*8fa2b2a7SDavid du Colombier Bputs(b, icon->bits);
120*8fa2b2a7SDavid du Colombier Bputl(b, 0); /* compression info */
121*8fa2b2a7SDavid du Colombier Bputl(b, 0);
122*8fa2b2a7SDavid du Colombier Bputl(b, 0);
123*8fa2b2a7SDavid du Colombier Bputl(b, 0);
124*8fa2b2a7SDavid du Colombier Bputl(b, 0);
125*8fa2b2a7SDavid du Colombier Bputl(b, 0);
126*8fa2b2a7SDavid du Colombier
127*8fa2b2a7SDavid du Colombier /* color map */
128*8fa2b2a7SDavid du Colombier if(Bwrite(b, icon->map, 4*icon->ncolor) < 0)
129*8fa2b2a7SDavid du Colombier sysfatal("writing color map: %r");
130*8fa2b2a7SDavid du Colombier
131*8fa2b2a7SDavid du Colombier /* xor bits */
132*8fa2b2a7SDavid du Colombier if(Bwrite(b, icon->xor, icon->xorlen) < 0)
133*8fa2b2a7SDavid du Colombier sysfatal("writing xor bits: %r");
134*8fa2b2a7SDavid du Colombier
135*8fa2b2a7SDavid du Colombier /* and bits */
136*8fa2b2a7SDavid du Colombier if(Bwrite(b, icon->and, icon->andlen) < 0)
137*8fa2b2a7SDavid du Colombier sysfatal("writing and bits: %r");
138*8fa2b2a7SDavid du Colombier }
139*8fa2b2a7SDavid du Colombier
140*8fa2b2a7SDavid du Colombier Bterm(b);
141*8fa2b2a7SDavid du Colombier exits(0);
142*8fa2b2a7SDavid du Colombier }
143*8fa2b2a7SDavid du Colombier
144*8fa2b2a7SDavid du Colombier void
readicon(char * file)145*8fa2b2a7SDavid du Colombier readicon(char *file)
146*8fa2b2a7SDavid du Colombier {
147*8fa2b2a7SDavid du Colombier int fd;
148*8fa2b2a7SDavid du Colombier Icon *icon;
149*8fa2b2a7SDavid du Colombier
150*8fa2b2a7SDavid du Colombier fd = open(file, OREAD);
151*8fa2b2a7SDavid du Colombier if(fd < 0)
152*8fa2b2a7SDavid du Colombier sysfatal("opening %s: %r", file);
153*8fa2b2a7SDavid du Colombier icon = emalloc(sizeof(Icon));
154*8fa2b2a7SDavid du Colombier icon->img = readimage(display, fd, 0);
155*8fa2b2a7SDavid du Colombier if(icon->img == nil)
156*8fa2b2a7SDavid du Colombier sysfatal("reading image %s: %r", file);
157*8fa2b2a7SDavid du Colombier close(fd);
158*8fa2b2a7SDavid du Colombier
159*8fa2b2a7SDavid du Colombier if(h.first)
160*8fa2b2a7SDavid du Colombier h.last->next = icon;
161*8fa2b2a7SDavid du Colombier else
162*8fa2b2a7SDavid du Colombier h.first = icon;
163*8fa2b2a7SDavid du Colombier h.last = icon;
164*8fa2b2a7SDavid du Colombier h.n++;
165*8fa2b2a7SDavid du Colombier
166*8fa2b2a7SDavid du Colombier icon->h = Dy(icon->img->r);
167*8fa2b2a7SDavid du Colombier icon->w = Dx(icon->img->r);
168*8fa2b2a7SDavid du Colombier icon->bits = 1<<icon->img->depth;
169*8fa2b2a7SDavid du Colombier icon->nplane = 1;
170*8fa2b2a7SDavid du Colombier
171*8fa2b2a7SDavid du Colombier /* convert to 8 bits per pixel */
172*8fa2b2a7SDavid du Colombier switch(icon->img->chan){
173*8fa2b2a7SDavid du Colombier case GREY8:
174*8fa2b2a7SDavid du Colombier case CMAP8:
175*8fa2b2a7SDavid du Colombier break;
176*8fa2b2a7SDavid du Colombier case GREY1:
177*8fa2b2a7SDavid du Colombier case GREY2:
178*8fa2b2a7SDavid du Colombier case GREY4:
179*8fa2b2a7SDavid du Colombier mk8bit(icon, 1);
180*8fa2b2a7SDavid du Colombier break;
181*8fa2b2a7SDavid du Colombier default:
182*8fa2b2a7SDavid du Colombier mk8bit(icon, 0);
183*8fa2b2a7SDavid du Colombier break;
184*8fa2b2a7SDavid du Colombier }
185*8fa2b2a7SDavid du Colombier icon->bits = 8;
186*8fa2b2a7SDavid du Colombier icon->file = file;
187*8fa2b2a7SDavid du Colombier
188*8fa2b2a7SDavid du Colombier /* create xor/and masks, minimizing bits per pixel */
189*8fa2b2a7SDavid du Colombier mkxorand(icon, icon->img->chan == GREY8);
190*8fa2b2a7SDavid du Colombier }
191*8fa2b2a7SDavid du Colombier
192*8fa2b2a7SDavid du Colombier void*
emalloc(int len)193*8fa2b2a7SDavid du Colombier emalloc(int len)
194*8fa2b2a7SDavid du Colombier {
195*8fa2b2a7SDavid du Colombier void *x;
196*8fa2b2a7SDavid du Colombier
197*8fa2b2a7SDavid du Colombier x = mallocz(len, 1);
198*8fa2b2a7SDavid du Colombier if(x == nil)
199*8fa2b2a7SDavid du Colombier sysfatal("memory: %r");
200*8fa2b2a7SDavid du Colombier return x;
201*8fa2b2a7SDavid du Colombier }
202*8fa2b2a7SDavid du Colombier
203*8fa2b2a7SDavid du Colombier /* convert to 8 bit */
204*8fa2b2a7SDavid du Colombier void
mk8bit(Icon * icon,int grey)205*8fa2b2a7SDavid du Colombier mk8bit(Icon *icon, int grey)
206*8fa2b2a7SDavid du Colombier {
207*8fa2b2a7SDavid du Colombier Image *img;
208*8fa2b2a7SDavid du Colombier
209*8fa2b2a7SDavid du Colombier img = allocimage(display, icon->img->r, grey ? GREY8 : CMAP8, 0, DNofill);
210*8fa2b2a7SDavid du Colombier if(img == nil)
211*8fa2b2a7SDavid du Colombier sysfatal("can't allocimage: %r");
212*8fa2b2a7SDavid du Colombier draw(img, img->r, icon->img, nil, ZP);
213*8fa2b2a7SDavid du Colombier freeimage(icon->img);
214*8fa2b2a7SDavid du Colombier icon->img = img;
215*8fa2b2a7SDavid du Colombier }
216*8fa2b2a7SDavid du Colombier
217*8fa2b2a7SDavid du Colombier /* make xor and and mask */
218*8fa2b2a7SDavid du Colombier void
mkxorand(Icon * icon,int grey)219*8fa2b2a7SDavid du Colombier mkxorand(Icon *icon, int grey)
220*8fa2b2a7SDavid du Colombier {
221*8fa2b2a7SDavid du Colombier int i, x, y, s, sa;
222*8fa2b2a7SDavid du Colombier uchar xx[256];
223*8fa2b2a7SDavid du Colombier uchar *data, *p, *e;
224*8fa2b2a7SDavid du Colombier int ndata;
225*8fa2b2a7SDavid du Colombier uchar *mp;
226*8fa2b2a7SDavid du Colombier int ncolor;
227*8fa2b2a7SDavid du Colombier ulong color;
228*8fa2b2a7SDavid du Colombier int bits;
229*8fa2b2a7SDavid du Colombier uchar andbyte, xorbyte;
230*8fa2b2a7SDavid du Colombier uchar *ato, *xto;
231*8fa2b2a7SDavid du Colombier int xorrl, andrl;
232*8fa2b2a7SDavid du Colombier
233*8fa2b2a7SDavid du Colombier ndata = icon->h * icon->w;
234*8fa2b2a7SDavid du Colombier data = emalloc(ndata);
235*8fa2b2a7SDavid du Colombier if(unloadimage(icon->img, icon->img->r, data, ndata) < 0)
236*8fa2b2a7SDavid du Colombier sysfatal("can't unload %s: %r", icon->file);
237*8fa2b2a7SDavid du Colombier e = data + ndata;
238*8fa2b2a7SDavid du Colombier
239*8fa2b2a7SDavid du Colombier /* find colors used */
240*8fa2b2a7SDavid du Colombier memset(xx, 0, sizeof xx);
241*8fa2b2a7SDavid du Colombier for(p = data; p < e; p++)
242*8fa2b2a7SDavid du Colombier xx[*p]++;
243*8fa2b2a7SDavid du Colombier
244*8fa2b2a7SDavid du Colombier /* count the colors and create a mapping from plan 9 */
245*8fa2b2a7SDavid du Colombier mp = icon->map;
246*8fa2b2a7SDavid du Colombier ncolor = 0;
247*8fa2b2a7SDavid du Colombier for(i = 0; i < 256; i++){
248*8fa2b2a7SDavid du Colombier if(xx[i] == 0)
249*8fa2b2a7SDavid du Colombier continue;
250*8fa2b2a7SDavid du Colombier if(grey){
251*8fa2b2a7SDavid du Colombier *mp++ = i;
252*8fa2b2a7SDavid du Colombier *mp++ = i;
253*8fa2b2a7SDavid du Colombier *mp++ = i;
254*8fa2b2a7SDavid du Colombier *mp++ = 0;
255*8fa2b2a7SDavid du Colombier } else {
256*8fa2b2a7SDavid du Colombier color = cmap2rgb(i);
257*8fa2b2a7SDavid du Colombier *mp++ = color;
258*8fa2b2a7SDavid du Colombier *mp++ = color>>8;
259*8fa2b2a7SDavid du Colombier *mp++ = color>>16;
260*8fa2b2a7SDavid du Colombier *mp++ = 0;
261*8fa2b2a7SDavid du Colombier }
262*8fa2b2a7SDavid du Colombier xx[i] = ncolor;
263*8fa2b2a7SDavid du Colombier ncolor++;
264*8fa2b2a7SDavid du Colombier }
265*8fa2b2a7SDavid du Colombier
266*8fa2b2a7SDavid du Colombier /* get minimum number of pixels per bit (with a color map) */
267*8fa2b2a7SDavid du Colombier if(ncolor <= 2){
268*8fa2b2a7SDavid du Colombier ncolor = 2;
269*8fa2b2a7SDavid du Colombier bits = 1;
270*8fa2b2a7SDavid du Colombier } else if(ncolor <= 4){
271*8fa2b2a7SDavid du Colombier ncolor = 4;
272*8fa2b2a7SDavid du Colombier bits = 2;
273*8fa2b2a7SDavid du Colombier } else if(ncolor <= 16){
274*8fa2b2a7SDavid du Colombier ncolor = 16;
275*8fa2b2a7SDavid du Colombier bits = 4;
276*8fa2b2a7SDavid du Colombier } else {
277*8fa2b2a7SDavid du Colombier ncolor = 256;
278*8fa2b2a7SDavid du Colombier bits = 8;
279*8fa2b2a7SDavid du Colombier }
280*8fa2b2a7SDavid du Colombier icon->bits = bits;
281*8fa2b2a7SDavid du Colombier icon->ncolor = ncolor;
282*8fa2b2a7SDavid du Colombier
283*8fa2b2a7SDavid du Colombier /* the xor mask rows are justified to a 32 bit boundary */
284*8fa2b2a7SDavid du Colombier /* the and mask is 1 bit grey */
285*8fa2b2a7SDavid du Colombier xorrl = 4*((bits*icon->w + 31)/32);
286*8fa2b2a7SDavid du Colombier andrl = 4*((icon->w + 31)/32);
287*8fa2b2a7SDavid du Colombier icon->xor = emalloc(xorrl * icon->h);
288*8fa2b2a7SDavid du Colombier icon->and = emalloc(andrl * icon->h);
289*8fa2b2a7SDavid du Colombier icon->xorlen = xorrl*icon->h;
290*8fa2b2a7SDavid du Colombier icon->andlen = andrl*icon->h;
291*8fa2b2a7SDavid du Colombier
292*8fa2b2a7SDavid du Colombier /* make both masks. they're upside down relative to plan9 ones */
293*8fa2b2a7SDavid du Colombier p = data;
294*8fa2b2a7SDavid du Colombier for(y = 0; y < icon->h; y++){
295*8fa2b2a7SDavid du Colombier andbyte = 0;
296*8fa2b2a7SDavid du Colombier xorbyte = 0;
297*8fa2b2a7SDavid du Colombier sa = s = 0;
298*8fa2b2a7SDavid du Colombier xto = icon->xor + (icon->h-1-y)*xorrl;
299*8fa2b2a7SDavid du Colombier ato = icon->and + (icon->h-1-y)*andrl;
300*8fa2b2a7SDavid du Colombier for(x = 0; x < icon->w; x++){
301*8fa2b2a7SDavid du Colombier xorbyte <<= bits;
302*8fa2b2a7SDavid du Colombier xorbyte |= xx[*p];
303*8fa2b2a7SDavid du Colombier s += bits;
304*8fa2b2a7SDavid du Colombier if(s == 8){
305*8fa2b2a7SDavid du Colombier *xto++ = xorbyte;
306*8fa2b2a7SDavid du Colombier xorbyte = 0;
307*8fa2b2a7SDavid du Colombier s = 0;
308*8fa2b2a7SDavid du Colombier }
309*8fa2b2a7SDavid du Colombier andbyte <<= 1;
310*8fa2b2a7SDavid du Colombier if(*p == 0xff)
311*8fa2b2a7SDavid du Colombier andbyte |= 1;
312*8fa2b2a7SDavid du Colombier sa++;
313*8fa2b2a7SDavid du Colombier if(sa == 0){
314*8fa2b2a7SDavid du Colombier *ato++ = andbyte;
315*8fa2b2a7SDavid du Colombier sa = 0;
316*8fa2b2a7SDavid du Colombier andbyte = 0;
317*8fa2b2a7SDavid du Colombier }
318*8fa2b2a7SDavid du Colombier p++;
319*8fa2b2a7SDavid du Colombier }
320*8fa2b2a7SDavid du Colombier }
321*8fa2b2a7SDavid du Colombier free(data);
322*8fa2b2a7SDavid du Colombier }
323