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 - 2.06: check for integer overflow (Glenn R-P)
48 ---------------------------------------------------------------------------
50 Copyright (c) 1998-2010, 2014-2015, 2017 Greg Roelofs. All rights
53 This software is provided "as is," without warranty of any kind,
54 express or implied. In no event shall the author or contributors
55 be held liable for any damages arising in any way from the use of
58 The contents of this file are DUAL-LICENSED. You may modify and/or
59 redistribute this software according to the terms of one of the
60 following two licenses (at your option):
63 LICENSE 1 ("BSD-like with advertising clause"):
65 Permission is granted to anyone to use this software for any purpose,
66 including commercial applications, and to alter it and redistribute
67 it freely, subject to the following restrictions:
69 1. Redistributions of source code must retain the above copyright
70 notice, disclaimer, and this list of conditions.
71 2. Redistributions in binary form must reproduce the above copyright
72 notice, disclaimer, and this list of conditions in the documenta-
73 tion and/or other materials provided with the distribution.
74 3. All advertising materials mentioning features or use of this
75 software must display the following acknowledgment:
77 This product includes software developed by Greg Roelofs
78 and contributors for the book, "PNG: The Definitive Guide,"
79 published by O'Reilly and Associates.
82 LICENSE 2 (GNU GPL v2 or later):
84 This program is free software; you can redistribute it and/or modify
85 it under the terms of the GNU General Public License as published by
86 the Free Software Foundation; either version 2 of the License, or
87 (at your option) any later version.
89 This program is distributed in the hope that it will be useful,
90 but WITHOUT ANY WARRANTY; without even the implied warranty of
91 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
92 GNU General Public License for more details.
94 You should have received a copy of the GNU General Public License
95 along with this program; if not, write to the Free Software Foundation,
96 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
98 ---------------------------------------------------------------------------*/
100 #define PROGNAME "rpng2-x"
101 #define LONGNAME "Progressive PNG Viewer for X"
102 #define VERSION "2.04 of 15 June 2014"
103 #define RESNAME "rpng2" /* our X resource application name */
104 #define RESCLASS "Rpng" /* our X resource class name */
110 #include <setjmp.h> /* for jmpbuf declaration in readpng2.h */
112 #include <math.h> /* only for PvdM background code */
113 #include <X11/Xlib.h>
114 #include <X11/Xutil.h>
116 #include <X11/keysym.h> /* defines XK_* macros */
118 #if _POSIX_C_SOURCE >= 199309L /* have nanosleep() */
120 # define usleep(usec) { \
121 struct timespec ts; \
123 ts.tv_nsec = (usec) * 1000; \
124 nanosleep(&ts, NULL); }
127 #ifndef usleep /* have neither nanosleep() nor usleep() */
128 # define usleep(x) sleep(((x)+499999)/1000000)
135 /* all for PvdM background code: */
137 # define PI 3.141592653589793238
139 #define PI_2 (PI*0.5)
140 #define INV_PI_360 (360.0 / PI)
141 #define MAX(a,b) (a>b?a:b)
142 #define MIN(a,b) (a<b?a:b)
143 #define CLIP(a,min,max) MAX(min,MIN((a),max))
144 #define ABS(a) ((a)<0?-(a):(a))
145 #define CLIP8P(c) MAX(0,(MIN((c),255))) /* 8-bit pos. integer (uch) */
146 #define ROUNDF(f) ((int)(f + 0.5))
148 #define QUIT(e,k) ((e.type == ButtonPress && e.xbutton.button == Button1) || \
149 (e.type == KeyPress && /* v--- or 1 for shifted keys */ \
150 ((k = XLookupKeysym(&e.xkey, 0)) == XK_q || k == XK_Escape)))
152 #define NO_24BIT_MASKS /* undef case not fully written--only for redisplay() */
154 #define rgb1_max bg_freq
155 #define rgb1_min bg_gray
156 #define rgb2_max bg_bsat
157 #define rgb2_min bg_brot
159 /* #define DEBUG */ /* this enables the Trace() macros */
161 #include "readpng2.h" /* typedefs, common macros, readpng2 prototypes */
164 /* could just include png.h, but this macro is the only thing we need
165 * (name and typedefs changed to local versions); note that side effects
166 * only happen with alpha (which could easily be avoided with
167 * "ush acopy = (alpha);") */
169 #define alpha_composite(composite, fg, alpha, bg) { \
170 ush temp = ((ush)(fg)*(ush)(alpha) + \
171 (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \
172 (composite) = (uch)((temp + (temp >> 8)) >> 8); \
176 #define INBUFSIZE 4096 /* with pseudo-timing on (1 sec delay/block), this
177 * block size corresponds roughly to a download
178 * speed 10% faster than theoretical 33.6K maximum
179 * (assuming 8 data bits, 1 stop bit and no other
182 /* local prototypes */
183 static void rpng2_x_init (void);
184 static int rpng2_x_create_window (void);
185 static int rpng2_x_load_bg_image (void);
186 static void rpng2_x_display_row (ulg row
);
187 static void rpng2_x_finish_display (void);
188 static void rpng2_x_redisplay_image (ulg startcol
, ulg startrow
,
189 ulg width
, ulg height
);
191 static void rpng2_x_reload_bg_image (void);
192 static int is_number (char *p
);
194 static void rpng2_x_cleanup (void);
195 static int rpng2_x_msb (ulg u32val
);
198 static char titlebar
[1024], *window_name
= titlebar
;
199 static char *appname
= LONGNAME
;
200 static char *icon_name
= PROGNAME
;
201 static char *res_name
= RESNAME
;
202 static char *res_class
= RESCLASS
;
203 static char *filename
;
206 static mainprog_info rpng2_info
;
208 static uch inbuf
[INBUFSIZE
];
211 static int pat
= 6; /* must be less than num_bgpat */
212 static int bg_image
= 0;
213 static int bgscale
, bgscale_default
= 16;
214 static ulg bg_rowbytes
;
217 int pause_after_pass
= FALSE
;
218 int demo_timing
= FALSE
;
219 ulg usleep_duration
= 0L;
221 static struct rgb_color
{
224 { 0, 0, 0}, /* 0: black */
225 {255, 255, 255}, /* 1: white */
226 {173, 132, 57}, /* 2: tan */
227 { 64, 132, 0}, /* 3: medium green */
228 {189, 117, 1}, /* 4: gold */
229 {253, 249, 1}, /* 5: yellow */
230 { 0, 0, 255}, /* 6: blue */
231 { 0, 0, 120}, /* 7: medium blue */
232 {255, 0, 255}, /* 8: magenta */
233 { 64, 0, 64}, /* 9: dark magenta */
234 {255, 0, 0}, /* 10: red */
235 { 64, 0, 0}, /* 11: dark red */
236 {255, 127, 0}, /* 12: orange */
237 {192, 96, 0}, /* 13: darker orange */
238 { 24, 60, 0}, /* 14: dark green-yellow */
239 { 85, 125, 200}, /* 15: ice blue */
240 {192, 192, 192} /* 16: Netscape/Mosaic gray */
242 /* not used for now, but should be for error-checking:
243 static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color);
247 This whole struct is a fairly cheesy way to keep the number of
248 command-line options to a minimum. The radial-waves background
249 type is a particularly poor fit to the integer elements of the
250 struct...but a few macros and a little fixed-point math will do
254 F E D C B A 9 8 7 6 5 4 3 2 1 0
256 | | +-+-+-- 0 = sharp-edged checkerboard
257 | | 1 = soft diamonds
260 | +-- gradient #2 inverted?
261 +-- alternating columns inverted?
263 static struct background_pattern
{
265 int rgb1_max
, rgb1_min
; /* or bg_freq, bg_gray */
266 int rgb2_max
, rgb2_min
; /* or bg_bsat, bg_brot (both scaled by 10)*/
268 {0, 1,1, 16,16}, /* checkered: white vs. light gray (basic) */
269 {0+8, 2,0, 1,15}, /* checkered: tan/black vs. white/ice blue */
270 {0+24, 2,0, 1,0}, /* checkered: tan/black vs. white/black */
271 {0+8, 4,5, 0,2}, /* checkered: gold/yellow vs. black/tan */
272 {0+8, 4,5, 0,6}, /* checkered: gold/yellow vs. black/blue */
273 {0, 7,0, 8,9}, /* checkered: deep blue/black vs. magenta */
274 {0+8, 13,0, 5,14}, /* checkered: orange/black vs. yellow */
275 {0+8, 12,0, 10,11}, /* checkered: orange/black vs. red */
276 {1, 7,0, 8,0}, /* diamonds: deep blue/black vs. magenta */
277 {1, 12,0, 11,0}, /* diamonds: orange vs. dark red */
278 {1, 10,0, 7,0}, /* diamonds: red vs. medium blue */
279 {1, 4,0, 5,0}, /* diamonds: gold vs. yellow */
280 {1, 3,0, 0,0}, /* diamonds: medium green vs. black */
281 {2, 16, 100, 20, 0}, /* radial: ~hard radial color-beams */
282 {2, 18, 100, 10, 2}, /* radial: soft, curved radial color-beams */
283 {2, 16, 256, 100, 250}, /* radial: very tight spiral */
284 {2, 10000, 256, 11, 0} /* radial: dipole-moire' (almost fractal) */
286 static int num_bgpat
= sizeof(bg
) / sizeof(struct background_pattern
);
289 /* X-specific variables */
290 static char *displayname
;
291 static XImage
*ximage
;
292 static Display
*display
;
294 static Visual
*visual
;
295 static XVisualInfo
*visual_list
;
296 static int RShift
, GShift
, BShift
;
297 static ulg RMask
, GMask
, BMask
;
298 static Window window
;
300 static Colormap colormap
;
302 static int have_nondefault_visual
= FALSE
;
303 static int have_colormap
= FALSE
;
304 static int have_window
= FALSE
;
305 static int have_gc
= FALSE
;
310 int main(int argc
, char **argv
)
315 char *p
, *bgstr
= NULL
;
322 long loop_interval
= -1; /* seconds (100,000 max) */
324 double LUT_exponent
; /* just the lookup table */
325 double CRT_exponent
= 2.2; /* just the monitor */
326 double default_display_exponent
; /* whole display system */
331 /* First initialize a few things, just to be sure--memset takes care of
332 * default background color (black), booleans (FALSE), pointers (NULL),
335 displayname
= (char *)NULL
;
336 filename
= (char *)NULL
;
337 memset(&rpng2_info
, 0, sizeof(mainprog_info
));
340 /* Set the default value for our display-system exponent, i.e., the
341 * product of the CRT exponent and the exponent corresponding to
342 * the frame-buffer's lookup table (LUT), if any. This is not an
343 * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
344 * ones), but it should cover 99% of the current possibilities. */
347 /* third-party utilities can modify the default LUT exponent */
348 LUT_exponent
= 1.0 / 2.2;
350 if (some_next_function_that_returns_gamma(&next_gamma))
351 LUT_exponent = 1.0 / next_gamma;
354 LUT_exponent
= 1.0 / 1.7;
355 /* there doesn't seem to be any documented function to
356 * get the "gamma" value, so we do it the hard way */
357 infile
= fopen("/etc/config/system.glGammaVal", "r");
361 fgets(tmpline
, 80, infile
);
363 sgi_gamma
= atof(tmpline
);
365 LUT_exponent
= 1.0 / sgi_gamma
;
367 #elif defined(Macintosh)
368 LUT_exponent
= 1.8 / 2.61;
370 if (some_mac_function_that_returns_gamma(&mac_gamma))
371 LUT_exponent = mac_gamma / 2.61;
374 LUT_exponent
= 1.0; /* assume no LUT: most PCs */
377 /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
378 default_display_exponent
= LUT_exponent
* CRT_exponent
;
381 /* If the user has set the SCREEN_GAMMA environment variable as suggested
382 * (somewhat imprecisely) in the libpng documentation, use that; otherwise
383 * use the default value we just calculated. Either way, the user may
384 * override this via a command-line option. */
386 if ((p
= getenv("SCREEN_GAMMA")) != NULL
)
387 rpng2_info
.display_exponent
= atof(p
);
389 rpng2_info
.display_exponent
= default_display_exponent
;
392 /* Now parse the command line for options and the PNG filename. */
394 while (*++argv
&& !error
) {
395 if (!strncmp(*argv
, "-display", 2)) {
400 } else if (!strncmp(*argv
, "-gamma", 2)) {
404 rpng2_info
.display_exponent
= atof(*argv
);
405 if (rpng2_info
.display_exponent
<= 0.0)
408 } else if (!strncmp(*argv
, "-bgcolor", 4)) {
413 if (strlen(bgstr
) != 7 || bgstr
[0] != '#')
420 } else if (!strncmp(*argv
, "-bgpat", 4)) {
425 if (pat
>= 0 && pat
< num_bgpat
) {
431 } else if (!strncmp(*argv
, "-usleep", 2)) {
435 usleep_duration
= (ulg
)atol(*argv
);
438 } else if (!strncmp(*argv
, "-pause", 2)) {
439 pause_after_pass
= TRUE
;
440 } else if (!strncmp(*argv
, "-timing", 2)) {
443 } else if (!strncmp(*argv
, "-loop", 2)) {
445 if (!argv
[1] || !is_number(argv
[1]))
449 loop_interval
= atol(*argv
);
450 if (loop_interval
< 0)
452 else if (loop_interval
> 100000) /* bit more than one day */
453 loop_interval
= 100000;
459 if (argv
[1]) /* shouldn't be any more args after filename */
462 ++error
; /* not expecting any other options */
470 /* print usage screen if any errors up to this point */
473 fprintf(stderr
, "\n%s %s: %s\n\n", PROGNAME
, VERSION
, appname
);
474 readpng2_version_info();
478 "%s [-display xdpy] [-gamma exp] [-bgcolor bg | -bgpat pat]\n"
479 " %*s [-usleep dur | -timing] [-pause]\n",
480 PROGNAME
, (int)strlen(PROGNAME
), " ");
487 " xdpy\tname of the target X display (e.g., ``hostname:0'')\n"
488 " exp \ttransfer-function exponent (``gamma'') of the display\n"
489 "\t\t system in floating-point format (e.g., ``%.1f''); equal\n"
490 "\t\t to the product of the lookup-table exponent (varies)\n",
491 default_display_exponent
);
493 "\t\t and the CRT exponent (usually 2.2); must be positive\n"
494 " bg \tdesired background color in 7-character hex RGB format\n"
495 "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n"
496 "\t\t used with transparent images; overrides -bgpat\n"
497 " pat \tdesired background pattern number (0-%d); used with\n"
498 "\t\t transparent images; overrides -bgcolor\n",
502 " -loop\tloops through background images after initial display\n"
503 "\t\t is complete (depends on -bgpat)\n"
504 " sec \tseconds to display each background image (default = 2)\n");
507 " dur \tduration in microseconds to wait after displaying each\n"
508 "\t\t row (for demo purposes)\n"
509 " -timing\tenables delay for every block read, to simulate modem\n"
510 "\t\t download of image (~36 Kbps)\n"
511 " -pause\tpauses after displaying each pass until mouse clicked\n"
512 "\nPress Q, Esc or mouse button 1 (within image window, after image\n"
513 "is displayed) to quit.\n");
517 if (!(infile
= fopen(filename
, "rb"))) {
518 fprintf(stderr
, PROGNAME
": can't open PNG file [%s]\n", filename
);
521 incount
= fread(inbuf
, 1, INBUFSIZE
, infile
);
522 if (incount
< 8 || !readpng2_check_sig(inbuf
, 8)) {
523 fprintf(stderr
, PROGNAME
524 ": [%s] is not a PNG file: incorrect signature\n",
527 } else if ((rc
= readpng2_init(&rpng2_info
)) != 0) {
530 fprintf(stderr
, PROGNAME
531 ": [%s] has bad IHDR (libpng longjmp)\n", filename
);
534 fprintf(stderr
, PROGNAME
": insufficient memory\n");
537 fprintf(stderr
, PROGNAME
538 ": unknown readpng2_init() error\n");
543 Trace((stderr
, "about to call XOpenDisplay()\n"))
544 display
= XOpenDisplay(displayname
);
546 readpng2_cleanup(&rpng2_info
);
547 fprintf(stderr
, PROGNAME
": can't open X display [%s]\n",
548 displayname
? displayname
: "default");
558 fprintf(stderr
, PROGNAME
": aborting.\n");
563 /* set the title-bar string, but make sure buffer doesn't overflow */
565 alen
= strlen(appname
);
566 flen
= strlen(filename
);
567 if (alen
+ flen
+ 3 > 1023)
568 sprintf(titlebar
, "%s: ...%s", appname
, filename
+(alen
+flen
+6-1023));
570 sprintf(titlebar
, "%s: %s", appname
, filename
);
573 /* set some final rpng2_info variables before entering main data loop */
576 unsigned r
, g
, b
; /* this approach quiets compiler warnings */
578 sscanf(bgstr
+1, "%2x%2x%2x", &r
, &g
, &b
);
579 rpng2_info
.bg_red
= (uch
)r
;
580 rpng2_info
.bg_green
= (uch
)g
;
581 rpng2_info
.bg_blue
= (uch
)b
;
583 rpng2_info
.need_bgcolor
= TRUE
;
585 rpng2_info
.state
= kPreInit
;
586 rpng2_info
.mainprog_init
= rpng2_x_init
;
587 rpng2_info
.mainprog_display_row
= rpng2_x_display_row
;
588 rpng2_info
.mainprog_finish_display
= rpng2_x_finish_display
;
591 /* OK, this is the fun part: call readpng2_decode_data() at the start of
592 * the loop to deal with our first buffer of data (read in above to verify
593 * that the file is a PNG image), then loop through the file and continue
594 * calling the same routine to handle each chunk of data. It in turn
595 * passes the data to libpng, which will invoke one or more of our call-
596 * backs as decoded data become available. We optionally call sleep() for
597 * one second per iteration to simulate downloading the image via an analog
601 Trace((stderr
, "about to call readpng2_decode_data()\n"))
602 if (readpng2_decode_data(&rpng2_info
, inbuf
, incount
))
604 Trace((stderr
, "done with readpng2_decode_data()\n"))
606 if (error
|| incount
!= INBUFSIZE
|| rpng2_info
.state
== kDone
) {
607 if (rpng2_info
.state
== kDone
) {
608 Trace((stderr
, "done decoding PNG image\n"))
609 } else if (ferror(infile
)) {
610 fprintf(stderr
, PROGNAME
611 ": error while reading PNG image file\n");
613 } else if (feof(infile
)) {
614 fprintf(stderr
, PROGNAME
": end of file reached "
615 "(unexpectedly) while reading PNG image file\n");
617 } else /* if (error) */ {
618 /* will print error message below */
626 incount
= fread(inbuf
, 1, INBUFSIZE
, infile
);
630 /* clean up PNG stuff and report any decoding errors */
633 Trace((stderr
, "about to call readpng2_cleanup()\n"))
634 readpng2_cleanup(&rpng2_info
);
637 fprintf(stderr
, PROGNAME
": libpng error while decoding PNG image\n");
644 if (loop
&& bg_image
) {
645 Trace((stderr
, "entering -loop loop (FEATURE_LOOP)\n"))
648 struct timeval now
, then
;
650 /* get current time and add loop_interval to get target time */
651 if (gettimeofday(&then
, NULL
) == 0) {
652 then
.tv_sec
+= loop_interval
;
657 /* do quick check for a quit event but don't wait for it */
658 /* GRR BUG: should also check for Expose events and redraw... */
659 if (XCheckMaskEvent(display
, KeyPressMask
| ButtonPressMask
, &e
))
663 /* generate next background image */
664 if (++pat
>= num_bgpat
)
666 rpng2_x_reload_bg_image();
668 /* wait for timeout, using whatever means are available */
669 if (use_sleep
|| gettimeofday(&now
, NULL
) != 0) {
670 for (i
= loop_interval
; i
> 0; --i
) {
672 /* GRR BUG: also need to check for Expose (and redraw!) */
673 if (XCheckMaskEvent(display
, KeyPressMask
| ButtonPressMask
,
679 if (now
.tv_sec
< then
.tv_sec
||
680 (now
.tv_sec
== then
.tv_sec
&& now
.tv_usec
< then
.tv_usec
))
683 long seconds_to_go
= then
.tv_sec
- now
.tv_sec
;
686 /* basically chew up most of remaining loop-interval with
687 * calls to sleep(1) interleaved with checks for quit
688 * events, but also recalc time-to-go periodically; when
689 * done, clean up any remaining time with usleep() call
690 * (could also use SIGALRM, but signals are a pain...) */
691 while (seconds_to_go
-- > 1) {
692 int seconds_done
= 0;
694 for (i
= seconds_to_go
; i
> 0 && !quit
; --i
) {
696 /* GRR BUG: need to check for Expose and redraw */
697 if (XCheckMaskEvent(display
, KeyPressMask
|
698 ButtonPressMask
, &e
) && QUIT(e
,k
))
700 if (++seconds_done
> 1000)
701 break; /* time to redo seconds_to_go meas. */
706 /* OK, more than 1000 seconds since last check:
707 * correct the time-to-go measurement for drift */
708 if (gettimeofday(&now
, NULL
) == 0) {
709 if (now
.tv_sec
>= then
.tv_sec
)
711 seconds_to_go
= then
.tv_sec
- now
.tv_sec
;
713 ++seconds_to_go
; /* restore what we subtracted */
716 break; /* breaks outer do-loop, skips redisplay */
718 /* since difference between "now" and "then" is already
719 * eaten up to within a couple of seconds, don't need to
720 * worry about overflow--but might have overshot (neg.) */
721 if (gettimeofday(&now
, NULL
) == 0) {
722 usleep_usec
= 1000000L*(then
.tv_sec
- now
.tv_sec
) +
723 then
.tv_usec
- now
.tv_usec
;
725 usleep((ulg
)usleep_usec
);
730 /* composite image against new background and display (note that
731 * we do not take into account the time spent doing this...) */
732 rpng2_x_redisplay_image (0, 0, rpng2_info
.width
, rpng2_info
.height
);
735 } else /* FALL THROUGH and do the normal thing */
737 #endif /* FEATURE_LOOP */
739 /* wait for the user to tell us when to quit */
741 if (rpng2_info
.state
>= kWindowInit
) {
742 Trace((stderr
, "entering final wait-for-quit-event loop\n"))
744 XNextEvent(display
, &e
);
745 if (e
.type
== Expose
) {
746 XExposeEvent
*ex
= (XExposeEvent
*)&e
;
747 rpng2_x_redisplay_image (ex
->x
, ex
->y
, ex
->width
, ex
->height
);
749 } while (!QUIT(e
,k
));
751 fprintf(stderr
, PROGNAME
": init callback never called: probable "
752 "libpng error while decoding PNG metadata\n");
757 /* we're done: clean up all image and X resources and go away */
759 Trace((stderr
, "about to call rpng2_x_cleanup()\n"))
762 (void)argc
; /* Unused */
771 /* this function is called by readpng2_info_callback() in readpng2.c, which
772 * in turn is called by libpng after all of the pre-IDAT chunks have been
773 * read and processed--i.e., we now have enough info to finish initializing */
775 static void rpng2_x_init(void)
778 ulg rowbytes
= rpng2_info
.rowbytes
;
780 Trace((stderr
, "beginning rpng2_x_init()\n"))
781 Trace((stderr
, " rowbytes = %d\n", rpng2_info
.rowbytes
))
782 Trace((stderr
, " width = %ld\n", rpng2_info
.width
))
783 Trace((stderr
, " height = %ld\n", rpng2_info
.height
))
785 /* Guard against integer overflow */
786 if (rpng2_info
.height
> ((size_t)(-1))/rpng2_info
.rowbytes
) {
787 fprintf(stderr
, PROGNAME
": image_data buffer would be too large\n");
788 readpng2_cleanup(&rpng2_info
);
792 rpng2_info
.image_data
= (uch
*)malloc(rowbytes
* rpng2_info
.height
);
793 if (!rpng2_info
.image_data
) {
794 readpng2_cleanup(&rpng2_info
);
798 rpng2_info
.row_pointers
= (uch
**)malloc(rpng2_info
.height
* sizeof(uch
*));
799 if (!rpng2_info
.row_pointers
) {
800 free(rpng2_info
.image_data
);
801 rpng2_info
.image_data
= NULL
;
802 readpng2_cleanup(&rpng2_info
);
806 for (i
= 0; i
< rpng2_info
.height
; ++i
)
807 rpng2_info
.row_pointers
[i
] = rpng2_info
.image_data
+ i
*rowbytes
;
810 /* do the basic X initialization stuff, make the window, and fill it with
811 * the user-specified, file-specified or default background color or
814 if (rpng2_x_create_window()) {
816 /* GRR TEMPORARY HACK: this is fundamentally no different from cases
817 * above; libpng should call our error handler to longjmp() back to us
818 * when png_ptr goes away. If we/it segfault instead, seems like a
821 /* we're here via libpng callback, so if window fails, clean and bail */
822 readpng2_cleanup(&rpng2_info
);
827 rpng2_info
.state
= kWindowInit
;
834 static int rpng2_x_create_window(void)
836 ulg bg_red
= rpng2_info
.bg_red
;
837 ulg bg_green
= rpng2_info
.bg_green
;
838 ulg bg_blue
= rpng2_info
.bg_blue
;
841 int need_colormap
= FALSE
;
847 XSetWindowAttributes attr
;
848 XTextProperty windowName
, *pWindowName
= &windowName
;
849 XTextProperty iconName
, *pIconName
= &iconName
;
850 XVisualInfo visual_info
;
851 XSizeHints
*size_hints
;
853 XClassHint
*class_hints
;
856 Trace((stderr
, "beginning rpng2_x_create_window()\n"))
858 screen
= DefaultScreen(display
);
859 depth
= DisplayPlanes(display
, screen
);
860 root
= RootWindow(display
, screen
);
863 XSynchronize(display
, True
);
866 if (depth
!= 16 && depth
!= 24 && depth
!= 32) {
867 int visuals_matched
= 0;
869 Trace((stderr
, "default depth is %d: checking other visuals\n",
873 visual_info
.screen
= screen
;
874 visual_info
.depth
= 24;
875 visual_list
= XGetVisualInfo(display
,
876 VisualScreenMask
| VisualDepthMask
, &visual_info
, &visuals_matched
);
877 if (visuals_matched
== 0) {
878 /* GRR: add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */
879 fprintf(stderr
, "default screen depth %d not supported, and no"
880 " 24-bit visuals found\n", depth
);
883 Trace((stderr
, "XGetVisualInfo() returned %d 24-bit visuals\n",
885 visual
= visual_list
[0].visual
;
886 depth
= visual_list
[0].depth
;
888 colormap_size = visual_list[0].colormap_size;
889 visual_class = visual->class;
890 visualID = XVisualIDFromVisual(visual);
892 have_nondefault_visual
= TRUE
;
893 need_colormap
= TRUE
;
895 XMatchVisualInfo(display
, screen
, depth
, TrueColor
, &visual_info
);
896 visual
= visual_info
.visual
;
899 RMask
= visual
->red_mask
;
900 GMask
= visual
->green_mask
;
901 BMask
= visual
->blue_mask
;
903 /* GRR: add/check 8-bit support */
904 if (depth
== 8 || need_colormap
) {
905 colormap
= XCreateColormap(display
, root
, visual
, AllocNone
);
907 fprintf(stderr
, "XCreateColormap() failed\n");
910 have_colormap
= TRUE
;
912 bg_image
= FALSE
; /* gradient just wastes palette entries */
914 if (depth
== 15 || depth
== 16) {
915 RShift
= 15 - rpng2_x_msb(RMask
); /* these are right-shifts */
916 GShift
= 15 - rpng2_x_msb(GMask
);
917 BShift
= 15 - rpng2_x_msb(BMask
);
918 } else if (depth
> 16) {
919 RShift
= rpng2_x_msb(RMask
) - 7; /* these are left-shifts */
920 GShift
= rpng2_x_msb(GMask
) - 7;
921 BShift
= rpng2_x_msb(BMask
) - 7;
923 if (depth
>= 15 && (RShift
< 0 || GShift
< 0 || BShift
< 0)) {
924 fprintf(stderr
, "rpng2 internal logic error: negative X shift(s)!\n");
928 /*---------------------------------------------------------------------------
929 Finally, create the window.
930 ---------------------------------------------------------------------------*/
932 attr
.backing_store
= Always
;
933 attr
.event_mask
= ExposureMask
| KeyPressMask
| ButtonPressMask
;
934 attrmask
= CWBackingStore
| CWEventMask
;
935 if (have_nondefault_visual
) {
936 attr
.colormap
= colormap
;
937 attr
.background_pixel
= 0;
938 attr
.border_pixel
= 1;
939 attrmask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
942 window
= XCreateWindow(display
, root
, 0, 0, rpng2_info
.width
,
943 rpng2_info
.height
, 0, depth
, InputOutput
, visual
, attrmask
, &attr
);
945 if (window
== None
) {
946 fprintf(stderr
, "XCreateWindow() failed\n");
952 XSetWindowColormap(display
, window
, colormap
);
954 if (!XStringListToTextProperty(&window_name
, 1, pWindowName
))
956 if (!XStringListToTextProperty(&icon_name
, 1, pIconName
))
959 /* OK if either hints allocation fails; XSetWMProperties() allows NULLs */
961 if ((size_hints
= XAllocSizeHints()) != NULL
) {
962 /* window will not be resizable */
963 size_hints
->flags
= PMinSize
| PMaxSize
;
964 size_hints
->min_width
= size_hints
->max_width
= (int)rpng2_info
.width
;
965 size_hints
->min_height
= size_hints
->max_height
=
966 (int)rpng2_info
.height
;
969 if ((wm_hints
= XAllocWMHints()) != NULL
) {
970 wm_hints
->initial_state
= NormalState
;
971 wm_hints
->input
= True
;
972 /* wm_hints->icon_pixmap = icon_pixmap; */
973 wm_hints
->flags
= StateHint
| InputHint
/* | IconPixmapHint */ ;
976 if ((class_hints
= XAllocClassHint()) != NULL
) {
977 class_hints
->res_name
= res_name
;
978 class_hints
->res_class
= res_class
;
981 XSetWMProperties(display
, window
, pWindowName
, pIconName
, NULL
, 0,
982 size_hints
, wm_hints
, class_hints
);
984 /* various properties and hints no longer needed; free memory */
986 XFree(pWindowName
->value
);
988 XFree(pIconName
->value
);
996 XMapWindow(display
, window
);
998 gc
= XCreateGC(display
, window
, 0, &gcvalues
);
1001 /*---------------------------------------------------------------------------
1002 Allocate memory for the X- and display-specific version of the image.
1003 ---------------------------------------------------------------------------*/
1005 if (depth
== 24 || depth
== 32) {
1006 xdata
= (uch
*)malloc(4*rpng2_info
.width
*rpng2_info
.height
);
1008 } else if (depth
== 16) {
1009 xdata
= (uch
*)malloc(2*rpng2_info
.width
*rpng2_info
.height
);
1011 } else /* depth == 8 */ {
1012 xdata
= (uch
*)malloc(rpng2_info
.width
*rpng2_info
.height
);
1017 fprintf(stderr
, PROGNAME
": unable to allocate image memory\n");
1021 ximage
= XCreateImage(display
, visual
, depth
, ZPixmap
, 0,
1022 (char *)xdata
, rpng2_info
.width
, rpng2_info
.height
, pad
, 0);
1025 fprintf(stderr
, PROGNAME
": XCreateImage() failed\n");
1030 /* to avoid testing the byte order every pixel (or doubling the size of
1031 * the drawing routine with a giant if-test), we arbitrarily set the byte
1032 * order to MSBFirst and let Xlib worry about inverting things on little-
1033 * endian machines (e.g., Linux/x86, old VAXen, etc.)--this is not the
1034 * most efficient approach (the giant if-test would be better), but in
1035 * the interest of clarity, we'll take the easy way out... */
1037 ximage
->byte_order
= MSBFirst
;
1039 /*---------------------------------------------------------------------------
1040 Fill window with the specified background color (default is black) or
1041 faked "background image" (but latter is disabled if 8-bit; gradients
1042 just waste palette entries).
1043 ---------------------------------------------------------------------------*/
1046 rpng2_x_load_bg_image(); /* resets bg_image if fails */
1049 if (depth
== 24 || depth
== 32) {
1050 bg_pixel
= (bg_red
<< RShift
) |
1051 (bg_green
<< GShift
) |
1052 (bg_blue
<< BShift
);
1053 } else if (depth
== 16) {
1054 bg_pixel
= (((bg_red
<< 8) >> RShift
) & RMask
) |
1055 (((bg_green
<< 8) >> GShift
) & GMask
) |
1056 (((bg_blue
<< 8) >> BShift
) & BMask
);
1057 } else /* depth == 8 */ {
1059 /* GRR: add 8-bit support */
1062 XSetForeground(display
, gc
, bg_pixel
);
1063 XFillRectangle(display
, window
, gc
, 0, 0, rpng2_info
.width
,
1067 /*---------------------------------------------------------------------------
1068 Wait for first Expose event to do any drawing, then flush and return.
1069 ---------------------------------------------------------------------------*/
1072 XNextEvent(display
, &e
);
1073 while (e
.type
!= Expose
|| e
.xexpose
.count
);
1079 } /* end function rpng2_x_create_window() */
1085 static int rpng2_x_load_bg_image(void)
1089 uch r1
, r2
, g1
, g2
, b1
, b2
;
1090 uch r1_inv
, r2_inv
, g1_inv
, g2_inv
, b1_inv
, b2_inv
;
1092 int xidx
, yidx
, yidx_max
;
1093 int even_odd_vert
, even_odd_horiz
, even_odd
;
1094 int invert_gradient2
= (bg
[pat
].type
& 0x08);
1096 int ximage_rowbytes
= ximage
->bytes_per_line
;
1100 /*---------------------------------------------------------------------------
1101 Allocate buffer for fake background image to be used with transparent
1102 images; if this fails, revert to plain background color.
1103 ---------------------------------------------------------------------------*/
1105 bg_rowbytes
= 3 * rpng2_info
.width
;
1106 bg_data
= (uch
*)malloc(bg_rowbytes
* rpng2_info
.height
);
1108 fprintf(stderr
, PROGNAME
1109 ": unable to allocate memory for background image\n");
1114 bgscale
= (pat
== 0)? 8 : bgscale_default
;
1115 yidx_max
= bgscale
- 1;
1117 /*---------------------------------------------------------------------------
1118 Vertical gradients (ramps) in NxN squares, alternating direction and
1119 colors (N == bgscale).
1120 ---------------------------------------------------------------------------*/
1122 if ((bg
[pat
].type
& 0x07) == 0) {
1123 uch r1_min
= rgb
[bg
[pat
].rgb1_min
].r
;
1124 uch g1_min
= rgb
[bg
[pat
].rgb1_min
].g
;
1125 uch b1_min
= rgb
[bg
[pat
].rgb1_min
].b
;
1126 uch r2_min
= rgb
[bg
[pat
].rgb2_min
].r
;
1127 uch g2_min
= rgb
[bg
[pat
].rgb2_min
].g
;
1128 uch b2_min
= rgb
[bg
[pat
].rgb2_min
].b
;
1129 int r1_diff
= rgb
[bg
[pat
].rgb1_max
].r
- r1_min
;
1130 int g1_diff
= rgb
[bg
[pat
].rgb1_max
].g
- g1_min
;
1131 int b1_diff
= rgb
[bg
[pat
].rgb1_max
].b
- b1_min
;
1132 int r2_diff
= rgb
[bg
[pat
].rgb2_max
].r
- r2_min
;
1133 int g2_diff
= rgb
[bg
[pat
].rgb2_max
].g
- g2_min
;
1134 int b2_diff
= rgb
[bg
[pat
].rgb2_max
].b
- b2_min
;
1136 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1137 yidx
= (int)(row
% bgscale
);
1138 even_odd_vert
= (int)((row
/ bgscale
) & 1);
1140 r1
= r1_min
+ (r1_diff
* yidx
) / yidx_max
;
1141 g1
= g1_min
+ (g1_diff
* yidx
) / yidx_max
;
1142 b1
= b1_min
+ (b1_diff
* yidx
) / yidx_max
;
1143 r1_inv
= r1_min
+ (r1_diff
* (yidx_max
-yidx
)) / yidx_max
;
1144 g1_inv
= g1_min
+ (g1_diff
* (yidx_max
-yidx
)) / yidx_max
;
1145 b1_inv
= b1_min
+ (b1_diff
* (yidx_max
-yidx
)) / yidx_max
;
1147 r2
= r2_min
+ (r2_diff
* yidx
) / yidx_max
;
1148 g2
= g2_min
+ (g2_diff
* yidx
) / yidx_max
;
1149 b2
= b2_min
+ (b2_diff
* yidx
) / yidx_max
;
1150 r2_inv
= r2_min
+ (r2_diff
* (yidx_max
-yidx
)) / yidx_max
;
1151 g2_inv
= g2_min
+ (g2_diff
* (yidx_max
-yidx
)) / yidx_max
;
1152 b2_inv
= b2_min
+ (b2_diff
* (yidx_max
-yidx
)) / yidx_max
;
1154 dest
= (char *)bg_data
+ row
*bg_rowbytes
;
1155 for (i
= 0; i
< rpng2_info
.width
; ++i
) {
1156 even_odd_horiz
= (int)((i
/ bgscale
) & 1);
1157 even_odd
= even_odd_vert
^ even_odd_horiz
;
1159 (even_odd_horiz
&& (bg
[pat
].type
& 0x10));
1160 if (even_odd
== 0) { /* gradient #1 */
1161 if (invert_column
) {
1170 } else { /* gradient #2 */
1171 if ((invert_column
&& invert_gradient2
) ||
1172 (!invert_column
&& !invert_gradient2
))
1174 *dest
++ = r2
; /* not inverted or */
1175 *dest
++ = g2
; /* doubly inverted */
1179 *dest
++ = g2_inv
; /* singly inverted */
1186 /*---------------------------------------------------------------------------
1187 Soft gradient-diamonds with scale = bgscale. Code contributed by Adam
1189 ---------------------------------------------------------------------------*/
1191 } else if ((bg
[pat
].type
& 0x07) == 1) {
1193 hmax
= (bgscale
-1)/2; /* half the max weight of a color */
1194 max
= 2*hmax
; /* the max weight of a color */
1196 r1
= rgb
[bg
[pat
].rgb1_max
].r
;
1197 g1
= rgb
[bg
[pat
].rgb1_max
].g
;
1198 b1
= rgb
[bg
[pat
].rgb1_max
].b
;
1199 r2
= rgb
[bg
[pat
].rgb2_max
].r
;
1200 g2
= rgb
[bg
[pat
].rgb2_max
].g
;
1201 b2
= rgb
[bg
[pat
].rgb2_max
].b
;
1203 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1204 yidx
= (int)(row
% bgscale
);
1206 yidx
= bgscale
-1 - yidx
;
1207 dest
= (char *)bg_data
+ row
*bg_rowbytes
;
1208 for (i
= 0; i
< rpng2_info
.width
; ++i
) {
1209 xidx
= (int)(i
% bgscale
);
1211 xidx
= bgscale
-1 - xidx
;
1213 *dest
++ = (k
*r1
+ (max
-k
)*r2
) / max
;
1214 *dest
++ = (k
*g1
+ (max
-k
)*g2
) / max
;
1215 *dest
++ = (k
*b1
+ (max
-k
)*b2
) / max
;
1219 /*---------------------------------------------------------------------------
1220 Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
1221 soids will equal bgscale?]. This one is slow but very cool. Code con-
1222 tributed by Pieter S. van der Meulen (originally in Smalltalk).
1223 ---------------------------------------------------------------------------*/
1225 } else if ((bg
[pat
].type
& 0x07) == 2) {
1227 int ii
, x
, y
, hw
, hh
, grayspot
;
1228 double freq
, rotate
, saturate
, gray
, intensity
;
1229 double angle
=0.0, aoffset
=0.0, maxDist
, dist
;
1230 double red
=0.0, green
=0.0, blue
=0.0, hue
, s
, v
, f
, p
, q
, t
;
1232 fprintf(stderr
, "%s: computing radial background...",
1236 hh
= (int)(rpng2_info
.height
/ 2);
1237 hw
= (int)(rpng2_info
.width
/ 2);
1239 /* variables for radial waves:
1240 * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED]
1241 * freq: number of color beams originating from the center
1242 * grayspot: size of the graying center area (anti-alias)
1243 * rotate: rotation of the beams as a function of radius
1244 * saturate: saturation of beams' shape azimuthally
1246 angle
= CLIP(angle
, 0.0, 360.0);
1247 grayspot
= CLIP(bg
[pat
].bg_gray
, 1, (hh
+ hw
));
1248 freq
= MAX((double)bg
[pat
].bg_freq
, 0.0);
1249 saturate
= (double)bg
[pat
].bg_bsat
* 0.1;
1250 rotate
= (double)bg
[pat
].bg_brot
* 0.1;
1253 maxDist
= (double)((hw
*hw
) + (hh
*hh
));
1255 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1256 y
= (int)(row
- hh
);
1257 dest
= (char *)bg_data
+ row
*bg_rowbytes
;
1258 for (i
= 0; i
< rpng2_info
.width
; ++i
) {
1260 angle
= (x
== 0)? PI_2
: atan((double)y
/ (double)x
);
1261 gray
= (double)MAX(ABS(y
), ABS(x
)) / grayspot
;
1262 gray
= MIN(1.0, gray
);
1263 dist
= (double)((x
*x
) + (y
*y
)) / maxDist
;
1264 intensity
= cos((angle
+(rotate
*dist
*PI
)) * freq
) *
1266 intensity
= (MAX(MIN(intensity
,1.0),-1.0) + 1.0) * 0.5;
1267 hue
= (angle
+ PI
) * INV_PI_360
+ aoffset
;
1268 s
= gray
* ((double)(ABS(x
)+ABS(y
)) / (double)(hw
+ hh
));
1269 s
= MIN(MAX(s
,0.0), 1.0);
1270 v
= MIN(MAX(intensity
,0.0), 1.0);
1273 ch
= (uch
)(v
* 255.0);
1278 if ((hue
< 0.0) || (hue
>= 360.0))
1279 hue
-= (((int)(hue
/ 360.0)) * 360.0);
1282 f
= hue
- (double)ii
;
1284 q
= (1.0 - (s
* f
)) * v
;
1285 t
= (1.0 - (s
* (1.0 - f
))) * v
;
1286 if (ii
== 0) { red
= v
; green
= t
; blue
= p
; }
1287 else if (ii
== 1) { red
= q
; green
= v
; blue
= p
; }
1288 else if (ii
== 2) { red
= p
; green
= v
; blue
= t
; }
1289 else if (ii
== 3) { red
= p
; green
= q
; blue
= v
; }
1290 else if (ii
== 4) { red
= t
; green
= p
; blue
= v
; }
1291 else if (ii
== 5) { red
= v
; green
= p
; blue
= q
; }
1292 *dest
++ = (uch
)(red
* 255.0);
1293 *dest
++ = (uch
)(green
* 255.0);
1294 *dest
++ = (uch
)(blue
* 255.0);
1298 fprintf(stderr
, "done.\n");
1302 /*---------------------------------------------------------------------------
1303 Blast background image to display buffer before beginning PNG decode.
1304 ---------------------------------------------------------------------------*/
1306 if (depth
== 24 || depth
== 32) {
1307 ulg red
, green
, blue
;
1308 int bpp
= ximage
->bits_per_pixel
;
1310 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1311 src
= bg_data
+ row
*bg_rowbytes
;
1312 dest
= ximage
->data
+ row
*ximage_rowbytes
;
1313 if (bpp
== 32) { /* slightly optimized version */
1314 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1318 pixel
= (red
<< RShift
) |
1321 /* recall that we set ximage->byte_order = MSBFirst above */
1322 *dest
++ = (char)((pixel
>> 24) & 0xff);
1323 *dest
++ = (char)((pixel
>> 16) & 0xff);
1324 *dest
++ = (char)((pixel
>> 8) & 0xff);
1325 *dest
++ = (char)( pixel
& 0xff);
1328 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1332 pixel
= (red
<< RShift
) |
1335 /* recall that we set ximage->byte_order = MSBFirst above */
1336 /* GRR BUG? this assumes bpp == 24 & bits are packed low */
1337 /* (probably need to use RShift, RMask, etc.) */
1338 *dest
++ = (char)((pixel
>> 16) & 0xff);
1339 *dest
++ = (char)((pixel
>> 8) & 0xff);
1340 *dest
++ = (char)( pixel
& 0xff);
1345 } else if (depth
== 16) {
1346 ush red
, green
, blue
;
1348 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1349 src
= bg_data
+ row
*bg_rowbytes
;
1350 dest
= ximage
->data
+ row
*ximage_rowbytes
;
1351 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1352 red
= ((ush
)(*src
) << 8); ++src
;
1353 green
= ((ush
)(*src
) << 8); ++src
;
1354 blue
= ((ush
)(*src
) << 8); ++src
;
1355 pixel
= ((red
>> RShift
) & RMask
) |
1356 ((green
>> GShift
) & GMask
) |
1357 ((blue
>> BShift
) & BMask
);
1358 /* recall that we set ximage->byte_order = MSBFirst above */
1359 *dest
++ = (char)((pixel
>> 8) & 0xff);
1360 *dest
++ = (char)( pixel
& 0xff);
1364 } else /* depth == 8 */ {
1366 /* GRR: add 8-bit support */
1370 XPutImage(display
, window
, gc
, ximage
, 0, 0, 0, 0, rpng2_info
.width
,
1375 } /* end function rpng2_x_load_bg_image() */
1381 static void rpng2_x_display_row(ulg row
)
1383 uch bg_red
= rpng2_info
.bg_red
;
1384 uch bg_green
= rpng2_info
.bg_green
;
1385 uch bg_blue
= rpng2_info
.bg_blue
;
1386 uch
*src
, *src2
=NULL
;
1389 int ximage_rowbytes
= ximage
->bytes_per_line
;
1391 static int rows
=0, prevpass
=(-1);
1392 static ulg firstrow
;
1394 /*---------------------------------------------------------------------------
1395 rows and firstrow simply track how many rows (and which ones) have not
1396 yet been displayed; alternatively, we could call XPutImage() for every
1397 row and not bother with the records-keeping.
1398 ---------------------------------------------------------------------------*/
1400 Trace((stderr
, "beginning rpng2_x_display_row()\n"))
1402 if (rpng2_info
.pass
!= prevpass
) {
1403 if (pause_after_pass
&& rpng2_info
.pass
> 0) {
1408 "%s: end of pass %d of 7; click in image window to continue\n",
1409 PROGNAME
, prevpass
+ 1);
1411 XNextEvent(display
, &e
);
1414 fprintf(stderr
, "%s: pass %d of 7\r", PROGNAME
, rpng2_info
.pass
+ 1);
1416 prevpass
= rpng2_info
.pass
;
1420 firstrow
= row
; /* first row that is not yet displayed */
1422 ++rows
; /* count of rows received but not yet displayed */
1424 /*---------------------------------------------------------------------------
1425 Aside from the use of the rpng2_info struct, the lack of an outer loop
1426 (over rows) and moving the XPutImage() call outside the "if (depth)"
1427 tests, this routine is identical to rpng_x_display_image() in the non-
1428 progressive version of the program.
1429 ---------------------------------------------------------------------------*/
1431 if (depth
== 24 || depth
== 32) {
1432 ulg red
, green
, blue
;
1433 int bpp
= ximage
->bits_per_pixel
;
1435 src
= rpng2_info
.image_data
+ row
*rpng2_info
.rowbytes
;
1437 src2
= bg_data
+ row
*bg_rowbytes
;
1438 dest
= ximage
->data
+ row
*ximage_rowbytes
;
1439 if (rpng2_info
.channels
== 3) {
1440 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1444 pixel
= (red
<< RShift
) |
1447 /* recall that we set ximage->byte_order = MSBFirst above */
1449 *dest
++ = (char)((pixel
>> 24) & 0xff);
1450 *dest
++ = (char)((pixel
>> 16) & 0xff);
1451 *dest
++ = (char)((pixel
>> 8) & 0xff);
1452 *dest
++ = (char)( pixel
& 0xff);
1454 /* GRR BUG? this assumes bpp == 24 & bits are packed low */
1455 /* (probably need to use RShift, RMask, etc.) */
1456 *dest
++ = (char)((pixel
>> 16) & 0xff);
1457 *dest
++ = (char)((pixel
>> 8) & 0xff);
1458 *dest
++ = (char)( pixel
& 0xff);
1461 } else /* if (rpng2_info.channels == 4) */ {
1462 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1476 } else if (a
== 0) {
1481 /* this macro (from png.h) composites the foreground
1482 * and background values and puts the result into the
1484 alpha_composite(red
, r
, a
, bg_red
);
1485 alpha_composite(green
, g
, a
, bg_green
);
1486 alpha_composite(blue
, b
, a
, bg_blue
);
1488 pixel
= (red
<< RShift
) |
1491 /* recall that we set ximage->byte_order = MSBFirst above */
1493 *dest
++ = (char)((pixel
>> 24) & 0xff);
1494 *dest
++ = (char)((pixel
>> 16) & 0xff);
1495 *dest
++ = (char)((pixel
>> 8) & 0xff);
1496 *dest
++ = (char)( pixel
& 0xff);
1498 /* GRR BUG? this assumes bpp == 24 & bits are packed low */
1499 /* (probably need to use RShift, RMask, etc.) */
1500 *dest
++ = (char)((pixel
>> 16) & 0xff);
1501 *dest
++ = (char)((pixel
>> 8) & 0xff);
1502 *dest
++ = (char)( pixel
& 0xff);
1507 } else if (depth
== 16) {
1508 ush red
, green
, blue
;
1510 src
= rpng2_info
.row_pointers
[row
];
1512 src2
= bg_data
+ row
*bg_rowbytes
;
1513 dest
= ximage
->data
+ row
*ximage_rowbytes
;
1514 if (rpng2_info
.channels
== 3) {
1515 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1516 red
= ((ush
)(*src
) << 8);
1518 green
= ((ush
)(*src
) << 8);
1520 blue
= ((ush
)(*src
) << 8);
1522 pixel
= ((red
>> RShift
) & RMask
) |
1523 ((green
>> GShift
) & GMask
) |
1524 ((blue
>> BShift
) & BMask
);
1525 /* recall that we set ximage->byte_order = MSBFirst above */
1526 *dest
++ = (char)((pixel
>> 8) & 0xff);
1527 *dest
++ = (char)( pixel
& 0xff);
1529 } else /* if (rpng2_info.channels == 4) */ {
1530 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1541 red
= ((ush
)r
<< 8);
1542 green
= ((ush
)g
<< 8);
1543 blue
= ((ush
)b
<< 8);
1544 } else if (a
== 0) {
1545 red
= ((ush
)bg_red
<< 8);
1546 green
= ((ush
)bg_green
<< 8);
1547 blue
= ((ush
)bg_blue
<< 8);
1549 /* this macro (from png.h) composites the foreground
1550 * and background values and puts the result back into
1551 * the first argument (== fg byte here: safe) */
1552 alpha_composite(r
, r
, a
, bg_red
);
1553 alpha_composite(g
, g
, a
, bg_green
);
1554 alpha_composite(b
, b
, a
, bg_blue
);
1555 red
= ((ush
)r
<< 8);
1556 green
= ((ush
)g
<< 8);
1557 blue
= ((ush
)b
<< 8);
1559 pixel
= ((red
>> RShift
) & RMask
) |
1560 ((green
>> GShift
) & GMask
) |
1561 ((blue
>> BShift
) & BMask
);
1562 /* recall that we set ximage->byte_order = MSBFirst above */
1563 *dest
++ = (char)((pixel
>> 8) & 0xff);
1564 *dest
++ = (char)( pixel
& 0xff);
1568 } else /* depth == 8 */ {
1570 /* GRR: add 8-bit support */
1575 /*---------------------------------------------------------------------------
1576 Display after every 16 rows or when on one of last two rows. (Region
1577 may include previously displayed lines due to interlacing--i.e., not
1578 contiguous. Also, second-to-last row is final one in interlaced images
1579 with odd number of rows.) For demos, flush (and delay) after every 16th
1580 row so "sparse" passes don't go twice as fast.
1581 ---------------------------------------------------------------------------*/
1583 if (demo_timing
&& (row
- firstrow
>= 16 || row
>= rpng2_info
.height
-2)) {
1584 XPutImage(display
, window
, gc
, ximage
, 0, (int)firstrow
, 0,
1585 (int)firstrow
, rpng2_info
.width
, row
- firstrow
+ 1);
1588 usleep(usleep_duration
);
1590 if (!demo_timing
&& ((rows
& 0xf) == 0 || row
>= rpng2_info
.height
-2)) {
1591 XPutImage(display
, window
, gc
, ximage
, 0, (int)firstrow
, 0,
1592 (int)firstrow
, rpng2_info
.width
, row
- firstrow
+ 1);
1603 static void rpng2_x_finish_display(void)
1605 Trace((stderr
, "beginning rpng2_x_finish_display()\n"))
1607 /* last row has already been displayed by rpng2_x_display_row(), so we
1608 * have nothing to do here except set a flag and let the user know that
1609 * the image is done */
1611 rpng2_info
.state
= kDone
;
1613 "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n");
1621 static void rpng2_x_redisplay_image(ulg startcol
, ulg startrow
,
1622 ulg width
, ulg height
)
1624 uch bg_red
= rpng2_info
.bg_red
;
1625 uch bg_green
= rpng2_info
.bg_green
;
1626 uch bg_blue
= rpng2_info
.bg_blue
;
1627 uch
*src
, *src2
=NULL
;
1630 ulg i
, row
, lastrow
= 0;
1632 int ximage_rowbytes
= ximage
->bytes_per_line
;
1635 Trace((stderr
, "beginning display loop (image_channels == %d)\n",
1636 rpng2_info
.channels
))
1637 Trace((stderr
, " (width = %ld, rowbytes = %d, ximage_rowbytes = %d)\n",
1638 rpng2_info
.width
, rpng2_info
.rowbytes
, ximage_rowbytes
))
1639 Trace((stderr
, " (bpp = %d)\n", ximage
->bits_per_pixel
))
1640 Trace((stderr
, " (byte_order = %s)\n", ximage
->byte_order
== MSBFirst
?
1641 "MSBFirst" : (ximage
->byte_order
== LSBFirst
? "LSBFirst" : "unknown")))
1643 /*---------------------------------------------------------------------------
1644 Aside from the use of the rpng2_info struct and of src2 (for background
1645 image), this routine is identical to rpng_x_display_image() in the non-
1646 progressive version of the program--for the simple reason that redisplay
1647 of the image against a new background happens after the image is fully
1648 decoded and therefore is, by definition, non-progressive.
1649 ---------------------------------------------------------------------------*/
1651 if (depth
== 24 || depth
== 32) {
1652 ulg red
, green
, blue
;
1653 int bpp
= ximage
->bits_per_pixel
;
1655 for (lastrow
= row
= startrow
; row
< startrow
+height
; ++row
) {
1656 src
= rpng2_info
.image_data
+ row
*rpng2_info
.rowbytes
;
1658 src2
= bg_data
+ row
*bg_rowbytes
;
1659 dest
= ximage
->data
+ row
*ximage_rowbytes
;
1660 if (rpng2_info
.channels
== 3) {
1661 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1665 #ifdef NO_24BIT_MASKS
1666 pixel
= (red
<< RShift
) |
1669 /* recall that we set ximage->byte_order = MSBFirst above */
1671 *dest
++ = (char)((pixel
>> 24) & 0xff);
1672 *dest
++ = (char)((pixel
>> 16) & 0xff);
1673 *dest
++ = (char)((pixel
>> 8) & 0xff);
1674 *dest
++ = (char)( pixel
& 0xff);
1676 /* this assumes bpp == 24 & bits are packed low */
1677 /* (probably need to use RShift, RMask, etc.) */
1678 *dest
++ = (char)((pixel
>> 16) & 0xff);
1679 *dest
++ = (char)((pixel
>> 8) & 0xff);
1680 *dest
++ = (char)( pixel
& 0xff);
1683 red
= (RShift
< 0)? red
<< (-RShift
) : red
>> RShift
;
1684 green
= (GShift
< 0)? green
<< (-GShift
) : green
>> GShift
;
1685 blue
= (BShift
< 0)? blue
<< (-BShift
) : blue
>> BShift
;
1686 pixel
= (red
& RMask
) | (green
& GMask
) | (blue
& BMask
);
1687 /* recall that we set ximage->byte_order = MSBFirst above */
1689 *dest
++ = (char)((pixel
>> 24) & 0xff);
1690 *dest
++ = (char)((pixel
>> 16) & 0xff);
1691 *dest
++ = (char)((pixel
>> 8) & 0xff);
1692 *dest
++ = (char)( pixel
& 0xff);
1695 /* this assumes bpp == 24 & bits are packed low */
1696 /* (probably need to use RShift/RMask/etc. here, too) */
1697 *dest
++ = (char)((pixel
>> 16) & 0xff);
1698 *dest
++ = (char)((pixel
>> 8) & 0xff);
1699 *dest
++ = (char)( pixel
& 0xff);
1704 } else /* if (rpng2_info.channels == 4) */ {
1705 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1719 } else if (a
== 0) {
1724 /* this macro (from png.h) composites the foreground
1725 * and background values and puts the result into the
1727 alpha_composite(red
, r
, a
, bg_red
);
1728 alpha_composite(green
, g
, a
, bg_green
);
1729 alpha_composite(blue
, b
, a
, bg_blue
);
1731 #ifdef NO_24BIT_MASKS
1732 pixel
= (red
<< RShift
) |
1735 /* recall that we set ximage->byte_order = MSBFirst above */
1737 *dest
++ = (char)((pixel
>> 24) & 0xff);
1738 *dest
++ = (char)((pixel
>> 16) & 0xff);
1739 *dest
++ = (char)((pixel
>> 8) & 0xff);
1740 *dest
++ = (char)( pixel
& 0xff);
1742 /* this assumes bpp == 24 & bits are packed low */
1743 /* (probably need to use RShift, RMask, etc.) */
1744 *dest
++ = (char)((pixel
>> 16) & 0xff);
1745 *dest
++ = (char)((pixel
>> 8) & 0xff);
1746 *dest
++ = (char)( pixel
& 0xff);
1749 red
= (RShift
< 0)? red
<< (-RShift
) : red
>> RShift
;
1750 green
= (GShift
< 0)? green
<< (-GShift
) : green
>> GShift
;
1751 blue
= (BShift
< 0)? blue
<< (-BShift
) : blue
>> BShift
;
1752 pixel
= (red
& RMask
) | (green
& GMask
) | (blue
& BMask
);
1753 /* recall that we set ximage->byte_order = MSBFirst above */
1755 *dest
++ = (char)((pixel
>> 24) & 0xff);
1756 *dest
++ = (char)((pixel
>> 16) & 0xff);
1757 *dest
++ = (char)((pixel
>> 8) & 0xff);
1758 *dest
++ = (char)( pixel
& 0xff);
1761 /* this assumes bpp == 24 & bits are packed low */
1762 /* (probably need to use RShift/RMask/etc. here, too) */
1763 *dest
++ = (char)((pixel
>> 16) & 0xff);
1764 *dest
++ = (char)((pixel
>> 8) & 0xff);
1765 *dest
++ = (char)( pixel
& 0xff);
1770 /* display after every 16 lines */
1771 if (((row
+1) & 0xf) == 0) {
1772 XPutImage(display
, window
, gc
, ximage
, 0, (int)lastrow
, 0,
1773 (int)lastrow
, rpng2_info
.width
, 16);
1779 } else if (depth
== 16) {
1780 ush red
, green
, blue
;
1782 for (lastrow
= row
= startrow
; row
< startrow
+height
; ++row
) {
1783 src
= rpng2_info
.row_pointers
[row
];
1785 src2
= bg_data
+ row
*bg_rowbytes
;
1786 dest
= ximage
->data
+ row
*ximage_rowbytes
;
1787 if (rpng2_info
.channels
== 3) {
1788 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1789 red
= ((ush
)(*src
) << 8);
1791 green
= ((ush
)(*src
) << 8);
1793 blue
= ((ush
)(*src
) << 8);
1795 pixel
= ((red
>> RShift
) & RMask
) |
1796 ((green
>> GShift
) & GMask
) |
1797 ((blue
>> BShift
) & BMask
);
1798 /* recall that we set ximage->byte_order = MSBFirst above */
1799 *dest
++ = (char)((pixel
>> 8) & 0xff);
1800 *dest
++ = (char)( pixel
& 0xff);
1802 } else /* if (rpng2_info.channels == 4) */ {
1803 for (i
= rpng2_info
.width
; i
> 0; --i
) {
1814 red
= ((ush
)r
<< 8);
1815 green
= ((ush
)g
<< 8);
1816 blue
= ((ush
)b
<< 8);
1817 } else if (a
== 0) {
1818 red
= ((ush
)bg_red
<< 8);
1819 green
= ((ush
)bg_green
<< 8);
1820 blue
= ((ush
)bg_blue
<< 8);
1822 /* this macro (from png.h) composites the foreground
1823 * and background values and puts the result back into
1824 * the first argument (== fg byte here: safe) */
1825 alpha_composite(r
, r
, a
, bg_red
);
1826 alpha_composite(g
, g
, a
, bg_green
);
1827 alpha_composite(b
, b
, a
, bg_blue
);
1828 red
= ((ush
)r
<< 8);
1829 green
= ((ush
)g
<< 8);
1830 blue
= ((ush
)b
<< 8);
1832 pixel
= ((red
>> RShift
) & RMask
) |
1833 ((green
>> GShift
) & GMask
) |
1834 ((blue
>> BShift
) & BMask
);
1835 /* recall that we set ximage->byte_order = MSBFirst above */
1836 *dest
++ = (char)((pixel
>> 8) & 0xff);
1837 *dest
++ = (char)( pixel
& 0xff);
1840 /* display after every 16 lines */
1841 if (((row
+1) & 0xf) == 0) {
1842 XPutImage(display
, window
, gc
, ximage
, 0, (int)lastrow
, 0,
1843 (int)lastrow
, rpng2_info
.width
, 16);
1849 } else /* depth == 8 */ {
1851 /* GRR: add 8-bit support */
1855 Trace((stderr
, "calling final XPutImage()\n"))
1856 if (lastrow
< startrow
+height
) {
1857 XPutImage(display
, window
, gc
, ximage
, 0, (int)lastrow
, 0,
1858 (int)lastrow
, rpng2_info
.width
, rpng2_info
.height
-lastrow
);
1865 } /* end function rpng2_x_redisplay_image() */
1873 static void rpng2_x_reload_bg_image(void)
1876 uch r1
, r2
, g1
, g2
, b1
, b2
;
1877 uch r1_inv
, r2_inv
, g1_inv
, g2_inv
, b1_inv
, b2_inv
;
1879 int xidx
, yidx
, yidx_max
;
1880 int even_odd_vert
, even_odd_horiz
, even_odd
;
1881 int invert_gradient2
= (bg
[pat
].type
& 0x08);
1886 bgscale
= (pat
== 0)? 8 : bgscale_default
;
1887 yidx_max
= bgscale
- 1;
1889 /*---------------------------------------------------------------------------
1890 Vertical gradients (ramps) in NxN squares, alternating direction and
1891 colors (N == bgscale).
1892 ---------------------------------------------------------------------------*/
1894 if ((bg
[pat
].type
& 0x07) == 0) {
1895 uch r1_min
= rgb
[bg
[pat
].rgb1_min
].r
;
1896 uch g1_min
= rgb
[bg
[pat
].rgb1_min
].g
;
1897 uch b1_min
= rgb
[bg
[pat
].rgb1_min
].b
;
1898 uch r2_min
= rgb
[bg
[pat
].rgb2_min
].r
;
1899 uch g2_min
= rgb
[bg
[pat
].rgb2_min
].g
;
1900 uch b2_min
= rgb
[bg
[pat
].rgb2_min
].b
;
1901 int r1_diff
= rgb
[bg
[pat
].rgb1_max
].r
- r1_min
;
1902 int g1_diff
= rgb
[bg
[pat
].rgb1_max
].g
- g1_min
;
1903 int b1_diff
= rgb
[bg
[pat
].rgb1_max
].b
- b1_min
;
1904 int r2_diff
= rgb
[bg
[pat
].rgb2_max
].r
- r2_min
;
1905 int g2_diff
= rgb
[bg
[pat
].rgb2_max
].g
- g2_min
;
1906 int b2_diff
= rgb
[bg
[pat
].rgb2_max
].b
- b2_min
;
1908 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1909 yidx
= (int)(row
% bgscale
);
1910 even_odd_vert
= (int)((row
/ bgscale
) & 1);
1912 r1
= r1_min
+ (r1_diff
* yidx
) / yidx_max
;
1913 g1
= g1_min
+ (g1_diff
* yidx
) / yidx_max
;
1914 b1
= b1_min
+ (b1_diff
* yidx
) / yidx_max
;
1915 r1_inv
= r1_min
+ (r1_diff
* (yidx_max
-yidx
)) / yidx_max
;
1916 g1_inv
= g1_min
+ (g1_diff
* (yidx_max
-yidx
)) / yidx_max
;
1917 b1_inv
= b1_min
+ (b1_diff
* (yidx_max
-yidx
)) / yidx_max
;
1919 r2
= r2_min
+ (r2_diff
* yidx
) / yidx_max
;
1920 g2
= g2_min
+ (g2_diff
* yidx
) / yidx_max
;
1921 b2
= b2_min
+ (b2_diff
* yidx
) / yidx_max
;
1922 r2_inv
= r2_min
+ (r2_diff
* (yidx_max
-yidx
)) / yidx_max
;
1923 g2_inv
= g2_min
+ (g2_diff
* (yidx_max
-yidx
)) / yidx_max
;
1924 b2_inv
= b2_min
+ (b2_diff
* (yidx_max
-yidx
)) / yidx_max
;
1926 dest
= (char *)bg_data
+ row
*bg_rowbytes
;
1927 for (i
= 0; i
< rpng2_info
.width
; ++i
) {
1928 even_odd_horiz
= (int)((i
/ bgscale
) & 1);
1929 even_odd
= even_odd_vert
^ even_odd_horiz
;
1931 (even_odd_horiz
&& (bg
[pat
].type
& 0x10));
1932 if (even_odd
== 0) { /* gradient #1 */
1933 if (invert_column
) {
1942 } else { /* gradient #2 */
1943 if ((invert_column
&& invert_gradient2
) ||
1944 (!invert_column
&& !invert_gradient2
))
1946 *dest
++ = r2
; /* not inverted or */
1947 *dest
++ = g2
; /* doubly inverted */
1951 *dest
++ = g2_inv
; /* singly inverted */
1958 /*---------------------------------------------------------------------------
1959 Soft gradient-diamonds with scale = bgscale. Code contributed by Adam
1961 ---------------------------------------------------------------------------*/
1963 } else if ((bg
[pat
].type
& 0x07) == 1) {
1965 hmax
= (bgscale
-1)/2; /* half the max weight of a color */
1966 max
= 2*hmax
; /* the max weight of a color */
1968 r1
= rgb
[bg
[pat
].rgb1_max
].r
;
1969 g1
= rgb
[bg
[pat
].rgb1_max
].g
;
1970 b1
= rgb
[bg
[pat
].rgb1_max
].b
;
1971 r2
= rgb
[bg
[pat
].rgb2_max
].r
;
1972 g2
= rgb
[bg
[pat
].rgb2_max
].g
;
1973 b2
= rgb
[bg
[pat
].rgb2_max
].b
;
1975 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
1976 yidx
= (int)(row
% bgscale
);
1978 yidx
= bgscale
-1 - yidx
;
1979 dest
= (char *)bg_data
+ row
*bg_rowbytes
;
1980 for (i
= 0; i
< rpng2_info
.width
; ++i
) {
1981 xidx
= (int)(i
% bgscale
);
1983 xidx
= bgscale
-1 - xidx
;
1985 *dest
++ = (k
*r1
+ (max
-k
)*r2
) / max
;
1986 *dest
++ = (k
*g1
+ (max
-k
)*g2
) / max
;
1987 *dest
++ = (k
*b1
+ (max
-k
)*b2
) / max
;
1991 /*---------------------------------------------------------------------------
1992 Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
1993 soids will equal bgscale?]. This one is slow but very cool. Code con-
1994 tributed by Pieter S. van der Meulen (originally in Smalltalk).
1995 ---------------------------------------------------------------------------*/
1997 } else if ((bg
[pat
].type
& 0x07) == 2) {
1999 int ii
, x
, y
, hw
, hh
, grayspot
;
2000 double freq
, rotate
, saturate
, gray
, intensity
;
2001 double angle
=0.0, aoffset
=0.0, maxDist
, dist
;
2002 double red
=0.0, green
=0.0, blue
=0.0, hue
, s
, v
, f
, p
, q
, t
;
2004 hh
= (int)(rpng2_info
.height
/ 2);
2005 hw
= (int)(rpng2_info
.width
/ 2);
2007 /* variables for radial waves:
2008 * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED]
2009 * freq: number of color beams originating from the center
2010 * grayspot: size of the graying center area (anti-alias)
2011 * rotate: rotation of the beams as a function of radius
2012 * saturate: saturation of beams' shape azimuthally
2014 angle
= CLIP(angle
, 0.0, 360.0);
2015 grayspot
= CLIP(bg
[pat
].bg_gray
, 1, (hh
+ hw
));
2016 freq
= MAX((double)bg
[pat
].bg_freq
, 0.0);
2017 saturate
= (double)bg
[pat
].bg_bsat
* 0.1;
2018 rotate
= (double)bg
[pat
].bg_brot
* 0.1;
2021 maxDist
= (double)((hw
*hw
) + (hh
*hh
));
2023 for (row
= 0; row
< rpng2_info
.height
; ++row
) {
2024 y
= (int)(row
- hh
);
2025 dest
= (char *)bg_data
+ row
*bg_rowbytes
;
2026 for (i
= 0; i
< rpng2_info
.width
; ++i
) {
2028 angle
= (x
== 0)? PI_2
: atan((double)y
/ (double)x
);
2029 gray
= (double)MAX(ABS(y
), ABS(x
)) / grayspot
;
2030 gray
= MIN(1.0, gray
);
2031 dist
= (double)((x
*x
) + (y
*y
)) / maxDist
;
2032 intensity
= cos((angle
+(rotate
*dist
*PI
)) * freq
) *
2034 intensity
= (MAX(MIN(intensity
,1.0),-1.0) + 1.0) * 0.5;
2035 hue
= (angle
+ PI
) * INV_PI_360
+ aoffset
;
2036 s
= gray
* ((double)(ABS(x
)+ABS(y
)) / (double)(hw
+ hh
));
2037 s
= MIN(MAX(s
,0.0), 1.0);
2038 v
= MIN(MAX(intensity
,0.0), 1.0);
2041 ch
= (uch
)(v
* 255.0);
2046 if ((hue
< 0.0) || (hue
>= 360.0))
2047 hue
-= (((int)(hue
/ 360.0)) * 360.0);
2050 f
= hue
- (double)ii
;
2052 q
= (1.0 - (s
* f
)) * v
;
2053 t
= (1.0 - (s
* (1.0 - f
))) * v
;
2054 if (ii
== 0) { red
= v
; green
= t
; blue
= p
; }
2055 else if (ii
== 1) { red
= q
; green
= v
; blue
= p
; }
2056 else if (ii
== 2) { red
= p
; green
= v
; blue
= t
; }
2057 else if (ii
== 3) { red
= p
; green
= q
; blue
= v
; }
2058 else if (ii
== 4) { red
= t
; green
= p
; blue
= v
; }
2059 else if (ii
== 5) { red
= v
; green
= p
; blue
= q
; }
2060 *dest
++ = (uch
)(red
* 255.0);
2061 *dest
++ = (uch
)(green
* 255.0);
2062 *dest
++ = (uch
)(blue
* 255.0);
2068 } /* end function rpng2_x_reload_bg_image() */
2074 static int is_number(char *p
)
2084 #endif /* FEATURE_LOOP */
2090 static void rpng2_x_cleanup(void)
2092 if (bg_image
&& bg_data
) {
2097 if (rpng2_info
.image_data
) {
2098 free(rpng2_info
.image_data
);
2099 rpng2_info
.image_data
= NULL
;
2102 if (rpng2_info
.row_pointers
) {
2103 free(rpng2_info
.row_pointers
);
2104 rpng2_info
.row_pointers
= NULL
;
2109 free(ximage
->data
); /* we allocated it, so we free it */
2110 ximage
->data
= (char *)NULL
; /* instead of XDestroyImage() */
2112 XDestroyImage(ximage
);
2117 XFreeGC(display
, gc
);
2120 XDestroyWindow(display
, window
);
2123 XFreeColormap(display
, colormap
);
2125 if (have_nondefault_visual
)
2133 static int rpng2_x_msb(ulg u32val
)
2137 for (i
= 31; i
>= 0; --i
) {
2138 if (u32val
& 0x80000000L
)