1 /*---------------------------------------------------------------------------
3 rpng2 - progressive-model PNG display program rpng2-x.c
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).
12 Thanks to Adam Costello and Pieter S. van der Meulen for the "diamond"
13 and "radial waves" patterns, respectively.
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?
21 ---------------------------------------------------------------------------
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
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-
43 - 2.03: deleted runtime MMX-enabling/disabling and obsolete -mmx* options
44 - 2.04: Added "void(foo);" statements to quiet pedantic compiler warnings
45 about unused variables (GR-P)
46 - 2.05: Use nanosleep() instead of usleep(), which is deprecated (GR-P).
47 ---------------------------------------------------------------------------
49 Copyright (c) 1998-2010, 2014-2015 Greg Roelofs. All rights reserved.
51 This software is provided "as is," without warranty of any kind,
52 express or implied. In no event shall the author or contributors
53 be held liable for any damages arising in any way from the use of
56 The contents of this file are DUAL-LICENSED. You may modify and/or
57 redistribute this software according to the terms of one of the
58 following two licenses (at your option):
61 LICENSE 1 ("BSD-like with advertising clause"):
63 Permission is granted to anyone to use this software for any purpose,
64 including commercial applications, and to alter it and redistribute
65 it freely, subject to the following restrictions:
67 1. Redistributions of source code must retain the above copyright
68 notice, disclaimer, and this list of conditions.
69 2. Redistributions in binary form must reproduce the above copyright
70 notice, disclaimer, and this list of conditions in the documenta-
71 tion and/or other materials provided with the distribution.
72 3. All advertising materials mentioning features or use of this
73 software must display the following acknowledgment:
75 This product includes software developed by Greg Roelofs
76 and contributors for the book, "PNG: The Definitive Guide,"
77 published by O'Reilly and Associates.
80 LICENSE 2 (GNU GPL v2 or later):
82 This program is free software; you can redistribute it and/or modify
83 it under the terms of the GNU General Public License as published by
84 the Free Software Foundation; either version 2 of the License, or
85 (at your option) any later version.
87 This program is distributed in the hope that it will be useful,
88 but WITHOUT ANY WARRANTY; without even the implied warranty of
89 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
90 GNU General Public License for more details.
92 You should have received a copy of the GNU General Public License
93 along with this program; if not, write to the Free Software Foundation,
94 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
96 ---------------------------------------------------------------------------*/
98 #define PROGNAME "rpng2-x"
99 #define LONGNAME "Progressive PNG Viewer for X"
100 #define VERSION "2.04 of 15 June 2014"
101 #define RESNAME "rpng2" /* our X resource application name */
102 #define RESCLASS "Rpng" /* our X resource class name */
108 #include <setjmp.h> /* for jmpbuf declaration in readpng2.h */
110 #include <math.h> /* only for PvdM background code */
111 #include <X11/Xlib.h>
112 #include <X11/Xutil.h>
114 #include <X11/keysym.h> /* defines XK_* macros */
116 #if _POSIX_C_SOURCE >= 199309L /* have nanosleep() */
118 # define usleep(usec) { \
119 struct timespec ts; \
121 ts.tv_nsec = (usec) * 1000; \
122 nanosleep(&ts, NULL); }
125 #ifndef usleep /* have neither nanosleep() nor usleep() */
126 # define usleep(x) sleep(((x)+499999)/1000000)
133 /* all for PvdM background code: */
135 # define PI 3.141592653589793238
137 #define PI_2 (PI*0.5)
138 #define INV_PI_360 (360.0 / PI)
139 #define MAX(a,b) (a>b?a:b)
140 #define MIN(a,b) (a<b?a:b)
141 #define CLIP(a,min,max) MAX(min,MIN((a),max))
142 #define ABS(a) ((a)<0?-(a):(a))
143 #define CLIP8P(c) MAX(0,(MIN((c),255))) /* 8-bit pos. integer (uch) */
144 #define ROUNDF(f) ((int)(f + 0.5))
146 #define QUIT(e,k) ((e.type == ButtonPress && e.xbutton.button == Button1) || \
147 (e.type == KeyPress && /* v--- or 1 for shifted keys */ \
148 ((k = XLookupKeysym(&e.xkey, 0)) == XK_q || k == XK_Escape)))
150 #define NO_24BIT_MASKS /* undef case not fully written--only for redisplay() */
152 #define rgb1_max bg_freq
153 #define rgb1_min bg_gray
154 #define rgb2_max bg_bsat
155 #define rgb2_min bg_brot
157 /* #define DEBUG */ /* this enables the Trace() macros */
159 #include "readpng2.h" /* typedefs, common macros, readpng2 prototypes */
162 /* could just include png.h, but this macro is the only thing we need
163 * (name and typedefs changed to local versions); note that side effects
164 * only happen with alpha (which could easily be avoided with
165 * "ush acopy = (alpha);") */
167 #define alpha_composite(composite, fg, alpha, bg) { \
168 ush temp = ((ush)(fg)*(ush)(alpha) + \
169 (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \
170 (composite) = (uch)((temp + (temp >> 8)) >> 8); \
174 #define INBUFSIZE 4096 /* with pseudo-timing on (1 sec delay/block), this
175 * block size corresponds roughly to a download
176 * speed 10% faster than theoretical 33.6K maximum
177 * (assuming 8 data bits, 1 stop bit and no other
180 /* local prototypes */
181 static void rpng2_x_init (void);
182 static int rpng2_x_create_window (void);
183 static int rpng2_x_load_bg_image (void);
184 static void rpng2_x_display_row (ulg row
);
185 static void rpng2_x_finish_display (void);
186 static void rpng2_x_redisplay_image (ulg startcol
, ulg startrow
,
187 ulg width
, ulg height
);
189 static void rpng2_x_reload_bg_image (void);
190 static int is_number (char *p
);
192 static void rpng2_x_cleanup (void);
193 static int rpng2_x_msb (ulg u32val
);
196 static char titlebar
[1024], *window_name
= titlebar
;
197 static char *appname
= LONGNAME
;
198 static char *icon_name
= PROGNAME
;
199 static char *res_name
= RESNAME
;
200 static char *res_class
= RESCLASS
;
201 static char *filename
;
204 static mainprog_info rpng2_info
;
206 static uch inbuf
[INBUFSIZE
];
209 static int pat
= 6; /* must be less than num_bgpat */
210 static int bg_image
= 0;
211 static int bgscale
, bgscale_default
= 16;
212 static ulg bg_rowbytes
;
215 int pause_after_pass
= FALSE
;
216 int demo_timing
= FALSE
;
217 ulg usleep_duration
= 0L;
219 static struct rgb_color
{
222 { 0, 0, 0}, /* 0: black */
223 {255, 255, 255}, /* 1: white */
224 {173, 132, 57}, /* 2: tan */
225 { 64, 132, 0}, /* 3: medium green */
226 {189, 117, 1}, /* 4: gold */
227 {253, 249, 1}, /* 5: yellow */
228 { 0, 0, 255}, /* 6: blue */
229 { 0, 0, 120}, /* 7: medium blue */
230 {255, 0, 255}, /* 8: magenta */
231 { 64, 0, 64}, /* 9: dark magenta */
232 {255, 0, 0}, /* 10: red */
233 { 64, 0, 0}, /* 11: dark red */
234 {255, 127, 0}, /* 12: orange */
235 {192, 96, 0}, /* 13: darker orange */
236 { 24, 60, 0}, /* 14: dark green-yellow */
237 { 85, 125, 200}, /* 15: ice blue */
238 {192, 192, 192} /* 16: Netscape/Mosaic gray */
240 /* not used for now, but should be for error-checking:
241 static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color);
245 This whole struct is a fairly cheesy way to keep the number of
246 command-line options to a minimum. The radial-waves background
247 type is a particularly poor fit to the integer elements of the
248 struct...but a few macros and a little fixed-point math will do
252 F E D C B A 9 8 7 6 5 4 3 2 1 0
254 | | +-+-+-- 0 = sharp-edged checkerboard
255 | | 1 = soft diamonds
258 | +-- gradient #2 inverted?
259 +-- alternating columns inverted?
261 static struct background_pattern
{
263 int rgb1_max
, rgb1_min
; /* or bg_freq, bg_gray */
264 int rgb2_max
, rgb2_min
; /* or bg_bsat, bg_brot (both scaled by 10)*/
266 {0, 1,1, 16,16}, /* checkered: white vs. light gray (basic) */
267 {0+8, 2,0, 1,15}, /* checkered: tan/black vs. white/ice blue */
268 {0+24, 2,0, 1,0}, /* checkered: tan/black vs. white/black */
269 {0+8, 4,5, 0,2}, /* checkered: gold/yellow vs. black/tan */
270 {0+8, 4,5, 0,6}, /* checkered: gold/yellow vs. black/blue */
271 {0, 7,0, 8,9}, /* checkered: deep blue/black vs. magenta */
272 {0+8, 13,0, 5,14}, /* checkered: orange/black vs. yellow */
273 {0+8, 12,0, 10,11}, /* checkered: orange/black vs. red */
274 {1, 7,0, 8,0}, /* diamonds: deep blue/black vs. magenta */
275 {1, 12,0, 11,0}, /* diamonds: orange vs. dark red */
276 {1, 10,0, 7,0}, /* diamonds: red vs. medium blue */
277 {1, 4,0, 5,0}, /* diamonds: gold vs. yellow */
278 {1, 3,0, 0,0}, /* diamonds: medium green vs. black */
279 {2, 16, 100, 20, 0}, /* radial: ~hard radial color-beams */
280 {2, 18, 100, 10, 2}, /* radial: soft, curved radial color-beams */
281 {2, 16, 256, 100, 250}, /* radial: very tight spiral */
282 {2, 10000, 256, 11, 0} /* radial: dipole-moire' (almost fractal) */
284 static int num_bgpat
= sizeof(bg
) / sizeof(struct background_pattern
);
287 /* X-specific variables */
288 static char *displayname
;
289 static XImage
*ximage
;
290 static Display
*display
;
292 static Visual
*visual
;
293 static XVisualInfo
*visual_list
;
294 static int RShift
, GShift
, BShift
;
295 static ulg RMask
, GMask
, BMask
;
296 static Window window
;
298 static Colormap colormap
;
300 static int have_nondefault_visual
= FALSE
;
301 static int have_colormap
= FALSE
;
302 static int have_window
= FALSE
;
303 static int have_gc
= FALSE
;
308 int main(int argc
, char **argv
)
313 char *p
, *bgstr
= NULL
;
320 long loop_interval
= -1; /* seconds (100,000 max) */
322 double LUT_exponent
; /* just the lookup table */
323 double CRT_exponent
= 2.2; /* just the monitor */
324 double default_display_exponent
; /* whole display system */
329 /* First initialize a few things, just to be sure--memset takes care of
330 * default background color (black), booleans (FALSE), pointers (NULL),
333 displayname
= (char *)NULL
;
334 filename
= (char *)NULL
;
335 memset(&rpng2_info
, 0, sizeof(mainprog_info
));
338 /* Set the default value for our display-system exponent, i.e., the
339 * product of the CRT exponent and the exponent corresponding to
340 * the frame-buffer's lookup table (LUT), if any. This is not an
341 * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
342 * ones), but it should cover 99% of the current possibilities. */
345 /* third-party utilities can modify the default LUT exponent */
346 LUT_exponent
= 1.0 / 2.2;
348 if (some_next_function_that_returns_gamma(&next_gamma))
349 LUT_exponent = 1.0 / next_gamma;
352 LUT_exponent
= 1.0 / 1.7;
353 /* there doesn't seem to be any documented function to
354 * get the "gamma" value, so we do it the hard way */
355 infile
= fopen("/etc/config/system.glGammaVal", "r");
359 fgets(tmpline
, 80, infile
);
361 sgi_gamma
= atof(tmpline
);
363 LUT_exponent
= 1.0 / sgi_gamma
;
365 #elif defined(Macintosh)
366 LUT_exponent
= 1.8 / 2.61;
368 if (some_mac_function_that_returns_gamma(&mac_gamma))
369 LUT_exponent = mac_gamma / 2.61;
372 LUT_exponent
= 1.0; /* assume no LUT: most PCs */
375 /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
376 default_display_exponent
= LUT_exponent
* CRT_exponent
;
379 /* If the user has set the SCREEN_GAMMA environment variable as suggested
380 * (somewhat imprecisely) in the libpng documentation, use that; otherwise
381 * use the default value we just calculated. Either way, the user may
382 * override this via a command-line option. */
384 if ((p
= getenv("SCREEN_GAMMA")) != NULL
)
385 rpng2_info
.display_exponent
= atof(p
);
387 rpng2_info
.display_exponent
= default_display_exponent
;
390 /* Now parse the command line for options and the PNG filename. */
392 while (*++argv
&& !error
) {
393 if (!strncmp(*argv
, "-display", 2)) {
398 } else if (!strncmp(*argv
, "-gamma", 2)) {
402 rpng2_info
.display_exponent
= atof(*argv
);
403 if (rpng2_info
.display_exponent
<= 0.0)
406 } else if (!strncmp(*argv
, "-bgcolor", 4)) {
411 if (strlen(bgstr
) != 7 || bgstr
[0] != '#')
418 } else if (!strncmp(*argv
, "-bgpat", 4)) {
423 if (pat
>= 0 && pat
< num_bgpat
) {
429 } else if (!strncmp(*argv
, "-usleep", 2)) {
433 usleep_duration
= (ulg
)atol(*argv
);
436 } else if (!strncmp(*argv
, "-pause", 2)) {
437 pause_after_pass
= TRUE
;
438 } else if (!strncmp(*argv
, "-timing", 2)) {
441 } else if (!strncmp(*argv
, "-loop", 2)) {
443 if (!argv
[1] || !is_number(argv
[1]))
447 loop_interval
= atol(*argv
);
448 if (loop_interval
< 0)
450 else if (loop_interval
> 100000) /* bit more than one day */
451 loop_interval
= 100000;
457 if (argv
[1]) /* shouldn't be any more args after filename */
460 ++error
; /* not expecting any other options */
468 /* print usage screen if any errors up to this point */
471 fprintf(stderr
, "\n%s %s: %s\n\n", PROGNAME
, VERSION
, appname
);
472 readpng2_version_info();
476 "%s [-display xdpy] [-gamma exp] [-bgcolor bg | -bgpat pat]\n"
477 " %*s [-usleep dur | -timing] [-pause]\n",
478 PROGNAME
, (int)strlen(PROGNAME
), " ");
485 " xdpy\tname of the target X display (e.g., ``hostname:0'')\n"
486 " exp \ttransfer-function exponent (``gamma'') of the display\n"
487 "\t\t system in floating-point format (e.g., ``%.1f''); equal\n"
488 "\t\t to the product of the lookup-table exponent (varies)\n",
489 default_display_exponent
);
491 "\t\t and the CRT exponent (usually 2.2); must be positive\n"
492 " bg \tdesired background color in 7-character hex RGB format\n"
493 "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n"
494 "\t\t used with transparent images; overrides -bgpat\n"
495 " pat \tdesired background pattern number (0-%d); used with\n"
496 "\t\t transparent images; overrides -bgcolor\n",
500 " -loop\tloops through background images after initial display\n"
501 "\t\t is complete (depends on -bgpat)\n"
502 " sec \tseconds to display each background image (default = 2)\n");
505 " dur \tduration in microseconds to wait after displaying each\n"
506 "\t\t row (for demo purposes)\n"
507 " -timing\tenables delay for every block read, to simulate modem\n"
508 "\t\t download of image (~36 Kbps)\n"
509 " -pause\tpauses after displaying each pass until mouse clicked\n"
510 "\nPress Q, Esc or mouse button 1 (within image window, after image\n"
511 "is displayed) to quit.\n");
515 if (!(infile
= fopen(filename
, "rb"))) {
516 fprintf(stderr
, PROGNAME
": can't open PNG file [%s]\n", filename
);
519 incount
= fread(inbuf
, 1, INBUFSIZE
, infile
);
520 if (incount
< 8 || !readpng2_check_sig(inbuf
, 8)) {
521 fprintf(stderr
, PROGNAME
522 ": [%s] is not a PNG file: incorrect signature\n",
525 } else if ((rc
= readpng2_init(&rpng2_info
)) != 0) {
528 fprintf(stderr
, PROGNAME
529 ": [%s] has bad IHDR (libpng longjmp)\n", filename
);
532 fprintf(stderr
, PROGNAME
": insufficient memory\n");
535 fprintf(stderr
, PROGNAME
536 ": unknown readpng2_init() error\n");
541 Trace((stderr
, "about to call XOpenDisplay()\n"))
542 display
= XOpenDisplay(displayname
);
544 readpng2_cleanup(&rpng2_info
);
545 fprintf(stderr
, PROGNAME
": can't open X display [%s]\n",
546 displayname
? displayname
: "default");
556 fprintf(stderr
, PROGNAME
": aborting.\n");
561 /* set the title-bar string, but make sure buffer doesn't overflow */
563 alen
= strlen(appname
);
564 flen
= strlen(filename
);
565 if (alen
+ flen
+ 3 > 1023)
566 sprintf(titlebar
, "%s: ...%s", appname
, filename
+(alen
+flen
+6-1023));
568 sprintf(titlebar
, "%s: %s", appname
, filename
);
571 /* set some final rpng2_info variables before entering main data loop */
574 unsigned r
, g
, b
; /* this approach quiets compiler warnings */
576 sscanf(bgstr
+1, "%2x%2x%2x", &r
, &g
, &b
);
577 rpng2_info
.bg_red
= (uch
)r
;
578 rpng2_info
.bg_green
= (uch
)g
;
579 rpng2_info
.bg_blue
= (uch
)b
;
581 rpng2_info
.need_bgcolor
= TRUE
;
583 rpng2_info
.state
= kPreInit
;
584 rpng2_info
.mainprog_init
= rpng2_x_init
;
585 rpng2_info
.mainprog_display_row
= rpng2_x_display_row
;
586 rpng2_info
.mainprog_finish_display
= rpng2_x_finish_display
;
589 /* OK, this is the fun part: call readpng2_decode_data() at the start of
590 * the loop to deal with our first buffer of data (read in above to verify
591 * that the file is a PNG image), then loop through the file and continue
592 * calling the same routine to handle each chunk of data. It in turn
593 * passes the data to libpng, which will invoke one or more of our call-
594 * backs as decoded data become available. We optionally call sleep() for
595 * one second per iteration to simulate downloading the image via an analog
599 Trace((stderr
, "about to call readpng2_decode_data()\n"))
600 if (readpng2_decode_data(&rpng2_info
, inbuf
, incount
))
602 Trace((stderr
, "done with readpng2_decode_data()\n"))
604 if (error
|| incount
!= INBUFSIZE
|| rpng2_info
.state
== kDone
) {
605 if (rpng2_info
.state
== kDone
) {
606 Trace((stderr
, "done decoding PNG image\n"))
607 } else if (ferror(infile
)) {
608 fprintf(stderr
, PROGNAME
609 ": error while reading PNG image file\n");
611 } else if (feof(infile
)) {
612 fprintf(stderr
, PROGNAME
": end of file reached "
613 "(unexpectedly) while reading PNG image file\n");
615 } else /* if (error) */ {
616 /* will print error message below */
624 incount
= fread(inbuf
, 1, INBUFSIZE
, infile
);
628 /* clean up PNG stuff and report any decoding errors */
631 Trace((stderr
, "about to call readpng2_cleanup()\n"))
632 readpng2_cleanup(&rpng2_info
);
635 fprintf(stderr
, PROGNAME
": libpng error while decoding PNG image\n");
642 if (loop
&& bg_image
) {
643 Trace((stderr
, "entering -loop loop (FEATURE_LOOP)\n"))
646 struct timeval now
, then
;
648 /* get current time and add loop_interval to get target time */
649 if (gettimeofday(&then
, NULL
) == 0) {
650 then
.tv_sec
+= loop_interval
;
655 /* do quick check for a quit event but don't wait for it */
656 /* GRR BUG: should also check for Expose events and redraw... */
657 if (XCheckMaskEvent(display
, KeyPressMask
| ButtonPressMask
, &e
))
661 /* generate next background image */
662 if (++pat
>= num_bgpat
)
664 rpng2_x_reload_bg_image();
666 /* wait for timeout, using whatever means are available */
667 if (use_sleep
|| gettimeofday(&now
, NULL
) != 0) {
668 for (i
= loop_interval
; i
> 0; --i
) {
670 /* GRR BUG: also need to check for Expose (and redraw!) */
671 if (XCheckMaskEvent(display
, KeyPressMask
| ButtonPressMask
,
677 if (now
.tv_sec
< then
.tv_sec
||
678 (now
.tv_sec
== then
.tv_sec
&& now
.tv_usec
< then
.tv_usec
))
681 long seconds_to_go
= then
.tv_sec
- now
.tv_sec
;
684 /* basically chew up most of remaining loop-interval with
685 * calls to sleep(1) interleaved with checks for quit
686 * events, but also recalc time-to-go periodically; when
687 * done, clean up any remaining time with usleep() call
688 * (could also use SIGALRM, but signals are a pain...) */
689 while (seconds_to_go
-- > 1) {
690 int seconds_done
= 0;
692 for (i
= seconds_to_go
; i
> 0 && !quit
; --i
) {
694 /* GRR BUG: need to check for Expose and redraw */
695 if (XCheckMaskEvent(display
, KeyPressMask
|
696 ButtonPressMask
, &e
) && QUIT(e
,k
))
698 if (++seconds_done
> 1000)
699 break; /* time to redo seconds_to_go meas. */
704 /* OK, more than 1000 seconds since last check:
705 * correct the time-to-go measurement for drift */
706 if (gettimeofday(&now
, NULL
) == 0) {
707 if (now
.tv_sec
>= then
.tv_sec
)
709 seconds_to_go
= then
.tv_sec
- now
.tv_sec
;
711 ++seconds_to_go
; /* restore what we subtracted */
714 break; /* breaks outer do-loop, skips redisplay */
716 /* since difference between "now" and "then" is already
717 * eaten up to within a couple of seconds, don't need to
718 * worry about overflow--but might have overshot (neg.) */
719 if (gettimeofday(&now
, NULL
) == 0) {
720 usleep_usec
= 1000000L*(then
.tv_sec
- now
.tv_sec
) +
721 then
.tv_usec
- now
.tv_usec
;
723 usleep((ulg
)usleep_usec
);
728 /* composite image against new background and display (note that
729 * we do not take into account the time spent doing this...) */
730 rpng2_x_redisplay_image (0, 0, rpng2_info
.width
, rpng2_info
.height
);
733 } else /* FALL THROUGH and do the normal thing */
735 #endif /* FEATURE_LOOP */
737 /* wait for the user to tell us when to quit */
739 if (rpng2_info
.state
>= kWindowInit
) {
740 Trace((stderr
, "entering final wait-for-quit-event loop\n"))
742 XNextEvent(display
, &e
);
743 if (e
.type
== Expose
) {
744 XExposeEvent
*ex
= (XExposeEvent
*)&e
;
745 rpng2_x_redisplay_image (ex
->x
, ex
->y
, ex
->width
, ex
->height
);
747 } while (!QUIT(e
,k
));
749 fprintf(stderr
, PROGNAME
": init callback never called: probable "
750 "libpng error while decoding PNG metadata\n");
755 /* we're done: clean up all image and X resources and go away */
757 Trace((stderr
, "about to call rpng2_x_cleanup()\n"))
760 (void)argc
; /* Unused */
769 /* this function is called by readpng2_info_callback() in readpng2.c, which
770 * in turn is called by libpng after all of the pre-IDAT chunks have been
771 * read and processed--i.e., we now have enough info to finish initializing */
773 static void rpng2_x_init(void)
776 ulg rowbytes
= rpng2_info
.rowbytes
;
778 Trace((stderr
, "beginning rpng2_x_init()\n"))
779 Trace((stderr
, " rowbytes = %d\n", rpng2_info
.rowbytes
))
780 Trace((stderr
, " width = %ld\n", rpng2_info
.width
))
781 Trace((stderr
, " height = %ld\n", rpng2_info
.height
))
783 rpng2_info
.image_data
= (uch
*)malloc(rowbytes
* rpng2_info
.height
);
784 if (!rpng2_info
.image_data
) {
785 readpng2_cleanup(&rpng2_info
);
789 rpng2_info
.row_pointers
= (uch
**)malloc(rpng2_info
.height
* sizeof(uch
*));
790 if (!rpng2_info
.row_pointers
) {
791 free(rpng2_info
.image_data
);
792 rpng2_info
.image_data
= NULL
;
793 readpng2_cleanup(&rpng2_info
);
797 for (i
= 0; i
< rpng2_info
.height
; ++i
)
798 rpng2_info
.row_pointers
[i
] = rpng2_info
.image_data
+ i
*rowbytes
;
801 /* do the basic X initialization stuff, make the window, and fill it with
802 * the user-specified, file-specified or default background color or
805 if (rpng2_x_create_window()) {
807 /* GRR TEMPORARY HACK: this is fundamentally no different from cases
808 * above; libpng should call our error handler to longjmp() back to us
809 * when png_ptr goes away. If we/it segfault instead, seems like a
812 /* we're here via libpng callback, so if window fails, clean and bail */
813 readpng2_cleanup(&rpng2_info
);
818 rpng2_info
.state
= kWindowInit
;
825 static int rpng2_x_create_window(void)
827 ulg bg_red
= rpng2_info
.bg_red
;
828 ulg bg_green
= rpng2_info
.bg_green
;
829 ulg bg_blue
= rpng2_info
.bg_blue
;
832 int need_colormap
= FALSE
;
838 XSetWindowAttributes attr
;
839 XTextProperty windowName
, *pWindowName
= &windowName
;
840 XTextProperty iconName
, *pIconName
= &iconName
;
841 XVisualInfo visual_info
;
842 XSizeHints
*size_hints
;
844 XClassHint
*class_hints
;
847 Trace((stderr
, "beginning rpng2_x_create_window()\n"))
849 screen
= DefaultScreen(display
);
850 depth
= DisplayPlanes(display
, screen
);
851 root
= RootWindow(display
, screen
);
854 XSynchronize(display
, True
);
857 if (depth
!= 16 && depth
!= 24 && depth
!= 32) {
858 int visuals_matched
= 0;
860 Trace((stderr
, "default depth is %d: checking other visuals\n",
864 visual_info
.screen
= screen
;
865 visual_info
.depth
= 24;
866 visual_list
= XGetVisualInfo(display
,
867 VisualScreenMask
| VisualDepthMask
, &visual_info
, &visuals_matched
);
868 if (visuals_matched
== 0) {
869 /* GRR: add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */
870 fprintf(stderr
, "default screen depth %d not supported, and no"
871 " 24-bit visuals found\n", depth
);
874 Trace((stderr
, "XGetVisualInfo() returned %d 24-bit visuals\n",
876 visual
= visual_list
[0].visual
;
877 depth
= visual_list
[0].depth
;
879 colormap_size = visual_list[0].colormap_size;
880 visual_class = visual->class;
881 visualID = XVisualIDFromVisual(visual);
883 have_nondefault_visual
= TRUE
;
884 need_colormap
= TRUE
;
886 XMatchVisualInfo(display
, screen
, depth
, TrueColor
, &visual_info
);
887 visual
= visual_info
.visual
;
890 RMask
= visual
->red_mask
;
891 GMask
= visual
->green_mask
;
892 BMask
= visual
->blue_mask
;
894 /* GRR: add/check 8-bit support */
895 if (depth
== 8 || need_colormap
) {
896 colormap
= XCreateColormap(display
, root
, visual
, AllocNone
);
898 fprintf(stderr
, "XCreateColormap() failed\n");
901 have_colormap
= TRUE
;
903 bg_image
= FALSE
; /* gradient just wastes palette entries */
905 if (depth
== 15 || depth
== 16) {
906 RShift
= 15 - rpng2_x_msb(RMask
); /* these are right-shifts */
907 GShift
= 15 - rpng2_x_msb(GMask
);
908 BShift
= 15 - rpng2_x_msb(BMask
);
909 } else if (depth
> 16) {
910 RShift
= rpng2_x_msb(RMask
) - 7; /* these are left-shifts */
911 GShift
= rpng2_x_msb(GMask
) - 7;
912 BShift
= rpng2_x_msb(BMask
) - 7;
914 if (depth
>= 15 && (RShift
< 0 || GShift
< 0 || BShift
< 0)) {
915 fprintf(stderr
, "rpng2 internal logic error: negative X shift(s)!\n");
919 /*---------------------------------------------------------------------------
920 Finally, create the window.
921 ---------------------------------------------------------------------------*/
923 attr
.backing_store
= Always
;
924 attr
.event_mask
= ExposureMask
| KeyPressMask
| ButtonPressMask
;
925 attrmask
= CWBackingStore
| CWEventMask
;
926 if (have_nondefault_visual
) {
927 attr
.colormap
= colormap
;
928 attr
.background_pixel
= 0;
929 attr
.border_pixel
= 1;
930 attrmask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
933 window
= XCreateWindow(display
, root
, 0, 0, rpng2_info
.width
,
934 rpng2_info
.height
, 0, depth
, InputOutput
, visual
, attrmask
, &attr
);
936 if (window
== None
) {
937 fprintf(stderr
, "XCreateWindow() failed\n");
943 XSetWindowColormap(display
, window
, colormap
);
945 if (!XStringListToTextProperty(&window_name
, 1, pWindowName
))
947 if (!XStringListToTextProperty(&icon_name
, 1, pIconName
))
950 /* OK if either hints allocation fails; XSetWMProperties() allows NULLs */
952 if ((size_hints
= XAllocSizeHints()) != NULL
) {
953 /* window will not be resizable */
954 size_hints
->flags
= PMinSize
| PMaxSize
;
955 size_hints
->min_width
= size_hints
->max_width
= (int)rpng2_info
.width
;
956 size_hints
->min_height
= size_hints
->max_height
=
957 (int)rpng2_info
.height
;
960 if ((wm_hints
= XAllocWMHints()) != NULL
) {
961 wm_hints
->initial_state
= NormalState
;
962 wm_hints
->input
= True
;
963 /* wm_hints->icon_pixmap = icon_pixmap; */
964 wm_hints
->flags
= StateHint
| InputHint
/* | IconPixmapHint */ ;
967 if ((class_hints
= XAllocClassHint()) != NULL
) {
968 class_hints
->res_name
= res_name
;
969 class_hints
->res_class
= res_class
;
972 XSetWMProperties(display
, window
, pWindowName
, pIconName
, NULL
, 0,
973 size_hints
, wm_hints
, class_hints
);
975 /* various properties and hints no longer needed; free memory */
977 XFree(pWindowName
->value
);
979 XFree(pIconName
->value
);
987 XMapWindow(display
, window
);
989 gc
= XCreateGC(display
, window
, 0, &gcvalues
);
992 /*---------------------------------------------------------------------------
993 Allocate memory for the X- and display-specific version of the image.
994 ---------------------------------------------------------------------------*/
996 if (depth
== 24 || depth
== 32) {
997 xdata
= (uch
*)malloc(4*rpng2_info
.width
*rpng2_info
.height
);
999 } else if (depth
== 16) {
1000 xdata
= (uch
*)malloc(2*rpng2_info
.width
*rpng2_info
.height
);
1002 } else /* depth == 8 */ {
1003 xdata
= (uch
*)malloc(rpng2_info
.width
*rpng2_info
.height
);
1008 fprintf(stderr
, PROGNAME
": unable to allocate image memory\n");
1012 ximage
= XCreateImage(display
, visual
, depth
, ZPixmap
, 0,
1013 (char *)xdata
, rpng2_info
.width
, rpng2_info
.height
, pad
, 0);
1016 fprintf(stderr
, PROGNAME
": XCreateImage() failed\n");
1021 /* to avoid testing the byte order every pixel (or doubling the size of
1022 * the drawing routine with a giant if-test), we arbitrarily set the byte
1023 * order to MSBFirst and let Xlib worry about inverting things on little-
1024 * endian machines (e.g., Linux/x86, old VAXen, etc.)--this is not the
1025 * most efficient approach (the giant if-test would be better), but in
1026 * the interest of clarity, we'll take the easy way out... */
1028 ximage
->byte_order
= MSBFirst
;
1030 /*---------------------------------------------------------------------------
1031 Fill window with the specified background color (default is black) or
1032 faked "background image" (but latter is disabled if 8-bit; gradients
1033 just waste palette entries).
1034 ---------------------------------------------------------------------------*/
1037 rpng2_x_load_bg_image(); /* resets bg_image if fails */
1040 if (depth
== 24 || depth
== 32) {
1041 bg_pixel
= (bg_red
<< RShift
) |
1042 (bg_green
<< GShift
) |
1043 (bg_blue
<< BShift
);
1044 } else if (depth
== 16) {
1045 bg_pixel
= (((bg_red
<< 8) >> RShift
) & RMask
) |
1046 (((bg_green
<< 8) >> GShift
) & GMask
) |
1047 (((bg_blue
<< 8) >> BShift
) & BMask
);
1048 } else /* depth == 8 */ {
1050 /* GRR: add 8-bit support */
1053 XSetForeground(display
, gc
, bg_pixel
);
1054 XFillRectangle(display
, window
, gc
, 0, 0, rpng2_info
.width
,
1058 /*---------------------------------------------------------------------------
1059 Wait for first Expose event to do any drawing, then flush and return.
1060 ---------------------------------------------------------------------------*/
1063 XNextEvent(display
, &e
);
1064 while (e
.type
!= Expose
|| e
.xexpose
.count
);
1070 } /* end function rpng2_x_create_window() */
1076 static int rpng2_x_load_bg_image(void)
1080 uch r1
, r2
, g1
, g2
, b1
, b2
;
1081 uch r1_inv
, r2_inv
, g1_inv
, g2_inv
, b1_inv
, b2_inv
;
1083 int xidx
, yidx
, yidx_max
;
1084 int even_odd_vert
, even_odd_horiz
, even_odd
;
1085 int invert_gradient2
= (bg
[pat
].type
& 0x08);
1087 int ximage_rowbytes
= ximage
->bytes_per_line
;
1091 /*---------------------------------------------------------------------------
1092 Allocate buffer for fake background image to be used with transparent
1093 images; if this fails, revert to plain background color.
1094 ---------------------------------------------------------------------------*/
1096 bg_rowbytes
= 3 * rpng2_info
.width
;
1097 bg_data
= (uch
*)malloc(bg_rowbytes
* rpng2_info
.height
);
1099 fprintf(stderr
, PROGNAME
1100 ": unable to allocate memory for background image\n");
1105 bgscale
= (pat
== 0)? 8 : bgscale_default
;
1106 yidx_max
= bgscale
- 1;
1108 /*---------------------------------------------------------------------------
1109 Vertical gradients (ramps) in NxN squares, alternating direction and
1110 colors (N == bgscale).
1111 ---------------------------------------------------------------------------*/
1113 if ((bg
[pat
].type
& 0x07) == 0) {
1114 uch r1_min
= rgb
[bg
[pat
].rgb1_min
].r
;
1115 uch g1_min
= rgb
[bg
[pat
].rgb1_min
].g
;
1116 uch b1_min
= rgb
[bg
[pat
].rgb1_min
].b
;
1117 uch r2_min
= rgb
[bg
[pat
].rgb2_min
].r
;
1118 uch g2_min
= rgb
[bg
[pat
].rgb2_min
].g
;
1119 uch b2_min
= rgb
[bg
[pat
].rgb2_min
].b
;
1120 int r1_diff
= rgb
[bg
[pat
].rgb1_max
].r
- r1_min
;
1121 int g1_diff
= rgb
[bg
[pat
].rgb1_max
].g
- g1_min
;
1122 int b1_diff
= rgb
[bg
[pat
].rgb1_max
].b
- b1_min
;
1123 int r2_diff
= rgb
[bg
[pat
].rgb2_max
].r
- r2_min
;
1124 int g2_diff
= rgb
[bg
[pat
].rgb2_max
].g
- g2_min
;
1125 int b2_diff
= rgb
[bg
[pat
].rgb2_max
].b
- b2_min
;
1127 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1128 yidx
= (int)(row
% bgscale
);
1129 even_odd_vert
= (int)((row
/ bgscale
) & 1);
1131 r1
= r1_min
+ (r1_diff
* yidx
) / yidx_max
;
1132 g1
= g1_min
+ (g1_diff
* yidx
) / yidx_max
;
1133 b1
= b1_min
+ (b1_diff
* yidx
) / yidx_max
;
1134 r1_inv
= r1_min
+ (r1_diff
* (yidx_max
-yidx
)) / yidx_max
;
1135 g1_inv
= g1_min
+ (g1_diff
* (yidx_max
-yidx
)) / yidx_max
;
1136 b1_inv
= b1_min
+ (b1_diff
* (yidx_max
-yidx
)) / yidx_max
;
1138 r2
= r2_min
+ (r2_diff
* yidx
) / yidx_max
;
1139 g2
= g2_min
+ (g2_diff
* yidx
) / yidx_max
;
1140 b2
= b2_min
+ (b2_diff
* yidx
) / yidx_max
;
1141 r2_inv
= r2_min
+ (r2_diff
* (yidx_max
-yidx
)) / yidx_max
;
1142 g2_inv
= g2_min
+ (g2_diff
* (yidx_max
-yidx
)) / yidx_max
;
1143 b2_inv
= b2_min
+ (b2_diff
* (yidx_max
-yidx
)) / yidx_max
;
1145 dest
= (char *)bg_data
+ row
*bg_rowbytes
;
1146 for (i
= 0; i
< rpng2_info
.width
; ++i
) {
1147 even_odd_horiz
= (int)((i
/ bgscale
) & 1);
1148 even_odd
= even_odd_vert
^ even_odd_horiz
;
1150 (even_odd_horiz
&& (bg
[pat
].type
& 0x10));
1151 if (even_odd
== 0) { /* gradient #1 */
1152 if (invert_column
) {
1161 } else { /* gradient #2 */
1162 if ((invert_column
&& invert_gradient2
) ||
1163 (!invert_column
&& !invert_gradient2
))
1165 *dest
++ = r2
; /* not inverted or */
1166 *dest
++ = g2
; /* doubly inverted */
1170 *dest
++ = g2_inv
; /* singly inverted */
1177 /*---------------------------------------------------------------------------
1178 Soft gradient-diamonds with scale = bgscale. Code contributed by Adam
1180 ---------------------------------------------------------------------------*/
1182 } else if ((bg
[pat
].type
& 0x07) == 1) {
1184 hmax
= (bgscale
-1)/2; /* half the max weight of a color */
1185 max
= 2*hmax
; /* the max weight of a color */
1187 r1
= rgb
[bg
[pat
].rgb1_max
].r
;
1188 g1
= rgb
[bg
[pat
].rgb1_max
].g
;
1189 b1
= rgb
[bg
[pat
].rgb1_max
].b
;
1190 r2
= rgb
[bg
[pat
].rgb2_max
].r
;
1191 g2
= rgb
[bg
[pat
].rgb2_max
].g
;
1192 b2
= rgb
[bg
[pat
].rgb2_max
].b
;
1194 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1195 yidx
= (int)(row
% bgscale
);
1197 yidx
= bgscale
-1 - yidx
;
1198 dest
= (char *)bg_data
+ row
*bg_rowbytes
;
1199 for (i
= 0; i
< rpng2_info
.width
; ++i
) {
1200 xidx
= (int)(i
% bgscale
);
1202 xidx
= bgscale
-1 - xidx
;
1204 *dest
++ = (k
*r1
+ (max
-k
)*r2
) / max
;
1205 *dest
++ = (k
*g1
+ (max
-k
)*g2
) / max
;
1206 *dest
++ = (k
*b1
+ (max
-k
)*b2
) / max
;
1210 /*---------------------------------------------------------------------------
1211 Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
1212 soids will equal bgscale?]. This one is slow but very cool. Code con-
1213 tributed by Pieter S. van der Meulen (originally in Smalltalk).
1214 ---------------------------------------------------------------------------*/
1216 } else if ((bg
[pat
].type
& 0x07) == 2) {
1218 int ii
, x
, y
, hw
, hh
, grayspot
;
1219 double freq
, rotate
, saturate
, gray
, intensity
;
1220 double angle
=0.0, aoffset
=0.0, maxDist
, dist
;
1221 double red
=0.0, green
=0.0, blue
=0.0, hue
, s
, v
, f
, p
, q
, t
;
1223 fprintf(stderr
, "%s: computing radial background...",
1227 hh
= (int)(rpng2_info
.height
/ 2);
1228 hw
= (int)(rpng2_info
.width
/ 2);
1230 /* variables for radial waves:
1231 * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED]
1232 * freq: number of color beams originating from the center
1233 * grayspot: size of the graying center area (anti-alias)
1234 * rotate: rotation of the beams as a function of radius
1235 * saturate: saturation of beams' shape azimuthally
1237 angle
= CLIP(angle
, 0.0, 360.0);
1238 grayspot
= CLIP(bg
[pat
].bg_gray
, 1, (hh
+ hw
));
1239 freq
= MAX((double)bg
[pat
].bg_freq
, 0.0);
1240 saturate
= (double)bg
[pat
].bg_bsat
* 0.1;
1241 rotate
= (double)bg
[pat
].bg_brot
* 0.1;
1244 maxDist
= (double)((hw
*hw
) + (hh
*hh
));
1246 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1247 y
= (int)(row
- hh
);
1248 dest
= (char *)bg_data
+ row
*bg_rowbytes
;
1249 for (i
= 0; i
< rpng2_info
.width
; ++i
) {
1251 angle
= (x
== 0)? PI_2
: atan((double)y
/ (double)x
);
1252 gray
= (double)MAX(ABS(y
), ABS(x
)) / grayspot
;
1253 gray
= MIN(1.0, gray
);
1254 dist
= (double)((x
*x
) + (y
*y
)) / maxDist
;
1255 intensity
= cos((angle
+(rotate
*dist
*PI
)) * freq
) *
1257 intensity
= (MAX(MIN(intensity
,1.0),-1.0) + 1.0) * 0.5;
1258 hue
= (angle
+ PI
) * INV_PI_360
+ aoffset
;
1259 s
= gray
* ((double)(ABS(x
)+ABS(y
)) / (double)(hw
+ hh
));
1260 s
= MIN(MAX(s
,0.0), 1.0);
1261 v
= MIN(MAX(intensity
,0.0), 1.0);
1264 ch
= (uch
)(v
* 255.0);
1269 if ((hue
< 0.0) || (hue
>= 360.0))
1270 hue
-= (((int)(hue
/ 360.0)) * 360.0);
1273 f
= hue
- (double)ii
;
1275 q
= (1.0 - (s
* f
)) * v
;
1276 t
= (1.0 - (s
* (1.0 - f
))) * v
;
1277 if (ii
== 0) { red
= v
; green
= t
; blue
= p
; }
1278 else if (ii
== 1) { red
= q
; green
= v
; blue
= p
; }
1279 else if (ii
== 2) { red
= p
; green
= v
; blue
= t
; }
1280 else if (ii
== 3) { red
= p
; green
= q
; blue
= v
; }
1281 else if (ii
== 4) { red
= t
; green
= p
; blue
= v
; }
1282 else if (ii
== 5) { red
= v
; green
= p
; blue
= q
; }
1283 *dest
++ = (uch
)(red
* 255.0);
1284 *dest
++ = (uch
)(green
* 255.0);
1285 *dest
++ = (uch
)(blue
* 255.0);
1289 fprintf(stderr
, "done.\n");
1293 /*---------------------------------------------------------------------------
1294 Blast background image to display buffer before beginning PNG decode.
1295 ---------------------------------------------------------------------------*/
1297 if (depth
== 24 || depth
== 32) {
1298 ulg red
, green
, blue
;
1299 int bpp
= ximage
->bits_per_pixel
;
1301 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1302 src
= bg_data
+ row
*bg_rowbytes
;
1303 dest
= ximage
->data
+ row
*ximage_rowbytes
;
1304 if (bpp
== 32) { /* slightly optimized version */
1305 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1309 pixel
= (red
<< RShift
) |
1312 /* recall that we set ximage->byte_order = MSBFirst above */
1313 *dest
++ = (char)((pixel
>> 24) & 0xff);
1314 *dest
++ = (char)((pixel
>> 16) & 0xff);
1315 *dest
++ = (char)((pixel
>> 8) & 0xff);
1316 *dest
++ = (char)( pixel
& 0xff);
1319 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1323 pixel
= (red
<< RShift
) |
1326 /* recall that we set ximage->byte_order = MSBFirst above */
1327 /* GRR BUG? this assumes bpp == 24 & bits are packed low */
1328 /* (probably need to use RShift, RMask, etc.) */
1329 *dest
++ = (char)((pixel
>> 16) & 0xff);
1330 *dest
++ = (char)((pixel
>> 8) & 0xff);
1331 *dest
++ = (char)( pixel
& 0xff);
1336 } else if (depth
== 16) {
1337 ush red
, green
, blue
;
1339 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1340 src
= bg_data
+ row
*bg_rowbytes
;
1341 dest
= ximage
->data
+ row
*ximage_rowbytes
;
1342 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1343 red
= ((ush
)(*src
) << 8); ++src
;
1344 green
= ((ush
)(*src
) << 8); ++src
;
1345 blue
= ((ush
)(*src
) << 8); ++src
;
1346 pixel
= ((red
>> RShift
) & RMask
) |
1347 ((green
>> GShift
) & GMask
) |
1348 ((blue
>> BShift
) & BMask
);
1349 /* recall that we set ximage->byte_order = MSBFirst above */
1350 *dest
++ = (char)((pixel
>> 8) & 0xff);
1351 *dest
++ = (char)( pixel
& 0xff);
1355 } else /* depth == 8 */ {
1357 /* GRR: add 8-bit support */
1361 XPutImage(display
, window
, gc
, ximage
, 0, 0, 0, 0, rpng2_info
.width
,
1366 } /* end function rpng2_x_load_bg_image() */
1372 static void rpng2_x_display_row(ulg row
)
1374 uch bg_red
= rpng2_info
.bg_red
;
1375 uch bg_green
= rpng2_info
.bg_green
;
1376 uch bg_blue
= rpng2_info
.bg_blue
;
1377 uch
*src
, *src2
=NULL
;
1380 int ximage_rowbytes
= ximage
->bytes_per_line
;
1382 static int rows
=0, prevpass
=(-1);
1383 static ulg firstrow
;
1385 /*---------------------------------------------------------------------------
1386 rows and firstrow simply track how many rows (and which ones) have not
1387 yet been displayed; alternatively, we could call XPutImage() for every
1388 row and not bother with the records-keeping.
1389 ---------------------------------------------------------------------------*/
1391 Trace((stderr
, "beginning rpng2_x_display_row()\n"))
1393 if (rpng2_info
.pass
!= prevpass
) {
1394 if (pause_after_pass
&& rpng2_info
.pass
> 0) {
1399 "%s: end of pass %d of 7; click in image window to continue\n",
1400 PROGNAME
, prevpass
+ 1);
1402 XNextEvent(display
, &e
);
1405 fprintf(stderr
, "%s: pass %d of 7\r", PROGNAME
, rpng2_info
.pass
+ 1);
1407 prevpass
= rpng2_info
.pass
;
1411 firstrow
= row
; /* first row that is not yet displayed */
1413 ++rows
; /* count of rows received but not yet displayed */
1415 /*---------------------------------------------------------------------------
1416 Aside from the use of the rpng2_info struct, the lack of an outer loop
1417 (over rows) and moving the XPutImage() call outside the "if (depth)"
1418 tests, this routine is identical to rpng_x_display_image() in the non-
1419 progressive version of the program.
1420 ---------------------------------------------------------------------------*/
1422 if (depth
== 24 || depth
== 32) {
1423 ulg red
, green
, blue
;
1424 int bpp
= ximage
->bits_per_pixel
;
1426 src
= rpng2_info
.image_data
+ row
*rpng2_info
.rowbytes
;
1428 src2
= bg_data
+ row
*bg_rowbytes
;
1429 dest
= ximage
->data
+ row
*ximage_rowbytes
;
1430 if (rpng2_info
.channels
== 3) {
1431 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1435 pixel
= (red
<< RShift
) |
1438 /* recall that we set ximage->byte_order = MSBFirst above */
1440 *dest
++ = (char)((pixel
>> 24) & 0xff);
1441 *dest
++ = (char)((pixel
>> 16) & 0xff);
1442 *dest
++ = (char)((pixel
>> 8) & 0xff);
1443 *dest
++ = (char)( pixel
& 0xff);
1445 /* GRR BUG? this assumes bpp == 24 & bits are packed low */
1446 /* (probably need to use RShift, RMask, etc.) */
1447 *dest
++ = (char)((pixel
>> 16) & 0xff);
1448 *dest
++ = (char)((pixel
>> 8) & 0xff);
1449 *dest
++ = (char)( pixel
& 0xff);
1452 } else /* if (rpng2_info.channels == 4) */ {
1453 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1467 } else if (a
== 0) {
1472 /* this macro (from png.h) composites the foreground
1473 * and background values and puts the result into the
1475 alpha_composite(red
, r
, a
, bg_red
);
1476 alpha_composite(green
, g
, a
, bg_green
);
1477 alpha_composite(blue
, b
, a
, bg_blue
);
1479 pixel
= (red
<< RShift
) |
1482 /* recall that we set ximage->byte_order = MSBFirst above */
1484 *dest
++ = (char)((pixel
>> 24) & 0xff);
1485 *dest
++ = (char)((pixel
>> 16) & 0xff);
1486 *dest
++ = (char)((pixel
>> 8) & 0xff);
1487 *dest
++ = (char)( pixel
& 0xff);
1489 /* GRR BUG? this assumes bpp == 24 & bits are packed low */
1490 /* (probably need to use RShift, RMask, etc.) */
1491 *dest
++ = (char)((pixel
>> 16) & 0xff);
1492 *dest
++ = (char)((pixel
>> 8) & 0xff);
1493 *dest
++ = (char)( pixel
& 0xff);
1498 } else if (depth
== 16) {
1499 ush red
, green
, blue
;
1501 src
= rpng2_info
.row_pointers
[row
];
1503 src2
= bg_data
+ row
*bg_rowbytes
;
1504 dest
= ximage
->data
+ row
*ximage_rowbytes
;
1505 if (rpng2_info
.channels
== 3) {
1506 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1507 red
= ((ush
)(*src
) << 8);
1509 green
= ((ush
)(*src
) << 8);
1511 blue
= ((ush
)(*src
) << 8);
1513 pixel
= ((red
>> RShift
) & RMask
) |
1514 ((green
>> GShift
) & GMask
) |
1515 ((blue
>> BShift
) & BMask
);
1516 /* recall that we set ximage->byte_order = MSBFirst above */
1517 *dest
++ = (char)((pixel
>> 8) & 0xff);
1518 *dest
++ = (char)( pixel
& 0xff);
1520 } else /* if (rpng2_info.channels == 4) */ {
1521 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1532 red
= ((ush
)r
<< 8);
1533 green
= ((ush
)g
<< 8);
1534 blue
= ((ush
)b
<< 8);
1535 } else if (a
== 0) {
1536 red
= ((ush
)bg_red
<< 8);
1537 green
= ((ush
)bg_green
<< 8);
1538 blue
= ((ush
)bg_blue
<< 8);
1540 /* this macro (from png.h) composites the foreground
1541 * and background values and puts the result back into
1542 * the first argument (== fg byte here: safe) */
1543 alpha_composite(r
, r
, a
, bg_red
);
1544 alpha_composite(g
, g
, a
, bg_green
);
1545 alpha_composite(b
, b
, a
, bg_blue
);
1546 red
= ((ush
)r
<< 8);
1547 green
= ((ush
)g
<< 8);
1548 blue
= ((ush
)b
<< 8);
1550 pixel
= ((red
>> RShift
) & RMask
) |
1551 ((green
>> GShift
) & GMask
) |
1552 ((blue
>> BShift
) & BMask
);
1553 /* recall that we set ximage->byte_order = MSBFirst above */
1554 *dest
++ = (char)((pixel
>> 8) & 0xff);
1555 *dest
++ = (char)( pixel
& 0xff);
1559 } else /* depth == 8 */ {
1561 /* GRR: add 8-bit support */
1566 /*---------------------------------------------------------------------------
1567 Display after every 16 rows or when on one of last two rows. (Region
1568 may include previously displayed lines due to interlacing--i.e., not
1569 contiguous. Also, second-to-last row is final one in interlaced images
1570 with odd number of rows.) For demos, flush (and delay) after every 16th
1571 row so "sparse" passes don't go twice as fast.
1572 ---------------------------------------------------------------------------*/
1574 if (demo_timing
&& (row
- firstrow
>= 16 || row
>= rpng2_info
.height
-2)) {
1575 XPutImage(display
, window
, gc
, ximage
, 0, (int)firstrow
, 0,
1576 (int)firstrow
, rpng2_info
.width
, row
- firstrow
+ 1);
1579 usleep(usleep_duration
);
1581 if (!demo_timing
&& ((rows
& 0xf) == 0 || row
>= rpng2_info
.height
-2)) {
1582 XPutImage(display
, window
, gc
, ximage
, 0, (int)firstrow
, 0,
1583 (int)firstrow
, rpng2_info
.width
, row
- firstrow
+ 1);
1594 static void rpng2_x_finish_display(void)
1596 Trace((stderr
, "beginning rpng2_x_finish_display()\n"))
1598 /* last row has already been displayed by rpng2_x_display_row(), so we
1599 * have nothing to do here except set a flag and let the user know that
1600 * the image is done */
1602 rpng2_info
.state
= kDone
;
1604 "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n");
1612 static void rpng2_x_redisplay_image(ulg startcol
, ulg startrow
,
1613 ulg width
, ulg height
)
1615 uch bg_red
= rpng2_info
.bg_red
;
1616 uch bg_green
= rpng2_info
.bg_green
;
1617 uch bg_blue
= rpng2_info
.bg_blue
;
1618 uch
*src
, *src2
=NULL
;
1621 ulg i
, row
, lastrow
= 0;
1623 int ximage_rowbytes
= ximage
->bytes_per_line
;
1626 Trace((stderr
, "beginning display loop (image_channels == %d)\n",
1627 rpng2_info
.channels
))
1628 Trace((stderr
, " (width = %ld, rowbytes = %d, ximage_rowbytes = %d)\n",
1629 rpng2_info
.width
, rpng2_info
.rowbytes
, ximage_rowbytes
))
1630 Trace((stderr
, " (bpp = %d)\n", ximage
->bits_per_pixel
))
1631 Trace((stderr
, " (byte_order = %s)\n", ximage
->byte_order
== MSBFirst
?
1632 "MSBFirst" : (ximage
->byte_order
== LSBFirst
? "LSBFirst" : "unknown")))
1634 /*---------------------------------------------------------------------------
1635 Aside from the use of the rpng2_info struct and of src2 (for background
1636 image), this routine is identical to rpng_x_display_image() in the non-
1637 progressive version of the program--for the simple reason that redisplay
1638 of the image against a new background happens after the image is fully
1639 decoded and therefore is, by definition, non-progressive.
1640 ---------------------------------------------------------------------------*/
1642 if (depth
== 24 || depth
== 32) {
1643 ulg red
, green
, blue
;
1644 int bpp
= ximage
->bits_per_pixel
;
1646 for (lastrow
= row
= startrow
; row
< startrow
+height
; ++row
) {
1647 src
= rpng2_info
.image_data
+ row
*rpng2_info
.rowbytes
;
1649 src2
= bg_data
+ row
*bg_rowbytes
;
1650 dest
= ximage
->data
+ row
*ximage_rowbytes
;
1651 if (rpng2_info
.channels
== 3) {
1652 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1656 #ifdef NO_24BIT_MASKS
1657 pixel
= (red
<< RShift
) |
1660 /* recall that we set ximage->byte_order = MSBFirst above */
1662 *dest
++ = (char)((pixel
>> 24) & 0xff);
1663 *dest
++ = (char)((pixel
>> 16) & 0xff);
1664 *dest
++ = (char)((pixel
>> 8) & 0xff);
1665 *dest
++ = (char)( pixel
& 0xff);
1667 /* this assumes bpp == 24 & bits are packed low */
1668 /* (probably need to use RShift, RMask, etc.) */
1669 *dest
++ = (char)((pixel
>> 16) & 0xff);
1670 *dest
++ = (char)((pixel
>> 8) & 0xff);
1671 *dest
++ = (char)( pixel
& 0xff);
1674 red
= (RShift
< 0)? red
<< (-RShift
) : red
>> RShift
;
1675 green
= (GShift
< 0)? green
<< (-GShift
) : green
>> GShift
;
1676 blue
= (BShift
< 0)? blue
<< (-BShift
) : blue
>> BShift
;
1677 pixel
= (red
& RMask
) | (green
& GMask
) | (blue
& BMask
);
1678 /* recall that we set ximage->byte_order = MSBFirst above */
1680 *dest
++ = (char)((pixel
>> 24) & 0xff);
1681 *dest
++ = (char)((pixel
>> 16) & 0xff);
1682 *dest
++ = (char)((pixel
>> 8) & 0xff);
1683 *dest
++ = (char)( pixel
& 0xff);
1686 /* this assumes bpp == 24 & bits are packed low */
1687 /* (probably need to use RShift/RMask/etc. here, too) */
1688 *dest
++ = (char)((pixel
>> 16) & 0xff);
1689 *dest
++ = (char)((pixel
>> 8) & 0xff);
1690 *dest
++ = (char)( pixel
& 0xff);
1695 } else /* if (rpng2_info.channels == 4) */ {
1696 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1710 } else if (a
== 0) {
1715 /* this macro (from png.h) composites the foreground
1716 * and background values and puts the result into the
1718 alpha_composite(red
, r
, a
, bg_red
);
1719 alpha_composite(green
, g
, a
, bg_green
);
1720 alpha_composite(blue
, b
, a
, bg_blue
);
1722 #ifdef NO_24BIT_MASKS
1723 pixel
= (red
<< RShift
) |
1726 /* recall that we set ximage->byte_order = MSBFirst above */
1728 *dest
++ = (char)((pixel
>> 24) & 0xff);
1729 *dest
++ = (char)((pixel
>> 16) & 0xff);
1730 *dest
++ = (char)((pixel
>> 8) & 0xff);
1731 *dest
++ = (char)( pixel
& 0xff);
1733 /* this assumes bpp == 24 & bits are packed low */
1734 /* (probably need to use RShift, RMask, etc.) */
1735 *dest
++ = (char)((pixel
>> 16) & 0xff);
1736 *dest
++ = (char)((pixel
>> 8) & 0xff);
1737 *dest
++ = (char)( pixel
& 0xff);
1740 red
= (RShift
< 0)? red
<< (-RShift
) : red
>> RShift
;
1741 green
= (GShift
< 0)? green
<< (-GShift
) : green
>> GShift
;
1742 blue
= (BShift
< 0)? blue
<< (-BShift
) : blue
>> BShift
;
1743 pixel
= (red
& RMask
) | (green
& GMask
) | (blue
& BMask
);
1744 /* recall that we set ximage->byte_order = MSBFirst above */
1746 *dest
++ = (char)((pixel
>> 24) & 0xff);
1747 *dest
++ = (char)((pixel
>> 16) & 0xff);
1748 *dest
++ = (char)((pixel
>> 8) & 0xff);
1749 *dest
++ = (char)( pixel
& 0xff);
1752 /* this assumes bpp == 24 & bits are packed low */
1753 /* (probably need to use RShift/RMask/etc. here, too) */
1754 *dest
++ = (char)((pixel
>> 16) & 0xff);
1755 *dest
++ = (char)((pixel
>> 8) & 0xff);
1756 *dest
++ = (char)( pixel
& 0xff);
1761 /* display after every 16 lines */
1762 if (((row
+1) & 0xf) == 0) {
1763 XPutImage(display
, window
, gc
, ximage
, 0, (int)lastrow
, 0,
1764 (int)lastrow
, rpng2_info
.width
, 16);
1770 } else if (depth
== 16) {
1771 ush red
, green
, blue
;
1773 for (lastrow
= row
= startrow
; row
< startrow
+height
; ++row
) {
1774 src
= rpng2_info
.row_pointers
[row
];
1776 src2
= bg_data
+ row
*bg_rowbytes
;
1777 dest
= ximage
->data
+ row
*ximage_rowbytes
;
1778 if (rpng2_info
.channels
== 3) {
1779 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1780 red
= ((ush
)(*src
) << 8);
1782 green
= ((ush
)(*src
) << 8);
1784 blue
= ((ush
)(*src
) << 8);
1786 pixel
= ((red
>> RShift
) & RMask
) |
1787 ((green
>> GShift
) & GMask
) |
1788 ((blue
>> BShift
) & BMask
);
1789 /* recall that we set ximage->byte_order = MSBFirst above */
1790 *dest
++ = (char)((pixel
>> 8) & 0xff);
1791 *dest
++ = (char)( pixel
& 0xff);
1793 } else /* if (rpng2_info.channels == 4) */ {
1794 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1805 red
= ((ush
)r
<< 8);
1806 green
= ((ush
)g
<< 8);
1807 blue
= ((ush
)b
<< 8);
1808 } else if (a
== 0) {
1809 red
= ((ush
)bg_red
<< 8);
1810 green
= ((ush
)bg_green
<< 8);
1811 blue
= ((ush
)bg_blue
<< 8);
1813 /* this macro (from png.h) composites the foreground
1814 * and background values and puts the result back into
1815 * the first argument (== fg byte here: safe) */
1816 alpha_composite(r
, r
, a
, bg_red
);
1817 alpha_composite(g
, g
, a
, bg_green
);
1818 alpha_composite(b
, b
, a
, bg_blue
);
1819 red
= ((ush
)r
<< 8);
1820 green
= ((ush
)g
<< 8);
1821 blue
= ((ush
)b
<< 8);
1823 pixel
= ((red
>> RShift
) & RMask
) |
1824 ((green
>> GShift
) & GMask
) |
1825 ((blue
>> BShift
) & BMask
);
1826 /* recall that we set ximage->byte_order = MSBFirst above */
1827 *dest
++ = (char)((pixel
>> 8) & 0xff);
1828 *dest
++ = (char)( pixel
& 0xff);
1831 /* display after every 16 lines */
1832 if (((row
+1) & 0xf) == 0) {
1833 XPutImage(display
, window
, gc
, ximage
, 0, (int)lastrow
, 0,
1834 (int)lastrow
, rpng2_info
.width
, 16);
1840 } else /* depth == 8 */ {
1842 /* GRR: add 8-bit support */
1846 Trace((stderr
, "calling final XPutImage()\n"))
1847 if (lastrow
< startrow
+height
) {
1848 XPutImage(display
, window
, gc
, ximage
, 0, (int)lastrow
, 0,
1849 (int)lastrow
, rpng2_info
.width
, rpng2_info
.height
-lastrow
);
1856 } /* end function rpng2_x_redisplay_image() */
1864 static void rpng2_x_reload_bg_image(void)
1867 uch r1
, r2
, g1
, g2
, b1
, b2
;
1868 uch r1_inv
, r2_inv
, g1_inv
, g2_inv
, b1_inv
, b2_inv
;
1870 int xidx
, yidx
, yidx_max
;
1871 int even_odd_vert
, even_odd_horiz
, even_odd
;
1872 int invert_gradient2
= (bg
[pat
].type
& 0x08);
1877 bgscale
= (pat
== 0)? 8 : bgscale_default
;
1878 yidx_max
= bgscale
- 1;
1880 /*---------------------------------------------------------------------------
1881 Vertical gradients (ramps) in NxN squares, alternating direction and
1882 colors (N == bgscale).
1883 ---------------------------------------------------------------------------*/
1885 if ((bg
[pat
].type
& 0x07) == 0) {
1886 uch r1_min
= rgb
[bg
[pat
].rgb1_min
].r
;
1887 uch g1_min
= rgb
[bg
[pat
].rgb1_min
].g
;
1888 uch b1_min
= rgb
[bg
[pat
].rgb1_min
].b
;
1889 uch r2_min
= rgb
[bg
[pat
].rgb2_min
].r
;
1890 uch g2_min
= rgb
[bg
[pat
].rgb2_min
].g
;
1891 uch b2_min
= rgb
[bg
[pat
].rgb2_min
].b
;
1892 int r1_diff
= rgb
[bg
[pat
].rgb1_max
].r
- r1_min
;
1893 int g1_diff
= rgb
[bg
[pat
].rgb1_max
].g
- g1_min
;
1894 int b1_diff
= rgb
[bg
[pat
].rgb1_max
].b
- b1_min
;
1895 int r2_diff
= rgb
[bg
[pat
].rgb2_max
].r
- r2_min
;
1896 int g2_diff
= rgb
[bg
[pat
].rgb2_max
].g
- g2_min
;
1897 int b2_diff
= rgb
[bg
[pat
].rgb2_max
].b
- b2_min
;
1899 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1900 yidx
= (int)(row
% bgscale
);
1901 even_odd_vert
= (int)((row
/ bgscale
) & 1);
1903 r1
= r1_min
+ (r1_diff
* yidx
) / yidx_max
;
1904 g1
= g1_min
+ (g1_diff
* yidx
) / yidx_max
;
1905 b1
= b1_min
+ (b1_diff
* yidx
) / yidx_max
;
1906 r1_inv
= r1_min
+ (r1_diff
* (yidx_max
-yidx
)) / yidx_max
;
1907 g1_inv
= g1_min
+ (g1_diff
* (yidx_max
-yidx
)) / yidx_max
;
1908 b1_inv
= b1_min
+ (b1_diff
* (yidx_max
-yidx
)) / yidx_max
;
1910 r2
= r2_min
+ (r2_diff
* yidx
) / yidx_max
;
1911 g2
= g2_min
+ (g2_diff
* yidx
) / yidx_max
;
1912 b2
= b2_min
+ (b2_diff
* yidx
) / yidx_max
;
1913 r2_inv
= r2_min
+ (r2_diff
* (yidx_max
-yidx
)) / yidx_max
;
1914 g2_inv
= g2_min
+ (g2_diff
* (yidx_max
-yidx
)) / yidx_max
;
1915 b2_inv
= b2_min
+ (b2_diff
* (yidx_max
-yidx
)) / yidx_max
;
1917 dest
= (char *)bg_data
+ row
*bg_rowbytes
;
1918 for (i
= 0; i
< rpng2_info
.width
; ++i
) {
1919 even_odd_horiz
= (int)((i
/ bgscale
) & 1);
1920 even_odd
= even_odd_vert
^ even_odd_horiz
;
1922 (even_odd_horiz
&& (bg
[pat
].type
& 0x10));
1923 if (even_odd
== 0) { /* gradient #1 */
1924 if (invert_column
) {
1933 } else { /* gradient #2 */
1934 if ((invert_column
&& invert_gradient2
) ||
1935 (!invert_column
&& !invert_gradient2
))
1937 *dest
++ = r2
; /* not inverted or */
1938 *dest
++ = g2
; /* doubly inverted */
1942 *dest
++ = g2_inv
; /* singly inverted */
1949 /*---------------------------------------------------------------------------
1950 Soft gradient-diamonds with scale = bgscale. Code contributed by Adam
1952 ---------------------------------------------------------------------------*/
1954 } else if ((bg
[pat
].type
& 0x07) == 1) {
1956 hmax
= (bgscale
-1)/2; /* half the max weight of a color */
1957 max
= 2*hmax
; /* the max weight of a color */
1959 r1
= rgb
[bg
[pat
].rgb1_max
].r
;
1960 g1
= rgb
[bg
[pat
].rgb1_max
].g
;
1961 b1
= rgb
[bg
[pat
].rgb1_max
].b
;
1962 r2
= rgb
[bg
[pat
].rgb2_max
].r
;
1963 g2
= rgb
[bg
[pat
].rgb2_max
].g
;
1964 b2
= rgb
[bg
[pat
].rgb2_max
].b
;
1966 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1967 yidx
= (int)(row
% bgscale
);
1969 yidx
= bgscale
-1 - yidx
;
1970 dest
= (char *)bg_data
+ row
*bg_rowbytes
;
1971 for (i
= 0; i
< rpng2_info
.width
; ++i
) {
1972 xidx
= (int)(i
% bgscale
);
1974 xidx
= bgscale
-1 - xidx
;
1976 *dest
++ = (k
*r1
+ (max
-k
)*r2
) / max
;
1977 *dest
++ = (k
*g1
+ (max
-k
)*g2
) / max
;
1978 *dest
++ = (k
*b1
+ (max
-k
)*b2
) / max
;
1982 /*---------------------------------------------------------------------------
1983 Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
1984 soids will equal bgscale?]. This one is slow but very cool. Code con-
1985 tributed by Pieter S. van der Meulen (originally in Smalltalk).
1986 ---------------------------------------------------------------------------*/
1988 } else if ((bg
[pat
].type
& 0x07) == 2) {
1990 int ii
, x
, y
, hw
, hh
, grayspot
;
1991 double freq
, rotate
, saturate
, gray
, intensity
;
1992 double angle
=0.0, aoffset
=0.0, maxDist
, dist
;
1993 double red
=0.0, green
=0.0, blue
=0.0, hue
, s
, v
, f
, p
, q
, t
;
1995 hh
= (int)(rpng2_info
.height
/ 2);
1996 hw
= (int)(rpng2_info
.width
/ 2);
1998 /* variables for radial waves:
1999 * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED]
2000 * freq: number of color beams originating from the center
2001 * grayspot: size of the graying center area (anti-alias)
2002 * rotate: rotation of the beams as a function of radius
2003 * saturate: saturation of beams' shape azimuthally
2005 angle
= CLIP(angle
, 0.0, 360.0);
2006 grayspot
= CLIP(bg
[pat
].bg_gray
, 1, (hh
+ hw
));
2007 freq
= MAX((double)bg
[pat
].bg_freq
, 0.0);
2008 saturate
= (double)bg
[pat
].bg_bsat
* 0.1;
2009 rotate
= (double)bg
[pat
].bg_brot
* 0.1;
2012 maxDist
= (double)((hw
*hw
) + (hh
*hh
));
2014 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
2015 y
= (int)(row
- hh
);
2016 dest
= (char *)bg_data
+ row
*bg_rowbytes
;
2017 for (i
= 0; i
< rpng2_info
.width
; ++i
) {
2019 angle
= (x
== 0)? PI_2
: atan((double)y
/ (double)x
);
2020 gray
= (double)MAX(ABS(y
), ABS(x
)) / grayspot
;
2021 gray
= MIN(1.0, gray
);
2022 dist
= (double)((x
*x
) + (y
*y
)) / maxDist
;
2023 intensity
= cos((angle
+(rotate
*dist
*PI
)) * freq
) *
2025 intensity
= (MAX(MIN(intensity
,1.0),-1.0) + 1.0) * 0.5;
2026 hue
= (angle
+ PI
) * INV_PI_360
+ aoffset
;
2027 s
= gray
* ((double)(ABS(x
)+ABS(y
)) / (double)(hw
+ hh
));
2028 s
= MIN(MAX(s
,0.0), 1.0);
2029 v
= MIN(MAX(intensity
,0.0), 1.0);
2032 ch
= (uch
)(v
* 255.0);
2037 if ((hue
< 0.0) || (hue
>= 360.0))
2038 hue
-= (((int)(hue
/ 360.0)) * 360.0);
2041 f
= hue
- (double)ii
;
2043 q
= (1.0 - (s
* f
)) * v
;
2044 t
= (1.0 - (s
* (1.0 - f
))) * v
;
2045 if (ii
== 0) { red
= v
; green
= t
; blue
= p
; }
2046 else if (ii
== 1) { red
= q
; green
= v
; blue
= p
; }
2047 else if (ii
== 2) { red
= p
; green
= v
; blue
= t
; }
2048 else if (ii
== 3) { red
= p
; green
= q
; blue
= v
; }
2049 else if (ii
== 4) { red
= t
; green
= p
; blue
= v
; }
2050 else if (ii
== 5) { red
= v
; green
= p
; blue
= q
; }
2051 *dest
++ = (uch
)(red
* 255.0);
2052 *dest
++ = (uch
)(green
* 255.0);
2053 *dest
++ = (uch
)(blue
* 255.0);
2059 } /* end function rpng2_x_reload_bg_image() */
2065 static int is_number(char *p
)
2075 #endif /* FEATURE_LOOP */
2081 static void rpng2_x_cleanup(void)
2083 if (bg_image
&& bg_data
) {
2088 if (rpng2_info
.image_data
) {
2089 free(rpng2_info
.image_data
);
2090 rpng2_info
.image_data
= NULL
;
2093 if (rpng2_info
.row_pointers
) {
2094 free(rpng2_info
.row_pointers
);
2095 rpng2_info
.row_pointers
= NULL
;
2100 free(ximage
->data
); /* we allocated it, so we free it */
2101 ximage
->data
= (char *)NULL
; /* instead of XDestroyImage() */
2103 XDestroyImage(ximage
);
2108 XFreeGC(display
, gc
);
2111 XDestroyWindow(display
, window
);
2114 XFreeColormap(display
, colormap
);
2116 if (have_nondefault_visual
)
2124 static int rpng2_x_msb(ulg u32val
)
2128 for (i
= 31; i
>= 0; --i
) {
2129 if (u32val
& 0x80000000L
)