main.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /****************************************************************************
  2. *
  3. * MODULE: ximgview
  4. * AUTHOR(S): Glynn Clements
  5. * PURPOSE: View BMP images from the PNG driver
  6. * COPYRIGHT: (C) 2007 Glynn Clements
  7. *
  8. * This program is free software under the GNU General Public
  9. * License (>=v2). Read the file COPYING that comes with GRASS
  10. * for details.
  11. *
  12. *****************************************************************************/
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <unistd.h>
  16. #include <string.h>
  17. #include <signal.h>
  18. #include <errno.h>
  19. #include <unistd.h>
  20. #include <fcntl.h>
  21. #include <sys/mman.h>
  22. #include <sys/stat.h>
  23. #include <sys/time.h>
  24. #include <sys/types.h>
  25. #include <X11/Xlib.h>
  26. #include <X11/Xutil.h>
  27. #include <grass/gis.h>
  28. #include <grass/glocale.h>
  29. #define HEADER_SIZE 64
  30. Display *dpy;
  31. int scrn;
  32. Window grwin;
  33. XWindowAttributes xwa;
  34. static int evmask = ExposureMask | StructureNotifyMask;
  35. static int w_width, w_height;
  36. static int i_width, i_height;
  37. static unsigned long last;
  38. static double fraction;
  39. static void *imgbuf;
  40. static void *xbuf;
  41. static XImage *ximg;
  42. static GC gc;
  43. extern Colormap InitColorTableFixed(Colormap cmap);
  44. extern unsigned long find_color(unsigned int r, unsigned int g,
  45. unsigned int b);
  46. static void create_window(void)
  47. {
  48. XSetWindowAttributes xswa;
  49. Colormap fixedcmap;
  50. dpy = XOpenDisplay(NULL);
  51. if (!dpy)
  52. G_fatal_error(_("Unable to open display"));
  53. scrn = DefaultScreen(dpy);
  54. xswa.event_mask = evmask;
  55. xswa.backing_store = NotUseful;
  56. xswa.background_pixel = BlackPixel(dpy, scrn);
  57. grwin = XCreateWindow(dpy, RootWindow(dpy, scrn),
  58. 0, 0,
  59. 800, 600,
  60. 0,
  61. DefaultDepth(dpy, scrn),
  62. InputOutput,
  63. DefaultVisual(dpy, scrn),
  64. CWEventMask | CWBackingStore | CWBackPixel, &xswa);
  65. XMapWindow(dpy, grwin);
  66. if (!XGetWindowAttributes(dpy, grwin, &xwa))
  67. G_fatal_error(_("Unable to get window attributes"));
  68. fixedcmap = InitColorTableFixed(DefaultColormap(dpy, scrn));
  69. XSetWindowColormap(dpy, grwin, fixedcmap);
  70. gc = XCreateGC(dpy, grwin, 0UL, NULL);
  71. xbuf = G_malloc(i_width * i_height * 4);
  72. ximg = XCreateImage(dpy, xwa.visual, xwa.depth, ZPixmap,
  73. 0, xbuf, i_width, i_height, 32, 0);
  74. w_width = xwa.width;
  75. w_height = xwa.height;
  76. XFlush(dpy);
  77. }
  78. static void draw(void)
  79. {
  80. int x0 = (w_width - i_width) / 2;
  81. int y0 = (w_height - i_height) / 2;
  82. const unsigned char *p = imgbuf;
  83. int row, col;
  84. for (row = 0; row < i_height; row++) {
  85. for (col = 0; col < i_width; col++) {
  86. unsigned char b = *p++;
  87. unsigned char g = *p++;
  88. unsigned char r = *p++;
  89. unsigned char a = *p++;
  90. unsigned long c = find_color(r, g, b);
  91. XPutPixel(ximg, col, row, c);
  92. }
  93. }
  94. XPutImage(dpy, grwin, gc, ximg, 0, 0, x0, y0, i_width, i_height);
  95. XSync(dpy, False);
  96. }
  97. static void redraw(void)
  98. {
  99. struct timeval tv0, tv1;
  100. gettimeofday(&tv0, NULL);
  101. draw();
  102. gettimeofday(&tv1, NULL);
  103. last = (tv1.tv_sec - tv0.tv_sec) * 1000000L + (tv1.tv_usec - tv0.tv_usec);
  104. }
  105. static void dummy_handler(int sig)
  106. {
  107. }
  108. static void main_loop(void)
  109. {
  110. int xfd = ConnectionNumber(dpy);
  111. struct sigaction act;
  112. act.sa_handler = &dummy_handler;
  113. sigemptyset(&act.sa_mask);
  114. act.sa_flags = 0;
  115. sigaction(SIGUSR1, &act, NULL);
  116. for (;;) {
  117. fd_set waitset;
  118. struct timeval tv;
  119. unsigned long delay;
  120. while (XPending(dpy) > 0) {
  121. XEvent event;
  122. XNextEvent(dpy, &event);
  123. switch (event.type) {
  124. case Expose:
  125. draw();
  126. break;
  127. case ConfigureNotify:
  128. w_width = event.xconfigure.width;
  129. w_height = event.xconfigure.height;
  130. break;
  131. }
  132. }
  133. if (fraction > 0.001)
  134. delay = (unsigned long)(last / fraction);
  135. tv.tv_sec = delay / 1000000;
  136. tv.tv_usec = delay % 1000000;
  137. FD_ZERO(&waitset);
  138. FD_SET(xfd, &waitset);
  139. errno = 0;
  140. if (select(FD_SETSIZE, &waitset, NULL, NULL, &tv) < 0 && errno != EINTR)
  141. continue;
  142. if (!FD_ISSET(xfd, &waitset) || errno == EINTR)
  143. redraw();
  144. }
  145. }
  146. static unsigned int get_2(const unsigned char **q)
  147. {
  148. const unsigned char *p = *q;
  149. unsigned int n = (p[0] << 0) | (p[1] << 8);
  150. *q += 2;
  151. return n;
  152. }
  153. static unsigned int get_4(const unsigned char **q)
  154. {
  155. const unsigned char *p = *q;
  156. unsigned int n = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
  157. *q += 4;
  158. return n;
  159. }
  160. static int read_bmp_header(const unsigned char *p)
  161. {
  162. int size;
  163. if (*p++ != 'B')
  164. return 0;
  165. if (*p++ != 'M')
  166. return 0;
  167. size = get_4(&p);
  168. get_4(&p);
  169. if (get_4(&p) != HEADER_SIZE)
  170. return 0;
  171. if (get_4(&p) != 40)
  172. return 0;
  173. i_width = get_4(&p);
  174. i_height = -get_4(&p);
  175. get_2(&p);
  176. if (get_2(&p) != 32)
  177. return 0;
  178. if (get_4(&p) != 0)
  179. return 0;
  180. if (get_4(&p) != i_width * i_height * 4)
  181. return 0;
  182. if (size != HEADER_SIZE + i_width * i_height * 4)
  183. return 0;
  184. get_4(&p);
  185. get_4(&p);
  186. get_4(&p);
  187. get_4(&p);
  188. return 1;
  189. }
  190. static void map_file(const char *filename)
  191. {
  192. char header[HEADER_SIZE];
  193. size_t size;
  194. void *ptr;
  195. int fd;
  196. fd = open(filename, O_RDONLY);
  197. if (fd < 0)
  198. G_fatal_error(_("Unable to open image file"));
  199. if (read(fd, header, sizeof(header)) != sizeof(header))
  200. G_fatal_error(_("Unable to read BMP header"));
  201. if (!read_bmp_header(header))
  202. G_fatal_error(_("Invalid BMP header"));
  203. size = HEADER_SIZE + i_width * i_height * 4;
  204. ptr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, (off_t) 0);
  205. if (ptr == MAP_FAILED)
  206. G_fatal_error(_("Unable to map image file"));
  207. imgbuf = (char *)ptr + HEADER_SIZE;
  208. close(fd);
  209. }
  210. int main(int argc, char **argv)
  211. {
  212. struct GModule *module;
  213. struct
  214. {
  215. struct Option *image, *percent;
  216. } opt;
  217. const char *filename;
  218. int percent;
  219. G_gisinit(argv[0]);
  220. module = G_define_module();
  221. G_add_keyword(_("display"));
  222. module->description = _("View BMP images from the PNG driver.");
  223. opt.image = G_define_option();
  224. opt.image->key = "image";
  225. opt.image->type = TYPE_STRING;
  226. opt.image->required = YES;
  227. opt.image->multiple = NO;
  228. opt.image->gisprompt = "old_file,file,input";
  229. opt.image->description = _("Image file");
  230. opt.percent = G_define_option();
  231. opt.percent->key = "percent";
  232. opt.percent->type = TYPE_INTEGER;
  233. opt.percent->required = NO;
  234. opt.percent->multiple = NO;
  235. opt.percent->description = _("Percentage of CPU time to use");
  236. opt.percent->answer = "10";
  237. if (G_parser(argc, argv))
  238. exit(EXIT_FAILURE);
  239. filename = opt.image->answer;
  240. percent = atoi(opt.percent->answer);
  241. fraction = percent / 100.0;
  242. map_file(filename);
  243. create_window();
  244. main_loop();
  245. XCloseDisplay(dpy);
  246. return EXIT_SUCCESS;
  247. }