toico.c 5.5 KB

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