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
#include <event.h>
6
#include <cursor.h>
7
 
8
typedef struct Icon Icon;
9
struct Icon
10
{
11
	Icon	*next;
12
 
13
	uchar	w;		/* icon width */
14
	uchar	h;		/* icon height */
15
	ushort	ncolor;		/* number of colors */
16
	ushort	nplane;		/* number of bit planes */
17
	ushort	bits;		/* bits per pixel */
18
	ulong	len;		/* length of data */
19
	ulong	offset;		/* file offset to data */
20
 
21
	Image	*img;
22
	Image	*mask;
23
 
24
	Rectangle r;		/* relative */
25
	Rectangle sr;		/* abs */
26
};
27
 
28
typedef struct Header Header;
29
struct Header
30
{
31
	uint	n;
32
	Icon	*first;
33
	Icon	*last;
34
};
35
 
36
int debug;
37
Mouse mouse;
38
Header h;
39
Image *background;
40
 
41
ushort
42
gets(uchar *p)
43
{
44
	return p[0] | (p[1]<<8);
45
}
46
 
47
ulong
48
getl(uchar *p)
49
{
50
	return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
51
}
52
 
53
int
54
Bgetheader(Biobuf *b, Header *h)
55
{
56
	Icon *icon;
57
	int i;
58
	uchar buf[40];
59
 
60
	memset(h, 0, sizeof(*h));
61
	if(Bread(b, buf, 6) != 6)
62
		goto eof;
63
	if(gets(&buf[0]) != 0)
64
		goto header;
65
	if(gets(&buf[2]) != 1)
66
		goto header;
67
	h->n = gets(&buf[4]);
68
 
69
	for(i = 0; i < h->n; i++){
70
		icon = mallocz(sizeof(*icon), 1);
71
		if(icon == nil)
72
			sysfatal("malloc: %r");
73
		if(Bread(b, buf, 16) != 16)
74
			goto eof;
75
		icon->w = buf[0];
76
		icon->h = buf[1];
77
		icon->ncolor = buf[2] == 0 ? 256 : buf[2];
78
		if(buf[3] != 0)
79
			goto header;
80
		icon->nplane = gets(&buf[4]);
81
		icon->bits = gets(&buf[6]);
82
		icon->len = getl(&buf[8]);
83
		icon->offset = getl(&buf[12]);
84
 
85
		if(i == 0)
86
			h->first = icon;
87
		else
88
			h->last->next = icon;
89
		h->last = icon;
90
	}
91
	return 0;
92
 
93
eof:
94
	werrstr("unexpected EOF");
95
	return -1;
96
header:
97
	werrstr("unknown header format");
98
	return -1;
99
}
100
 
101
uchar*
102
transcmap(Icon *icon, uchar *map)
103
{
104
	uchar *m, *p;
105
	int i;
106
 
107
	p = m = malloc(sizeof(int)*(1<<icon->bits));
108
	for(i = 0; i < icon->ncolor; i++){
109
		*p++ = rgb2cmap(map[2], map[1], map[0]);
110
		map += 4;
111
	}
112
	return m;
113
}
114
 
115
Image*
116
xor2img(Icon *icon, uchar *xor, uchar *map)
117
{
118
	uchar *data;
119
	Image *img;
120
	int inxlen;
121
	uchar *from, *to;
122
	int s, byte, mask;
123
	int x, y;
124
 
125
	inxlen = 4*((icon->bits*icon->w+31)/32);
126
	to = data = malloc(icon->w*icon->h);
127
 
128
	/* rotate around the y axis, go to 8 bits, and convert color */
129
	mask = (1<<icon->bits)-1;
130
	for(y = 0; y < icon->h; y++){
131
		s = -1;
132
		byte = 0;
133
		from = xor + (icon->h - 1 - y)*inxlen;
134
		for(x = 0; x < icon->w; x++){
135
			if(s < 0){
136
				byte = *from++;
137
				s = 8-icon->bits;
138
			}
139
			*to++ = map[(byte>>s) & mask];
140
			s -= icon->bits;
141
		}
142
	}
143
 
144
	/* stick in an image */
145
	img = allocimage(display, Rect(0,0,icon->w,icon->h), CMAP8, 0, DNofill);
146
	loadimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*icon->w);
147
 
148
	free(data);
149
	return img;
150
}
151
 
152
Image*
153
and2img(Icon *icon, uchar *and)
154
{
155
	uchar *data;
156
	Image *img;
157
	int inxlen;
158
	int outxlen;
159
	uchar *from, *to;
160
	int x, y;
161
 
162
	inxlen = 4*((icon->w+31)/32);
163
	to = data = malloc(inxlen*icon->h);
164
 
165
	/* rotate around the y axis and invert bits */
166
	outxlen = (icon->w+7)/8;
167
	for(y = 0; y < icon->h; y++){
168
		from = and + (icon->h - 1 - y)*inxlen;
169
		for(x = 0; x < outxlen; x++){
170
			*to++ = ~(*from++);
171
		}
172
	}
173
 
174
	/* stick in an image */
175
	img = allocimage(display, Rect(0,0,icon->w,icon->h), GREY1, 0, DNofill);
176
	loadimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*outxlen);
