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]
rpng2-x.c
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------
2 
3  rpng2 - progressive-model PNG display program rpng2-x.c
4 
5  This program decodes and displays PNG files progressively, as if it were
6  a web browser (though the front end is only set up to read from files).
7  It supports gamma correction, user-specified background colors, and user-
8  specified background patterns (for transparent images). This version is
9  for the X Window System (tested by the author under Unix and by Martin
10  Zinser under OpenVMS; may work under OS/2 with a little tweaking).
11 
12  Thanks to Adam Costello and Pieter S. van der Meulen for the "diamond"
13  and "radial waves" patterns, respectively.
14 
15  to do (someday, maybe):
16  - fix expose/redraw code: don't draw entire row if only part exposed
17  - 8-bit (colormapped) X support
18  - finish resizable checkerboard-gradient (sizes 4-128?)
19  - use %.1023s to simplify truncation of title-bar string?
20 
21  ---------------------------------------------------------------------------
22 
23  Changelog:
24  - 1.01: initial public release
25  - 1.02: modified to allow abbreviated options; fixed char/uchar mismatch
26  - 1.10: added support for non-default visuals; fixed X pixel-conversion
27  - 1.11: added -usleep option for demos; fixed command-line parsing bug
28  - 1.12: added -pause option for demos and testing
29  - 1.20: added runtime MMX-enabling/disabling and new -mmx* options
30  - 1.21: fixed some small X memory leaks (thanks to François Petitjean)
31  - 1.22: fixed XFreeGC() crash bug (thanks to Patrick Welche)
32  - 1.23: added -bgpat 0 mode (std white/gray checkerboard, 8x8 squares)
33  - 1.30: added -loop option for -bgpat (ifdef FEATURE_LOOP); fixed bpp =
34  24; added support for X resources (thanks to Gerhard Niklasch)
35  - 1.31: added code to skip unused chunks (thanks to Glenn Randers-Pehrson)
36  - 1.32: added AMD64/EM64T support (__x86_64__); added basic expose/redraw
37  handling
38  - 2.00: dual-licensed (added GNU GPL)
39  - 2.01: fixed 64-bit typo in readpng2.c; fixed -pause usage description
40  - 2.02: fixed improper display of usage screen on PNG error(s); fixed
41  unexpected-EOF and file-read-error cases; fixed Trace() cut-and-
42  paste bugs
43 
44  ---------------------------------------------------------------------------
45 
46  Copyright (c) 1998-2008 Greg Roelofs. All rights reserved.
47 
48  This software is provided "as is," without warranty of any kind,
49  express or implied. In no event shall the author or contributors
50  be held liable for any damages arising in any way from the use of
51  this software.
52 
53  The contents of this file are DUAL-LICENSED. You may modify and/or
54  redistribute this software according to the terms of one of the
55  following two licenses (at your option):
56 
57 
58  LICENSE 1 ("BSD-like with advertising clause"):
59 
60  Permission is granted to anyone to use this software for any purpose,
61  including commercial applications, and to alter it and redistribute
62  it freely, subject to the following restrictions:
63 
64  1. Redistributions of source code must retain the above copyright
65  notice, disclaimer, and this list of conditions.
66  2. Redistributions in binary form must reproduce the above copyright
67  notice, disclaimer, and this list of conditions in the documenta-
68  tion and/or other materials provided with the distribution.
69  3. All advertising materials mentioning features or use of this
70  software must display the following acknowledgment:
71 
72  This product includes software developed by Greg Roelofs
73  and contributors for the book, "PNG: The Definitive Guide,"
74  published by O'Reilly and Associates.
75 
76 
77  LICENSE 2 (GNU GPL v2 or later):
78 
79  This program is free software; you can redistribute it and/or modify
80  it under the terms of the GNU General Public License as published by
81  the Free Software Foundation; either version 2 of the License, or
82  (at your option) any later version.
83 
84  This program is distributed in the hope that it will be useful,
85  but WITHOUT ANY WARRANTY; without even the implied warranty of
86  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
87  GNU General Public License for more details.
88 
89  You should have received a copy of the GNU General Public License
90  along with this program; if not, write to the Free Software Foundation,
91  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
92 
93  ---------------------------------------------------------------------------*/
94 
95 #define PROGNAME "rpng2-x"
96 #define LONGNAME "Progressive PNG Viewer for X"
97 #define VERSION "2.02 of 16 March 2008"
98 #define RESNAME "rpng2" /* our X resource application name */
99 #define RESCLASS "Rpng" /* our X resource class name */
100 
101 #include <stdio.h>
102 #include <stdlib.h>
103 #include <ctype.h>
104 #include <string.h>
105 #include <setjmp.h> /* for jmpbuf declaration in readpng2.h */
106 #include <time.h>
107 #include <math.h> /* only for PvdM background code */
108 #include <X11/Xlib.h>
109 #include <X11/Xutil.h>
110 #include <X11/Xos.h>
111 #include <X11/keysym.h> /* defines XK_* macros */
112 
113 #ifdef VMS
114 # include <unistd.h>
115 #endif
116 
117 /* all for PvdM background code: */
118 #ifndef PI
119 # define PI 3.141592653589793238
120 #endif
121 #define PI_2 (PI*0.5)
122 #define INV_PI_360 (360.0 / PI)
123 #define MAX(a,b) (a>b?a:b)
124 #define MIN(a,b) (a<b?a:b)
125 #define CLIP(a,min,max) MAX(min,MIN((a),max))
126 #define ABS(a) ((a)<0?-(a):(a))
127 #define CLIP8P(c) MAX(0,(MIN((c),255))) /* 8-bit pos. integer (uch) */
128 #define ROUNDF(f) ((int)(f + 0.5))
129 
130 #define QUIT(e,k) ((e.type == ButtonPress && e.xbutton.button == Button1) || \
131  (e.type == KeyPress && /* v--- or 1 for shifted keys */ \
132  ((k = XLookupKeysym(&e.xkey, 0)) == XK_q || k == XK_Escape)))
133 
134 #define NO_24BIT_MASKS /* undef case not fully written--only for redisplay() */
135 
136 #define rgb1_max bg_freq
137 #define rgb1_min bg_gray
138 #define rgb2_max bg_bsat
139 #define rgb2_min bg_brot
140 
141 /* #define DEBUG */ /* this enables the Trace() macros */
142 
143 #include "readpng2.h" /* typedefs, common macros, readpng2 prototypes */
144 
145 
146 /* could just include png.h, but this macro is the only thing we need
147  * (name and typedefs changed to local versions); note that side effects
148  * only happen with alpha (which could easily be avoided with
149  * "ush acopy = (alpha);") */
150 
151 #define alpha_composite(composite, fg, alpha, bg) { \
152  ush temp = ((ush)(fg)*(ush)(alpha) + \
153  (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \
154  (composite) = (uch)((temp + (temp >> 8)) >> 8); \
155 }
156 
157 
158 #define INBUFSIZE 4096 /* with pseudo-timing on (1 sec delay/block), this
159  * block size corresponds roughly to a download
160  * speed 10% faster than theoretical 33.6K maximum
161  * (assuming 8 data bits, 1 stop bit and no other
162  * overhead) */
163 
164 /* local prototypes */
165 static void rpng2_x_init (void);
166 static int rpng2_x_create_window (void);
167 static int rpng2_x_load_bg_image (void);
168 static void rpng2_x_display_row (ulg row);
169 static void rpng2_x_finish_display (void);
170 static void rpng2_x_redisplay_image (ulg startcol, ulg startrow,
171  ulg width, ulg height);
172 #ifdef FEATURE_LOOP
173 static void rpng2_x_reload_bg_image (void);
174 static int is_number (char *p);
175 #endif
176 static void rpng2_x_cleanup (void);
177 static int rpng2_x_msb (ulg u32val);
178 
179 
180 static char titlebar[1024], *window_name = titlebar;
181 static char *appname = LONGNAME;
182 static char *icon_name = PROGNAME;
183 static char *res_name = RESNAME;
184 static char *res_class = RESCLASS;
185 static char *filename;
186 static FILE *infile;
187 
188 static mainprog_info rpng2_info;
189 
190 static uch inbuf[INBUFSIZE];
191 static int incount;
192 
193 static int pat = 6; /* must be less than num_bgpat */
194 static int bg_image = 0;
195 static int bgscale, bgscale_default = 16;
196 static ulg bg_rowbytes;
197 static uch *bg_data;
198 
202 
203 static struct rgb_color {
204  uch r, g, b;
205 } rgb[] = {
206  { 0, 0, 0}, /* 0: black */
207  {255, 255, 255}, /* 1: white */
208  {173, 132, 57}, /* 2: tan */
209  { 64, 132, 0}, /* 3: medium green */
210  {189, 117, 1}, /* 4: gold */
211  {253, 249, 1}, /* 5: yellow */
212  { 0, 0, 255}, /* 6: blue */
213  { 0, 0, 120}, /* 7: medium blue */
214  {255, 0, 255}, /* 8: magenta */
215  { 64, 0, 64}, /* 9: dark magenta */
216  {255, 0, 0}, /* 10: red */
217  { 64, 0, 0}, /* 11: dark red */
218  {255, 127, 0}, /* 12: orange */
219  {192, 96, 0}, /* 13: darker orange */
220  { 24, 60, 0}, /* 14: dark green-yellow */
221  { 85, 125, 200}, /* 15: ice blue */
222  {192, 192, 192} /* 16: Netscape/Mosaic gray */
223 };
224 /* not used for now, but should be for error-checking:
225 static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color);
226  */
227 
228 /*
229  This whole struct is a fairly cheesy way to keep the number of
230  command-line options to a minimum. The radial-waves background
231  type is a particularly poor fit to the integer elements of the
232  struct...but a few macros and a little fixed-point math will do
233  wonders for ya.
234 
235  type bits:
236  F E D C B A 9 8 7 6 5 4 3 2 1 0
237  | | | | |
238  | | +-+-+-- 0 = sharp-edged checkerboard
239  | | 1 = soft diamonds
240  | | 2 = radial waves
241  | | 3-7 = undefined
242  | +-- gradient #2 inverted?
243  +-- alternating columns inverted?
244  */
245 static struct background_pattern {
246  ush type;
247  int rgb1_max, rgb1_min; /* or bg_freq, bg_gray */
248  int rgb2_max, rgb2_min; /* or bg_bsat, bg_brot (both scaled by 10)*/
249 } bg[] = {
250  {0, 1,1, 16,16}, /* checkered: white vs. light gray (basic) */
251  {0+8, 2,0, 1,15}, /* checkered: tan/black vs. white/ice blue */
252  {0+24, 2,0, 1,0}, /* checkered: tan/black vs. white/black */
253  {0+8, 4,5, 0,2}, /* checkered: gold/yellow vs. black/tan */
254  {0+8, 4,5, 0,6}, /* checkered: gold/yellow vs. black/blue */
255  {0, 7,0, 8,9}, /* checkered: deep blue/black vs. magenta */
256  {0+8, 13,0, 5,14}, /* checkered: orange/black vs. yellow */
257  {0+8, 12,0, 10,11}, /* checkered: orange/black vs. red */
258  {1, 7,0, 8,0}, /* diamonds: deep blue/black vs. magenta */
259  {1, 12,0, 11,0}, /* diamonds: orange vs. dark red */
260  {1, 10,0, 7,0}, /* diamonds: red vs. medium blue */
261  {1, 4,0, 5,0}, /* diamonds: gold vs. yellow */
262  {1, 3,0, 0,0}, /* diamonds: medium green vs. black */
263  {2, 16, 100, 20, 0}, /* radial: ~hard radial color-beams */
264  {2, 18, 100, 10, 2}, /* radial: soft, curved radial color-beams */
265  {2, 16, 256, 100, 250}, /* radial: very tight spiral */
266  {2, 10000, 256, 11, 0} /* radial: dipole-moire' (almost fractal) */
267 };
268 static int num_bgpat = sizeof(bg) / sizeof(struct background_pattern);
269 
270 
271 /* X-specific variables */
272 static char *displayname;
273 static XImage *ximage;
274 static Display *display;
275 static int depth;
276 static Visual *visual;
277 static XVisualInfo *visual_list;
278 static int RShift, GShift, BShift;
279 static ulg RMask, GMask, BMask;
280 static Window window;
281 static GC gc;
282 static Colormap colormap;
283 
284 static int have_nondefault_visual = FALSE;
285 static int have_colormap = FALSE;
286 static int have_window = FALSE;
287 static int have_gc = FALSE;
288 
289 
290 
291 
292 int main(int argc, char **argv)
293 {
294 #ifdef sgi
295  char tmpline[80];
296 #endif
297  char *p, *bgstr = NULL;
298  int rc, alen, flen;
299  int error = 0;
300  int timing = FALSE;
301  int have_bg = FALSE;
302 #ifdef FEATURE_LOOP
303  int loop = FALSE;
304  long loop_interval = -1; /* seconds (100,000 max) */
305 #endif
306  double LUT_exponent; /* just the lookup table */
307  double CRT_exponent = 2.2; /* just the monitor */
308  double default_display_exponent; /* whole display system */
309  XEvent e;
310  KeySym k;
311 
312 
313  /* First initialize a few things, just to be sure--memset takes care of
314  * default background color (black), booleans (FALSE), pointers (NULL),
315  * etc. */
316 
317  displayname = (char *)NULL;
318  filename = (char *)NULL;
319  memset(&rpng2_info, 0, sizeof(mainprog_info));
320 
321 
322  /* Set the default value for our display-system exponent, i.e., the
323  * product of the CRT exponent and the exponent corresponding to
324  * the frame-buffer's lookup table (LUT), if any. This is not an
325  * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
326  * ones), but it should cover 99% of the current possibilities. */
327 
328 #if defined(NeXT)
329  /* third-party utilities can modify the default LUT exponent */
330  LUT_exponent = 1.0 / 2.2;
331  /*
332  if (some_next_function_that_returns_gamma(&next_gamma))
333  LUT_exponent = 1.0 / next_gamma;
334  */
335 #elif defined(sgi)
336  LUT_exponent = 1.0 / 1.7;
337  /* there doesn't seem to be any documented function to
338  * get the "gamma" value, so we do it the hard way */
339  infile = fopen("/etc/config/system.glGammaVal", "r");
340  if (infile) {
341  double sgi_gamma;
342 
343  fgets(tmpline, 80, infile);
344  fclose(infile);
345  sgi_gamma = atof(tmpline);
346  if (sgi_gamma > 0.0)
347  LUT_exponent = 1.0 / sgi_gamma;
348  }
349 #elif defined(Macintosh)
350  LUT_exponent = 1.8 / 2.61;
351  /*
352  if (some_mac_function_that_returns_gamma(&mac_gamma))
353  LUT_exponent = mac_gamma / 2.61;
354  */
355 #else
356  LUT_exponent = 1.0; /* assume no LUT: most PCs */
357 #endif
358 
359  /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
360  default_display_exponent = LUT_exponent * CRT_exponent;
361 
362 
363  /* If the user has set the SCREEN_GAMMA environment variable as suggested
364  * (somewhat imprecisely) in the libpng documentation, use that; otherwise
365  * use the default value we just calculated. Either way, the user may
366  * override this via a command-line option. */
367 
368  if ((p = getenv("SCREEN_GAMMA")) != NULL)
369  rpng2_info.display_exponent = atof(p);
370  else
371  rpng2_info.display_exponent = default_display_exponent;
372 
373 
374  /* Now parse the command line for options and the PNG filename. */
375 
376  while (*++argv && !error) {
377  if (!strncmp(*argv, "-display", 2)) {
378  if (!*++argv)
379  ++error;
380  else
381  displayname = *argv;
382  } else if (!strncmp(*argv, "-gamma", 2)) {
383  if (!*++argv)
384  ++error;
385  else {
386  rpng2_info.display_exponent = atof(*argv);
387  if (rpng2_info.display_exponent <= 0.0)
388  ++error;
389  }
390  } else if (!strncmp(*argv, "-bgcolor", 4)) {
391  if (!*++argv)
392  ++error;
393  else {
394  bgstr = *argv;
395  if (strlen(bgstr) != 7 || bgstr[0] != '#')
396  ++error;
397  else {
398  have_bg = TRUE;
399  bg_image = FALSE;
400  }
401  }
402  } else if (!strncmp(*argv, "-bgpat", 4)) {
403  if (!*++argv)
404  ++error;
405  else {
406  pat = atoi(*argv);
407  if (pat >= 0 && pat < num_bgpat) {
408  bg_image = TRUE;
409  have_bg = FALSE;
410  } else
411  ++error;
412  }
413  } else if (!strncmp(*argv, "-usleep", 2)) {
414  if (!*++argv)
415  ++error;
416  else {
417  usleep_duration = (ulg)atol(*argv);
418  demo_timing = TRUE;
419  }
420  } else if (!strncmp(*argv, "-pause", 2)) {
422  } else if (!strncmp(*argv, "-timing", 2)) {
423  timing = TRUE;
424 #ifdef FEATURE_LOOP
425  } else if (!strncmp(*argv, "-loop", 2)) {
426  loop = TRUE;
427  if (!argv[1] || !is_number(argv[1]))
428  loop_interval = 2;
429  else {
430  ++argv;
431  loop_interval = atol(*argv);
432  if (loop_interval < 0)
433  loop_interval = 2;
434  else if (loop_interval > 100000) /* bit more than one day */
435  loop_interval = 100000;
436  }
437 #endif
438 #if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__))
439  } else if (!strncmp(*argv, "-nommxfilters", 7)) {
440  rpng2_info.nommxfilters = TRUE;
441  } else if (!strncmp(*argv, "-nommxcombine", 7)) {
442  rpng2_info.nommxcombine = TRUE;
443  } else if (!strncmp(*argv, "-nommxinterlace", 7)) {
444  rpng2_info.nommxinterlace = TRUE;
445  } else if (!strcmp(*argv, "-nommx")) {
446  rpng2_info.nommxfilters = TRUE;
447  rpng2_info.nommxcombine = TRUE;
448  rpng2_info.nommxinterlace = TRUE;
449 #endif
450  } else {
451  if (**argv != '-') {
452  filename = *argv;
453  if (argv[1]) /* shouldn't be any more args after filename */
454  ++error;
455  } else
456  ++error; /* not expecting any other options */
457  }
458  }
459 
460  if (!filename)
461  ++error;
462 
463 
464  /* print usage screen if any errors up to this point */
465 
466  if (error) {
467  fprintf(stderr, "\n%s %s: %s\n\n", PROGNAME, VERSION, appname);
469  fprintf(stderr, "\n"
470  "Usage: %s [-display xdpy] [-gamma exp] [-bgcolor bg | -bgpat pat]\n"
471 #if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__))
472  " %*s [[-nommxfilters] [-nommxcombine] [-nommxinterlace] | -nommx]\n"
473 #endif
474 #ifdef FEATURE_LOOP
475  " %*s [-usleep dur | -timing] [-pause] [-loop [sec]] file.png\n\n"
476 #else
477  " %*s [-usleep dur | -timing] [-pause] file.png\n\n"
478 #endif
479  " xdpy\tname of the target X display (e.g., ``hostname:0'')\n"
480  " exp \ttransfer-function exponent (``gamma'') of the display\n"
481  "\t\t system in floating-point format (e.g., ``%.1f''); equal\n"
482  "\t\t to the product of the lookup-table exponent (varies)\n"
483  "\t\t and the CRT exponent (usually 2.2); must be positive\n"
484  " bg \tdesired background color in 7-character hex RGB format\n"
485  "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n"
486  "\t\t used with transparent images; overrides -bgpat\n"
487  " pat \tdesired background pattern number (0-%d); used with\n"
488  "\t\t transparent images; overrides -bgcolor\n"
489 #ifdef FEATURE_LOOP
490  " -loop\tloops through background images after initial display\n"
491  "\t\t is complete (depends on -bgpat)\n"
492  " sec \tseconds to display each background image (default = 2)\n"
493 #endif
494 #if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__))
495  " -nommx*\tdisable optimized MMX routines for decoding row filters,\n"
496  "\t\t combining rows, and expanding interlacing, respectively\n"
497 #endif
498  " dur \tduration in microseconds to wait after displaying each\n"
499  "\t\t row (for demo purposes)\n"
500  " -timing\tenables delay for every block read, to simulate modem\n"
501  "\t\t download of image (~36 Kbps)\n"
502  " -pause\tpauses after displaying each pass until mouse clicked\n"
503  "\nPress Q, Esc or mouse button 1 (within image window, after image\n"
504  "is displayed) to quit.\n"
505  "\n", PROGNAME,
506 #if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__))
507  (int)strlen(PROGNAME), " ",
508 #endif
509  (int)strlen(PROGNAME), " ", default_display_exponent, num_bgpat-1);
510  exit(1);
511  }
512 
513 
514  if (!(infile = fopen(filename, "rb"))) {
515  fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename);
516  ++error;
517  } else {
518  incount = fread(inbuf, 1, INBUFSIZE, infile);
519  if (incount < 8 || !readpng2_check_sig(inbuf, 8)) {
520  fprintf(stderr, PROGNAME
521  ": [%s] is not a PNG file: incorrect signature\n",
522  filename);
523  ++error;
524  } else if ((rc = readpng2_init(&rpng2_info)) != 0) {
525  switch (rc) {
526  case 2:
527  fprintf(stderr, PROGNAME
528  ": [%s] has bad IHDR (libpng longjmp)\n", filename);
529  break;
530  case 4:
531  fprintf(stderr, PROGNAME ": insufficient memory\n");
532  break;
533  default:
534  fprintf(stderr, PROGNAME
535  ": unknown readpng2_init() error\n");
536  break;
537  }
538  ++error;
539  } else {
540  Trace((stderr, "about to call XOpenDisplay()\n"))
541  display = XOpenDisplay(displayname);
542  if (!display) {
543  readpng2_cleanup(&rpng2_info);
544  fprintf(stderr, PROGNAME ": can't open X display [%s]\n",
545  displayname? displayname : "default");
546  ++error;
547  }
548  }
549  if (error)
550  fclose(infile);
551  }
552 
553 
554  if (error) {
555  fprintf(stderr, PROGNAME ": aborting.\n");
556  exit(2);
557  }
558 
559 
560  /* set the title-bar string, but make sure buffer doesn't overflow */
561 
562  alen = strlen(appname);
563  flen = strlen(filename);
564  if (alen + flen + 3 > 1023)
565  sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023));
566  else
567  sprintf(titlebar, "%s: %s", appname, filename);
568 
569 
570  /* set some final rpng2_info variables before entering main data loop */
571 
572  if (have_bg) {
573  unsigned r, g, b; /* this approach quiets compiler warnings */
574 
575  sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
576  rpng2_info.bg_red = (uch)r;
577  rpng2_info.bg_green = (uch)g;
578  rpng2_info.bg_blue = (uch)b;
579  } else
580  rpng2_info.need_bgcolor = TRUE;
581 
582  rpng2_info.state = kPreInit;
583  rpng2_info.mainprog_init = rpng2_x_init;
584  rpng2_info.mainprog_display_row = rpng2_x_display_row;
585  rpng2_info.mainprog_finish_display = rpng2_x_finish_display;
586 
587 
588  /* OK, this is the fun part: call readpng2_decode_data() at the start of
589  * the loop to deal with our first buffer of data (read in above to verify
590  * that the file is a PNG image), then loop through the file and continue
591  * calling the same routine to handle each chunk of data. It in turn
592  * passes the data to libpng, which will invoke one or more of our call-
593  * backs as decoded data become available. We optionally call sleep() for
594  * one second per iteration to simulate downloading the image via an analog
595  * modem. */
596 
597  for (;;) {
598  Trace((stderr, "about to call readpng2_decode_data()\n"))
599  if (readpng2_decode_data(&rpng2_info, inbuf, incount))
600  ++error;
601  Trace((stderr, "done with readpng2_decode_data()\n"))
602 
603  if (error || incount != INBUFSIZE || rpng2_info.state == kDone) {
604  if (rpng2_info.state == kDone) {
605  Trace((stderr, "done decoding PNG image\n"))
606  } else if (ferror(infile)) {
607  fprintf(stderr, PROGNAME
608  ": error while reading PNG image file\n");
609  exit(3);
610  } else if (feof(infile)) {
611  fprintf(stderr, PROGNAME ": end of file reached "
612  "(unexpectedly) while reading PNG image file\n");
613  exit(3);
614  } else /* if (error) */ {
615  // will print error message below
616  }
617  break;
618  }
619 
620  if (timing)
621  sleep(1);
622 
623  incount = fread(inbuf, 1, INBUFSIZE, infile);
624  }
625 
626 
627  /* clean up PNG stuff and report any decoding errors */
628 
629  fclose(infile);
630  Trace((stderr, "about to call readpng2_cleanup()\n"))
631  readpng2_cleanup(&rpng2_info);
632 
633  if (error) {
634  fprintf(stderr, PROGNAME ": libpng error while decoding PNG image\n");
635  exit(3);
636  }
637 
638 
639 #ifdef FEATURE_LOOP
640 
641  if (loop && bg_image) {
642  Trace((stderr, "entering -loop loop (FEATURE_LOOP)\n"))
643  for (;;) {
644  int i, use_sleep;
645  struct timeval now, then;
646 
647  /* get current time and add loop_interval to get target time */
648  if (gettimeofday(&then, NULL) == 0) {
649  then.tv_sec += loop_interval;
650  use_sleep = FALSE;
651  } else
652  use_sleep = TRUE;
653 
654  /* do quick check for a quit event but don't wait for it */
655  /* GRR BUG: should also check for Expose events and redraw... */
656  if (XCheckMaskEvent(display, KeyPressMask | ButtonPressMask, &e))
657  if (QUIT(e,k))
658  break;
659 
660  /* generate next background image */
661  if (++pat >= num_bgpat)
662  pat = 0;
663  rpng2_x_reload_bg_image();
664 
665  /* wait for timeout, using whatever means are available */
666  if (use_sleep || gettimeofday(&now, NULL) != 0) {
667  for (i = loop_interval; i > 0; --i) {
668  sleep(1);
669  /* GRR BUG: also need to check for Expose (and redraw!) */
670  if (XCheckMaskEvent(display, KeyPressMask | ButtonPressMask,
671  &e) && QUIT(e,k))
672  break;
673  }
674  } else {
675  /* Y2038 BUG! */
676  if (now.tv_sec < then.tv_sec ||
677  (now.tv_sec == then.tv_sec && now.tv_usec < then.tv_usec))
678  {
679  int quit = FALSE;
680  long seconds_to_go = then.tv_sec - now.tv_sec;
681  long usleep_usec;
682 
683  /* basically chew up most of remaining loop-interval with
684  * calls to sleep(1) interleaved with checks for quit
685  * events, but also recalc time-to-go periodically; when
686  * done, clean up any remaining time with usleep() call
687  * (could also use SIGALRM, but signals are a pain...) */
688  while (seconds_to_go-- > 1) {
689  int seconds_done = 0;
690 
691  for (i = seconds_to_go; i > 0 && !quit; --i) {
692  sleep(1);
693  /* GRR BUG: need to check for Expose and redraw */
694  if (XCheckMaskEvent(display, KeyPressMask |
695  ButtonPressMask, &e) && QUIT(e,k))
696  quit = TRUE;
697  if (++seconds_done > 1000)
698  break; /* time to redo seconds_to_go meas. */
699  }
700  if (quit)
701  break;
702 
703  /* OK, more than 1000 seconds since last check:
704  * correct the time-to-go measurement for drift */
705  if (gettimeofday(&now, NULL) == 0) {
706  if (now.tv_sec >= then.tv_sec)
707  break;
708  seconds_to_go = then.tv_sec - now.tv_sec;
709  } else
710  ++seconds_to_go; /* restore what we subtracted */
711  }
712  if (quit)
713  break; /* breaks outer do-loop, skips redisplay */
714 
715  /* since difference between "now" and "then" is already
716  * eaten up to within a couple of seconds, don't need to
717  * worry about overflow--but might have overshot (neg.) */
718  if (gettimeofday(&now, NULL) == 0) {
719  usleep_usec = 1000000L*(then.tv_sec - now.tv_sec) +
720  then.tv_usec - now.tv_usec;
721  if (usleep_usec > 0)
722  usleep((ulg)usleep_usec);
723  }
724  }
725  }
726 
727  /* composite image against new background and display (note that
728  * we do not take into account the time spent doing this...) */
729  rpng2_x_redisplay_image (0, 0, rpng2_info.width, rpng2_info.height);
730  }
731 
732  } else /* FALL THROUGH and do the normal thing */
733 
734 #endif /* FEATURE_LOOP */
735 
736  /* wait for the user to tell us when to quit */
737 
738  if (rpng2_info.state >= kWindowInit) {
739  Trace((stderr, "entering final wait-for-quit-event loop\n"))
740  do {
741  XNextEvent(display, &e);
742  if (e.type == Expose) {
743  XExposeEvent *ex = (XExposeEvent *)&e;
744  rpng2_x_redisplay_image (ex->x, ex->y, ex->width, ex->height);
745  }
746  } while (!QUIT(e,k));
747  } else {
748  fprintf(stderr, PROGNAME ": init callback never called: probable "
749  "libpng error while decoding PNG metadata\n");
750  exit(4);
751  }
752 
753 
754  /* we're done: clean up all image and X resources and go away */
755 
756  Trace((stderr, "about to call rpng2_x_cleanup()\n"))
757  rpng2_x_cleanup();
758 
759  return 0;
760 }
761 
762 
763 
764 
765 
766 /* this function is called by readpng2_info_callback() in readpng2.c, which
767  * in turn is called by libpng after all of the pre-IDAT chunks have been
768  * read and processed--i.e., we now have enough info to finish initializing */
769 
770 static void rpng2_x_init(void)
771 {
772  ulg i;
773  ulg rowbytes = rpng2_info.rowbytes;
774 
775  Trace((stderr, "beginning rpng2_x_init()\n"))
776  Trace((stderr, " rowbytes = %d\n", rpng2_info.rowbytes))
777  Trace((stderr, " width = %ld\n", rpng2_info.width))
778  Trace((stderr, " height = %ld\n", rpng2_info.height))
779 
780  rpng2_info.image_data = (uch *)malloc(rowbytes * rpng2_info.height);
781  if (!rpng2_info.image_data) {
782  readpng2_cleanup(&rpng2_info);
783  return;
784  }
785 
786  rpng2_info.row_pointers = (uch **)malloc(rpng2_info.height * sizeof(uch *));
787  if (!rpng2_info.row_pointers) {
788  free(rpng2_info.image_data);
789  rpng2_info.image_data = NULL;
790  readpng2_cleanup(&rpng2_info);
791  return;
792  }
793 
794  for (i = 0; i < rpng2_info.height; ++i)
795  rpng2_info.row_pointers[i] = rpng2_info.image_data + i*rowbytes;
796 
797 
798  /* do the basic X initialization stuff, make the window, and fill it with
799  * the user-specified, file-specified or default background color or
800  * pattern */
801 
802  if (rpng2_x_create_window()) {
803 
804  /* GRR TEMPORARY HACK: this is fundamentally no different from cases
805  * above; libpng should longjmp() back to us when png_ptr goes away.
806  * If we/it segfault instead, seems like a libpng bug... */
807 
808  /* we're here via libpng callback, so if window fails, clean and bail */
809  readpng2_cleanup(&rpng2_info);
810  rpng2_x_cleanup();
811  exit(2);
812  }
813 
814  rpng2_info.state = kWindowInit;
815 }
816 
817 
818 
819 
820 
821 static int rpng2_x_create_window(void)
822 {
823  ulg bg_red = rpng2_info.bg_red;
824  ulg bg_green = rpng2_info.bg_green;
825  ulg bg_blue = rpng2_info.bg_blue;
826  ulg bg_pixel = 0L;
827  ulg attrmask;
828  int need_colormap = FALSE;
829  int screen, pad;
830  uch *xdata;
831  Window root;
832  XEvent e;
833  XGCValues gcvalues;
834  XSetWindowAttributes attr;
835  XTextProperty windowName, *pWindowName = &windowName;
836  XTextProperty iconName, *pIconName = &iconName;
837  XVisualInfo visual_info;
838  XSizeHints *size_hints;
839  XWMHints *wm_hints;
840  XClassHint *class_hints;
841 
842 
843  Trace((stderr, "beginning rpng2_x_create_window()\n"))
844 
845  screen = DefaultScreen(display);
846  depth = DisplayPlanes(display, screen);
847  root = RootWindow(display, screen);
848 
849 #ifdef DEBUG
850  XSynchronize(display, True);
851 #endif
852 
853  if (depth != 16 && depth != 24 && depth != 32) {
854  int visuals_matched = 0;
855 
856  Trace((stderr, "default depth is %d: checking other visuals\n",
857  depth))
858 
859  /* 24-bit first */
860  visual_info.screen = screen;
861  visual_info.depth = 24;
862  visual_list = XGetVisualInfo(display,
863  VisualScreenMask | VisualDepthMask, &visual_info, &visuals_matched);
864  if (visuals_matched == 0) {
865 /* GRR: add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */
866  fprintf(stderr, "default screen depth %d not supported, and no"
867  " 24-bit visuals found\n", depth);
868  return 2;
869  }
870  Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n",
871  visuals_matched))
872  visual = visual_list[0].visual;
873  depth = visual_list[0].depth;
874 /*
875  colormap_size = visual_list[0].colormap_size;
876  visual_class = visual->class;
877  visualID = XVisualIDFromVisual(visual);
878  */
879  have_nondefault_visual = TRUE;
880  need_colormap = TRUE;
881  } else {
882  XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info);
883  visual = visual_info.visual;
884  }
885 
886  RMask = visual->red_mask;
887  GMask = visual->green_mask;
888  BMask = visual->blue_mask;
889 
890 /* GRR: add/check 8-bit support */
891  if (depth == 8 || need_colormap) {
892  colormap = XCreateColormap(display, root, visual, AllocNone);
893  if (!colormap) {
894  fprintf(stderr, "XCreateColormap() failed\n");
895  return 2;
896  }
897  have_colormap = TRUE;
898  if (depth == 8)
899  bg_image = FALSE; /* gradient just wastes palette entries */
900  }
901  if (depth == 15 || depth == 16) {
902  RShift = 15 - rpng2_x_msb(RMask); /* these are right-shifts */
903  GShift = 15 - rpng2_x_msb(GMask);
904  BShift = 15 - rpng2_x_msb(BMask);
905  } else if (depth > 16) {
906  RShift = rpng2_x_msb(RMask) - 7; /* these are left-shifts */
907  GShift = rpng2_x_msb(GMask) - 7;
908  BShift = rpng2_x_msb(BMask) - 7;
909  }
910  if (depth >= 15 && (RShift < 0 || GShift < 0 || BShift < 0)) {
911  fprintf(stderr, "rpng2 internal logic error: negative X shift(s)!\n");
912  return 2;
913  }
914 
915 /*---------------------------------------------------------------------------
916  Finally, create the window.
917  ---------------------------------------------------------------------------*/
918 
919  attr.backing_store = Always;
920  attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask;
921  attrmask = CWBackingStore | CWEventMask;
922  if (have_nondefault_visual) {
923  attr.colormap = colormap;
924  attr.background_pixel = 0;
925  attr.border_pixel = 1;
926  attrmask |= CWColormap | CWBackPixel | CWBorderPixel;
927  }
928 
929  window = XCreateWindow(display, root, 0, 0, rpng2_info.width,
930  rpng2_info.height, 0, depth, InputOutput, visual, attrmask, &attr);
931 
932  if (window == None) {
933  fprintf(stderr, "XCreateWindow() failed\n");
934  return 2;
935  } else
936  have_window = TRUE;
937 
938  if (depth == 8)
939  XSetWindowColormap(display, window, colormap);
940 
941  if (!XStringListToTextProperty(&window_name, 1, pWindowName))
942  pWindowName = NULL;
943  if (!XStringListToTextProperty(&icon_name, 1, pIconName))
944  pIconName = NULL;
945 
946  /* OK if either hints allocation fails; XSetWMProperties() allows NULLs */
947 
948  if ((size_hints = XAllocSizeHints()) != NULL) {
949  /* window will not be resizable */
950  size_hints->flags = PMinSize | PMaxSize;
951  size_hints->min_width = size_hints->max_width = (int)rpng2_info.width;
952  size_hints->min_height = size_hints->max_height =
953  (int)rpng2_info.height;
954  }
955 
956  if ((wm_hints = XAllocWMHints()) != NULL) {
957  wm_hints->initial_state = NormalState;
958  wm_hints->input = True;
959  /* wm_hints->icon_pixmap = icon_pixmap; */
960  wm_hints->flags = StateHint | InputHint /* | IconPixmapHint */ ;
961  }
962 
963  if ((class_hints = XAllocClassHint()) != NULL) {
964  class_hints->res_name = res_name;
965  class_hints->res_class = res_class;
966  }
967 
968  XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0,
969  size_hints, wm_hints, class_hints);
970 
971  /* various properties and hints no longer needed; free memory */
972  if (pWindowName)
973  XFree(pWindowName->value);
974  if (pIconName)
975  XFree(pIconName->value);
976  if (size_hints)
977  XFree(size_hints);
978  if (wm_hints)
979  XFree(wm_hints);
980  if (class_hints)
981  XFree(class_hints);
982 
983  XMapWindow(display, window);
984 
985  gc = XCreateGC(display, window, 0, &gcvalues);
986  have_gc = TRUE;
987 
988 /*---------------------------------------------------------------------------
989  Allocate memory for the X- and display-specific version of the image.
990  ---------------------------------------------------------------------------*/
991 
992  if (depth == 24 || depth == 32) {
993  xdata = (uch *)malloc(4*rpng2_info.width*rpng2_info.height);
994  pad = 32;
995  } else if (depth == 16) {
996  xdata = (uch *)malloc(2*rpng2_info.width*rpng2_info.height);
997  pad = 16;
998  } else /* depth == 8 */ {
999  xdata = (uch *)malloc(rpng2_info.width*rpng2_info.height);
1000  pad = 8;
1001  }
1002 
1003  if (!xdata) {
1004  fprintf(stderr, PROGNAME ": unable to allocate image memory\n");
1005  return 4;
1006  }
1007 
1008  ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
1009  (char *)xdata, rpng2_info.width, rpng2_info.height, pad, 0);
1010 
1011  if (!ximage) {
1012  fprintf(stderr, PROGNAME ": XCreateImage() failed\n");
1013  free(xdata);
1014  return 3;
1015  }
1016 
1017  /* to avoid testing the byte order every pixel (or doubling the size of
1018  * the drawing routine with a giant if-test), we arbitrarily set the byte
1019  * order to MSBFirst and let Xlib worry about inverting things on little-
1020  * endian machines (e.g., Linux/x86, old VAXen, etc.)--this is not the
1021  * most efficient approach (the giant if-test would be better), but in
1022  * the interest of clarity, we'll take the easy way out... */
1023 
1024  ximage->byte_order = MSBFirst;
1025 
1026 /*---------------------------------------------------------------------------
1027  Fill window with the specified background color (default is black) or
1028  faked "background image" (but latter is disabled if 8-bit; gradients
1029  just waste palette entries).
1030  ---------------------------------------------------------------------------*/
1031 
1032  if (bg_image)
1033  rpng2_x_load_bg_image(); /* resets bg_image if fails */
1034 
1035  if (!bg_image) {
1036  if (depth == 24 || depth == 32) {
1037  bg_pixel = (bg_red << RShift) |
1038  (bg_green << GShift) |
1039  (bg_blue << BShift);
1040  } else if (depth == 16) {
1041  bg_pixel = (((bg_red << 8) >> RShift) & RMask) |
1042  (((bg_green << 8) >> GShift) & GMask) |
1043  (((bg_blue << 8) >> BShift) & BMask);
1044  } else /* depth == 8 */ {
1045 
1046  /* GRR: add 8-bit support */
1047 
1048  }
1049  XSetForeground(display, gc, bg_pixel);
1050  XFillRectangle(display, window, gc, 0, 0, rpng2_info.width,
1051  rpng2_info.height);
1052  }
1053 
1054 /*---------------------------------------------------------------------------
1055  Wait for first Expose event to do any drawing, then flush and return.
1056  ---------------------------------------------------------------------------*/
1057 
1058  do
1059  XNextEvent(display, &e);
1060  while (e.type != Expose || e.xexpose.count);
1061 
1062  XFlush(display);
1063 
1064  return 0;
1065 
1066 } /* end function rpng2_x_create_window() */
1067 
1068 
1069 
1070 
1071 
1072 static int rpng2_x_load_bg_image(void)
1073 {
1074  uch *src;
1075  char *dest;
1076  uch r1, r2, g1, g2, b1, b2;
1077  uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv;
1078  int k, hmax, max;
1079  int xidx, yidx, yidx_max;
1080  int even_odd_vert, even_odd_horiz, even_odd;
1081  int invert_gradient2 = (bg[pat].type & 0x08);
1082  int invert_column;
1083  int ximage_rowbytes = ximage->bytes_per_line;
1084  ulg i, row;
1085  ulg pixel;
1086 
1087 /*---------------------------------------------------------------------------
1088  Allocate buffer for fake background image to be used with transparent
1089  images; if this fails, revert to plain background color.
1090  ---------------------------------------------------------------------------*/
1091 
1092  bg_rowbytes = 3 * rpng2_info.width;
1093  bg_data = (uch *)malloc(bg_rowbytes * rpng2_info.height);
1094  if (!bg_data) {
1095  fprintf(stderr, PROGNAME
1096  ": unable to allocate memory for background image\n");
1097  bg_image = 0;
1098  return 1;
1099  }
1100 
1101  bgscale = (pat == 0)? 8 : bgscale_default;
1102  yidx_max = bgscale - 1;
1103 
1104 /*---------------------------------------------------------------------------
1105  Vertical gradients (ramps) in NxN squares, alternating direction and
1106  colors (N == bgscale).
1107  ---------------------------------------------------------------------------*/
1108 
1109  if ((bg[pat].type & 0x07) == 0) {
1110  uch r1_min = rgb[bg[pat].rgb1_min].r;
1111  uch g1_min = rgb[bg[pat].rgb1_min].g;
1112  uch b1_min = rgb[bg[pat].rgb1_min].b;
1113  uch r2_min = rgb[bg[pat].rgb2_min].r;
1114  uch g2_min = rgb[bg[pat].rgb2_min].g;
1115  uch b2_min = rgb[bg[pat].rgb2_min].b;
1116  int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min;
1117  int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min;
1118  int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min;
1119  int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min;
1120  int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min;
1121  int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min;
1122 
1123  for (row = 0; row < rpng2_info.height; ++row) {
1124  yidx = (int)(row % bgscale);
1125  even_odd_vert = (int)((row / bgscale) & 1);
1126 
1127  r1 = r1_min + (r1_diff * yidx) / yidx_max;
1128  g1 = g1_min + (g1_diff * yidx) / yidx_max;
1129  b1 = b1_min + (b1_diff * yidx) / yidx_max;
1130  r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max;
1131  g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max;
1132  b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max;
1133 
1134  r2 = r2_min + (r2_diff * yidx) / yidx_max;
1135  g2 = g2_min + (g2_diff * yidx) / yidx_max;
1136  b2 = b2_min + (b2_diff * yidx) / yidx_max;
1137  r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max;
1138  g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max;
1139  b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max;
1140 
1141  dest = (char *)bg_data + row*bg_rowbytes;
1142  for (i = 0; i < rpng2_info.width; ++i) {
1143  even_odd_horiz = (int)((i / bgscale) & 1);
1144  even_odd = even_odd_vert ^ even_odd_horiz;
1145  invert_column =
1146  (even_odd_horiz && (bg[pat].type & 0x10));
1147  if (even_odd == 0) { /* gradient #1 */
1148  if (invert_column) {
1149  *dest++ = r1_inv;
1150  *dest++ = g1_inv;
1151  *dest++ = b1_inv;
1152  } else {
1153  *dest++ = r1;
1154  *dest++ = g1;
1155  *dest++ = b1;
1156  }
1157  } else { /* gradient #2 */
1158  if ((invert_column && invert_gradient2) ||
1159  (!invert_column && !invert_gradient2))
1160  {
1161  *dest++ = r2; /* not inverted or */
1162  *dest++ = g2; /* doubly inverted */
1163  *dest++ = b2;
1164  } else {
1165  *dest++ = r2_inv;
1166  *dest++ = g2_inv; /* singly inverted */
1167  *dest++ = b2_inv;
1168  }
1169  }
1170  }
1171  }
1172 
1173 /*---------------------------------------------------------------------------
1174  Soft gradient-diamonds with scale = bgscale. Code contributed by Adam
1175  M. Costello.
1176  ---------------------------------------------------------------------------*/
1177 
1178  } else if ((bg[pat].type & 0x07) == 1) {
1179 
1180  hmax = (bgscale-1)/2; /* half the max weight of a color */
1181  max = 2*hmax; /* the max weight of a color */
1182 
1183  r1 = rgb[bg[pat].rgb1_max].r;
1184  g1 = rgb[bg[pat].rgb1_max].g;
1185  b1 = rgb[bg[pat].rgb1_max].b;
1186  r2 = rgb[bg[pat].rgb2_max].r;
1187  g2 = rgb[bg[pat].rgb2_max].g;
1188  b2 = rgb[bg[pat].rgb2_max].b;
1189 
1190  for (row = 0; row < rpng2_info.height; ++row) {
1191  yidx = (int)(row % bgscale);
1192  if (yidx > hmax)
1193  yidx = bgscale-1 - yidx;
1194  dest = (char *)bg_data + row*bg_rowbytes;
1195  for (i = 0; i < rpng2_info.width; ++i) {
1196  xidx = (int)(i % bgscale);
1197  if (xidx > hmax)
1198  xidx = bgscale-1 - xidx;
1199  k = xidx + yidx;
1200  *dest++ = (k*r1 + (max-k)*r2) / max;
1201  *dest++ = (k*g1 + (max-k)*g2) / max;
1202  *dest++ = (k*b1 + (max-k)*b2) / max;
1203  }
1204  }
1205 
1206 /*---------------------------------------------------------------------------
1207  Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
1208  soids will equal bgscale?]. This one is slow but very cool. Code con-
1209  tributed by Pieter S. van der Meulen (originally in Smalltalk).
1210  ---------------------------------------------------------------------------*/
1211 
1212  } else if ((bg[pat].type & 0x07) == 2) {
1213  uch ch;
1214  int ii, x, y, hw, hh, grayspot;
1215  double freq, rotate, saturate, gray, intensity;
1216  double angle=0.0, aoffset=0.0, maxDist, dist;
1217  double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t;
1218 
1219  fprintf(stderr, "%s: computing radial background...",
1220  PROGNAME);
1221  fflush(stderr);
1222 
1223  hh = (int)(rpng2_info.height / 2);
1224  hw = (int)(rpng2_info.width / 2);
1225 
1226  /* variables for radial waves:
1227  * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED]
1228  * freq: number of color beams originating from the center
1229  * grayspot: size of the graying center area (anti-alias)
1230  * rotate: rotation of the beams as a function of radius
1231  * saturate: saturation of beams' shape azimuthally
1232  */
1233  angle = CLIP(angle, 0.0, 360.0);
1234  grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw));
1235  freq = MAX((double)bg[pat].bg_freq, 0.0);
1236  saturate = (double)bg[pat].bg_bsat * 0.1;
1237  rotate = (double)bg[pat].bg_brot * 0.1;
1238  gray = 0.0;
1239  intensity = 0.0;
1240  maxDist = (double)((hw*hw) + (hh*hh));
1241 
1242  for (row = 0; row < rpng2_info.height; ++row) {
1243  y = (int)(row - hh);
1244  dest = (char *)bg_data + row*bg_rowbytes;
1245  for (i = 0; i < rpng2_info.width; ++i) {
1246  x = (int)(i - hw);
1247  angle = (x == 0)? PI_2 : atan((double)y / (double)x);
1248  gray = (double)MAX(ABS(y), ABS(x)) / grayspot;
1249  gray = MIN(1.0, gray);
1250  dist = (double)((x*x) + (y*y)) / maxDist;
1251  intensity = cos((angle+(rotate*dist*PI)) * freq) *
1252  gray * saturate;
1253  intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5;
1254  hue = (angle + PI) * INV_PI_360 + aoffset;
1255  s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh));
1256  s = MIN(MAX(s,0.0), 1.0);
1257  v = MIN(MAX(intensity,0.0), 1.0);
1258 
1259  if (s == 0.0) {
1260  ch = (uch)(v * 255.0);
1261  *dest++ = ch;
1262  *dest++ = ch;
1263  *dest++ = ch;
1264  } else {
1265  if ((hue < 0.0) || (hue >= 360.0))
1266  hue -= (((int)(hue / 360.0)) * 360.0);
1267  hue /= 60.0;
1268  ii = (int)hue;
1269  f = hue - (double)ii;
1270  p = (1.0 - s) * v;
1271  q = (1.0 - (s * f)) * v;
1272  t = (1.0 - (s * (1.0 - f))) * v;
1273  if (ii == 0) { red = v; green = t; blue = p; }
1274  else if (ii == 1) { red = q; green = v; blue = p; }
1275  else if (ii == 2) { red = p; green = v; blue = t; }
1276  else if (ii == 3) { red = p; green = q; blue = v; }
1277  else if (ii == 4) { red = t; green = p; blue = v; }
1278  else if (ii == 5) { red = v; green = p; blue = q; }
1279  *dest++ = (uch)(red * 255.0);
1280  *dest++ = (uch)(green * 255.0);
1281  *dest++ = (uch)(blue * 255.0);
1282  }
1283  }
1284  }
1285  fprintf(stderr, "done.\n");
1286  fflush(stderr);
1287  }
1288 
1289 /*---------------------------------------------------------------------------
1290  Blast background image to display buffer before beginning PNG decode.
1291  ---------------------------------------------------------------------------*/
1292 
1293  if (depth == 24 || depth == 32) {
1294  ulg red, green, blue;
1295  int bpp = ximage->bits_per_pixel;
1296 
1297  for (row = 0; row < rpng2_info.height; ++row) {
1298  src = bg_data + row*bg_rowbytes;
1299  dest = ximage->data + row*ximage_rowbytes;
1300  if (bpp == 32) { /* slightly optimized version */
1301  for (i = rpng2_info.width; i > 0; --i) {
1302  red = *src++;
1303  green = *src++;
1304  blue = *src++;
1305  pixel = (red << RShift) |
1306  (green << GShift) |
1307  (blue << BShift);
1308  /* recall that we set ximage->byte_order = MSBFirst above */
1309  *dest++ = (char)((pixel >> 24) & 0xff);
1310  *dest++ = (char)((pixel >> 16) & 0xff);
1311  *dest++ = (char)((pixel >> 8) & 0xff);
1312  *dest++ = (char)( pixel & 0xff);
1313  }
1314  } else {
1315  for (i = rpng2_info.width; i > 0; --i) {
1316  red = *src++;
1317  green = *src++;
1318  blue = *src++;
1319  pixel = (red << RShift) |
1320  (green << GShift) |
1321  (blue << BShift);
1322  /* recall that we set ximage->byte_order = MSBFirst above */
1323  /* GRR BUG? this assumes bpp == 24 & bits are packed low */
1324  /* (probably need to use RShift, RMask, etc.) */
1325  *dest++ = (char)((pixel >> 16) & 0xff);
1326  *dest++ = (char)((pixel >> 8) & 0xff);
1327  *dest++ = (char)( pixel & 0xff);
1328  }
1329  }
1330  }
1331 
1332  } else if (depth == 16) {
1333  ush red, green, blue;
1334 
1335  for (row = 0; row < rpng2_info.height; ++row) {
1336  src = bg_data + row*bg_rowbytes;
1337  dest = ximage->data + row*ximage_rowbytes;
1338  for (i = rpng2_info.width; i > 0; --i) {
1339  red = ((ush)(*src) << 8); ++src;
1340  green = ((ush)(*src) << 8); ++src;
1341  blue = ((ush)(*src) << 8); ++src;
1342  pixel = ((red >> RShift) & RMask) |
1343  ((green >> GShift) & GMask) |
1344  ((blue >> BShift) & BMask);
1345  /* recall that we set ximage->byte_order = MSBFirst above */
1346  *dest++ = (char)((pixel >> 8) & 0xff);
1347  *dest++ = (char)( pixel & 0xff);
1348  }
1349  }
1350 
1351  } else /* depth == 8 */ {
1352 
1353  /* GRR: add 8-bit support */
1354 
1355  }
1356 
1357  XPutImage(display, window, gc, ximage, 0, 0, 0, 0, rpng2_info.width,
1358  rpng2_info.height);
1359 
1360  return 0;
1361 
1362 } /* end function rpng2_x_load_bg_image() */
1363 
1364 
1365 
1366 
1367 
1368 static void rpng2_x_display_row(ulg row)
1369 {
1370  uch bg_red = rpng2_info.bg_red;
1371  uch bg_green = rpng2_info.bg_green;
1372  uch bg_blue = rpng2_info.bg_blue;
1373  uch *src, *src2=NULL;
1374  char *dest;
1375  uch r, g, b, a;
1376  int ximage_rowbytes = ximage->bytes_per_line;
1377  ulg i, pixel;
1378  static int rows=0, prevpass=(-1);
1379  static ulg firstrow;
1380 
1381 /*---------------------------------------------------------------------------
1382  rows and firstrow simply track how many rows (and which ones) have not
1383  yet been displayed; alternatively, we could call XPutImage() for every
1384  row and not bother with the records-keeping.
1385  ---------------------------------------------------------------------------*/
1386 
1387  Trace((stderr, "beginning rpng2_x_display_row()\n"))
1388 
1389  if (rpng2_info.pass != prevpass) {
1390  if (pause_after_pass && rpng2_info.pass > 0) {
1391  XEvent e;
1392  KeySym k;
1393 
1394  fprintf(stderr,
1395  "%s: end of pass %d of 7; click in image window to continue\n",
1396  PROGNAME, prevpass + 1);
1397  do
1398  XNextEvent(display, &e);
1399  while (!QUIT(e,k));
1400  }
1401  fprintf(stderr, "%s: pass %d of 7\r", PROGNAME, rpng2_info.pass + 1);
1402  fflush(stderr);
1403  prevpass = rpng2_info.pass;
1404  }
1405 
1406  if (rows == 0)
1407  firstrow = row; /* first row that is not yet displayed */
1408 
1409  ++rows; /* count of rows received but not yet displayed */
1410 
1411 /*---------------------------------------------------------------------------
1412  Aside from the use of the rpng2_info struct, the lack of an outer loop
1413  (over rows) and moving the XPutImage() call outside the "if (depth)"
1414  tests, this routine is identical to rpng_x_display_image() in the non-
1415  progressive version of the program.
1416  ---------------------------------------------------------------------------*/
1417 
1418  if (depth == 24 || depth == 32) {
1419  ulg red, green, blue;
1420  int bpp = ximage->bits_per_pixel;
1421 
1422  src = rpng2_info.image_data + row*rpng2_info.rowbytes;
1423  if (bg_image)
1424  src2 = bg_data + row*bg_rowbytes;
1425  dest = ximage->data + row*ximage_rowbytes;
1426  if (rpng2_info.channels == 3) {
1427  for (i = rpng2_info.width; i > 0; --i) {
1428  red = *src++;
1429  green = *src++;
1430  blue = *src++;
1431  pixel = (red << RShift) |
1432  (green << GShift) |
1433  (blue << BShift);
1434  /* recall that we set ximage->byte_order = MSBFirst above */
1435  if (bpp == 32) {
1436  *dest++ = (char)((pixel >> 24) & 0xff);
1437  *dest++ = (char)((pixel >> 16) & 0xff);
1438  *dest++ = (char)((pixel >> 8) & 0xff);
1439  *dest++ = (char)( pixel & 0xff);
1440  } else {
1441  /* GRR BUG? this assumes bpp == 24 & bits are packed low */
1442  /* (probably need to use RShift, RMask, etc.) */
1443  *dest++ = (char)((pixel >> 16) & 0xff);
1444  *dest++ = (char)((pixel >> 8) & 0xff);
1445  *dest++ = (char)( pixel & 0xff);
1446  }
1447  }
1448  } else /* if (rpng2_info.channels == 4) */ {
1449  for (i = rpng2_info.width; i > 0; --i) {
1450  r = *src++;
1451  g = *src++;
1452  b = *src++;
1453  a = *src++;
1454  if (bg_image) {
1455  bg_red = *src2++;
1456  bg_green = *src2++;
1457  bg_blue = *src2++;
1458  }
1459  if (a == 255) {
1460  red = r;
1461  green = g;
1462  blue = b;
1463  } else if (a == 0) {
1464  red = bg_red;
1465  green = bg_green;
1466  blue = bg_blue;
1467  } else {
1468  /* this macro (from png.h) composites the foreground
1469  * and background values and puts the result into the
1470  * first argument */
1471  alpha_composite(red, r, a, bg_red);
1472  alpha_composite(green, g, a, bg_green);
1473  alpha_composite(blue, b, a, bg_blue);
1474  }
1475  pixel = (red << RShift) |
1476  (green << GShift) |
1477  (blue << BShift);
1478  /* recall that we set ximage->byte_order = MSBFirst above */
1479  if (bpp == 32) {
1480  *dest++ = (char)((pixel >> 24) & 0xff);
1481  *dest++ = (char)((pixel >> 16) & 0xff);
1482  *dest++ = (char)((pixel >> 8) & 0xff);
1483  *dest++ = (char)( pixel & 0xff);
1484  } else {
1485  /* GRR BUG? this assumes bpp == 24 & bits are packed low */
1486  /* (probably need to use RShift, RMask, etc.) */
1487  *dest++ = (char)((pixel >> 16) & 0xff);
1488  *dest++ = (char)((pixel >> 8) & 0xff);
1489  *dest++ = (char)( pixel & 0xff);
1490  }
1491  }
1492  }
1493 
1494  } else if (depth == 16) {
1495  ush red, green, blue;
1496 
1497  src = rpng2_info.row_pointers[row];
1498  if (bg_image)
1499  src2 = bg_data + row*bg_rowbytes;
1500  dest = ximage->data + row*ximage_rowbytes;
1501  if (rpng2_info.channels == 3) {
1502  for (i = rpng2_info.width; i > 0; --i) {
1503  red = ((ush)(*src) << 8);
1504  ++src;
1505  green = ((ush)(*src) << 8);
1506  ++src;
1507  blue = ((ush)(*src) << 8);
1508  ++src;
1509  pixel = ((red >> RShift) & RMask) |
1510  ((green >> GShift) & GMask) |
1511  ((blue >> BShift) & BMask);
1512  /* recall that we set ximage->byte_order = MSBFirst above */
1513  *dest++ = (char)((pixel >> 8) & 0xff);
1514  *dest++ = (char)( pixel & 0xff);
1515  }
1516  } else /* if (rpng2_info.channels == 4) */ {
1517  for (i = rpng2_info.width; i > 0; --i) {
1518  r = *src++;
1519  g = *src++;
1520  b = *src++;
1521  a = *src++;
1522  if (bg_image) {
1523  bg_red = *src2++;
1524  bg_green = *src2++;
1525  bg_blue = *src2++;
1526  }
1527  if (a == 255) {
1528  red = ((ush)r << 8);
1529  green = ((ush)g << 8);
1530  blue = ((ush)b << 8);
1531  } else if (a == 0) {
1532  red = ((ush)bg_red << 8);
1533  green = ((ush)bg_green << 8);
1534  blue = ((ush)bg_blue << 8);
1535  } else {
1536  /* this macro (from png.h) composites the foreground
1537  * and background values and puts the result back into
1538  * the first argument (== fg byte here: safe) */
1539  alpha_composite(r, r, a, bg_red);
1540  alpha_composite(g, g, a, bg_green);
1541  alpha_composite(b, b, a, bg_blue);
1542  red = ((ush)r << 8);
1543  green = ((ush)g << 8);
1544  blue = ((ush)b << 8);
1545  }
1546  pixel = ((red >> RShift) & RMask) |
1547  ((green >> GShift) & GMask) |
1548  ((blue >> BShift) & BMask);
1549  /* recall that we set ximage->byte_order = MSBFirst above */
1550  *dest++ = (char)((pixel >> 8) & 0xff);
1551  *dest++ = (char)( pixel & 0xff);
1552  }
1553  }
1554 
1555  } else /* depth == 8 */ {
1556 
1557  /* GRR: add 8-bit support */
1558 
1559  }
1560 
1561 
1562 /*---------------------------------------------------------------------------
1563  Display after every 16 rows or when on one of last two rows. (Region
1564  may include previously displayed lines due to interlacing--i.e., not
1565  contiguous. Also, second-to-last row is final one in interlaced images
1566  with odd number of rows.) For demos, flush (and delay) after every 16th
1567  row so "sparse" passes don't go twice as fast.
1568  ---------------------------------------------------------------------------*/
1569 
1570  if (demo_timing && (row - firstrow >= 16 || row >= rpng2_info.height-2)) {
1571  XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0,
1572  (int)firstrow, rpng2_info.width, row - firstrow + 1);
1573  XFlush(display);
1574  rows = 0;
1575  usleep(usleep_duration);
1576  } else
1577  if (!demo_timing && ((rows & 0xf) == 0 || row >= rpng2_info.height-2)) {
1578  XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0,
1579  (int)firstrow, rpng2_info.width, row - firstrow + 1);
1580  XFlush(display);
1581  rows = 0;
1582  }
1583 
1584 }
1585 
1586 
1587 
1588 
1589 
1590 static void rpng2_x_finish_display(void)
1591 {
1592  Trace((stderr, "beginning rpng2_x_finish_display()\n"))
1593 
1594  /* last row has already been displayed by rpng2_x_display_row(), so we
1595  * have nothing to do here except set a flag and let the user know that
1596  * the image is done */
1597 
1598  rpng2_info.state = kDone;
1599  printf(
1600  "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n");
1601  fflush(stdout);
1602 }
1603 
1604 
1605 
1606 
1607 
1608 static void rpng2_x_redisplay_image(ulg startcol, ulg startrow,
1609  ulg width, ulg height)
1610 {
1611  uch bg_red = rpng2_info.bg_red;
1612  uch bg_green = rpng2_info.bg_green;
1613  uch bg_blue = rpng2_info.bg_blue;
1614  uch *src, *src2=NULL;
1615  char *dest;
1616  uch r, g, b, a;
1617  ulg i, row, lastrow = 0;
1618  ulg pixel;
1619  int ximage_rowbytes = ximage->bytes_per_line;
1620 
1621 
1622  Trace((stderr, "beginning display loop (image_channels == %d)\n",
1623  rpng2_info.channels))
1624  Trace((stderr, " (width = %ld, rowbytes = %d, ximage_rowbytes = %d)\n",
1625  rpng2_info.width, rpng2_info.rowbytes, ximage_rowbytes))
1626  Trace((stderr, " (bpp = %d)\n", ximage->bits_per_pixel))
1627  Trace((stderr, " (byte_order = %s)\n", ximage->byte_order == MSBFirst?
1628  "MSBFirst" : (ximage->byte_order == LSBFirst? "LSBFirst" : "unknown")))
1629 
1630 /*---------------------------------------------------------------------------
1631  Aside from the use of the rpng2_info struct and of src2 (for background
1632  image), this routine is identical to rpng_x_display_image() in the non-
1633  progressive version of the program--for the simple reason that redisplay
1634  of the image against a new background happens after the image is fully
1635  decoded and therefore is, by definition, non-progressive.
1636  ---------------------------------------------------------------------------*/
1637 
1638  if (depth == 24 || depth == 32) {
1639  ulg red, green, blue;
1640  int bpp = ximage->bits_per_pixel;
1641 
1642  for (lastrow = row = startrow; row < startrow+height; ++row) {
1643  src = rpng2_info.image_data + row*rpng2_info.rowbytes;
1644  if (bg_image)
1645  src2 = bg_data + row*bg_rowbytes;
1646  dest = ximage->data + row*ximage_rowbytes;
1647  if (rpng2_info.channels == 3) {
1648  for (i = rpng2_info.width; i > 0; --i) {
1649  red = *src++;
1650  green = *src++;
1651  blue = *src++;
1652 #ifdef NO_24BIT_MASKS
1653  pixel = (red << RShift) |
1654  (green << GShift) |
1655  (blue << BShift);
1656  /* recall that we set ximage->byte_order = MSBFirst above */
1657  if (bpp == 32) {
1658  *dest++ = (char)((pixel >> 24) & 0xff);
1659  *dest++ = (char)((pixel >> 16) & 0xff);
1660  *dest++ = (char)((pixel >> 8) & 0xff);
1661  *dest++ = (char)( pixel & 0xff);
1662  } else {
1663  /* this assumes bpp == 24 & bits are packed low */
1664  /* (probably need to use RShift, RMask, etc.) */
1665  *dest++ = (char)((pixel >> 16) & 0xff);
1666  *dest++ = (char)((pixel >> 8) & 0xff);
1667  *dest++ = (char)( pixel & 0xff);
1668  }
1669 #else
1670  red = (RShift < 0)? red << (-RShift) : red >> RShift;
1671  green = (GShift < 0)? green << (-GShift) : green >> GShift;
1672  blue = (BShift < 0)? blue << (-BShift) : blue >> BShift;
1673  pixel = (red & RMask) | (green & GMask) | (blue & BMask);
1674  /* recall that we set ximage->byte_order = MSBFirst above */
1675  if (bpp == 32) {
1676  *dest++ = (char)((pixel >> 24) & 0xff);
1677  *dest++ = (char)((pixel >> 16) & 0xff);
1678  *dest++ = (char)((pixel >> 8) & 0xff);
1679  *dest++ = (char)( pixel & 0xff);
1680  } else {
1681  /* GRR BUG */
1682  /* this assumes bpp == 24 & bits are packed low */
1683  /* (probably need to use RShift/RMask/etc. here, too) */
1684  *dest++ = (char)((pixel >> 16) & 0xff);
1685  *dest++ = (char)((pixel >> 8) & 0xff);
1686  *dest++ = (char)( pixel & 0xff);
1687  }
1688 #endif
1689  }
1690 
1691  } else /* if (rpng2_info.channels == 4) */ {
1692  for (i = rpng2_info.width; i > 0; --i) {
1693  r = *src++;
1694  g = *src++;
1695  b = *src++;
1696  a = *src++;
1697  if (bg_image) {
1698  bg_red = *src2++;
1699  bg_green = *src2++;
1700  bg_blue = *src2++;
1701  }
1702  if (a == 255) {
1703  red = r;
1704  green = g;
1705  blue = b;
1706  } else if (a == 0) {
1707  red = bg_red;
1708  green = bg_green;
1709  blue = bg_blue;
1710  } else {
1711  /* this macro (from png.h) composites the foreground
1712  * and background values and puts the result into the
1713  * first argument */
1714  alpha_composite(red, r, a, bg_red);
1715  alpha_composite(green, g, a, bg_green);
1716  alpha_composite(blue, b, a, bg_blue);
1717  }
1718 #ifdef NO_24BIT_MASKS
1719  pixel = (red << RShift) |
1720  (green << GShift) |
1721  (blue << BShift);
1722  /* recall that we set ximage->byte_order = MSBFirst above */
1723  if (bpp == 32) {
1724  *dest++ = (char)((pixel >> 24) & 0xff);
1725  *dest++ = (char)((pixel >> 16) & 0xff);
1726  *dest++ = (char)((pixel >> 8) & 0xff);
1727  *dest++ = (char)( pixel & 0xff);
1728  } else {
1729  /* this assumes bpp == 24 & bits are packed low */
1730  /* (probably need to use RShift, RMask, etc.) */
1731  *dest++ = (char)((pixel >> 16) & 0xff);
1732  *dest++ = (char)((pixel >> 8) & 0xff);
1733  *dest++ = (char)( pixel & 0xff);
1734  }
1735 #else
1736  red = (RShift < 0)? red << (-RShift) : red >> RShift;
1737  green = (GShift < 0)? green << (-GShift) : green >> GShift;
1738  blue = (BShift < 0)? blue << (-BShift) : blue >> BShift;
1739  pixel = (red & RMask) | (green & GMask) | (blue & BMask);
1740  /* recall that we set ximage->byte_order = MSBFirst above */
1741  if (bpp == 32) {
1742  *dest++ = (char)((pixel >> 24) & 0xff);
1743  *dest++ = (char)((pixel >> 16) & 0xff);
1744  *dest++ = (char)((pixel >> 8) & 0xff);
1745  *dest++ = (char)( pixel & 0xff);
1746  } else {
1747  /* GRR BUG */
1748  /* this assumes bpp == 24 & bits are packed low */
1749  /* (probably need to use RShift/RMask/etc. here, too) */
1750  *dest++ = (char)((pixel >> 16) & 0xff);
1751  *dest++ = (char)((pixel >> 8) & 0xff);
1752  *dest++ = (char)( pixel & 0xff);
1753  }
1754 #endif
1755  }
1756  }
1757  /* display after every 16 lines */
1758  if (((row+1) & 0xf) == 0) {
1759  XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
1760  (int)lastrow, rpng2_info.width, 16);
1761  XFlush(display);
1762  lastrow = row + 1;
1763  }
1764  }
1765 
1766  } else if (depth == 16) {
1767  ush red, green, blue;
1768 
1769  for (lastrow = row = startrow; row < startrow+height; ++row) {
1770  src = rpng2_info.row_pointers[row];
1771  if (bg_image)
1772  src2 = bg_data + row*bg_rowbytes;
1773  dest = ximage->data + row*ximage_rowbytes;
1774  if (rpng2_info.channels == 3) {
1775  for (i = rpng2_info.width; i > 0; --i) {
1776  red = ((ush)(*src) << 8);
1777  ++src;
1778  green = ((ush)(*src) << 8);
1779  ++src;
1780  blue = ((ush)(*src) << 8);
1781  ++src;
1782  pixel = ((red >> RShift) & RMask) |
1783  ((green >> GShift) & GMask) |
1784  ((blue >> BShift) & BMask);
1785  /* recall that we set ximage->byte_order = MSBFirst above */
1786  *dest++ = (char)((pixel >> 8) & 0xff);
1787  *dest++ = (char)( pixel & 0xff);
1788  }
1789  } else /* if (rpng2_info.channels == 4) */ {
1790  for (i = rpng2_info.width; i > 0; --i) {
1791  r = *src++;
1792  g = *src++;
1793  b = *src++;
1794  a = *src++;
1795  if (bg_image) {
1796  bg_red = *src2++;
1797  bg_green = *src2++;
1798  bg_blue = *src2++;
1799  }
1800  if (a == 255) {
1801  red = ((ush)r << 8);
1802  green = ((ush)g << 8);
1803  blue = ((ush)b << 8);
1804  } else if (a == 0) {
1805  red = ((ush)bg_red << 8);
1806  green = ((ush)bg_green << 8);
1807  blue = ((ush)bg_blue << 8);
1808  } else {
1809  /* this macro (from png.h) composites the foreground
1810  * and background values and puts the result back into
1811  * the first argument (== fg byte here: safe) */
1812  alpha_composite(r, r, a, bg_red);
1813  alpha_composite(g, g, a, bg_green);
1814  alpha_composite(b, b, a, bg_blue);
1815  red = ((ush)r << 8);
1816  green = ((ush)g << 8);
1817  blue = ((ush)b << 8);
1818  }
1819  pixel = ((red >> RShift) & RMask) |
1820  ((green >> GShift) & GMask) |
1821  ((blue >> BShift) & BMask);
1822  /* recall that we set ximage->byte_order = MSBFirst above */
1823  *dest++ = (char)((pixel >> 8) & 0xff);
1824  *dest++ = (char)( pixel & 0xff);
1825  }
1826  }
1827  /* display after every 16 lines */
1828  if (((row+1) & 0xf) == 0) {
1829  XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
1830  (int)lastrow, rpng2_info.width, 16);
1831  XFlush(display);
1832  lastrow = row + 1;
1833  }
1834  }
1835 
1836  } else /* depth == 8 */ {
1837 
1838  /* GRR: add 8-bit support */
1839 
1840  }
1841 
1842  Trace((stderr, "calling final XPutImage()\n"))
1843  if (lastrow < startrow+height) {
1844  XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
1845  (int)lastrow, rpng2_info.width, rpng2_info.height-lastrow);
1846  XFlush(display);
1847  }
1848 
1849 } /* end function rpng2_x_redisplay_image() */
1850 
1851 
1852 
1853 
1854 
1855 #ifdef FEATURE_LOOP
1856 
1857 static void rpng2_x_reload_bg_image(void)
1858 {
1859  char *dest;
1860  uch r1, r2, g1, g2, b1, b2;
1861  uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv;
1862  int k, hmax, max;
1863  int xidx, yidx, yidx_max;
1864  int even_odd_vert, even_odd_horiz, even_odd;
1865  int invert_gradient2 = (bg[pat].type & 0x08);
1866  int invert_column;
1867  ulg i, row;
1868 
1869 
1870  bgscale = (pat == 0)? 8 : bgscale_default;
1871  yidx_max = bgscale - 1;
1872 
1873 /*---------------------------------------------------------------------------
1874  Vertical gradients (ramps) in NxN squares, alternating direction and
1875  colors (N == bgscale).
1876  ---------------------------------------------------------------------------*/
1877 
1878  if ((bg[pat].type & 0x07) == 0) {
1879  uch r1_min = rgb[bg[pat].rgb1_min].r;
1880  uch g1_min = rgb[bg[pat].rgb1_min].g;
1881  uch b1_min = rgb[bg[pat].rgb1_min].b;
1882  uch r2_min = rgb[bg[pat].rgb2_min].r;
1883  uch g2_min = rgb[bg[pat].rgb2_min].g;
1884  uch b2_min = rgb[bg[pat].rgb2_min].b;
1885  int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min;
1886  int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min;
1887  int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min;
1888  int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min;
1889  int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min;
1890  int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min;
1891 
1892  for (row = 0; row < rpng2_info.height; ++row) {
1893  yidx = (int)(row % bgscale);
1894  even_odd_vert = (int)((row / bgscale) & 1);
1895 
1896  r1 = r1_min + (r1_diff * yidx) / yidx_max;
1897  g1 = g1_min + (g1_diff * yidx) / yidx_max;
1898  b1 = b1_min + (b1_diff * yidx) / yidx_max;
1899  r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max;
1900  g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max;
1901  b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max;
1902 
1903  r2 = r2_min + (r2_diff * yidx) / yidx_max;
1904  g2 = g2_min + (g2_diff * yidx) / yidx_max;
1905  b2 = b2_min + (b2_diff * yidx) / yidx_max;
1906  r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max;
1907  g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max;
1908  b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max;
1909 
1910  dest = (char *)bg_data + row*bg_rowbytes;
1911  for (i = 0; i < rpng2_info.width; ++i) {
1912  even_odd_horiz = (int)((i / bgscale) & 1);
1913  even_odd = even_odd_vert ^ even_odd_horiz;
1914  invert_column =
1915  (even_odd_horiz && (bg[pat].type & 0x10));
1916  if (even_odd == 0) { /* gradient #1 */
1917  if (invert_column) {
1918  *dest++ = r1_inv;
1919  *dest++ = g1_inv;
1920  *dest++ = b1_inv;
1921  } else {
1922  *dest++ = r1;
1923  *dest++ = g1;
1924  *dest++ = b1;
1925  }
1926  } else { /* gradient #2 */
1927  if ((invert_column && invert_gradient2) ||
1928  (!invert_column && !invert_gradient2))
1929  {
1930  *dest++ = r2; /* not inverted or */
1931  *dest++ = g2; /* doubly inverted */
1932  *dest++ = b2;
1933  } else {
1934  *dest++ = r2_inv;
1935  *dest++ = g2_inv; /* singly inverted */
1936  *dest++ = b2_inv;
1937  }
1938  }
1939  }
1940  }
1941 
1942 /*---------------------------------------------------------------------------
1943  Soft gradient-diamonds with scale = bgscale. Code contributed by Adam
1944  M. Costello.
1945  ---------------------------------------------------------------------------*/
1946 
1947  } else if ((bg[pat].type & 0x07) == 1) {
1948 
1949  hmax = (bgscale-1)/2; /* half the max weight of a color */
1950  max = 2*hmax; /* the max weight of a color */
1951 
1952  r1 = rgb[bg[pat].rgb1_max].r;
1953  g1 = rgb[bg[pat].rgb1_max].g;
1954  b1 = rgb[bg[pat].rgb1_max].b;
1955  r2 = rgb[bg[pat].rgb2_max].r;
1956  g2 = rgb[bg[pat].rgb2_max].g;
1957  b2 = rgb[bg[pat].rgb2_max].b;
1958 
1959  for (row = 0; row < rpng2_info.height; ++row) {
1960  yidx = (int)(row % bgscale);
1961  if (yidx > hmax)
1962  yidx = bgscale-1 - yidx;
1963  dest = (char *)bg_data + row*bg_rowbytes;
1964  for (i = 0; i < rpng2_info.width; ++i) {
1965  xidx = (int)(i % bgscale);
1966  if (xidx > hmax)
1967  xidx = bgscale-1 - xidx;
1968  k = xidx + yidx;
1969  *dest++ = (k*r1 + (max-k)*r2) / max;
1970  *dest++ = (k*g1 + (max-k)*g2) / max;
1971  *dest++ = (k*b1 + (max-k)*b2) / max;
1972  }
1973  }
1974 
1975 /*---------------------------------------------------------------------------
1976  Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
1977  soids will equal bgscale?]. This one is slow but very cool. Code con-
1978  tributed by Pieter S. van der Meulen (originally in Smalltalk).
1979  ---------------------------------------------------------------------------*/
1980 
1981  } else if ((bg[pat].type & 0x07) == 2) {
1982  uch ch;
1983  int ii, x, y, hw, hh, grayspot;
1984  double freq, rotate, saturate, gray, intensity;
1985  double angle=0.0, aoffset=0.0, maxDist, dist;
1986  double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t;
1987 
1988  hh = (int)(rpng2_info.height / 2);
1989  hw = (int)(rpng2_info.width / 2);
1990 
1991  /* variables for radial waves:
1992  * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED]
1993  * freq: number of color beams originating from the center
1994  * grayspot: size of the graying center area (anti-alias)
1995  * rotate: rotation of the beams as a function of radius
1996  * saturate: saturation of beams' shape azimuthally
1997  */
1998  angle = CLIP(angle, 0.0, 360.0);
1999  grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw));
2000  freq = MAX((double)bg[pat].bg_freq, 0.0);
2001  saturate = (double)bg[pat].bg_bsat * 0.1;
2002  rotate = (double)bg[pat].bg_brot * 0.1;
2003  gray = 0.0;
2004  intensity = 0.0;
2005  maxDist = (double)((hw*hw) + (hh*hh));
2006 
2007  for (row = 0; row < rpng2_info.height; ++row) {
2008  y = (int)(row - hh);
2009  dest = (char *)bg_data + row*bg_rowbytes;
2010  for (i = 0; i < rpng2_info.width; ++i) {
2011  x = (int)(i - hw);
2012  angle = (x == 0)? PI_2 : atan((double)y / (double)x);
2013  gray = (double)MAX(ABS(y), ABS(x)) / grayspot;
2014  gray = MIN(1.0, gray);
2015  dist = (double)((x*x) + (y*y)) / maxDist;
2016  intensity = cos((angle+(rotate*dist*PI)) * freq) *
2017  gray * saturate;
2018  intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5;
2019  hue = (angle + PI) * INV_PI_360 + aoffset;
2020  s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh));
2021  s = MIN(MAX(s,0.0), 1.0);
2022  v = MIN(MAX(intensity,0.0), 1.0);
2023 
2024  if (s == 0.0) {
2025  ch = (uch)(v * 255.0);
2026  *dest++ = ch;
2027  *dest++ = ch;
2028  *dest++ = ch;
2029  } else {
2030  if ((hue < 0.0) || (hue >= 360.0))
2031  hue -= (((int)(hue / 360.0)) * 360.0);
2032  hue /= 60.0;
2033  ii = (int)hue;
2034  f = hue - (double)ii;
2035  p = (1.0 - s) * v;
2036  q = (1.0 - (s * f)) * v;
2037  t = (1.0 - (s * (1.0 - f))) * v;
2038  if (ii == 0) { red = v; green = t; blue = p; }
2039  else if (ii == 1) { red = q; green = v; blue = p; }
2040  else if (ii == 2) { red = p; green = v; blue = t; }
2041  else if (ii == 3) { red = p; green = q; blue = v; }
2042  else if (ii == 4) { red = t; green = p; blue = v; }
2043  else if (ii == 5) { red = v; green = p; blue = q; }
2044  *dest++ = (uch)(red * 255.0);
2045  *dest++ = (uch)(green * 255.0);
2046  *dest++ = (uch)(blue * 255.0);
2047  }
2048  }
2049  }
2050  }
2051 
2052 } /* end function rpng2_x_reload_bg_image() */
2053 
2054 
2055 
2056 
2057 
2058 static int is_number(char *p)
2059 {
2060  while (*p) {
2061  if (!isdigit(*p))
2062  return FALSE;
2063  ++p;
2064  }
2065  return TRUE;
2066 }
2067 
2068 #endif /* FEATURE_LOOP */
2069 
2070 
2071 
2072 
2073 
2074 static void rpng2_x_cleanup(void)
2075 {
2076  if (bg_image && bg_data) {
2077  free(bg_data);
2078  bg_data = NULL;
2079  }
2080 
2081  if (rpng2_info.image_data) {
2082  free(rpng2_info.image_data);
2083  rpng2_info.image_data = NULL;
2084  }
2085 
2086  if (rpng2_info.row_pointers) {
2087  free(rpng2_info.row_pointers);
2088  rpng2_info.row_pointers = NULL;
2089  }
2090 
2091  if (ximage) {
2092  if (ximage->data) {
2093  free(ximage->data); /* we allocated it, so we free it */
2094  ximage->data = (char *)NULL; /* instead of XDestroyImage() */
2095  }
2096  XDestroyImage(ximage);
2097  ximage = NULL;
2098  }
2099 
2100  if (have_gc)
2101  XFreeGC(display, gc);
2102 
2103  if (have_window)
2104  XDestroyWindow(display, window);
2105 
2106  if (have_colormap)
2107  XFreeColormap(display, colormap);
2108 
2109  if (have_nondefault_visual)
2110  XFree(visual_list);
2111 }
2112 
2113 
2114 
2115 
2116 
2117 static int rpng2_x_msb(ulg u32val)
2118 {
2119  int i;
2120 
2121  for (i = 31; i >= 0; --i) {
2122  if (u32val & 0x80000000L)
2123  break;
2124  u32val <<= 1;
2125  }
2126  return i;
2127 }
#define alpha_composite(composite, fg, alpha, bg)
Definition: rpng2-x.c:151
GLint GLint GLsizei GLsizei height
#define rgb1_max
Definition: rpng2-x.c:136
GLboolean GLboolean GLboolean GLboolean a
GLfloat GLfloat p
GLint GLint GLsizei GLsizei GLsizei depth
void(* mainprog_init)(void)
Definition: readpng2.h:88
#define NULL
Definition: ftobjs.h:61
GLint GLint GLint GLint GLint GLint y
#define rgb2_min
Definition: rpng2-x.c:139
int readpng2_check_sig(uch *sig, int num)
Definition: readpng2.c:160
GLdouble GLdouble GLdouble GLdouble q
#define rgb1_min
Definition: rpng2-x.c:137
#define MAX(a, b)
Definition: rpng2-x.c:123
#define MSBFirst
Definition: pcf.h:169
char * malloc()
GLint GLint GLsizei width
#define ABS(a)
Definition: rpng2-x.c:126
GLint GLint GLint GLint GLint x
local void rotate(unsigned char *list, unsigned len, unsigned rot)
Definition: gzappend.c:123
const char * filename
Definition: ioapi.h:135
GLfloat green
#define QUIT(e, k)
Definition: rpng2-x.c:130
unsigned long ulg
Definition: zutil.h:38
GLboolean GLboolean GLboolean b
void readpng2_version_info(void)
Definition: readpng2.c:74
int pause_after_pass
Definition: rpng2-x.c:199
png_uint_32 i
Definition: png.h:2640
int demo_timing
Definition: rpng2-x.c:200
GLenum GLenum GLvoid * row
GLfloat GLfloat blue
void readpng2_cleanup(mainprog_info *mainprog_ptr)
Definition: readpng2.c:607
#define LSBFirst
Definition: pcf.h:168
unsigned short ush
Definition: zutil.h:36
void(* mainprog_finish_display)(void)
Definition: readpng2.h:90
#define PI_2
Definition: rpng2-x.c:121
FT_Error error
Definition: cffdrivr.c:411
const GLdouble * v
GLdouble GLdouble GLdouble r
JHUFF_TBL long freq[]
Definition: jchuff.h:47
unsigned char inbuf[SIZE]
Definition: gun.c:161
#define rgb2_max
Definition: rpng2-x.c:138
int main(int argc, char **argv)
Definition: rpng2-x.c:292
#define LONGNAME
Definition: rpng2-x.c:96
int free()
local int root
Definition: enough.c:171
GLenum src
GLfloat angle
#define RESNAME
Definition: rpng2-x.c:98
#define FALSE
Definition: ftobjs.h:57
T atan(T a)
Definition: glsl_math.hpp:277
local int max
Definition: enough.c:170
#define Trace(x)
Definition: zutil.h:197
if(!abbox) return FT_THROW(Invalid_Argument)
GLenum type
int readpng2_decode_data(mainprog_info *mainprog_ptr, uch *rawbuf, ulg length)
Definition: readpng2.c:351
typedef int
Definition: png.h:978
#define INBUFSIZE
Definition: rpng2-x.c:158
FILE * infile
Definition: cdjpeg.h:141
#define RESCLASS
Definition: rpng2-x.c:99
uch * image_data
Definition: readpng2.h:91
int readpng2_init(mainprog_info *mainprog_ptr)
Definition: readpng2.c:170
#define PROGNAME
Definition: rpng2-x.c:95
double display_exponent
Definition: readpng2.h:83
T cos(T a)
Definition: glsl_math.hpp:225
GLdouble s
GLboolean GLboolean g
ulg usleep_duration
Definition: rpng2-x.c:201
#define MIN(a, b)
Definition: rpng2-x.c:124
Definition: readpng2.h:75
void(* mainprog_display_row)(ulg row_num)
Definition: readpng2.h:89
int double red
Definition: png.h:1498
GLdouble GLdouble t
int need_bgcolor
Definition: readpng2.h:98
#define VERSION
Definition: rpng2-x.c:97
#define CLIP(a, min, max)
Definition: rpng2-x.c:125
local void quit(char *why)
Definition: fitblk.c:62
GLfloat f
uch ** row_pointers
Definition: readpng2.h:92
#define TRUE
Definition: ftobjs.h:53
#define INV_PI_360
Definition: rpng2-x.c:122
unsigned char uch
Definition: zutil.h:34
#define PI
Definition: rpng2-x.c:119