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