177
 
178
	free(data);
179
	return img;
180
}
181
 
182
int
183
Bgeticon(Biobuf *b, Icon *icon)
184
{
185
	ulong l;
186
	ushort s;
187
	uchar *xor;
188
	uchar *and;
189
	uchar *cm;
190
	uchar *buf;
191
	uchar *map2map;
192
	Image *img;
193
 
194
	Bseek(b, icon->offset, 0);
195
	buf = malloc(icon->len);
196
	if(buf == nil)
197
		return -1;
198
	if(Bread(b, buf, icon->len) != icon->len){
199
		werrstr("unexpected EOF");
200
		return -1;
201
	}
202
 
203
	/* this header's info takes precedence over previous one */
204
	if(getl(buf) != 40){
205
		werrstr("bad icon header");
206
		return -1;
207
	}
208
	l = getl(buf+4);
209
	if(l != icon->w)
210
		icon->w = l;
211
	l = getl(buf+8);
212
	if(l>>1 != icon->h)
213
		icon->h = l>>1;
214
	s = gets(buf+12);
215
	if(s != icon->nplane)
216
		icon->nplane = s;
217
	s = gets(buf+14);
218
	if(s != icon->bits)
219
		icon->bits = s;
220
 
221
	/* limit what we handle */
222
	switch(icon->bits){
223
	case 1:
224
	case 2:
225
	case 4:
226
	case 8:
227
		break;
228
	default:
229
		werrstr("don't support %d bit pixels", icon->bits);
230
		return -1;
231
	}
232
	if(icon->nplane != 1){
233
		werrstr("don't support %d planes", icon->nplane);
234
		return -1;
235
	}
236
 
237
	cm = buf + 40;
238
	xor = cm + 4*icon->ncolor;
239
	and = xor + icon->h*4*((icon->bits*icon->w+31)/32);
240
 
241
	/* translate the color map to a plan 9 one */
242
	map2map = transcmap(icon, cm);
243
 
244
	/* convert the images */
245
	icon->img = xor2img(icon, xor, map2map);
246
	icon->mask = and2img(icon, and);
247
 
248
	/* so that we save an image with a white background */
249
	img = allocimage(display, icon->img->r, CMAP8, 0, DWhite);
250
	draw(img, icon->img->r, icon->img, icon->mask, ZP);
251
	icon->img = img;
252
 
253
	free(buf);
254
	free(map2map);
255
	return 0;
256
}
257
 
258
void
259
usage(void)
260
{
261
	fprint(2, "usage: %s [file]\n", argv0);
262
	exits("usage");
263
}
264
 
265
enum
266
{
267
	Mimage,
268
	Mmask,
269
	Mexit,
270
 
271
	Up= 1,
272
	Down= 0,
273
};
274
 
275
char	*menu3str[] = {
276
	[Mimage]	"write image",
277
	[Mmask]		"write mask",
278
	[Mexit]		"exit",
279
	0,
280
};
281
 
282
Menu	menu3 = {
283
	menu3str
284
};
285
 
286
Cursor sight = {
287
	{-7, -7},
288
	{0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0xFB, 0xDF,
289
	 0xF3, 0xCF, 0xE3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF,
290
	 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC7, 0xF3, 0xCF,
291
	 0x7B, 0xDF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8,},
292
	{0x00, 0x00, 0x0F, 0xF0, 0x31, 0x8C, 0x21, 0x84,
293
	 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x7F, 0xFE,
294
	 0x7F, 0xFE, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82,
295
	 0x21, 0x84, 0x31, 0x8C, 0x0F, 0xF0, 0x00, 0x00,}
296
};
297
 
298
void
299
buttons(int ud)
300
{
301
	while((mouse.buttons==0) != ud)
302
		mouse = emouse();
303
}
304
 
305
void
306
mesg(char *fmt, ...)
307
{
308
	va_list arg;
309
	char buf[1024];
310
	static char obuf[1024];
311
 
312
	va_start(arg, fmt);
313
	vseprint(buf, buf+sizeof(buf), fmt, arg);
314
	va_end(arg);
315
	string(screen, screen->r.min, background, ZP, font, obuf);
316
	string(screen, screen->r.min, display->white, ZP, font, buf);
317
	strcpy(obuf, buf);
318
}
319
 
320
void
321
doimage(Icon *icon)
322
{
323
	int rv;
324
	char file[256];
325
	int fd;
326
 
327
	rv = -1;
328
	snprint(file, sizeof(file), "%dx%d.img", icon->w, icon->h);
329
	fd = create(file, OWRITE, 0664);
330
	if(fd >= 0){
331
		rv = writeimage(fd, icon->img, 0);
332
		close(fd);
333
	}
334
	if(rv < 0)
335
		mesg("error writing %s: %r", file);
336
	else
337
		mesg("created %s", file);
338
}
339
 
