URI:
       tico.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tico.c (8791B)
       ---
            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 -W winsize [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         "write image",
          277         "write mask",
          278         "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 fd;
          443         Rectangle r;
          444         Event e;
          445 
          446         ARGBEGIN{
          447         case 'W':
          448                 winsize = EARGF(usage());
          449                 break;
          450         case 'd':
          451                 debug = 1;
          452                 break;
          453         }ARGEND;
          454 
          455         fd = -1;
          456         switch(argc){
          457         case 0:
          458                 fd = 0;
          459                 break;
          460         case 1:
          461                 fd = open(argv[0], OREAD);
          462                 if(fd < 0)
          463                         sysfatal("opening: %r");
          464                 break;
          465         default:
          466                 usage();
          467                 break;
          468         }
          469 
          470         Binit(&in, fd, OREAD);
          471 
          472         if(Bgetheader(&in, &h) < 0)
          473                 sysfatal("reading header: %r");
          474 
          475         initdraw(0, nil, "ico");
          476         background = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x808080FF);
          477 
          478         einit(Emouse|Ekeyboard);
          479 
          480         r.min = Pt(4, 4);
          481         for(icon = h.first; icon != nil; icon = icon->next){
          482                 if(Bgeticon(&in, icon) < 0){
          483                         fprint(2, "bad rectangle: %r\n");
          484                         continue;
          485                 }
          486                 if(debug)
          487                         fprint(2, "w %ud h %ud ncolor %ud bits %ud len %lud offset %lud\n",
          488                            icon->w, icon->h, icon->ncolor, icon->bits, icon->len, icon->offset);
          489                 r.max = addpt(r.min, Pt(icon->w, icon->h));
          490                 icon->r = r;
          491                 r.min.x += r.max.x;
          492         }
          493         eresized(0);
          494 
          495         for(;;)
          496                 switch(event(&e)){
          497                 case Ekeyboard:
          498                         break;
          499                 case Emouse:
          500                         mouse = e.mouse;
          501                         if(mouse.buttons & 4)
          502                                 menu();
          503                         else
          504                                 mousemoved();
          505                         break;
          506                 }
          507 }