ico.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <draw.h>
  5. #include <event.h>
  6. #include <cursor.h>
  7. typedef struct Icon Icon;
  8. struct Icon
  9. {
  10. Icon *next;
  11. uchar w; /* icon width */
  12. uchar h; /* icon height */
  13. ushort ncolor; /* number of colors */
  14. ushort nplane; /* number of bit planes */
  15. ushort bits; /* bits per pixel */
  16. ulong len; /* length of data */
  17. ulong offset; /* file offset to data */
  18. Image *img;
  19. Image *mask;
  20. Rectangle r; /* relative */
  21. Rectangle sr; /* abs */
  22. };
  23. typedef struct Header Header;
  24. struct Header
  25. {
  26. uint n;
  27. Icon *first;
  28. Icon *last;
  29. };
  30. int debug;
  31. Mouse mouse;
  32. Header h;
  33. Image *background;
  34. ushort
  35. gets(uchar *p)
  36. {
  37. return p[0] | (p[1]<<8);
  38. }
  39. ulong
  40. getl(uchar *p)
  41. {
  42. return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
  43. }
  44. int
  45. Bgetheader(Biobuf *b, Header *h)
  46. {
  47. Icon *icon;
  48. int i;
  49. uchar buf[40];
  50. memset(h, 0, sizeof(*h));
  51. if(Bread(b, buf, 6) != 6)
  52. goto eof;
  53. if(gets(&buf[0]) != 0)
  54. goto header;
  55. if(gets(&buf[2]) != 1)
  56. goto header;
  57. h->n = gets(&buf[4]);
  58. for(i = 0; i < h->n; i++){
  59. icon = mallocz(sizeof(*icon), 1);
  60. if(icon == nil)
  61. sysfatal("malloc: %r");
  62. if(Bread(b, buf, 16) != 16)
  63. goto eof;
  64. icon->w = buf[0];
  65. icon->h = buf[1];
  66. icon->ncolor = buf[2] == 0 ? 256 : buf[2];
  67. if(buf[3] != 0)
  68. goto header;
  69. icon->nplane = gets(&buf[4]);
  70. icon->bits = gets(&buf[6]);
  71. icon->len = getl(&buf[8]);
  72. icon->offset = getl(&buf[12]);
  73. if(i == 0)
  74. h->first = icon;
  75. else
  76. h->last->next = icon;
  77. h->last = icon;
  78. }
  79. return 0;
  80. eof:
  81. werrstr("unexpected EOF");
  82. return -1;
  83. header:
  84. werrstr("unknown header format");
  85. return -1;
  86. }
  87. uchar*
  88. transcmap(Icon *icon, uchar *map)
  89. {
  90. uchar *m, *p;
  91. int i;
  92. p = m = malloc(sizeof(int)*(1<<icon->bits));
  93. for(i = 0; i < icon->ncolor; i++){
  94. *p++ = rgb2cmap(map[2], map[1], map[0]);
  95. map += 4;
  96. }
  97. return m;
  98. }
  99. Image*
  100. xor2img(Icon *icon, uchar *xor, uchar *map)
  101. {
  102. uchar *data;
  103. Image *img;
  104. int inxlen;
  105. uchar *from, *to;
  106. int s, byte, mask;
  107. int x, y;
  108. inxlen = 4*((icon->bits*icon->w+31)/32);
  109. to = data = malloc(icon->w*icon->h);
  110. /* rotate around the y axis, go to 8 bits, and convert color */
  111. mask = (1<<icon->bits)-1;
  112. for(y = 0; y < icon->h; y++){
  113. s = -1;
  114. byte = 0;
  115. from = xor + (icon->h - 1 - y)*inxlen;
  116. for(x = 0; x < icon->w; x++){
  117. if(s < 0){
  118. byte = *from++;
  119. s = 8-icon->bits;
  120. }
  121. *to++ = map[(byte>>s) & mask];
  122. s -= icon->bits;
  123. }
  124. }
  125. /* stick in an image */
  126. img = allocimage(display, Rect(0,0,icon->w,icon->h), CMAP8, 0, DNofill);
  127. loadimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*icon->w);
  128. free(data);
  129. return img;
  130. }
  131. Image*
  132. and2img(Icon *icon, uchar *and)
  133. {
  134. uchar *data;
  135. Image *img;
  136. int inxlen;
  137. int outxlen;
  138. uchar *from, *to;
  139. int x, y;
  140. inxlen = 4*((icon->w+31)/32);
  141. to = data = malloc(inxlen*icon->h);
  142. /* rotate around the y axis and invert bits */
  143. outxlen = (icon->w+7)/8;
  144. for(y = 0; y < icon->h; y++){
  145. from = and + (icon->h - 1 - y)*inxlen;
  146. for(x = 0; x < outxlen; x++){
  147. *to++ = ~(*from++);
  148. }
  149. }
  150. /* stick in an image */
  151. img = allocimage(display, Rect(0,0,icon->w,icon->h), GREY1, 0, DNofill);
  152. loadimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*outxlen);
  153. free(data);
  154. return img;
  155. }
  156. int
  157. Bgeticon(Biobuf *b, Icon *icon)
  158. {
  159. ulong l;
  160. ushort s;
  161. uchar *xor;
  162. uchar *and;
  163. uchar *cm;
  164. uchar *buf;
  165. uchar *map2map;
  166. Image *img;
  167. Bseek(b, icon->offset, 0);
  168. buf = malloc(icon->len);
  169. if(buf == nil)
  170. return -1;
  171. if(Bread(b, buf, icon->len) != icon->len){
  172. werrstr("unexpected EOF");
  173. return -1;
  174. }
  175. /* this header's info takes precedence over previous one */
  176. if(getl(buf) != 40){
  177. werrstr("bad icon header");
  178. return -1;
  179. }
  180. l = getl(buf+4);
  181. if(l != icon->w)
  182. icon->w = l;
  183. l = getl(buf+8);
  184. if(l>>1 != icon->h)
  185. icon->h = l>>1;
  186. s = gets(buf+12);
  187. if(s != icon->nplane)
  188. icon->nplane = s;
  189. s = gets(buf+14);
  190. if(s != icon->bits)
  191. icon->bits = s;
  192. /* limit what we handle */
  193. switch(icon->bits){
  194. case 1:
  195. case 2:
  196. case 4:
  197. case 8:
  198. break;
  199. default:
  200. werrstr("don't support %d bit pixels", icon->bits);
  201. return -1;
  202. }
  203. if(icon->nplane != 1){
  204. werrstr("don't support %d planes", icon->nplane);
  205. return -1;
  206. }
  207. cm = buf + 40;
  208. xor = cm + 4*icon->ncolor;
  209. and = xor + icon->h*4*((icon->bits*icon->w+31)/32);
  210. /* translate the color map to a plan 9 one */
  211. map2map = transcmap(icon, cm);
  212. /* convert the images */
  213. icon->img = xor2img(icon, xor, map2map);
  214. icon->mask = and2img(icon, and);
  215. /* so that we save an image with a white background */
  216. img = allocimage(display, icon->img->r, CMAP8, 0, DWhite);
  217. draw(img, icon->img->r, icon->img, icon->mask, ZP);
  218. icon->img = img;
  219. free(buf);
  220. free(map2map);
  221. return 0;
  222. }
  223. void
  224. usage(void)
  225. {
  226. fprint(2, "usage: %s [file]\n", argv0);
  227. exits("usage");
  228. }
  229. enum
  230. {
  231. Mimage,
  232. Mmask,
  233. Mexit,
  234. Up= 1,
  235. Down= 0,
  236. };
  237. char *menu3str[] = {
  238. [Mimage] "write image",
  239. [Mmask] "write mask",
  240. [Mexit] "exit",
  241. 0,
  242. };
  243. Menu menu3 = {
  244. menu3str
  245. };
  246. Cursor sight = {
  247. {-7, -7},
  248. {0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0xFB, 0xDF,
  249. 0xF3, 0xCF, 0xE3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF,
  250. 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC7, 0xF3, 0xCF,
  251. 0x7B, 0xDF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8,},
  252. {0x00, 0x00, 0x0F, 0xF0, 0x31, 0x8C, 0x21, 0x84,
  253. 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x7F, 0xFE,
  254. 0x7F, 0xFE, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82,
  255. 0x21, 0x84, 0x31, 0x8C, 0x0F, 0xF0, 0x00, 0x00,}
  256. };
  257. void
  258. buttons(int ud)
  259. {
  260. while((mouse.buttons==0) != ud)
  261. mouse = emouse();
  262. }
  263. void
  264. mesg(char *fmt, ...)
  265. {
  266. va_list arg;
  267. char buf[1024];
  268. static char obuf[1024];
  269. va_start(arg, fmt);
  270. vseprint(buf, buf+sizeof(buf), fmt, arg);
  271. va_end(arg);
  272. string(screen, screen->r.min, background, ZP, font, obuf);
  273. string(screen, screen->r.min, display->white, ZP, font, buf);
  274. strcpy(obuf, buf);
  275. }
  276. void
  277. doimage(Icon *icon)
  278. {
  279. int rv;
  280. char file[256];
  281. int fd;
  282. rv = -1;
  283. snprint(file, sizeof(file), "%dx%d.img", icon->w, icon->h);
  284. fd = create(file, OWRITE, 0664);
  285. if(fd >= 0){
  286. rv = writeimage(fd, icon->img, 0);
  287. close(fd);
  288. }
  289. if(rv < 0)
  290. mesg("error writing %s: %r", file);
  291. else
  292. mesg("created %s", file);
  293. }
  294. void
  295. domask(Icon *icon)
  296. {
  297. int rv;
  298. char file[64];
  299. int fd;
  300. rv = -1;
  301. snprint(file, sizeof(file), "%dx%d.mask", icon->w, icon->h);
  302. fd = create(file, OWRITE, 0664);
  303. if(fd >= 0){
  304. rv = writeimage(fd, icon->mask, 0);
  305. close(fd);
  306. }
  307. if(rv < 0)
  308. mesg("error writing %s: %r", file);
  309. else
  310. mesg("created %s", file);
  311. }
  312. void
  313. apply(void (*f)(Icon*))
  314. {
  315. Icon *icon;
  316. esetcursor(&sight);
  317. buttons(Down);
  318. if(mouse.buttons == 4)
  319. for(icon = h.first; icon; icon = icon->next)
  320. if(ptinrect(mouse.xy, icon->sr)){
  321. buttons(Up);
  322. f(icon);
  323. break;
  324. }
  325. buttons(Up);
  326. esetcursor(0);
  327. }
  328. void
  329. menu(void)
  330. {
  331. int sel;
  332. sel = emenuhit(3, &mouse, &menu3);
  333. switch(sel){
  334. case Mimage:
  335. apply(doimage);
  336. break;
  337. case Mmask:
  338. apply(domask);
  339. break;
  340. case Mexit:
  341. exits(0);
  342. break;
  343. }
  344. }
  345. void
  346. mousemoved(void)
  347. {
  348. Icon *icon;
  349. for(icon = h.first; icon; icon = icon->next)
  350. if(ptinrect(mouse.xy, icon->sr)){
  351. mesg("%dx%d", icon->w, icon->h);
  352. return;
  353. }
  354. mesg("");
  355. }
  356. enum
  357. {
  358. BORDER= 1,
  359. };
  360. void
  361. eresized(int new)
  362. {
  363. Icon *icon;
  364. Rectangle r;
  365. if(new && getwindow(display, Refnone) < 0)
  366. sysfatal("can't reattach to window");
  367. draw(screen, screen->clipr, background, nil, ZP);
  368. r.max.x = screen->r.min.x;
  369. r.min.y = screen->r.min.y + font->height + 2*BORDER;
  370. for(icon = h.first; icon != nil; icon = icon->next){
  371. r.min.x = r.max.x + BORDER;
  372. r.max.x = r.min.x + Dx(icon->img->r);
  373. r.max.y = r.min.y + Dy(icon->img->r);
  374. draw(screen, r, icon->img, nil, ZP);
  375. border(screen, r, -BORDER, display->black, ZP);
  376. icon->sr = r;
  377. }
  378. flushimage(display, 1);
  379. }
  380. void
  381. main(int argc, char **argv)
  382. {
  383. Biobuf in;
  384. Icon *icon;
  385. int num, fd;
  386. Rectangle r;
  387. Event e;
  388. ARGBEGIN{
  389. case 'd':
  390. debug = 1;
  391. break;
  392. }ARGEND;
  393. fd = -1;
  394. switch(argc){
  395. case 0:
  396. fd = 0;
  397. break;
  398. case 1:
  399. fd = open(argv[0], OREAD);
  400. if(fd < 0)
  401. sysfatal("opening: %r");
  402. break;
  403. default:
  404. usage();
  405. break;
  406. }
  407. Binit(&in, fd, OREAD);
  408. if(Bgetheader(&in, &h) < 0)
  409. sysfatal("reading header: %r");
  410. initdraw(nil, nil, "ico");
  411. background = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, (128<<24)|(128<<16)|(128<<8)|0xFF);
  412. einit(Emouse|Ekeyboard);
  413. num = 0;
  414. r.min = Pt(4, 4);
  415. for(icon = h.first; icon != nil; icon = icon->next){
  416. if(Bgeticon(&in, icon) < 0){
  417. fprint(2, "%s: read fail: %r\n", argv0);
  418. continue;
  419. }
  420. if(debug)
  421. fprint(2, "w %ud h %ud ncolor %ud bits %ud len %lud offset %lud\n",
  422. icon->w, icon->h, icon->ncolor, icon->bits, icon->len, icon->offset);
  423. r.max = addpt(r.min, Pt(icon->w, icon->h));
  424. icon->r = r;
  425. r.min.x += r.max.x;
  426. num++;
  427. }
  428. if(num == 0)
  429. exits("no images");
  430. eresized(0);
  431. for(;;)
  432. switch(event(&e)){
  433. case Ekeyboard:
  434. break;
  435. case Emouse:
  436. mouse = e.mouse;
  437. if(mouse.buttons & 4)
  438. menu();
  439. else
  440. mousemoved();
  441. break;
  442. }
  443. /* not reached */
  444. }