340
void
341
domask(Icon *icon)
342
{
343
	int rv;
344
	char file[64];
345
	int fd;
346
 
347
	rv = -1;
348
	snprint(file, sizeof(file), "%dx%d.mask", icon->w, icon->h);
349
	fd = create(file, OWRITE, 0664);
350
	if(fd >= 0){
351
		rv = writeimage(fd, icon->mask, 0);
352
		close(fd);
353
	}
354
	if(rv < 0)
355
		mesg("error writing %s: %r", file);
356
	else
357
		mesg("created %s", file);
358
}
359
 
360
void
361
apply(void (*f)(Icon*))
362
{
363
	Icon *icon;
364
 
365
	esetcursor(&sight);
366
	buttons(Down);
367
	if(mouse.buttons == 4)
368
		for(icon = h.first; icon; icon = icon->next)
369
			if(ptinrect(mouse.xy, icon->sr)){
370
				buttons(Up);
371
				f(icon);
372
				break;
373
			}
374
	buttons(Up);
375
	esetcursor(0);
376
}
377
 
378
void
379
menu(void)
380
{
381
	int sel;
382
 
383
	sel = emenuhit(3, &mouse, &menu3);
384
	switch(sel){
385
	case Mimage:
386
		apply(doimage);
387
		break;
388
	case Mmask:
389
		apply(domask);
390
		break;
391
	case Mexit:
392
		exits(0);
393
		break;
394
	}
395
}
396
 
397
void
398
mousemoved(void)
399
{
400
	Icon *icon;
401
 
402
	for(icon = h.first; icon; icon = icon->next)
403
		if(ptinrect(mouse.xy, icon->sr)){
404
			mesg("%dx%d", icon->w, icon->h);
405
			return;
406
		}
407
	mesg("");
408
}
409
 
410
enum
411
{
412
	BORDER= 1,
413
};
414
 
415
void
416
eresized(int new)
417
{
418
	Icon *icon;
419
	Rectangle r;
420
 
421
	if(new && getwindow(display, Refnone) < 0)
422
		sysfatal("can't reattach to window");
423
	draw(screen, screen->clipr, background, nil, ZP);
424
	r.max.x = screen->r.min.x;
425
	r.min.y = screen->r.min.y + font->height + 2*BORDER;
426
	for(icon = h.first; icon != nil; icon = icon->next){
427
		r.min.x = r.max.x + BORDER;
428
		r.max.x = r.min.x + Dx(icon->img->r);
429
		r.max.y = r.min.y + Dy(icon->img->r);
430
		draw(screen, r, icon->img, nil, ZP);
431
		border(screen, r, -BORDER, display->black, ZP);
432
		icon->sr = r;
433
	}
434
	flushimage(display, 1);
435
}
436
 
437
void
438
main(int argc, char **argv)
439
{
440
	Biobuf in;
441
	Icon *icon;
442
	int num, fd;
443
	Rectangle r;
444
	Event e;
445
 
446
	ARGBEGIN{
447
	case 'd':
448
		debug = 1;
449
		break;
450
	}ARGEND;
451
 
452
	fd = -1;
453
	switch(argc){
454
	case 0:
455
		fd = 0;
456
		break;
457
	case 1:
458
		fd = open(argv[0], OREAD);
459
		if(fd < 0)
460
			sysfatal("opening: %r");
461
		break;
462
	default:
463
		usage();
464
		break;
465
	}
466
 
467
	Binit(&in, fd, OREAD);
468
 
469
	if(Bgetheader(&in, &h) < 0)
470
		sysfatal("reading header: %r");
471
 
472
	initdraw(nil, nil, "ico");
473
	background = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, (128<<24)|(128<<16)|(128<<8)|0xFF);
474
 
475
	einit(Emouse|Ekeyboard);
476
 
477
	num = 0;
478
	r.min = Pt(4, 4);
479
	for(icon = h.first; icon != nil; icon = icon->next){
480
		if(Bgeticon(&in, icon) < 0){
481
			fprint(2, "%s: read fail: %r\n", argv0);
482
			continue;
483
		}
484
		if(debug)
485
			fprint(2, "w %ud h %ud ncolor %ud bits %ud len %lud offset %lud\n",
486
			   icon->w, icon->h, icon->ncolor, icon->bits, icon->len, icon->offset);
487
		r.max = addpt(r.min, Pt(icon->w, icon->h));
488
		icon->r = r;
489
		r.min.x += r.max.x;
490
		num++;
491
	}
492
 
493
	if(num == 0)
494
		exits("no images");
495
	eresized(0);
496
 
497
	for(;;)
498
		switch(event(&e)){
499
		case Ekeyboard:
500
			break;
501
		case Emouse:
502
			mouse = e.mouse;
503
			if(mouse.buttons & 4)
504
				menu();
505
			else
506
				mousemoved();
507
			break;
508
		}
509
	/* not reached */
510
}