Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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