tico.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
tico.c (8791B)
---
     1 #include 
     2 #include 
     3 #include 
     4 #include 
     5 #include 
     6 #include 
     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<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<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 }