URI: 
       ttoico.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
       ---
       ttoico.c (5627B)
       ---
            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         initdraw(0, nil, nil);
           79         if(argc < 1){
           80                 readicon("/dev/stdin");
           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 }