11 typedef struct Icon Icon;
16 uchar w; /* icon width */
17 uchar h; /* icon height */
18 ushort ncolor; /* number of colors */
19 ushort nplane; /* number of bit planes */
20 ushort bits; /* bits per pixel */
21 ulong len; /* length of data */
22 ulong offset; /* file offset to data */
27 Rectangle r; /* relative */
28 Rectangle sr; /* abs */
31 typedef struct Header Header;
48 return p[0] | (p[1]<<8);
54 return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
58 Bgetheader(Biobuf *b, Header *h)
64 memset(h, 0, sizeof(*h));
65 if(Bread(b, buf, 6) != 6)
67 if(gets(&buf[0]) != 0)
69 if(gets(&buf[2]) != 1)
72 for(i = 0; i < h->n; i++){
73 icon = mallocz(sizeof(*icon), 1);
75 sysfatal("malloc: %r");
76 if(Bread(b, buf, 16) != 16)
78 icon->w = buf[0] == 0 ? 256 : buf[0];
79 icon->h = buf[1] == 0 ? 256 : buf[1];
80 icon->ncolor = buf[2] == 0 ? 256 : buf[2];
81 icon->nplane = gets(&buf[4]);
82 icon->bits = gets(&buf[6]);
83 icon->len = getl(&buf[8]);
84 icon->offset = getl(&buf[12]);
94 werrstr("unexpected EOF");
97 werrstr("unknown header format");
102 transcmap(Icon *icon, int ncolor, uchar *map)
107 p = m = mallocz(sizeof(int)*(1<<icon->bits), 1);
109 sysfatal("malloc: %r");
110 for(i = 0; i < ncolor; i++){
111 *p++ = rgb2cmap(map[2], map[1], map[0]);
118 xor2img(Icon *icon, long chan, uchar *xor, uchar *map)
127 inxlen = 4*((icon->bits*icon->w+31)/32);
128 img = allocmemimage(Rect(0,0,icon->w,icon->h), chan);
133 from = xor + icon->h*inxlen;
134 for(y = 0; y < icon->h; y++){
136 loadmemimage(img, Rect(0,y,icon->w,y+1), from, inxlen);
141 to = data = malloc(icon->w*icon->h);
147 /* rotate around the y axis, go to 8 bits, and convert color */
148 mask = (1<<icon->bits)-1;
149 for(y = 0; y < icon->h; y++){
152 from = xor + (icon->h - 1 - y)*inxlen;
153 for(x = 0; x < icon->w; x++){
158 *to++ = map[(byte>>s) & mask];
162 /* stick in an image */
163 loadmemimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*icon->w);
169 and2img(Icon *icon, uchar *and)
178 inxlen = 4*((icon->w+31)/32);
179 to = data = malloc(inxlen*icon->h);
183 /* rotate around the y axis and invert bits */
184 outxlen = (icon->w+7)/8;
185 for(y = 0; y < icon->h; y++){
186 from = and + (icon->h - 1 - y)*inxlen;
187 for(x = 0; x < outxlen; x++)
191 /* stick in an image */
192 if(img = allocmemimage(Rect(0,0,icon->w,icon->h), GREY1))
193 loadmemimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*outxlen);
200 Bgeticon(Biobuf *b, Icon *icon)
213 Bseek(b, icon->offset, 0);
214 if(Bread(b, magic, 4) != 4){
215 werrstr("unexpected EOF");
218 if(magic[0] == 137 && memcmp(magic+1, "PNG", 3) == 0){
222 png = Breadpng(b, CRGB);
223 if(png == nil || png[0] == nil)
225 switch(png[0]->chandesc){
230 chan = CHAN2(CGrey, 8, CAlpha, 8);
239 werrstr("bad icon png channel descriptor");
243 icon->img = allocmemimage(png[0]->r, chan);
244 loadmemimage(icon->img, icon->img->r, png[0]->chans[0], png[0]->chanlen);
248 if(getl(magic) != 40){
249 werrstr("bad icon bmp header");
253 werrstr("bad icon bmp header length");
256 buf = malloc(icon->len);
259 memmove(buf, magic, 4);
260 if(Bread(b, buf+4, icon->len-4) != icon->len-4){
261 werrstr("unexpected EOF");
265 /* this header's info takes precedence over previous one */
267 icon->w = getl(buf+4);
268 icon->h = getl(buf+8)>>1;
269 icon->nplane = gets(buf+12);
270 icon->bits = gets(buf+14);
272 /* limit what we handle */
278 ncolor = icon->ncolor;
279 if(ncolor > (1<<icon->bits))
280 ncolor = 1<<icon->bits;
294 werrstr("don't support %d bit pixels", icon->bits);
297 if(icon->nplane != 1){
298 werrstr("don't support %d planes", icon->nplane);
305 end = xor + icon->h*4*((icon->bits*icon->w+31)/32);
306 if(end < buf || end > buf+icon->len){
307 werrstr("bad icon length %zux != %lux", end - buf, icon->len);
311 /* translate the color map to a plan 9 one */
314 map2map = transcmap(icon, ncolor, cm);
316 /* convert the images */
317 icon->img = xor2img(icon, chan, xor, map2map);
318 if(icon->img == nil){
319 werrstr("xor2img: %r");
324 /* check for and mask */
326 end += icon->h*4*((icon->w+31)/32);
327 if(end <= buf+icon->len)
328 icon->mask = and2img(icon, and);
330 /* so that we save an image with a white background */
331 if(img = allocmemimage(icon->img->r, icon->img->chan)){
332 memfillcolor(img, DWhite);
333 memimagedraw(img, icon->img->r, icon->img, ZP, icon->mask, ZP, SoverD);
334 freememimage(icon->img);
346 fprint(2, "usage: %s [ -c ] [ file ]\n", argv0);
361 [Mimage] "write image",
362 [Mmask] "write mask",
373 {0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0xFB, 0xDF,
374 0xF3, 0xCF, 0xE3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF,
375 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC7, 0xF3, 0xCF,
376 0x7B, 0xDF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8,},
377 {0x00, 0x00, 0x0F, 0xF0, 0x31, 0x8C, 0x21, 0x84,
378 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x7F, 0xFE,
379 0x7F, 0xFE, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82,
380 0x21, 0x84, 0x31, 0x8C, 0x0F, 0xF0, 0x00, 0x00,}
386 while((mouse.buttons==0) != ud)
395 static char obuf[1024];
398 vseprint(buf, buf+sizeof(buf), fmt, arg);
400 string(screen, screen->r.min, background, ZP, font, obuf);
401 string(screen, screen->r.min, display->white, ZP, font, buf);
413 snprint(file, sizeof(file), "%dx%d.img", icon->w, icon->h);
414 fd = create(file, OWRITE, 0664);
416 rv = writememimage(fd, icon->img);
420 mesg("error writing %s: %r", file);
422 mesg("created %s", file);
432 if(icon->mask == nil)
436 snprint(file, sizeof(file), "%dx%d.mask", icon->w, icon->h);
437 fd = create(file, OWRITE, 0664);
439 rv = writememimage(fd, icon->mask);
443 mesg("error writing %s: %r", file);
445 mesg("created %s", file);
449 apply(void (*f)(Icon*))
455 if(mouse.buttons == 4)
456 for(icon = h.first; icon; icon = icon->next)
457 if(ptinrect(mouse.xy, icon->sr)){
471 sel = emenuhit(3, &mouse, &menu3);
490 for(icon = h.first; icon; icon = icon->next)
491 if(ptinrect(mouse.xy, icon->sr)){
492 mesg("%dx%d", icon->w, icon->h);
504 screenimage(Memimage *m)
509 if(i = allocimage(display, m->r, m->chan, 0, DNofill)){
511 while(r.min.y < m->r.max.y){
513 loadimage(i, r, byteaddr(m, r.min), bytesperline(r, m->depth));
527 if(new && getwindow(display, Refnone) < 0)
528 sysfatal("can't reattach to window");
529 draw(screen, screen->clipr, background, nil, ZP);
530 r.max.x = screen->r.min.x;
531 r.min.y = screen->r.min.y + font->height + 2*BORDER;
532 for(icon = h.first; icon != nil; icon = icon->next){
533 r.min.x = r.max.x + BORDER;
534 r.max.x = r.min.x + Dx(icon->img->r);
535 r.max.y = r.min.y + Dy(icon->img->r);
536 if(i = screenimage(icon->img)){
537 draw(screen, r, i, nil, ZP);
540 border(screen, r, -BORDER, display->black, ZP);
543 flushimage(display, 1);
547 main(int argc, char **argv)
572 fd = open(argv[0], OREAD);
574 sysfatal("opening: %r");
582 Binit(&in, fd, OREAD);
584 if(Bgetheader(&in, &h) < 0)
585 sysfatal("reading header: %r");
589 for(icon = h.first; icon != nil; icon = icon->next){
590 if(Bgeticon(&in, icon) < 0){
591 fprint(2, "%s: read fail: %r\n", argv0);
595 fprint(2, "w %ud h %ud ncolor %ud bits %ud len %lud offset %lud\n",
596 icon->w, icon->h, icon->ncolor, icon->bits, icon->len, icon->offset);
597 r.max = addpt(r.min, Pt(icon->w, icon->h));
600 writememimage(1, icon->img);
607 if(num == 0 || cflag)
608 sysfatal("no images");
610 initdraw(nil, nil, "ico");
611 background = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x808080FF);
613 einit(Emouse|Ekeyboard);
620 if(mouse.buttons & 4)