/release/picobsd/tinyware/view/view.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 619 lines · 555 code · 25 blank · 39 comment · 80 complexity · e1c62641a128cd2d8fcffd517e937798 MD5 · raw file

  1. /*-
  2. * Copyright (c) 1998 Andrzej Bialecki
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. * SUCH DAMAGE.
  25. *
  26. * $FreeBSD$
  27. */
  28. /*
  29. * Small PNG viewer with scripting abilities
  30. */
  31. #include <stdio.h>
  32. #include <errno.h>
  33. #include <fcntl.h>
  34. #include <signal.h>
  35. #include <termios.h>
  36. #include <sys/types.h>
  37. #include <sys/fbio.h>
  38. #include <sys/consio.h>
  39. #include <sys/mouse.h>
  40. #include <vgl.h>
  41. #include <png.h>
  42. #define NUMBER 8
  43. extern char *optarg;
  44. extern int optind;
  45. /* Prototypes */
  46. int kbd_action(int x, int y, char hotkey);
  47. struct action {
  48. int zoom;
  49. int rotate;
  50. int Xshift,Yshift;
  51. };
  52. struct menu_item {
  53. char *descr;
  54. char hotkey;
  55. int (*func)(int x, int y, char hotkey);
  56. };
  57. struct menu_item std_menu[]= {
  58. {"q Quit",'q',kbd_action},
  59. {"n Next",'n',kbd_action},
  60. {"p Previous",'p',kbd_action},
  61. {"Z Zoom in",'Z',kbd_action},
  62. {"z Zoom out",'z',kbd_action},
  63. {"r Rotate",'r',kbd_action},
  64. {"R Refresh",'R',kbd_action},
  65. {"l Left",'l',kbd_action},
  66. {"h Right",'h',kbd_action},
  67. {"j Up",'j',kbd_action},
  68. {"k Down",'k',kbd_action},
  69. {NULL,0,NULL}
  70. };
  71. char *progname;
  72. VGLBitmap pic,bkg;
  73. struct action a;
  74. byte pal_red[256];
  75. byte pal_green[256];
  76. byte pal_blue[256];
  77. byte pal_colors;
  78. double screen_gamma;
  79. int max_screen_colors=15;
  80. int quit,changed;
  81. char **pres;
  82. int nimg=0;
  83. int auto_chg=0;
  84. int cur_img=0;
  85. char act;
  86. FILE *log;
  87. void
  88. usage()
  89. {
  90. fprintf(stderr,"\nVGL graphics viewer, 1.0 (c) Andrzej Bialecki.\n");
  91. fprintf(stderr,"\nUsage:\n");
  92. fprintf(stderr,"\t%s [-r n] [-g n.n] filename\n",progname);
  93. fprintf(stderr,"\nwhere:\n");
  94. fprintf(stderr,"\t-r n\tchoose resolution:\n");
  95. fprintf(stderr,"\t\t0 - 640x480x16 (default)\n");
  96. fprintf(stderr,"\t\t1 - 640x200x256\n");
  97. fprintf(stderr,"\t\t2 - 320x240x256\n");
  98. fprintf(stderr,"\t-g n.n\tset screen gamma (1.3 by default)\n");
  99. fprintf(stderr,"\n");
  100. }
  101. int
  102. pop_up(char *title,int x, int y)
  103. {
  104. VGLBitmap sav,clr;
  105. int x1,y1,width,height,i,j;
  106. int last_pos,cur_pos,max_item;
  107. char buttons;
  108. char *t;
  109. sav.Type=VGLDisplay->Type;
  110. clr.Type=VGLDisplay->Type;
  111. width=0;
  112. height=0;
  113. max_item=0;
  114. i=0;
  115. while(std_menu[i].descr!=NULL) {
  116. height++;
  117. max_item++;
  118. if(strlen(std_menu[i].descr)>width) width=strlen(std_menu[i].descr);
  119. i++;
  120. }
  121. width=width*8+2;
  122. height=height*9+4+8;
  123. sav.Xsize=width;
  124. sav.Ysize=height;
  125. clr.Xsize=width;
  126. clr.Ysize=height;
  127. sav.Bitmap=(byte *)calloc(width*height,1);
  128. clr.Bitmap=(byte *)calloc(width*height,1);
  129. if(x>(VGLDisplay->Xsize-width)) x1=VGLDisplay->Xsize-width;
  130. else x1=x;
  131. if(y>(VGLDisplay->Ysize-height)) y1=VGLDisplay->Ysize-height;
  132. else y1=y;
  133. VGLMouseMode(VGL_MOUSEHIDE);
  134. VGLBitmapCopy(VGLDisplay,x1,y1,&sav,0,0,width,height);
  135. VGLFilledBox(VGLDisplay,x1,y1,x1+width-1,y1+height-1,pal_colors-1);
  136. VGLBitmapString(VGLDisplay,x1+1,y1+1,title,0,pal_colors-1,0,0);
  137. VGLLine(VGLDisplay,x1,y1+9,x1+width,y1+9,0);
  138. i=0;
  139. while(std_menu[i].descr!=NULL) {
  140. VGLBitmapString(VGLDisplay,x1+1,y1+11+i*9,std_menu[i].descr,0,pal_colors-1,0,0);
  141. i++;
  142. }
  143. last_pos=-1;
  144. VGLMouseMode(VGL_MOUSESHOW);
  145. do {
  146. pause();
  147. VGLMouseStatus(&x,&y,&buttons);
  148. cur_pos=(y-y1-11)/9;
  149. if((cur_pos<0)||(cur_pos>max_item-1)) {
  150. if(last_pos==-1) last_pos=0;
  151. VGLBitmapString(VGLDisplay,x1+1,y1+11+last_pos*9,std_menu[last_pos].descr,0,pal_colors-1,0,0);
  152. last_pos=-1;
  153. } else if(last_pos!=cur_pos) {
  154. if(last_pos==-1) last_pos=0;
  155. VGLBitmapString(VGLDisplay,x1+1,y1+11+last_pos*9,std_menu[last_pos].descr,0,pal_colors-1,0,0);
  156. VGLBitmapString(VGLDisplay,x1+1,y1+11+cur_pos*9,std_menu[cur_pos].descr,pal_colors/2+1,pal_colors-1,0,0);
  157. last_pos=cur_pos;
  158. }
  159. } while (buttons & MOUSE_BUTTON3DOWN);
  160. VGLMouseMode(VGL_MOUSEHIDE);
  161. /* XXX Screws up totally when r==3. Libvgl bug! */
  162. VGLBitmapCopy(&clr,0,0,VGLDisplay,x1,y1,width,height);
  163. VGLBitmapCopy(&sav,0,0,VGLDisplay,x1,y1,width,height);
  164. VGLMouseMode(VGL_MOUSESHOW);
  165. free(sav.Bitmap);
  166. free(clr.Bitmap);
  167. changed++;
  168. if((cur_pos>=0) && (cur_pos<max_item)) {
  169. std_menu[cur_pos].func(x,y,std_menu[cur_pos].hotkey);
  170. }
  171. changed++;
  172. return(0);
  173. }
  174. void
  175. display( VGLBitmap *pic,
  176. byte *red,
  177. byte *green,
  178. byte *blue,
  179. struct action *e)
  180. {
  181. VGLBitmap target;
  182. int x,y,i=0,j=0;
  183. VGLMouseMode(VGL_MOUSEHIDE);
  184. VGLRestorePalette();
  185. /* XXX Broken in r!=2. Libvgl bug. */
  186. //VGLClear(VGLDisplay,0);
  187. VGLBitmapCopy(&bkg,0,0,VGLDisplay,0,0,bkg.Xsize,bkg.Ysize);
  188. if(e!=NULL) {
  189. if(e->zoom!=1 || e->rotate) {
  190. target.Bitmap=(byte *)calloc(pic->Xsize*pic->Ysize*e->zoom*e->zoom,1);
  191. if(e->rotate) {
  192. target.Xsize=pic->Ysize*e->zoom;
  193. target.Ysize=pic->Xsize*e->zoom;
  194. } else {
  195. target.Xsize=pic->Xsize*e->zoom;
  196. target.Ysize=pic->Ysize*e->zoom;
  197. }
  198. target.Type=pic->Type;
  199. for(x=0;x<pic->Xsize;x++) {
  200. for(y=0;y<pic->Ysize;y++) {
  201. for(i=0;i<e->zoom;i++) {
  202. for(j=0;j<e->zoom;j++) {
  203. if(e->rotate) {
  204. VGLSetXY(&target,target.Xsize-(e->zoom*y+i),e->zoom*x+j,VGLGetXY(pic,x,y));
  205. } else {
  206. VGLSetXY(&target,e->zoom*x+i,e->zoom*y+j,VGLGetXY(pic,x,y));
  207. }
  208. }
  209. }
  210. }
  211. }
  212. } else {
  213. target.Bitmap=(byte *)calloc(pic->Xsize*pic->Ysize,sizeof(byte));
  214. target.Xsize=pic->Xsize;
  215. target.Ysize=pic->Ysize;
  216. target.Type=pic->Type;
  217. VGLBitmapCopy(pic,0,0,&target,0,0,pic->Xsize,pic->Ysize);
  218. }
  219. } else {
  220. target.Bitmap=(byte *)calloc(pic->Xsize*pic->Ysize,sizeof(byte));
  221. target.Xsize=pic->Xsize;
  222. target.Ysize=pic->Ysize;
  223. target.Type=pic->Type;
  224. VGLBitmapCopy(pic,0,0,&target,0,0,pic->Xsize,pic->Ysize);
  225. }
  226. VGLSetPalette(red, green, blue);
  227. if(e!=NULL) {
  228. VGLBitmapCopy(&target,0,0,VGLDisplay,e->Xshift,e->Yshift,target.Xsize,target.Ysize);
  229. } else {
  230. VGLBitmapCopy(&target,0,0,VGLDisplay,0,0,target.Xsize,target.Ysize);
  231. }
  232. VGLMouseMode(VGL_MOUSESHOW);
  233. free(target.Bitmap);
  234. }
  235. int
  236. png_load(char *filename)
  237. {
  238. int i,j,k;
  239. FILE *fd;
  240. u_char header[NUMBER];
  241. png_structp png_ptr;
  242. png_infop info_ptr,end_info;
  243. png_uint_32 width,height;
  244. int bit_depth,color_type,interlace_type;
  245. int compression_type,filter_type;
  246. int channels,rowbytes;
  247. double gamma;
  248. png_colorp palette;
  249. int num_palette;
  250. png_bytep *row_pointers;
  251. char c;
  252. int res=0;
  253. fd=fopen(filename,"rb");
  254. if(fd==NULL) {
  255. VGLEnd();
  256. perror("fopen");
  257. exit(1);
  258. }
  259. fread(header,1,NUMBER,fd);
  260. if(!png_check_sig(header,NUMBER)) {
  261. fprintf(stderr,"Not a PNG file.\n");
  262. return(-1);
  263. }
  264. png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING,(void *)NULL,
  265. NULL,NULL);
  266. info_ptr=png_create_info_struct(png_ptr);
  267. end_info=png_create_info_struct(png_ptr);
  268. if(!png_ptr || !info_ptr || !end_info) {
  269. VGLEnd();
  270. fprintf(stderr,"failed to allocate needed structs!\n");
  271. png_destroy_read_struct(&png_ptr,&info_ptr,&end_info);
  272. return(-1);
  273. }
  274. png_set_sig_bytes(png_ptr,NUMBER);
  275. png_init_io(png_ptr,fd);
  276. png_read_info(png_ptr,info_ptr);
  277. png_get_IHDR(png_ptr,info_ptr,&width,&height,&bit_depth,
  278. &color_type,&interlace_type,&compression_type,&filter_type);
  279. png_get_PLTE(png_ptr,info_ptr,&palette,&num_palette);
  280. channels=png_get_channels(png_ptr,info_ptr);
  281. rowbytes=png_get_rowbytes(png_ptr,info_ptr);
  282. if(bit_depth==16)
  283. png_set_strip_16(png_ptr);
  284. if(color_type & PNG_COLOR_MASK_ALPHA)
  285. png_set_strip_alpha(png_ptr);
  286. if(png_get_gAMA(png_ptr,info_ptr,&gamma))
  287. png_set_gamma(png_ptr,screen_gamma,gamma);
  288. else
  289. png_set_gamma(png_ptr,screen_gamma,0.45);
  290. if(res==0) {
  291. /* Dither */
  292. if(color_type & PNG_COLOR_MASK_COLOR) {
  293. if(png_get_valid(png_ptr,info_ptr,PNG_INFO_PLTE)) {
  294. png_uint_16p histogram;
  295. png_get_hIST(png_ptr,info_ptr,&histogram);
  296. png_set_dither(png_ptr,palette,num_palette,max_screen_colors,histogram,0);
  297. } else {
  298. png_color std_color_cube[16]={
  299. {0x00,0x00,0x00},
  300. {0x02,0x02,0x02},
  301. {0x04,0x04,0x04},
  302. {0x06,0x06,0x06},
  303. {0x08,0x08,0x08},
  304. {0x0a,0x0a,0x0a},
  305. {0x0c,0x0c,0x0c},
  306. {0x0e,0x0e,0x0e},
  307. {0x10,0x10,0x10},
  308. {0x12,0x12,0x12},
  309. {0x14,0x14,0x14},
  310. {0x16,0x16,0x16},
  311. {0x18,0x18,0x18},
  312. {0x1a,0x1a,0x1a},
  313. {0x1d,0x1d,0x1d},
  314. {0xff,0xff,0xff},
  315. };
  316. png_set_dither(png_ptr,std_color_cube,max_screen_colors,max_screen_colors,NULL,0);
  317. }
  318. }
  319. }
  320. png_set_packing(png_ptr);
  321. if(png_get_valid(png_ptr,info_ptr,PNG_INFO_sBIT)) {
  322. png_color_8p sig_bit;
  323. png_get_sBIT(png_ptr,info_ptr,&sig_bit);
  324. png_set_shift(png_ptr,sig_bit);
  325. }
  326. png_read_update_info(png_ptr,info_ptr);
  327. png_get_IHDR(png_ptr,info_ptr,&width,&height,&bit_depth,
  328. &color_type,&interlace_type,&compression_type,&filter_type);
  329. png_get_PLTE(png_ptr,info_ptr,&palette,&num_palette);
  330. channels=png_get_channels(png_ptr,info_ptr);
  331. rowbytes=png_get_rowbytes(png_ptr,info_ptr);
  332. row_pointers=malloc(height*sizeof(png_bytep));
  333. for(i=0;i<height;i++) {
  334. row_pointers[i]=malloc(rowbytes);
  335. }
  336. png_read_image(png_ptr,row_pointers);
  337. png_read_end(png_ptr,end_info);
  338. png_destroy_read_struct(&png_ptr,&info_ptr,&end_info);
  339. fclose(fd);
  340. /* Set palette */
  341. if(res) k=2;
  342. else k=2;
  343. for(i=0;i<256;i++) {
  344. pal_red[i]=255;
  345. pal_green[i]=255;
  346. pal_blue[i]=255;
  347. }
  348. for(i=0;i<num_palette;i++) {
  349. pal_red[i]=(palette+i)->red>>k;
  350. pal_green[i]=(palette+i)->green>>k;
  351. pal_blue[i]=(palette+i)->blue>>k;
  352. }
  353. pal_colors=num_palette;
  354. if(pic.Bitmap!=NULL) free(pic.Bitmap);
  355. pic.Bitmap=(byte *)calloc(rowbytes*height,sizeof(byte));
  356. pic.Type=MEMBUF;
  357. pic.Xsize=rowbytes;
  358. pic.Ysize=height;
  359. for(i=0;i<rowbytes;i++) {
  360. for(j=0;j<height;j++) {
  361. VGLSetXY(&pic,
  362. i,j,row_pointers[j][i]);
  363. }
  364. }
  365. a.zoom=1;
  366. a.Xshift=(VGLDisplay->Xsize-pic.Xsize)/2;
  367. a.Yshift=(VGLDisplay->Ysize-pic.Ysize)/2;
  368. a.rotate=0;
  369. return(0);
  370. }
  371. void
  372. kbd_handler(int sig)
  373. {
  374. u_char buf[10];
  375. int res;
  376. res=read(0,&buf,10);
  377. changed++;
  378. act=buf[res-1];
  379. }
  380. int
  381. kbd_action(int x, int y, char key)
  382. {
  383. changed=0;
  384. if(key!='n') auto_chg=0;
  385. switch(key) {
  386. case 'q':
  387. quit=1;
  388. break;
  389. case 'Z':
  390. a.zoom++;
  391. changed++;
  392. break;
  393. case 'z':
  394. a.zoom--;
  395. if(a.zoom<1) a.zoom=1;
  396. changed++;
  397. break;
  398. case 'l':
  399. a.Xshift+=VGLDisplay->Xsize/5;
  400. changed++;
  401. break;
  402. case 'h':
  403. a.Xshift-=VGLDisplay->Xsize/5;
  404. changed++;
  405. break;
  406. case 'k':
  407. a.Yshift+=VGLDisplay->Ysize/5;
  408. changed++;
  409. break;
  410. case 'j':
  411. a.Yshift-=VGLDisplay->Ysize/5;
  412. changed++;
  413. break;
  414. case 'R':
  415. changed++;
  416. break;
  417. case 'r':
  418. if(a.rotate) a.rotate=0;
  419. else a.rotate=1;
  420. changed++;
  421. break;
  422. case '\n':
  423. case 'n':
  424. if(nimg>0) {
  425. if(cur_img<nimg-1) {
  426. cur_img++;
  427. } else {
  428. cur_img=0;
  429. }
  430. png_load(pres[cur_img]);
  431. changed++;
  432. }
  433. break;
  434. case 'p':
  435. if(nimg>0) {
  436. if(cur_img>0) {
  437. cur_img--;
  438. } else {
  439. cur_img=nimg-1;
  440. }
  441. png_load(pres[cur_img]);
  442. changed++;
  443. }
  444. break;
  445. }
  446. act=0;
  447. }
  448. int
  449. main(int argc, char *argv[])
  450. {
  451. int i,j,k;
  452. char c;
  453. int res=0;
  454. int x,y;
  455. char buttons;
  456. struct termios t_new,t_old;
  457. FILE *fsc;
  458. char buf[100];
  459. progname=argv[0];
  460. screen_gamma=1.5;
  461. #ifdef DEBUG
  462. log=fopen("/png/view.log","w");
  463. #endif
  464. while((c=getopt(argc,argv,"r:g:"))!=-1) {
  465. switch(c) {
  466. case 'r':
  467. res=atoi(optarg);
  468. if(res>0) max_screen_colors=256;
  469. break;
  470. case 'g':
  471. screen_gamma=atof(optarg);
  472. break;
  473. case '?':
  474. default:
  475. usage();
  476. exit(0);
  477. }
  478. }
  479. switch(res) {
  480. case 0:
  481. VGLInit(SW_CG640x480);
  482. break;
  483. case 1:
  484. VGLInit(SW_VGA_CG320);
  485. break;
  486. case 2:
  487. VGLInit(SW_VGA_MODEX);
  488. break;
  489. default:
  490. fprintf(stderr,"No such resolution!\n");
  491. usage();
  492. exit(-1);
  493. }
  494. #ifdef DEBUG
  495. fprintf(log,"VGL initialised\n");
  496. #endif
  497. VGLSavePalette();
  498. if(argc>optind) {
  499. res=png_load(argv[optind]);
  500. } else {
  501. VGLEnd();
  502. usage();
  503. exit(0);
  504. }
  505. if(res) {
  506. /* Hmm... Script? */
  507. fsc=fopen(argv[optind],"r");
  508. #ifdef DEBUG
  509. fprintf(log,"Trying script %s\n",argv[optind]);
  510. #endif
  511. fgets(buf,99,fsc);
  512. buf[strlen(buf)-1]='\0';
  513. if(strncmp("VIEW SCRIPT",buf,11)!=NULL) {
  514. VGLEnd();
  515. usage();
  516. }
  517. if(strlen(buf)>12) {
  518. auto_chg=atoi(buf+12);
  519. }
  520. fgets(buf,99,fsc);
  521. buf[strlen(buf)-1]='\0';
  522. nimg=atoi(buf);
  523. if(nimg==0) {
  524. VGLEnd();
  525. usage();
  526. }
  527. pres=(char **)calloc(nimg,sizeof(char *));
  528. for(i=0;i<nimg;i++) {
  529. fgets(buf,99,fsc);
  530. buf[strlen(buf)-1]='\0';
  531. pres[i]=strdup(buf);
  532. }
  533. fclose(fsc);
  534. cur_img=0;
  535. #ifdef DEBUG
  536. fprintf(log,"Script with %d entries\n",nimg);
  537. #endif
  538. png_load(pres[cur_img]);
  539. }
  540. VGLMouseInit(VGL_MOUSEHIDE);
  541. /* Prepare the keyboard */
  542. tcgetattr(0,&t_old);
  543. memcpy(&t_new,&t_old,sizeof(struct termios));
  544. cfmakeraw(&t_new);
  545. tcsetattr(0,TCSAFLUSH,&t_new);
  546. fcntl(0,F_SETFL,O_ASYNC);
  547. /* XXX VGLClear doesn't work.. :-(( Prepare a blank background */
  548. bkg.Bitmap=(byte *)calloc(VGLDisplay->Xsize*VGLDisplay->Ysize,1);
  549. bkg.Xsize=VGLDisplay->Xsize;
  550. bkg.Ysize=VGLDisplay->Ysize;
  551. bkg.Type=VGLDisplay->Type;
  552. signal(SIGIO,kbd_handler);
  553. a.zoom=1;
  554. a.Xshift=(VGLDisplay->Xsize-pic.Xsize)/2;
  555. a.Yshift=(VGLDisplay->Ysize-pic.Ysize)/2;
  556. a.rotate=0;
  557. quit=0;
  558. changed=0;
  559. display(&pic,pal_red,pal_green,pal_blue,&a);
  560. while(!quit) {
  561. if(act) {
  562. #ifdef DEBUG
  563. fprintf(log,"kbd_action(%c)\n",act);
  564. #endif
  565. kbd_action(x,y,act);
  566. }
  567. if(quit) break;
  568. if(changed) {
  569. #ifdef DEBUG
  570. fprintf(log,"changed, redisplaying\n");
  571. #endif
  572. display(&pic,pal_red,pal_green,pal_blue,&a);
  573. changed=0;
  574. }
  575. if(auto_chg) {
  576. sleep(auto_chg);
  577. kbd_action(x,y,'n');
  578. } else {
  579. pause();
  580. }
  581. VGLMouseStatus(&x,&y,&buttons);
  582. if(buttons & MOUSE_BUTTON3DOWN) {
  583. #ifdef DEBUG
  584. fprintf(log,"pop_up called\n");
  585. #endif
  586. pop_up("View",x,y);
  587. }
  588. }
  589. VGLEnd();
  590. #ifdef DEBUG
  591. fclose(log);
  592. #endif
  593. exit(0);
  594. }