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