xref: /plan9-contrib/sys/src/cmd/jpg/toico.c (revision 8fa2b2a7bbf95d4253e48d836188c408a39b43ab)
1*8fa2b2a7SDavid du Colombier #include <u.h>
2*8fa2b2a7SDavid du Colombier #include <libc.h>
3*8fa2b2a7SDavid du Colombier #include <bio.h>
4*8fa2b2a7SDavid du Colombier #include <draw.h>
5*8fa2b2a7SDavid du Colombier 
6*8fa2b2a7SDavid du Colombier enum
7*8fa2b2a7SDavid du Colombier {
8*8fa2b2a7SDavid du Colombier 	FileHdrLen=	6,
9*8fa2b2a7SDavid du Colombier 	IconDescrLen=	16,
10*8fa2b2a7SDavid du Colombier 	IconHdrLen=	40,
11*8fa2b2a7SDavid du Colombier };
12*8fa2b2a7SDavid du Colombier 
13*8fa2b2a7SDavid du Colombier typedef struct Icon Icon;
14*8fa2b2a7SDavid du Colombier struct Icon
15*8fa2b2a7SDavid du Colombier {
16*8fa2b2a7SDavid du Colombier 	Icon	*next;
17*8fa2b2a7SDavid du Colombier 	char	*file;
18*8fa2b2a7SDavid du Colombier 
19*8fa2b2a7SDavid du Colombier 	uchar	w;		/* icon width */
20*8fa2b2a7SDavid du Colombier 	uchar	h;		/* icon height */
21*8fa2b2a7SDavid du Colombier 	ushort	ncolor;		/* number of colors */
22*8fa2b2a7SDavid du Colombier 	ushort	nplane;		/* number of bit planes */
23*8fa2b2a7SDavid du Colombier 	ushort	bits;		/* bits per pixel */
24*8fa2b2a7SDavid du Colombier 	ulong	len;		/* length of data */
25*8fa2b2a7SDavid du Colombier 	ulong	offset;		/* file offset to data */
26*8fa2b2a7SDavid du Colombier 	uchar	map[4*256];	/* color map */
27*8fa2b2a7SDavid du Colombier 
28*8fa2b2a7SDavid du Colombier 	Image	*img;
29*8fa2b2a7SDavid du Colombier 
30*8fa2b2a7SDavid du Colombier 	uchar	*xor;
31*8fa2b2a7SDavid du Colombier 	int	xorlen;
32*8fa2b2a7SDavid du Colombier 	uchar	*and;
33*8fa2b2a7SDavid du Colombier 	int	andlen;
34*8fa2b2a7SDavid du Colombier };
35*8fa2b2a7SDavid du Colombier 
36*8fa2b2a7SDavid du Colombier typedef struct Header Header;
37*8fa2b2a7SDavid du Colombier struct Header
38*8fa2b2a7SDavid du Colombier {
39*8fa2b2a7SDavid du Colombier 	uint	n;
40*8fa2b2a7SDavid du Colombier 	Icon	*first;
41*8fa2b2a7SDavid du Colombier 	Icon	*last;
42*8fa2b2a7SDavid du Colombier };
43*8fa2b2a7SDavid du Colombier 
44*8fa2b2a7SDavid du Colombier void
Bputs(Biobuf * b,ushort x)45*8fa2b2a7SDavid du Colombier Bputs(Biobuf *b, ushort x)
46*8fa2b2a7SDavid du Colombier {
47*8fa2b2a7SDavid du Colombier 	Bputc(b, x&0xff);
48*8fa2b2a7SDavid du Colombier 	Bputc(b, x>>8);
49*8fa2b2a7SDavid du Colombier }
50*8fa2b2a7SDavid du Colombier 
51*8fa2b2a7SDavid du Colombier void
Bputl(Biobuf * b,ulong x)52*8fa2b2a7SDavid du Colombier Bputl(Biobuf *b, ulong x)
53*8fa2b2a7SDavid du Colombier {
54*8fa2b2a7SDavid du Colombier 	Bputs(b, x&0xffff);
55*8fa2b2a7SDavid du Colombier 	Bputs(b, x>>16);
56*8fa2b2a7SDavid du Colombier }
57*8fa2b2a7SDavid du Colombier 
58*8fa2b2a7SDavid du Colombier Header h;
59*8fa2b2a7SDavid du Colombier 
60*8fa2b2a7SDavid du Colombier void*	emalloc(int);
61*8fa2b2a7SDavid du Colombier void	mk8bit(Icon*, int);
62*8fa2b2a7SDavid du Colombier void	mkxorand(Icon*, int);
63*8fa2b2a7SDavid du Colombier void	readicon(char*);
64*8fa2b2a7SDavid du Colombier 
65*8fa2b2a7SDavid du Colombier void
main(int argc,char ** argv)66*8fa2b2a7SDavid du Colombier main(int argc, char **argv)
67*8fa2b2a7SDavid du Colombier {
68*8fa2b2a7SDavid du Colombier 	int i;
69*8fa2b2a7SDavid du Colombier 	Biobuf *b, out;
70*8fa2b2a7SDavid du Colombier 	Icon *icon;
71*8fa2b2a7SDavid du Colombier 	ulong offset;
72*8fa2b2a7SDavid du Colombier 	ulong len;
73*8fa2b2a7SDavid du Colombier 
74*8fa2b2a7SDavid du Colombier 	ARGBEGIN{
75*8fa2b2a7SDavid du Colombier 	}ARGEND;
76*8fa2b2a7SDavid du Colombier 
77*8fa2b2a7SDavid du Colombier 	/* read in all the images */
78*8fa2b2a7SDavid du Colombier 	display = initdisplay(nil, nil, nil);
79*8fa2b2a7SDavid du Colombier 	if(argc < 1){
80*8fa2b2a7SDavid du Colombier 		readicon("/fd/0");
81*8fa2b2a7SDavid du Colombier 	} else {
82*8fa2b2a7SDavid du Colombier 		for(i = 0; i < argc; i++)
83*8fa2b2a7SDavid du Colombier 			readicon(argv[i]);
84*8fa2b2a7SDavid du Colombier 	}
85*8fa2b2a7SDavid du Colombier 
86*8fa2b2a7SDavid du Colombier 	/* create the .ico file */
87*8fa2b2a7SDavid du Colombier 	b = &out;
88*8fa2b2a7SDavid du Colombier 	Binit(b, 1, OWRITE);
89*8fa2b2a7SDavid du Colombier 
90*8fa2b2a7SDavid du Colombier 	/* offset to first icon */
91*8fa2b2a7SDavid du Colombier 	offset = FileHdrLen + h.n*IconDescrLen;
92*8fa2b2a7SDavid du Colombier 
93*8fa2b2a7SDavid du Colombier 	/* file header is */
94*8fa2b2a7SDavid du Colombier 	Bputs(b, 0);
95*8fa2b2a7SDavid du Colombier 	Bputs(b, 1);
96*8fa2b2a7SDavid du Colombier 	Bputs(b, h.n);
97*8fa2b2a7SDavid du Colombier 
98*8fa2b2a7SDavid du Colombier 	/* icon description */
99*8fa2b2a7SDavid du Colombier 	for(icon = h.first; icon != nil; icon = icon->next){
100*8fa2b2a7SDavid du Colombier 		Bputc(b, icon->w);
101*8fa2b2a7SDavid du Colombier 		Bputc(b, icon->h);
102*8fa2b2a7SDavid du Colombier 		Bputc(b, icon->ncolor);
103*8fa2b2a7SDavid du Colombier 		Bputc(b, 0);
104*8fa2b2a7SDavid du Colombier 		Bputs(b, icon->nplane);
105*8fa2b2a7SDavid du Colombier 		Bputs(b, icon->bits);
106*8fa2b2a7SDavid du Colombier 		len = IconHdrLen + icon->ncolor*4 + icon->xorlen + icon->andlen;
107*8fa2b2a7SDavid du Colombier 		Bputl(b, len);
108*8fa2b2a7SDavid du Colombier 		Bputl(b, offset);
109*8fa2b2a7SDavid du Colombier 		offset += len;
110*8fa2b2a7SDavid du Colombier 	}
111*8fa2b2a7SDavid du Colombier 
112*8fa2b2a7SDavid du Colombier 	/* icons */
113*8fa2b2a7SDavid du Colombier 	for(icon = h.first; icon != nil; icon = icon->next){
114*8fa2b2a7SDavid du Colombier 		/* icon header (BMP like) */
115*8fa2b2a7SDavid du Colombier 		Bputl(b, IconHdrLen);
116*8fa2b2a7SDavid du Colombier 		Bputl(b, icon->w);
117*8fa2b2a7SDavid du Colombier 		Bputl(b, 2*icon->h);
118*8fa2b2a7SDavid du Colombier 		Bputs(b, icon->nplane);
119*8fa2b2a7SDavid du Colombier 		Bputs(b, icon->bits);
120*8fa2b2a7SDavid du Colombier 		Bputl(b, 0);	/* compression info */
121*8fa2b2a7SDavid du Colombier 		Bputl(b, 0);
122*8fa2b2a7SDavid du Colombier 		Bputl(b, 0);
123*8fa2b2a7SDavid du Colombier 		Bputl(b, 0);
124*8fa2b2a7SDavid du Colombier 		Bputl(b, 0);
125*8fa2b2a7SDavid du Colombier 		Bputl(b, 0);
126*8fa2b2a7SDavid du Colombier 
127*8fa2b2a7SDavid du Colombier 		/* color map */
128*8fa2b2a7SDavid du Colombier 		if(Bwrite(b, icon->map, 4*icon->ncolor) < 0)
129*8fa2b2a7SDavid du Colombier 			sysfatal("writing color map: %r");
130*8fa2b2a7SDavid du Colombier 
131*8fa2b2a7SDavid du Colombier 		/* xor bits */
132*8fa2b2a7SDavid du Colombier 		if(Bwrite(b, icon->xor, icon->xorlen) < 0)
133*8fa2b2a7SDavid du Colombier 			sysfatal("writing xor bits: %r");
134*8fa2b2a7SDavid du Colombier 
135*8fa2b2a7SDavid du Colombier 		/* and bits */
136*8fa2b2a7SDavid du Colombier 		if(Bwrite(b, icon->and, icon->andlen) < 0)
137*8fa2b2a7SDavid du Colombier 			sysfatal("writing and bits: %r");
138*8fa2b2a7SDavid du Colombier 	}
139*8fa2b2a7SDavid du Colombier 
140*8fa2b2a7SDavid du Colombier 	Bterm(b);
141*8fa2b2a7SDavid du Colombier 	exits(0);
142*8fa2b2a7SDavid du Colombier }
143*8fa2b2a7SDavid du Colombier 
144*8fa2b2a7SDavid du Colombier void
readicon(char * file)145*8fa2b2a7SDavid du Colombier readicon(char *file)
146*8fa2b2a7SDavid du Colombier {
147*8fa2b2a7SDavid du Colombier 	int fd;
148*8fa2b2a7SDavid du Colombier 	Icon *icon;
149*8fa2b2a7SDavid du Colombier 
150*8fa2b2a7SDavid du Colombier 	fd = open(file, OREAD);
151*8fa2b2a7SDavid du Colombier 	if(fd < 0)
152*8fa2b2a7SDavid du Colombier 		sysfatal("opening %s: %r", file);
153*8fa2b2a7SDavid du Colombier 	icon = emalloc(sizeof(Icon));
154*8fa2b2a7SDavid du Colombier 	icon->img = readimage(display, fd, 0);
155*8fa2b2a7SDavid du Colombier 	if(icon->img == nil)
156*8fa2b2a7SDavid du Colombier 		sysfatal("reading image %s: %r", file);
157*8fa2b2a7SDavid du Colombier 	close(fd);
158*8fa2b2a7SDavid du Colombier 
159*8fa2b2a7SDavid du Colombier 	if(h.first)
160*8fa2b2a7SDavid du Colombier 		h.last->next = icon;
161*8fa2b2a7SDavid du Colombier 	else
162*8fa2b2a7SDavid du Colombier 		h.first = icon;
163*8fa2b2a7SDavid du Colombier 	h.last = icon;
164*8fa2b2a7SDavid du Colombier 	h.n++;
165*8fa2b2a7SDavid du Colombier 
166*8fa2b2a7SDavid du Colombier 	icon->h = Dy(icon->img->r);
167*8fa2b2a7SDavid du Colombier 	icon->w = Dx(icon->img->r);
168*8fa2b2a7SDavid du Colombier 	icon->bits = 1<<icon->img->depth;
169*8fa2b2a7SDavid du Colombier 	icon->nplane = 1;
170*8fa2b2a7SDavid du Colombier 
171*8fa2b2a7SDavid du Colombier 	/* convert to 8 bits per pixel */
172*8fa2b2a7SDavid du Colombier 	switch(icon->img->chan){
173*8fa2b2a7SDavid du Colombier 	case GREY8:
174*8fa2b2a7SDavid du Colombier 	case CMAP8:
175*8fa2b2a7SDavid du Colombier 		break;
176*8fa2b2a7SDavid du Colombier 	case GREY1:
177*8fa2b2a7SDavid du Colombier 	case GREY2:
178*8fa2b2a7SDavid du Colombier 	case GREY4:
179*8fa2b2a7SDavid du Colombier 		mk8bit(icon, 1);
180*8fa2b2a7SDavid du Colombier 		break;
181*8fa2b2a7SDavid du Colombier 	default:
182*8fa2b2a7SDavid du Colombier 		mk8bit(icon, 0);
183*8fa2b2a7SDavid du Colombier 		break;
184*8fa2b2a7SDavid du Colombier 	}
185*8fa2b2a7SDavid du Colombier 	icon->bits = 8;
186*8fa2b2a7SDavid du Colombier 	icon->file = file;
187*8fa2b2a7SDavid du Colombier 
188*8fa2b2a7SDavid du Colombier 	/* create xor/and masks, minimizing bits per pixel */
189*8fa2b2a7SDavid du Colombier 	mkxorand(icon, icon->img->chan == GREY8);
190*8fa2b2a7SDavid du Colombier }
191*8fa2b2a7SDavid du Colombier 
192*8fa2b2a7SDavid du Colombier void*
emalloc(int len)193*8fa2b2a7SDavid du Colombier emalloc(int len)
194*8fa2b2a7SDavid du Colombier {
195*8fa2b2a7SDavid du Colombier 	void *x;
196*8fa2b2a7SDavid du Colombier 
197*8fa2b2a7SDavid du Colombier 	x = mallocz(len, 1);
198*8fa2b2a7SDavid du Colombier 	if(x == nil)
199*8fa2b2a7SDavid du Colombier 		sysfatal("memory: %r");
200*8fa2b2a7SDavid du Colombier 	return x;
201*8fa2b2a7SDavid du Colombier }
202*8fa2b2a7SDavid du Colombier 
203*8fa2b2a7SDavid du Colombier /* convert to 8 bit */
204*8fa2b2a7SDavid du Colombier void
mk8bit(Icon * icon,int grey)205*8fa2b2a7SDavid du Colombier mk8bit(Icon *icon, int grey)
206*8fa2b2a7SDavid du Colombier {
207*8fa2b2a7SDavid du Colombier 	Image *img;
208*8fa2b2a7SDavid du Colombier 
209*8fa2b2a7SDavid du Colombier 	img = allocimage(display, icon->img->r, grey ? GREY8 : CMAP8, 0, DNofill);
210*8fa2b2a7SDavid du Colombier 	if(img == nil)
211*8fa2b2a7SDavid du Colombier 		sysfatal("can't allocimage: %r");
212*8fa2b2a7SDavid du Colombier 	draw(img, img->r, icon->img, nil, ZP);
213*8fa2b2a7SDavid du Colombier 	freeimage(icon->img);
214*8fa2b2a7SDavid du Colombier 	icon->img = img;
215*8fa2b2a7SDavid du Colombier }
216*8fa2b2a7SDavid du Colombier 
217*8fa2b2a7SDavid du Colombier /* make xor and and mask */
218*8fa2b2a7SDavid du Colombier void
mkxorand(Icon * icon,int grey)219*8fa2b2a7SDavid du Colombier mkxorand(Icon *icon, int grey)
220*8fa2b2a7SDavid du Colombier {
221*8fa2b2a7SDavid du Colombier 	int i, x, y, s, sa;
222*8fa2b2a7SDavid du Colombier 	uchar xx[256];
223*8fa2b2a7SDavid du Colombier 	uchar *data, *p, *e;
224*8fa2b2a7SDavid du Colombier 	int ndata;
225*8fa2b2a7SDavid du Colombier 	uchar *mp;
226*8fa2b2a7SDavid du Colombier 	int ncolor;
227*8fa2b2a7SDavid du Colombier 	ulong color;
228*8fa2b2a7SDavid du Colombier 	int bits;
229*8fa2b2a7SDavid du Colombier 	uchar andbyte, xorbyte;
230*8fa2b2a7SDavid du Colombier 	uchar *ato, *xto;
231*8fa2b2a7SDavid du Colombier 	int xorrl, andrl;
232*8fa2b2a7SDavid du Colombier 
233*8fa2b2a7SDavid du Colombier 	ndata = icon->h * icon->w;
234*8fa2b2a7SDavid du Colombier 	data = emalloc(ndata);
235*8fa2b2a7SDavid du Colombier 	if(unloadimage(icon->img, icon->img->r, data, ndata) < 0)
236*8fa2b2a7SDavid du Colombier 		sysfatal("can't unload %s: %r", icon->file);
237*8fa2b2a7SDavid du Colombier 	e = data + ndata;
238*8fa2b2a7SDavid du Colombier 
239*8fa2b2a7SDavid du Colombier 	/* find colors used */
240*8fa2b2a7SDavid du Colombier 	memset(xx, 0, sizeof xx);
241*8fa2b2a7SDavid du Colombier 	for(p = data; p < e; p++)
242*8fa2b2a7SDavid du Colombier 		xx[*p]++;
243*8fa2b2a7SDavid du Colombier 
244*8fa2b2a7SDavid du Colombier 	/* count the colors and create a mapping from plan 9 */
245*8fa2b2a7SDavid du Colombier 	mp = icon->map;
246*8fa2b2a7SDavid du Colombier 	ncolor = 0;
247*8fa2b2a7SDavid du Colombier 	for(i = 0; i < 256; i++){
248*8fa2b2a7SDavid du Colombier 		if(xx[i] == 0)
249*8fa2b2a7SDavid du Colombier 			continue;
250*8fa2b2a7SDavid du Colombier 		if(grey){
251*8fa2b2a7SDavid du Colombier 			*mp++ = i;
252*8fa2b2a7SDavid du Colombier 			*mp++ = i;
253*8fa2b2a7SDavid du Colombier 			*mp++ = i;
254*8fa2b2a7SDavid du Colombier 			*mp++ = 0;
255*8fa2b2a7SDavid du Colombier 		} else {
256*8fa2b2a7SDavid du Colombier 			color = cmap2rgb(i);
257*8fa2b2a7SDavid du Colombier 			*mp++ = color;
258*8fa2b2a7SDavid du Colombier 			*mp++ = color>>8;
259*8fa2b2a7SDavid du Colombier 			*mp++ = color>>16;
260*8fa2b2a7SDavid du Colombier 			*mp++ = 0;
261*8fa2b2a7SDavid du Colombier 		}
262*8fa2b2a7SDavid du Colombier 		xx[i] = ncolor;
263*8fa2b2a7SDavid du Colombier 		ncolor++;
264*8fa2b2a7SDavid du Colombier 	}
265*8fa2b2a7SDavid du Colombier 
266*8fa2b2a7SDavid du Colombier 	/* get minimum number of pixels per bit (with a color map) */
267*8fa2b2a7SDavid du Colombier 	if(ncolor <= 2){
268*8fa2b2a7SDavid du Colombier 		ncolor = 2;
269*8fa2b2a7SDavid du Colombier 		bits = 1;
270*8fa2b2a7SDavid du Colombier 	} else if(ncolor <= 4){
271*8fa2b2a7SDavid du Colombier 		ncolor = 4;
272*8fa2b2a7SDavid du Colombier 		bits = 2;
273*8fa2b2a7SDavid du Colombier 	} else if(ncolor <= 16){
274*8fa2b2a7SDavid du Colombier 		ncolor = 16;
275*8fa2b2a7SDavid du Colombier 		bits = 4;
276*8fa2b2a7SDavid du Colombier 	} else {
277*8fa2b2a7SDavid du Colombier 		ncolor = 256;
278*8fa2b2a7SDavid du Colombier 		bits = 8;
279*8fa2b2a7SDavid du Colombier 	}
280*8fa2b2a7SDavid du Colombier 	icon->bits = bits;
281*8fa2b2a7SDavid du Colombier 	icon->ncolor = ncolor;
282*8fa2b2a7SDavid du Colombier 
283*8fa2b2a7SDavid du Colombier 	/* the xor mask rows are justified to a 32 bit boundary */
284*8fa2b2a7SDavid du Colombier 	/* the and mask is 1 bit grey */
285*8fa2b2a7SDavid du Colombier 	xorrl = 4*((bits*icon->w + 31)/32);
286*8fa2b2a7SDavid du Colombier 	andrl = 4*((icon->w + 31)/32);
287*8fa2b2a7SDavid du Colombier 	icon->xor = emalloc(xorrl * icon->h);
288*8fa2b2a7SDavid du Colombier 	icon->and = emalloc(andrl * icon->h);
289*8fa2b2a7SDavid du Colombier 	icon->xorlen = xorrl*icon->h;
290*8fa2b2a7SDavid du Colombier 	icon->andlen = andrl*icon->h;
291*8fa2b2a7SDavid du Colombier 
292*8fa2b2a7SDavid du Colombier 	/* make both masks.  they're upside down relative to plan9 ones */
293*8fa2b2a7SDavid du Colombier 	p = data;
294*8fa2b2a7SDavid du Colombier 	for(y = 0; y < icon->h; y++){
295*8fa2b2a7SDavid du Colombier 		andbyte = 0;
296*8fa2b2a7SDavid du Colombier 		xorbyte = 0;
297*8fa2b2a7SDavid du Colombier 		sa = s = 0;
298*8fa2b2a7SDavid du Colombier 		xto = icon->xor + (icon->h-1-y)*xorrl;
299*8fa2b2a7SDavid du Colombier 		ato = icon->and + (icon->h-1-y)*andrl;
300*8fa2b2a7SDavid du Colombier 		for(x = 0; x < icon->w; x++){
301*8fa2b2a7SDavid du Colombier 			xorbyte <<= bits;
302*8fa2b2a7SDavid du Colombier 			xorbyte |= xx[*p];
303*8fa2b2a7SDavid du Colombier 			s += bits;
304*8fa2b2a7SDavid du Colombier 			if(s == 8){
305*8fa2b2a7SDavid du Colombier 				*xto++ = xorbyte;
306*8fa2b2a7SDavid du Colombier 				xorbyte = 0;
307*8fa2b2a7SDavid du Colombier 				s = 0;
308*8fa2b2a7SDavid du Colombier 			}
309*8fa2b2a7SDavid du Colombier 			andbyte <<= 1;
310*8fa2b2a7SDavid du Colombier 			if(*p == 0xff)
311*8fa2b2a7SDavid du Colombier 				andbyte |= 1;
312*8fa2b2a7SDavid du Colombier 			sa++;
313*8fa2b2a7SDavid du Colombier 			if(sa == 0){
314*8fa2b2a7SDavid du Colombier 				*ato++ = andbyte;
315*8fa2b2a7SDavid du Colombier 				sa = 0;
316*8fa2b2a7SDavid du Colombier 				andbyte = 0;
317*8fa2b2a7SDavid du Colombier 			}
318*8fa2b2a7SDavid du Colombier 			p++;
319*8fa2b2a7SDavid du Colombier 		}
320*8fa2b2a7SDavid du Colombier 	}
321*8fa2b2a7SDavid du Colombier 	free(data);
322*8fa2b2a7SDavid du Colombier }
323