123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <draw.h>
- enum
- {
- FileHdrLen= 6,
- IconDescrLen= 16,
- IconHdrLen= 40,
- };
- typedef struct Icon Icon;
- struct Icon
- {
- Icon *next;
- char *file;
- uchar w; /* icon width */
- uchar h; /* icon height */
- ushort ncolor; /* number of colors */
- ushort nplane; /* number of bit planes */
- ushort bits; /* bits per pixel */
- ulong len; /* length of data */
- ulong offset; /* file offset to data */
- uchar map[4*256]; /* color map */
- Image *img;
- uchar *xor;
- int xorlen;
- uchar *and;
- int andlen;
- };
- typedef struct Header Header;
- struct Header
- {
- uint n;
- Icon *first;
- Icon *last;
- };
- void
- Bputs(Biobuf *b, ushort x)
- {
- Bputc(b, x&0xff);
- Bputc(b, x>>8);
- }
- void
- Bputl(Biobuf *b, ulong x)
- {
- Bputs(b, x&0xffff);
- Bputs(b, x>>16);
- }
- Header h;
- void* emalloc(int);
- void mk8bit(Icon*, int);
- void mkxorand(Icon*, int);
- void readicon(char*);
- void
- main(int argc, char **argv)
- {
- int i;
- Biobuf *b, out;
- Icon *icon;
- ulong offset;
- ulong len;
- ARGBEGIN{
- }ARGEND;
- /* read in all the images */
- display = initdisplay(nil, nil, nil);
- if(argc < 1){
- readicon("/fd/0");
- } else {
- for(i = 0; i < argc; i++)
- readicon(argv[i]);
- }
- /* create the .ico file */
- b = &out;
- Binit(b, 1, OWRITE);
- /* offset to first icon */
- offset = FileHdrLen + h.n*IconDescrLen;
- /* file header is */
- Bputs(b, 0);
- Bputs(b, 1);
- Bputs(b, h.n);
- /* icon description */
- for(icon = h.first; icon != nil; icon = icon->next){
- Bputc(b, icon->w);
- Bputc(b, icon->h);
- Bputc(b, icon->ncolor);
- Bputc(b, 0);
- Bputs(b, icon->nplane);
- Bputs(b, icon->bits);
- len = IconHdrLen + icon->ncolor*4 + icon->xorlen + icon->andlen;
- Bputl(b, len);
- Bputl(b, offset);
- offset += len;
- }
- /* icons */
- for(icon = h.first; icon != nil; icon = icon->next){
- /* icon header (BMP like) */
- Bputl(b, IconHdrLen);
- Bputl(b, icon->w);
- Bputl(b, 2*icon->h);
- Bputs(b, icon->nplane);
- Bputs(b, icon->bits);
- Bputl(b, 0); /* compression info */
- Bputl(b, 0);
- Bputl(b, 0);
- Bputl(b, 0);
- Bputl(b, 0);
- Bputl(b, 0);
- /* color map */
- if(Bwrite(b, icon->map, 4*icon->ncolor) < 0)
- sysfatal("writing color map: %r");
- /* xor bits */
- if(Bwrite(b, icon->xor, icon->xorlen) < 0)
- sysfatal("writing xor bits: %r");
- /* and bits */
- if(Bwrite(b, icon->and, icon->andlen) < 0)
- sysfatal("writing and bits: %r");
- }
- Bterm(b);
- exits(0);
- }
- void
- readicon(char *file)
- {
- int fd;
- Icon *icon;
- fd = open(file, OREAD);
- if(fd < 0)
- sysfatal("opening %s: %r", file);
- icon = emalloc(sizeof(Icon));
- icon->img = readimage(display, fd, 0);
- if(icon->img == nil)
- sysfatal("reading image %s: %r", file);
- close(fd);
- if(h.first)
- h.last->next = icon;
- else
- h.first = icon;
- h.last = icon;
- h.n++;
- icon->h = Dy(icon->img->r);
- icon->w = Dx(icon->img->r);
- icon->bits = 1<<icon->img->depth;
- icon->nplane = 1;
- /* convert to 8 bits per pixel */
- switch(icon->img->chan){
- case GREY8:
- case CMAP8:
- break;
- case GREY1:
- case GREY2:
- case GREY4:
- mk8bit(icon, 1);
- break;
- default:
- mk8bit(icon, 0);
- break;
- }
- icon->bits = 8;
- icon->file = file;
- /* create xor/and masks, minimizing bits per pixel */
- mkxorand(icon, icon->img->chan == GREY8);
- }
- void*
- emalloc(int len)
- {
- void *x;
- x = mallocz(len, 1);
- if(x == nil)
- sysfatal("memory: %r");
- return x;
- }
- /* convert to 8 bit */
- void
- mk8bit(Icon *icon, int grey)
- {
- Image *img;
- img = allocimage(display, icon->img->r, grey ? GREY8 : CMAP8, 0, DNofill);
- if(img == nil)
- sysfatal("can't allocimage: %r");
- draw(img, img->r, icon->img, nil, ZP);
- freeimage(icon->img);
- icon->img = img;
- }
- /* make xor and and mask */
- void
- mkxorand(Icon *icon, int grey)
- {
- int i, x, y, s, sa;
- uchar xx[256];
- uchar *data, *p, *e;
- int ndata;
- uchar *mp;
- int ncolor;
- ulong color;
- int bits;
- uchar andbyte, xorbyte;
- uchar *ato, *xto;
- int xorrl, andrl;
- ndata = icon->h * icon->w;
- data = emalloc(ndata);
- if(unloadimage(icon->img, icon->img->r, data, ndata) < 0)
- sysfatal("can't unload %s: %r", icon->file);
- e = data + ndata;
- /* find colors used */
- memset(xx, 0, sizeof xx);
- for(p = data; p < e; p++)
- xx[*p]++;
- /* count the colors and create a mapping from plan 9 */
- mp = icon->map;
- ncolor = 0;
- for(i = 0; i < 256; i++){
- if(xx[i] == 0)
- continue;
- if(grey){
- *mp++ = i;
- *mp++ = i;
- *mp++ = i;
- *mp++ = 0;
- } else {
- color = cmap2rgb(i);
- *mp++ = color;
- *mp++ = color>>8;
- *mp++ = color>>16;
- *mp++ = 0;
- }
- xx[i] = ncolor;
- ncolor++;
- }
- /* get minimum number of pixels per bit (with a color map) */
- if(ncolor <= 2){
- ncolor = 2;
- bits = 1;
- } else if(ncolor <= 4){
- ncolor = 4;
- bits = 2;
- } else if(ncolor <= 16){
- ncolor = 16;
- bits = 4;
- } else {
- ncolor = 256;
- bits = 8;
- }
- icon->bits = bits;
- icon->ncolor = ncolor;
- /* the xor mask rows are justified to a 32 bit boundary */
- /* the and mask is 1 bit grey */
- xorrl = 4*((bits*icon->w + 31)/32);
- andrl = 4*((icon->w + 31)/32);
- icon->xor = emalloc(xorrl * icon->h);
- icon->and = emalloc(andrl * icon->h);
- icon->xorlen = xorrl*icon->h;
- icon->andlen = andrl*icon->h;
- /* make both masks. they're upside down relative to plan9 ones */
- p = data;
- for(y = 0; y < icon->h; y++){
- andbyte = 0;
- xorbyte = 0;
- sa = s = 0;
- xto = icon->xor + (icon->h-1-y)*xorrl;
- ato = icon->and + (icon->h-1-y)*andrl;
- for(x = 0; x < icon->w; x++){
- xorbyte <<= bits;
- xorbyte |= xx[*p];
- s += bits;
- if(s == 8){
- *xto++ = xorbyte;
- xorbyte = 0;
- s = 0;
- }
- andbyte <<= 1;
- if(*p == 0xff)
- andbyte |= 1;
- sa++;
- if(sa == 0){
- *ato++ = andbyte;
- sa = 0;
- andbyte = 0;
- }
- p++;
- }
- }
- free(data);
- }
|