ico.c 11 KB

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