Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
rpng-x.c
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------
2 
3  rpng - simple PNG display program rpng-x.c
4 
5  This program decodes and displays PNG images, with gamma correction and
6  optionally with a user-specified background color (in case the image has
7  transparency). It is very nearly the most basic PNG viewer possible.
8  This version is for the X Window System (tested by author under Unix and
9  by Martin Zinser under OpenVMS; may work under OS/2 with some tweaking).
10 
11  to do:
12  - 8-bit (colormapped) X support
13  - use %.1023s to simplify truncation of title-bar string?
14 
15  ---------------------------------------------------------------------------
16 
17  Changelog:
18  - 1.01: initial public release
19  - 1.02: modified to allow abbreviated options; fixed long/ulong mis-
20  match; switched to png_jmpbuf() macro
21  - 1.10: added support for non-default visuals; fixed X pixel-conversion
22  - 1.11: added extra set of parentheses to png_jmpbuf() macro; fixed
23  command-line parsing bug
24  - 1.12: fixed some small X memory leaks (thanks to François Petitjean)
25  - 1.13: fixed XFreeGC() crash bug (thanks to Patrick Welche)
26  - 1.14: added support for X resources (thanks to Gerhard Niklasch)
27  - 2.00: dual-licensed (added GNU GPL)
28  - 2.01: fixed improper display of usage screen on PNG error(s)
29 
30  ---------------------------------------------------------------------------
31 
32  Copyright (c) 1998-2008 Greg Roelofs. All rights reserved.
33 
34  This software is provided "as is," without warranty of any kind,
35  express or implied. In no event shall the author or contributors
36  be held liable for any damages arising in any way from the use of
37  this software.
38 
39  The contents of this file are DUAL-LICENSED. You may modify and/or
40  redistribute this software according to the terms of one of the
41  following two licenses (at your option):
42 
43 
44  LICENSE 1 ("BSD-like with advertising clause"):
45 
46  Permission is granted to anyone to use this software for any purpose,
47  including commercial applications, and to alter it and redistribute
48  it freely, subject to the following restrictions:
49 
50  1. Redistributions of source code must retain the above copyright
51  notice, disclaimer, and this list of conditions.
52  2. Redistributions in binary form must reproduce the above copyright
53  notice, disclaimer, and this list of conditions in the documenta-
54  tion and/or other materials provided with the distribution.
55  3. All advertising materials mentioning features or use of this
56  software must display the following acknowledgment:
57 
58  This product includes software developed by Greg Roelofs
59  and contributors for the book, "PNG: The Definitive Guide,"
60  published by O'Reilly and Associates.
61 
62 
63  LICENSE 2 (GNU GPL v2 or later):
64 
65  This program is free software; you can redistribute it and/or modify
66  it under the terms of the GNU General Public License as published by
67  the Free Software Foundation; either version 2 of the License, or
68  (at your option) any later version.
69 
70  This program is distributed in the hope that it will be useful,
71  but WITHOUT ANY WARRANTY; without even the implied warranty of
72  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
73  GNU General Public License for more details.
74 
75  You should have received a copy of the GNU General Public License
76  along with this program; if not, write to the Free Software Foundation,
77  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
78 
79  ---------------------------------------------------------------------------*/
80 
81 #define PROGNAME "rpng-x"
82 #define LONGNAME "Simple PNG Viewer for X"
83 #define VERSION "2.01 of 16 March 2008"
84 #define RESNAME "rpng" /* our X resource application name */
85 #define RESCLASS "Rpng" /* our X resource class name */
86 
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include <string.h>
90 #include <time.h>
91 #include <X11/Xlib.h>
92 #include <X11/Xutil.h>
93 #include <X11/Xos.h>
94 #include <X11/keysym.h>
95 
96 /* #define DEBUG : this enables the Trace() macros */
97 
98 #include "readpng.h" /* typedefs, common macros, readpng prototypes */
99 
100 
101 /* could just include png.h, but this macro is the only thing we need
102  * (name and typedefs changed to local versions); note that side effects
103  * only happen with alpha (which could easily be avoided with
104  * "ush acopy = (alpha);") */
105 
106 #define alpha_composite(composite, fg, alpha, bg) { \
107  ush temp = ((ush)(fg)*(ush)(alpha) + \
108  (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \
109  (composite) = (uch)((temp + (temp >> 8)) >> 8); \
110 }
111 
112 
113 /* local prototypes */
114 static int rpng_x_create_window(void);
115 static int rpng_x_display_image(void);
116 static void rpng_x_cleanup(void);
117 static int rpng_x_msb(ulg u32val);
118 
119 
120 static char titlebar[1024], *window_name = titlebar;
121 static char *appname = LONGNAME;
122 static char *icon_name = PROGNAME;
123 static char *res_name = RESNAME;
124 static char *res_class = RESCLASS;
125 static char *filename;
126 static FILE *infile;
127 
128 static char *bgstr;
129 static uch bg_red=0, bg_green=0, bg_blue=0;
130 
131 static double display_exponent;
132 
133 static ulg image_width, image_height, image_rowbytes;
134 static int image_channels;
135 static uch *image_data;
136 
137 /* X-specific variables */
138 static char *displayname;
139 static XImage *ximage;
140 static Display *display;
141 static int depth;
142 static Visual *visual;
143 static XVisualInfo *visual_list;
144 static int RShift, GShift, BShift;
145 static ulg RMask, GMask, BMask;
146 static Window window;
147 static GC gc;
148 static Colormap colormap;
149 
150 static int have_nondefault_visual = FALSE;
151 static int have_colormap = FALSE;
152 static int have_window = FALSE;
153 static int have_gc = FALSE;
154 /*
155 ulg numcolors=0, pixels[256];
156 ush reds[256], greens[256], blues[256];
157  */
158 
159 
160 
161 
162 int main(int argc, char **argv)
163 {
164 #ifdef sgi
165  char tmpline[80];
166 #endif
167  char *p;
168  int rc, alen, flen;
169  int error = 0;
170  int have_bg = FALSE;
171  double LUT_exponent; /* just the lookup table */
172  double CRT_exponent = 2.2; /* just the monitor */
173  double default_display_exponent; /* whole display system */
174  XEvent e;
175  KeySym k;
176 
177 
178  displayname = (char *)NULL;
179  filename = (char *)NULL;
180 
181 
182  /* First set the default value for our display-system exponent, i.e.,
183  * the product of the CRT exponent and the exponent corresponding to
184  * the frame-buffer's lookup table (LUT), if any. This is not an
185  * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
186  * ones), but it should cover 99% of the current possibilities. */
187 
188 #if defined(NeXT)
189  LUT_exponent = 1.0 / 2.2;
190  /*
191  if (some_next_function_that_returns_gamma(&next_gamma))
192  LUT_exponent = 1.0 / next_gamma;
193  */
194 #elif defined(sgi)
195  LUT_exponent = 1.0 / 1.7;
196  /* there doesn't seem to be any documented function to get the
197  * "gamma" value, so we do it the hard way */
198  infile = fopen("/etc/config/system.glGammaVal", "r");
199  if (infile) {
200  double sgi_gamma;
201 
202  fgets(tmpline, 80, infile);
203  fclose(infile);
204  sgi_gamma = atof(tmpline);
205  if (sgi_gamma > 0.0)
206  LUT_exponent = 1.0 / sgi_gamma;
207  }
208 #elif defined(Macintosh)
209  LUT_exponent = 1.8 / 2.61;
210  /*
211  if (some_mac_function_that_returns_gamma(&mac_gamma))
212  LUT_exponent = mac_gamma / 2.61;
213  */
214 #else
215  LUT_exponent = 1.0; /* assume no LUT: most PCs */
216 #endif
217 
218  /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
219  default_display_exponent = LUT_exponent * CRT_exponent;
220 
221 
222  /* If the user has set the SCREEN_GAMMA environment variable as suggested
223  * (somewhat imprecisely) in the libpng documentation, use that; otherwise
224  * use the default value we just calculated. Either way, the user may
225  * override this via a command-line option. */
226 
227  if ((p = getenv("SCREEN_GAMMA")) != NULL)
228  display_exponent = atof(p);
229  else
230  display_exponent = default_display_exponent;
231 
232 
233  /* Now parse the command line for options and the PNG filename. */
234 
235  while (*++argv && !error) {
236  if (!strncmp(*argv, "-display", 2)) {
237  if (!*++argv)
238  ++error;
239  else
240  displayname = *argv;
241  } else if (!strncmp(*argv, "-gamma", 2)) {
242  if (!*++argv)
243  ++error;
244  else {
245  display_exponent = atof(*argv);
246  if (display_exponent <= 0.0)
247  ++error;
248  }
249  } else if (!strncmp(*argv, "-bgcolor", 2)) {
250  if (!*++argv)
251  ++error;
252  else {
253  bgstr = *argv;
254  if (strlen(bgstr) != 7 || bgstr[0] != '#')
255  ++error;
256  else
257  have_bg = TRUE;
258  }
259  } else {
260  if (**argv != '-') {
261  filename = *argv;
262  if (argv[1]) /* shouldn't be any more args after filename */
263  ++error;
264  } else
265  ++error; /* not expecting any other options */
266  }
267  }
268 
269  if (!filename)
270  ++error;
271 
272 
273  /* print usage screen if any errors up to this point */
274 
275  if (error) {
276  fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname);
278  fprintf(stderr, "\n"
279  "Usage: %s [-display xdpy] [-gamma exp] [-bgcolor bg] file.png\n"
280  " xdpy\tname of the target X display (e.g., ``hostname:0'')\n"
281  " exp \ttransfer-function exponent (``gamma'') of the display\n"
282  "\t\t system in floating-point format (e.g., ``%.1f''); equal\n"
283  "\t\t to the product of the lookup-table exponent (varies)\n"
284  "\t\t and the CRT exponent (usually 2.2); must be positive\n"
285  " bg \tdesired background color in 7-character hex RGB format\n"
286  "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n"
287  "\t\t used with transparent images\n"
288  "\nPress Q, Esc or mouse button 1 (within image window, after image\n"
289  "is displayed) to quit.\n"
290  "\n", PROGNAME, default_display_exponent);
291  exit(1);
292  }
293 
294 
295  if (!(infile = fopen(filename, "rb"))) {
296  fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename);
297  ++error;
298  } else {
299  if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) {
300  switch (rc) {
301  case 1:
302  fprintf(stderr, PROGNAME
303  ": [%s] is not a PNG file: incorrect signature\n",
304  filename);
305  break;
306  case 2:
307  fprintf(stderr, PROGNAME
308  ": [%s] has bad IHDR (libpng longjmp)\n", filename);
309  break;
310  case 4:
311  fprintf(stderr, PROGNAME ": insufficient memory\n");
312  break;
313  default:
314  fprintf(stderr, PROGNAME
315  ": unknown readpng_init() error\n");
316  break;
317  }
318  ++error;
319  } else {
320  display = XOpenDisplay(displayname);
321  if (!display) {
323  fprintf(stderr, PROGNAME ": can't open X display [%s]\n",
324  displayname? displayname : "default");
325  ++error;
326  }
327  }
328  if (error)
329  fclose(infile);
330  }
331 
332 
333  if (error) {
334  fprintf(stderr, PROGNAME ": aborting.\n");
335  exit(2);
336  }
337 
338 
339  /* set the title-bar string, but make sure buffer doesn't overflow */
340 
341  alen = strlen(appname);
342  flen = strlen(filename);
343  if (alen + flen + 3 > 1023)
344  sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023));
345  else
346  sprintf(titlebar, "%s: %s", appname, filename);
347 
348 
349  /* if the user didn't specify a background color on the command line,
350  * check for one in the PNG file--if not, the initialized values of 0
351  * (black) will be used */
352 
353  if (have_bg) {
354  unsigned r, g, b; /* this approach quiets compiler warnings */
355 
356  sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
357  bg_red = (uch)r;
358  bg_green = (uch)g;
359  bg_blue = (uch)b;
360  } else if (readpng_get_bgcolor(&bg_red, &bg_green, &bg_blue) > 1) {
362  fprintf(stderr, PROGNAME
363  ": libpng error while checking for background color\n");
364  exit(2);
365  }
366 
367 
368  /* do the basic X initialization stuff, make the window and fill it
369  * with the background color */
370 
371  if (rpng_x_create_window())
372  exit(2);
373 
374 
375  /* decode the image, all at once */
376 
377  Trace((stderr, "calling readpng_get_image()\n"))
378  image_data = readpng_get_image(display_exponent, &image_channels,
379  &image_rowbytes);
380  Trace((stderr, "done with readpng_get_image()\n"))
381 
382 
383  /* done with PNG file, so clean up to minimize memory usage (but do NOT
384  * nuke image_data!) */
385 
387  fclose(infile);
388 
389  if (!image_data) {
390  fprintf(stderr, PROGNAME ": unable to decode PNG image\n");
391  exit(3);
392  }
393 
394 
395  /* display image (composite with background if requested) */
396 
397  Trace((stderr, "calling rpng_x_display_image()\n"))
398  if (rpng_x_display_image()) {
399  free(image_data);
400  exit(4);
401  }
402  Trace((stderr, "done with rpng_x_display_image()\n"))
403 
404 
405  /* wait for the user to tell us when to quit */
406 
407  printf(
408  "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n");
409  fflush(stdout);
410 
411  do
412  XNextEvent(display, &e);
413  while (!(e.type == ButtonPress && e.xbutton.button == Button1) &&
414  !(e.type == KeyPress && /* v--- or 1 for shifted keys */
415  ((k = XLookupKeysym(&e.xkey, 0)) == XK_q || k == XK_Escape) ));
416 
417 
418  /* OK, we're done: clean up all image and X resources and go away */
419 
420  rpng_x_cleanup();
421 
422  return 0;
423 }
424 
425 
426 
427 
428 
429 static int rpng_x_create_window(void)
430 {
431  uch *xdata;
432  int need_colormap = FALSE;
433  int screen, pad;
434  ulg bg_pixel = 0L;
435  ulg attrmask;
436  Window root;
437  XEvent e;
438  XGCValues gcvalues;
439  XSetWindowAttributes attr;
440  XTextProperty windowName, *pWindowName = &windowName;
441  XTextProperty iconName, *pIconName = &iconName;
442  XVisualInfo visual_info;
443  XSizeHints *size_hints;
444  XWMHints *wm_hints;
445  XClassHint *class_hints;
446 
447 
448  screen = DefaultScreen(display);
449  depth = DisplayPlanes(display, screen);
450  root = RootWindow(display, screen);
451 
452 #ifdef DEBUG
453  XSynchronize(display, True);
454 #endif
455 
456 #if 0
457 /* GRR: add 8-bit support */
458  if (/* depth != 8 && */ depth != 16 && depth != 24 && depth != 32) {
459  fprintf(stderr,
460  "screen depth %d not supported (only 16-, 24- or 32-bit TrueColor)\n",
461  depth);
462  return 2;
463  }
464 
465  XMatchVisualInfo(display, screen, depth,
466  (depth == 8)? PseudoColor : TrueColor, &visual_info);
467  visual = visual_info.visual;
468 #else
469  if (depth != 16 && depth != 24 && depth != 32) {
470  int visuals_matched = 0;
471 
472  Trace((stderr, "default depth is %d: checking other visuals\n",
473  depth))
474 
475  /* 24-bit first */
476  visual_info.screen = screen;
477  visual_info.depth = 24;
478  visual_list = XGetVisualInfo(display,
479  VisualScreenMask | VisualDepthMask, &visual_info, &visuals_matched);
480  if (visuals_matched == 0) {
481 /* GRR: add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */
482  fprintf(stderr, "default screen depth %d not supported, and no"
483  " 24-bit visuals found\n", depth);
484  return 2;
485  }
486  Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n",
487  visuals_matched))
488  visual = visual_list[0].visual;
489  depth = visual_list[0].depth;
490 /*
491  colormap_size = visual_list[0].colormap_size;
492  visual_class = visual->class;
493  visualID = XVisualIDFromVisual(visual);
494  */
495  have_nondefault_visual = TRUE;
496  need_colormap = TRUE;
497  } else {
498  XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info);
499  visual = visual_info.visual;
500  }
501 #endif
502 
503  RMask = visual->red_mask;
504  GMask = visual->green_mask;
505  BMask = visual->blue_mask;
506 
507 /* GRR: add/check 8-bit support */
508  if (depth == 8 || need_colormap) {
509  colormap = XCreateColormap(display, root, visual, AllocNone);
510  if (!colormap) {
511  fprintf(stderr, "XCreateColormap() failed\n");
512  return 2;
513  }
514  have_colormap = TRUE;
515  }
516  if (depth == 15 || depth == 16) {
517  RShift = 15 - rpng_x_msb(RMask); /* these are right-shifts */
518  GShift = 15 - rpng_x_msb(GMask);
519  BShift = 15 - rpng_x_msb(BMask);
520  } else if (depth > 16) {
521 #define NO_24BIT_MASKS
522 #ifdef NO_24BIT_MASKS
523  RShift = rpng_x_msb(RMask) - 7; /* these are left-shifts */
524  GShift = rpng_x_msb(GMask) - 7;
525  BShift = rpng_x_msb(BMask) - 7;
526 #else
527  RShift = 7 - rpng_x_msb(RMask); /* these are right-shifts, too */
528  GShift = 7 - rpng_x_msb(GMask);
529  BShift = 7 - rpng_x_msb(BMask);
530 #endif
531  }
532  if (depth >= 15 && (RShift < 0 || GShift < 0 || BShift < 0)) {
533  fprintf(stderr, "rpng internal logic error: negative X shift(s)!\n");
534  return 2;
535  }
536 
537 /*---------------------------------------------------------------------------
538  Finally, create the window.
539  ---------------------------------------------------------------------------*/
540 
541  attr.backing_store = Always;
542  attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask;
543  attrmask = CWBackingStore | CWEventMask;
544  if (have_nondefault_visual) {
545  attr.colormap = colormap;
546  attr.background_pixel = 0;
547  attr.border_pixel = 1;
548  attrmask |= CWColormap | CWBackPixel | CWBorderPixel;
549  }
550 
551  window = XCreateWindow(display, root, 0, 0, image_width, image_height, 0,
552  depth, InputOutput, visual, attrmask, &attr);
553 
554  if (window == None) {
555  fprintf(stderr, "XCreateWindow() failed\n");
556  return 2;
557  } else
558  have_window = TRUE;
559 
560  if (depth == 8)
561  XSetWindowColormap(display, window, colormap);
562 
563  if (!XStringListToTextProperty(&window_name, 1, pWindowName))
564  pWindowName = NULL;
565  if (!XStringListToTextProperty(&icon_name, 1, pIconName))
566  pIconName = NULL;
567 
568  /* OK if any hints allocation fails; XSetWMProperties() allows NULLs */
569 
570  if ((size_hints = XAllocSizeHints()) != NULL) {
571  /* window will not be resizable */
572  size_hints->flags = PMinSize | PMaxSize;
573  size_hints->min_width = size_hints->max_width = (int)image_width;
574  size_hints->min_height = size_hints->max_height = (int)image_height;
575  }
576 
577  if ((wm_hints = XAllocWMHints()) != NULL) {
578  wm_hints->initial_state = NormalState;
579  wm_hints->input = True;
580  /* wm_hints->icon_pixmap = icon_pixmap; */
581  wm_hints->flags = StateHint | InputHint /* | IconPixmapHint */ ;
582  }
583 
584  if ((class_hints = XAllocClassHint()) != NULL) {
585  class_hints->res_name = res_name;
586  class_hints->res_class = res_class;
587  }
588 
589  XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0,
590  size_hints, wm_hints, class_hints);
591 
592  /* various properties and hints no longer needed; free memory */
593  if (pWindowName)
594  XFree(pWindowName->value);
595  if (pIconName)
596  XFree(pIconName->value);
597  if (size_hints)
598  XFree(size_hints);
599  if (wm_hints)
600  XFree(wm_hints);
601  if (class_hints)
602  XFree(class_hints);
603 
604  XMapWindow(display, window);
605 
606  gc = XCreateGC(display, window, 0, &gcvalues);
607  have_gc = TRUE;
608 
609 /*---------------------------------------------------------------------------
610  Fill window with the specified background color.
611  ---------------------------------------------------------------------------*/
612 
613  if (depth == 24 || depth == 32) {
614  bg_pixel = ((ulg)bg_red << RShift) |
615  ((ulg)bg_green << GShift) |
616  ((ulg)bg_blue << BShift);
617  } else if (depth == 16) {
618  bg_pixel = ((((ulg)bg_red << 8) >> RShift) & RMask) |
619  ((((ulg)bg_green << 8) >> GShift) & GMask) |
620  ((((ulg)bg_blue << 8) >> BShift) & BMask);
621  } else /* depth == 8 */ {
622 
623  /* GRR: add 8-bit support */
624 
625  }
626 
627  XSetForeground(display, gc, bg_pixel);
628  XFillRectangle(display, window, gc, 0, 0, image_width, image_height);
629 
630 /*---------------------------------------------------------------------------
631  Wait for first Expose event to do any drawing, then flush.
632  ---------------------------------------------------------------------------*/
633 
634  do
635  XNextEvent(display, &e);
636  while (e.type != Expose || e.xexpose.count);
637 
638  XFlush(display);
639 
640 /*---------------------------------------------------------------------------
641  Allocate memory for the X- and display-specific version of the image.
642  ---------------------------------------------------------------------------*/
643 
644  if (depth == 24 || depth == 32) {
645  xdata = (uch *)malloc(4*image_width*image_height);
646  pad = 32;
647  } else if (depth == 16) {
648  xdata = (uch *)malloc(2*image_width*image_height);
649  pad = 16;
650  } else /* depth == 8 */ {
651  xdata = (uch *)malloc(image_width*image_height);
652  pad = 8;
653  }
654 
655  if (!xdata) {
656  fprintf(stderr, PROGNAME ": unable to allocate image memory\n");
657  return 4;
658  }
659 
660  ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
661  (char *)xdata, image_width, image_height, pad, 0);
662 
663  if (!ximage) {
664  fprintf(stderr, PROGNAME ": XCreateImage() failed\n");
665  free(xdata);
666  return 3;
667  }
668 
669  /* to avoid testing the byte order every pixel (or doubling the size of
670  * the drawing routine with a giant if-test), we arbitrarily set the byte
671  * order to MSBFirst and let Xlib worry about inverting things on little-
672  * endian machines (like Linux/x86, old VAXen, etc.)--this is not the most
673  * efficient approach (the giant if-test would be better), but in the
674  * interest of clarity, we take the easy way out... */
675 
676  ximage->byte_order = MSBFirst;
677 
678  return 0;
679 
680 } /* end function rpng_x_create_window() */
681 
682 
683 
684 
685 
686 static int rpng_x_display_image(void)
687 {
688  uch *src;
689  char *dest;
690  uch r, g, b, a;
691  ulg i, row, lastrow = 0;
692  ulg pixel;
693  int ximage_rowbytes = ximage->bytes_per_line;
694 /* int bpp = ximage->bits_per_pixel; */
695 
696 
697  Trace((stderr, "beginning display loop (image_channels == %d)\n",
698  image_channels))
699  Trace((stderr, " (width = %ld, rowbytes = %ld, ximage_rowbytes = %d)\n",
700  image_width, image_rowbytes, ximage_rowbytes))
701  Trace((stderr, " (bpp = %d)\n", ximage->bits_per_pixel))
702  Trace((stderr, " (byte_order = %s)\n", ximage->byte_order == MSBFirst?
703  "MSBFirst" : (ximage->byte_order == LSBFirst? "LSBFirst" : "unknown")))
704 
705  if (depth == 24 || depth == 32) {
706  ulg red, green, blue;
707 
708  for (lastrow = row = 0; row < image_height; ++row) {
709  src = image_data + row*image_rowbytes;
710  dest = ximage->data + row*ximage_rowbytes;
711  if (image_channels == 3) {
712  for (i = image_width; i > 0; --i) {
713  red = *src++;
714  green = *src++;
715  blue = *src++;
716 #ifdef NO_24BIT_MASKS
717  pixel = (red << RShift) |
718  (green << GShift) |
719  (blue << BShift);
720  /* recall that we set ximage->byte_order = MSBFirst above */
721  /* GRR BUG: this assumes bpp == 32, but may be 24: */
722  *dest++ = (char)((pixel >> 24) & 0xff);
723  *dest++ = (char)((pixel >> 16) & 0xff);
724  *dest++ = (char)((pixel >> 8) & 0xff);
725  *dest++ = (char)( pixel & 0xff);
726 #else
727  red = (RShift < 0)? red << (-RShift) : red >> RShift;
728  green = (GShift < 0)? green << (-GShift) : green >> GShift;
729  blue = (BShift < 0)? blue << (-BShift) : blue >> BShift;
730  pixel = (red & RMask) | (green & GMask) | (blue & BMask);
731  /* recall that we set ximage->byte_order = MSBFirst above */
732  *dest++ = (char)((pixel >> 24) & 0xff);
733  *dest++ = (char)((pixel >> 16) & 0xff);
734  *dest++ = (char)((pixel >> 8) & 0xff);
735  *dest++ = (char)( pixel & 0xff);
736 #endif
737  }
738  } else /* if (image_channels == 4) */ {
739  for (i = image_width; i > 0; --i) {
740  r = *src++;
741  g = *src++;
742  b = *src++;
743  a = *src++;
744  if (a == 255) {
745  red = r;
746  green = g;
747  blue = b;
748  } else if (a == 0) {
749  red = bg_red;
750  green = bg_green;
751  blue = bg_blue;
752  } else {
753  /* this macro (from png.h) composites the foreground
754  * and background values and puts the result into the
755  * first argument */
756  alpha_composite(red, r, a, bg_red);
757  alpha_composite(green, g, a, bg_green);
758  alpha_composite(blue, b, a, bg_blue);
759  }
760  pixel = (red << RShift) |
761  (green << GShift) |
762  (blue << BShift);
763  /* recall that we set ximage->byte_order = MSBFirst above */
764  *dest++ = (char)((pixel >> 24) & 0xff);
765  *dest++ = (char)((pixel >> 16) & 0xff);
766  *dest++ = (char)((pixel >> 8) & 0xff);
767  *dest++ = (char)( pixel & 0xff);
768  }
769  }
770  /* display after every 16 lines */
771  if (((row+1) & 0xf) == 0) {
772  XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
773  (int)lastrow, image_width, 16);
774  XFlush(display);
775  lastrow = row + 1;
776  }
777  }
778 
779  } else if (depth == 16) {
780  ush red, green, blue;
781 
782  for (lastrow = row = 0; row < image_height; ++row) {
783  src = image_data + row*image_rowbytes;
784  dest = ximage->data + row*ximage_rowbytes;
785  if (image_channels == 3) {
786  for (i = image_width; i > 0; --i) {
787  red = ((ush)(*src) << 8);
788  ++src;
789  green = ((ush)(*src) << 8);
790  ++src;
791  blue = ((ush)(*src) << 8);
792  ++src;
793  pixel = ((red >> RShift) & RMask) |
794  ((green >> GShift) & GMask) |
795  ((blue >> BShift) & BMask);
796  /* recall that we set ximage->byte_order = MSBFirst above */
797  *dest++ = (char)((pixel >> 8) & 0xff);
798  *dest++ = (char)( pixel & 0xff);
799  }
800  } else /* if (image_channels == 4) */ {
801  for (i = image_width; i > 0; --i) {
802  r = *src++;
803  g = *src++;
804  b = *src++;
805  a = *src++;
806  if (a == 255) {
807  red = ((ush)r << 8);
808  green = ((ush)g << 8);
809  blue = ((ush)b << 8);
810  } else if (a == 0) {
811  red = ((ush)bg_red << 8);
812  green = ((ush)bg_green << 8);
813  blue = ((ush)bg_blue << 8);
814  } else {
815  /* this macro (from png.h) composites the foreground
816  * and background values and puts the result back into
817  * the first argument (== fg byte here: safe) */
818  alpha_composite(r, r, a, bg_red);
819  alpha_composite(g, g, a, bg_green);
820  alpha_composite(b, b, a, bg_blue);
821  red = ((ush)r << 8);
822  green = ((ush)g << 8);
823  blue = ((ush)b << 8);
824  }
825  pixel = ((red >> RShift) & RMask) |
826  ((green >> GShift) & GMask) |
827  ((blue >> BShift) & BMask);
828  /* recall that we set ximage->byte_order = MSBFirst above */
829  *dest++ = (char)((pixel >> 8) & 0xff);
830  *dest++ = (char)( pixel & 0xff);
831  }
832  }
833  /* display after every 16 lines */
834  if (((row+1) & 0xf) == 0) {
835  XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
836  (int)lastrow, image_width, 16);
837  XFlush(display);
838  lastrow = row + 1;
839  }
840  }
841 
842  } else /* depth == 8 */ {
843 
844  /* GRR: add 8-bit support */
845 
846  }
847 
848  Trace((stderr, "calling final XPutImage()\n"))
849  if (lastrow < image_height) {
850  XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
851  (int)lastrow, image_width, image_height-lastrow);
852  XFlush(display);
853  }
854 
855  return 0;
856 }
857 
858 
859 
860 
861 static void rpng_x_cleanup(void)
862 {
863  if (image_data) {
864  free(image_data);
865  image_data = NULL;
866  }
867 
868  if (ximage) {
869  if (ximage->data) {
870  free(ximage->data); /* we allocated it, so we free it */
871  ximage->data = (char *)NULL; /* instead of XDestroyImage() */
872  }
873  XDestroyImage(ximage);
874  ximage = NULL;
875  }
876 
877  if (have_gc)
878  XFreeGC(display, gc);
879 
880  if (have_window)
881  XDestroyWindow(display, window);
882 
883  if (have_colormap)
884  XFreeColormap(display, colormap);
885 
886  if (have_nondefault_visual)
887  XFree(visual_list);
888 }
889 
890 
891 
892 
893 
894 static int rpng_x_msb(ulg u32val)
895 {
896  int i;
897 
898  for (i = 31; i >= 0; --i) {
899  if (u32val & 0x80000000L)
900  break;
901  u32val <<= 1;
902  }
903  return i;
904 }
#define LONGNAME
Definition: rpng-x.c:82
GLboolean GLboolean GLboolean GLboolean a
GLfloat GLfloat p
GLint GLint GLsizei GLsizei GLsizei depth
#define NULL
Definition: ftobjs.h:61
#define MSBFirst
Definition: pcf.h:169
char * malloc()
const char * filename
Definition: ioapi.h:135
GLfloat green
unsigned long ulg
Definition: zutil.h:38
GLboolean GLboolean GLboolean b
int main(int argc, char **argv)
Definition: rpng-x.c:162
int image_height
png_uint_32 i
Definition: png.h:2640
#define PROGNAME
Definition: rpng-x.c:81
#define alpha_composite(composite, fg, alpha, bg)
Definition: rpng-x.c:106
GLenum GLenum GLvoid * row
GLfloat GLfloat blue
#define LSBFirst
Definition: pcf.h:168
unsigned short ush
Definition: zutil.h:36
uch * image_data
Definition: readpng.c:73
FT_Error error
Definition: cffdrivr.c:411
#define VERSION
Definition: rpng-x.c:83
GLdouble GLdouble GLdouble r
uch * readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes)
Definition: readpng.c:206
int free()
local int root
Definition: enough.c:171
GLenum src
#define FALSE
Definition: ftobjs.h:57
#define Trace(x)
Definition: zutil.h:197
void readpng_version_info(void)
Definition: readpng.c:76
typedef int
Definition: png.h:978
#define RESCLASS
Definition: rpng-x.c:85
FILE * infile
Definition: cdjpeg.h:141
GLboolean GLboolean g
#define RESNAME
Definition: rpng-x.c:84
int readpng_get_bgcolor(uch *red, uch *green, uch *blue)
Definition: readpng.c:154
int double red
Definition: png.h:1498
void readpng_cleanup(int free_image_data)
Definition: readpng.c:296
int image_width
int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight)
Definition: readpng.c:87
#define TRUE
Definition: ftobjs.h:53
unsigned char uch
Definition: zutil.h:34