plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

toico.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 }