]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/jpg/toico.c
cwfs: back to previous version
[plan9front.git] / sys / src / cmd / jpg / toico.c
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         display = initdisplay(nil, nil, nil);
79         if(argc < 1){
80                 readicon("/fd/0");
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 }