toico.c 5.9 KB

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