~ubuntu-branches/ubuntu/wily/ntop/wily-proposed

« back to all changes in this revision

Viewing changes to gdchart0.94c/gd-1.8.3/libpng-1.0.8/contrib/gregbook/rpng2-x.c

  • Committer: Bazaar Package Importer
  • Author(s): Dennis Schoen
  • Date: 2002-04-12 11:38:47 UTC
  • Revision ID: james.westby@ubuntu.com-20020412113847-4k4yydw0pzybc6g8
Tags: upstream-2.0.0
ImportĀ upstreamĀ versionĀ 2.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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:
 
16
    - 8-bit support
 
17
    - finish resizable checkerboard-gradient (sizes 4-128?)
 
18
    - use %.1023s to simplify truncation of title-bar string?
 
19
 
 
20
  ---------------------------------------------------------------------------
 
21
 
 
22
   Changelog:
 
23
    - 1.01:  initial public release
 
24
    - 1.02:  modified to allow abbreviated options; fixed char/uchar mismatch
 
25
    - 1.10:  added support for non-default visuals; fixed X pixel-conversion
 
26
    - 1.11:  added -usleep option for demos; fixed command-line parsing bug
 
27
    - 1.12:  added -pause option for demos and testing
 
28
 
 
29
  ---------------------------------------------------------------------------
 
30
 
 
31
      Copyright (c) 1998-2000 Greg Roelofs.  All rights reserved.
 
32
 
 
33
      This software is provided "as is," without warranty of any kind,
 
34
      express or implied.  In no event shall the author or contributors
 
35
      be held liable for any damages arising in any way from the use of
 
36
      this software.
 
37
 
 
38
      Permission is granted to anyone to use this software for any purpose,
 
39
      including commercial applications, and to alter it and redistribute
 
40
      it freely, subject to the following restrictions:
 
41
 
 
42
      1. Redistributions of source code must retain the above copyright
 
43
         notice, disclaimer, and this list of conditions.
 
44
      2. Redistributions in binary form must reproduce the above copyright
 
45
         notice, disclaimer, and this list of conditions in the documenta-
 
46
         tion and/or other materials provided with the distribution.
 
47
      3. All advertising materials mentioning features or use of this
 
48
         software must display the following acknowledgment:
 
49
 
 
50
            This product includes software developed by Greg Roelofs
 
51
            and contributors for the book, "PNG: The Definitive Guide,"
 
52
            published by O'Reilly and Associates.
 
53
 
 
54
  ---------------------------------------------------------------------------*/
 
55
 
 
56
#define PROGNAME  "rpng2-x"
 
57
#define LONGNAME  "Progressive PNG Viewer for X"
 
58
#define VERSION   "1.12 of 19 March 2000"
 
59
 
 
60
#include <stdio.h>
 
61
#include <stdlib.h>
 
62
#include <string.h>
 
63
#include <setjmp.h>       /* for jmpbuf declaration in readpng2.h */
 
64
#include <time.h>
 
65
#include <math.h>         /* only for PvdM background code */
 
66
#include <X11/Xlib.h>
 
67
#include <X11/Xutil.h>
 
68
#include <X11/Xos.h>
 
69
#include <X11/keysym.h>   /* defines XK_* macros */
 
70
 
 
71
#ifdef VMS
 
72
#  include <unistd.h>
 
73
#endif
 
74
 
 
75
/* all for PvdM background code: */
 
76
#ifndef PI
 
77
#  define PI             3.141592653589793238
 
78
#endif
 
79
#define PI_2             (PI*0.5)
 
80
#define INV_PI_360       (360.0 / PI)
 
81
#define MAX(a,b)         (a>b?a:b)
 
82
#define MIN(a,b)         (a<b?a:b)
 
83
#define CLIP(a,min,max)  MAX(min,MIN((a),max))
 
84
#define ABS(a)           ((a)<0?-(a):(a))
 
85
#define CLIP8P(c)        MAX(0,(MIN((c),255)))   /* 8-bit pos. integer (uch) */
 
86
#define ROUNDF(f)        ((int)(f + 0.5))
 
87
 
 
88
#define rgb1_max   bg_freq
 
89
#define rgb1_min   bg_gray
 
90
#define rgb2_max   bg_bsat
 
91
#define rgb2_min   bg_brot
 
92
 
 
93
/* #define DEBUG */     /* this enables the Trace() macros */
 
94
 
 
95
#include "readpng2.h"   /* typedefs, common macros, readpng2 prototypes */
 
96
 
 
97
 
 
98
/* could just include png.h, but this macro is the only thing we need
 
99
 * (name and typedefs changed to local versions); note that side effects
 
100
 * only happen with alpha (which could easily be avoided with
 
101
 * "ush acopy = (alpha);") */
 
102
 
 
103
#define alpha_composite(composite, fg, alpha, bg) {               \
 
104
    ush temp = ((ush)(fg)*(ush)(alpha) +                          \
 
105
                (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128);  \
 
106
    (composite) = (uch)((temp + (temp >> 8)) >> 8);               \
 
107
}
 
108
 
 
109
 
 
110
#define INBUFSIZE 4096   /* with pseudo-timing on (1 sec delay/block), this
 
111
                          *  block size corresponds roughly to a download
 
112
                          *  speed 10% faster than theoretical 33.6K maximum
 
113
                          *  (assuming 8 data bits, 1 stop bit and no other
 
114
                          *  overhead) */
 
115
 
 
116
/* local prototypes */
 
117
static void rpng2_x_init(void);
 
118
static int  rpng2_x_create_window(void);
 
119
static int  rpng2_x_load_bg_image(void);
 
120
static void rpng2_x_display_row(ulg row);
 
121
static void rpng2_x_finish_display(void);
 
122
static void rpng2_x_cleanup(void);
 
123
static int  rpng2_x_msb(ulg u32val);
 
124
 
 
125
 
 
126
static char titlebar[1024], *window_name = titlebar;
 
127
static char *appname = LONGNAME;
 
128
static char *icon_name = PROGNAME;
 
129
static char *filename;
 
130
static FILE *infile;
 
131
 
 
132
static mainprog_info rpng2_info;
 
133
 
 
134
static uch inbuf[INBUFSIZE];
 
135
static int incount;
 
136
 
 
137
static int pat = 6;        /* must be less than num_bgpat */
 
138
static int bg_image = 0;
 
139
static int bgscale = 16;
 
140
static ulg bg_rowbytes;
 
141
static uch *bg_data;
 
142
 
 
143
int pause_after_pass = FALSE;
 
144
int demo_timing = FALSE;
 
145
ulg usleep_duration = 0L;
 
146
 
 
147
static struct rgb_color {
 
148
    uch r, g, b;
 
149
} rgb[] = {
 
150
    {  0,   0,   0},    /*  0:  black */
 
151
    {255, 255, 255},    /*  1:  white */
 
152
    {173, 132,  57},    /*  2:  tan */
 
153
    { 64, 132,   0},    /*  3:  medium green */
 
154
    {189, 117,   1},    /*  4:  gold */
 
155
    {253, 249,   1},    /*  5:  yellow */
 
156
    {  0,   0, 255},    /*  6:  blue */
 
157
    {  0,   0, 120},    /*  7:  medium blue */
 
158
    {255,   0, 255},    /*  8:  magenta */
 
159
    { 64,   0,  64},    /*  9:  dark magenta */
 
160
    {255,   0,   0},    /* 10:  red */
 
161
    { 64,   0,   0},    /* 11:  dark red */
 
162
    {255, 127,   0},    /* 12:  orange */
 
163
    {192,  96,   0},    /* 13:  darker orange */
 
164
    { 24,  60,   0},    /* 14:  dark green-yellow */
 
165
    { 85, 125, 200}     /* 15:  ice blue */
 
166
};
 
167
/* not used for now, but should be for error-checking:
 
168
static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color);
 
169
 */
 
170
 
 
171
/*
 
172
    This whole struct is a fairly cheesy way to keep the number of
 
173
    command-line options to a minimum.  The radial-waves background
 
174
    type is a particularly poor fit to the integer elements of the
 
175
    struct...but a few macros and a little fixed-point math will do
 
176
    wonders for ya.
 
177
 
 
178
    type bits:
 
179
       F E D C B A 9 8 7 6 5 4 3 2 1 0
 
180
                             | | | | |
 
181
                             | | +-+-+-- 0 = sharp-edged checkerboard
 
182
                             | |         1 = soft diamonds
 
183
                             | |         2 = radial waves
 
184
                             | |       3-7 = undefined
 
185
                             | +-- gradient #2 inverted?
 
186
                             +-- alternating columns inverted?
 
187
 */
 
188
static struct background_pattern {
 
189
    ush type;
 
190
    int rgb1_max, rgb1_min;     /* or bg_freq, bg_gray */
 
191
    int rgb2_max, rgb2_min;     /* or bg_bsat, bg_brot (both scaled by 10)*/
 
192
} bg[] = {
 
193
    {0+8,   2,0,  1,15},        /* checkered:  tan/black vs. white/ice blue */
 
194
    {0+24,  2,0,  1,0},         /* checkered:  tan/black vs. white/black */
 
195
    {0+8,   4,5,  0,2},         /* checkered:  gold/yellow vs. black/tan */
 
196
    {0+8,   4,5,  0,6},         /* checkered:  gold/yellow vs. black/blue */
 
197
    {0,     7,0,  8,9},         /* checkered:  deep blue/black vs. magenta */
 
198
    {0+8,  13,0,  5,14},        /* checkered:  orange/black vs. yellow */
 
199
    {0+8,  12,0, 10,11},        /* checkered:  orange/black vs. red */
 
200
    {1,     7,0,  8,0},         /* diamonds:  deep blue/black vs. magenta */
 
201
    {1,    12,0, 11,0},         /* diamonds:  orange vs. dark red */
 
202
    {1,    10,0,  7,0},         /* diamonds:  red vs. medium blue */
 
203
    {1,     4,0,  5,0},         /* diamonds:  gold vs. yellow */
 
204
    {1,     3,0,  0,0},         /* diamonds:  medium green vs. black */
 
205
    {2,    16, 100,  20,   0},  /* radial:  ~hard radial color-beams */
 
206
    {2,    18, 100,  10,   2},  /* radial:  soft, curved radial color-beams */
 
207
    {2,    16, 256, 100, 250},  /* radial:  very tight spiral */
 
208
    {2, 10000, 256,  11,   0}   /* radial:  dipole-moire' (almost fractal) */
 
209
};
 
210
static int num_bgpat = sizeof(bg) / sizeof(struct background_pattern);
 
211
 
 
212
 
 
213
/* X-specific variables */
 
214
static char *displayname;
 
215
static XImage *ximage;
 
216
static Display *display;
 
217
static int depth;
 
218
static Visual *visual;
 
219
static XVisualInfo *visual_list;
 
220
static int RShift, GShift, BShift;
 
221
static ulg RMask, GMask, BMask;
 
222
static Window window;
 
223
static GC gc;
 
224
static Colormap colormap;
 
225
 
 
226
static int have_nondefault_visual = FALSE;
 
227
static int have_colormap = FALSE;
 
228
static int have_window = FALSE;
 
229
 
 
230
 
 
231
 
 
232
 
 
233
int main(int argc, char **argv)
 
234
{
 
235
#ifdef sgi
 
236
    char tmpline[80];
 
237
#endif
 
238
    char *p, *bgstr = NULL;
 
239
    int rc, alen, flen;
 
240
    int error = 0;
 
241
    int timing = FALSE;
 
242
    int have_bg = FALSE;
 
243
    double LUT_exponent;                /* just the lookup table */
 
244
    double CRT_exponent = 2.2;          /* just the monitor */
 
245
    double default_display_exponent;    /* whole display system */
 
246
    XEvent e;
 
247
    KeySym k;
 
248
 
 
249
 
 
250
    /* First initialize a few things, just to be sure--memset takes care of
 
251
     * default background color (black), booleans (FALSE), pointers (NULL),
 
252
     * etc. */
 
253
 
 
254
    displayname = (char *)NULL;
 
255
    filename = (char *)NULL;
 
256
    memset(&rpng2_info, 0, sizeof(mainprog_info));
 
257
 
 
258
 
 
259
    /* Set the default value for our display-system exponent, i.e., the
 
260
     * product of the CRT exponent and the exponent corresponding to
 
261
     * the frame-buffer's lookup table (LUT), if any.  This is not an
 
262
     * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
 
263
     * ones), but it should cover 99% of the current possibilities. */
 
264
 
 
265
#if defined(NeXT)
 
266
    /* third-party utilities can modify the default LUT exponent */
 
267
    LUT_exponent = 1.0 / 2.2;
 
268
    /*
 
269
    if (some_next_function_that_returns_gamma(&next_gamma))
 
270
        LUT_exponent = 1.0 / next_gamma;
 
271
     */
 
272
#elif defined(sgi)
 
273
    LUT_exponent = 1.0 / 1.7;
 
274
    /* there doesn't seem to be any documented function to
 
275
     * get the "gamma" value, so we do it the hard way */
 
276
    infile = fopen("/etc/config/system.glGammaVal", "r");
 
277
    if (infile) {
 
278
        double sgi_gamma;
 
279
 
 
280
        fgets(tmpline, 80, infile);
 
281
        fclose(infile);
 
282
        sgi_gamma = atof(tmpline);
 
283
        if (sgi_gamma > 0.0)
 
284
            LUT_exponent = 1.0 / sgi_gamma;
 
285
    }
 
286
#elif defined(Macintosh)
 
287
    LUT_exponent = 1.8 / 2.61;
 
288
    /*
 
289
    if (some_mac_function_that_returns_gamma(&mac_gamma))
 
290
        LUT_exponent = mac_gamma / 2.61;
 
291
     */
 
292
#else
 
293
    LUT_exponent = 1.0;   /* assume no LUT:  most PCs */
 
294
#endif
 
295
 
 
296
    /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
 
297
    default_display_exponent = LUT_exponent * CRT_exponent;
 
298
 
 
299
 
 
300
    /* If the user has set the SCREEN_GAMMA environment variable as suggested
 
301
     * (somewhat imprecisely) in the libpng documentation, use that; otherwise
 
302
     * use the default value we just calculated.  Either way, the user may
 
303
     * override this via a command-line option. */
 
304
 
 
305
    if ((p = getenv("SCREEN_GAMMA")) != NULL)
 
306
        rpng2_info.display_exponent = atof(p);
 
307
    else
 
308
        rpng2_info.display_exponent = default_display_exponent;
 
309
 
 
310
 
 
311
    /* Now parse the command line for options and the PNG filename. */
 
312
 
 
313
    while (*++argv && !error) {
 
314
        if (!strncmp(*argv, "-display", 2)) {
 
315
            if (!*++argv)
 
316
                ++error;
 
317
            else
 
318
                displayname = *argv;
 
319
        } else if (!strncmp(*argv, "-gamma", 2)) {
 
320
            if (!*++argv)
 
321
                ++error;
 
322
            else {
 
323
                rpng2_info.display_exponent = atof(*argv);
 
324
                if (rpng2_info.display_exponent <= 0.0)
 
325
                    ++error;
 
326
            }
 
327
        } else if (!strncmp(*argv, "-bgcolor", 4)) {
 
328
            if (!*++argv)
 
329
                ++error;
 
330
            else {
 
331
                bgstr = *argv;
 
332
                if (strlen(bgstr) != 7 || bgstr[0] != '#')
 
333
                    ++error;
 
334
                else {
 
335
                    have_bg = TRUE;
 
336
                    bg_image = FALSE;
 
337
                }
 
338
            }
 
339
        } else if (!strncmp(*argv, "-bgpat", 4)) {
 
340
            if (!*++argv)
 
341
                ++error;
 
342
            else {
 
343
                pat = atoi(*argv) - 1;
 
344
                if (pat < 0 || pat >= num_bgpat)
 
345
                    ++error;
 
346
                else {
 
347
                    bg_image = TRUE;
 
348
                    have_bg = FALSE;
 
349
                }
 
350
            }
 
351
        } else if (!strncmp(*argv, "-usleep", 2)) {
 
352
            if (!*++argv)
 
353
                ++error;
 
354
            else {
 
355
                usleep_duration = (ulg)atol(*argv);
 
356
                demo_timing = TRUE;
 
357
            }
 
358
        } else if (!strncmp(*argv, "-pause", 2)) {
 
359
            pause_after_pass = TRUE;
 
360
        } else if (!strncmp(*argv, "-timing", 2)) {
 
361
            timing = TRUE;
 
362
        } else {
 
363
            if (**argv != '-') {
 
364
                filename = *argv;
 
365
                if (argv[1])   /* shouldn't be any more args after filename */
 
366
                    ++error;
 
367
            } else
 
368
                ++error;   /* not expecting any other options */
 
369
        }
 
370
    }
 
371
 
 
372
    if (!filename) {
 
373
        ++error;
 
374
    } else if (!(infile = fopen(filename, "rb"))) {
 
375
        fprintf(stderr, PROGNAME ":  can't open PNG file [%s]\n", filename);
 
376
        ++error;
 
377
    } else {
 
378
        incount = fread(inbuf, 1, INBUFSIZE, infile);
 
379
        if (incount < 8 || !readpng2_check_sig(inbuf, 8)) {
 
380
            fprintf(stderr, PROGNAME
 
381
              ":  [%s] is not a PNG file: incorrect signature\n",
 
382
              filename);
 
383
            ++error;
 
384
        } else if ((rc = readpng2_init(&rpng2_info)) != 0) {
 
385
            switch (rc) {
 
386
                case 2:
 
387
                    fprintf(stderr, PROGNAME
 
388
                      ":  [%s] has bad IHDR (libpng longjmp)\n",
 
389
                      filename);
 
390
                    break;
 
391
                case 4:
 
392
                    fprintf(stderr, PROGNAME ":  insufficient memory\n");
 
393
                    break;
 
394
                default:
 
395
                    fprintf(stderr, PROGNAME
 
396
                      ":  unknown readpng2_init() error\n");
 
397
                    break;
 
398
            }
 
399
            ++error;
 
400
        } else {
 
401
            display = XOpenDisplay(displayname);
 
402
            if (!display) {
 
403
                readpng2_cleanup(&rpng2_info);
 
404
                fprintf(stderr, PROGNAME ":  can't open X display [%s]\n",
 
405
                  displayname? displayname : "default");
 
406
                ++error;
 
407
            }
 
408
        }
 
409
        if (error)
 
410
            fclose(infile);
 
411
    }
 
412
 
 
413
 
 
414
    /* usage screen */
 
415
 
 
416
    if (error) {
 
417
        fprintf(stderr, "\n%s %s:  %s\n", PROGNAME, VERSION, appname);
 
418
        readpng2_version_info();
 
419
        fprintf(stderr, "\n"
 
420
          "Usage:  %s [-display xdpy] [-gamma exp] [-bgcolor bg | -bgpat pat]\n"
 
421
          "        %*s [-usleep dur | -timing] [-pause] file.png\n\n"
 
422
          "    xdpy\tname of the target X display (e.g., ``hostname:0'')\n"
 
423
          "    exp \ttransfer-function exponent (``gamma'') of the display\n"
 
424
          "\t\t  system in floating-point format (e.g., ``%.1f''); equal\n"
 
425
          "\t\t  to the product of the lookup-table exponent (varies)\n"
 
426
          "\t\t  and the CRT exponent (usually 2.2); must be positive\n"
 
427
          "    bg  \tdesired background color in 7-character hex RGB format\n"
 
428
          "\t\t  (e.g., ``#ff7700'' for orange:  same as HTML colors);\n"
 
429
          "\t\t  used with transparent images; overrides -bgpat\n"
 
430
          "    pat \tdesired background pattern number (1-%d); used with\n"
 
431
          "\t\t  transparent images; overrides -bgcolor\n"
 
432
          "    dur \tduration in microseconds to wait after displaying each\n"
 
433
          "\t\t  row (for demo purposes)\n"
 
434
          "    -timing\tenables delay for every block read, to simulate modem\n"
 
435
          "\t\t  download of image (~36 Kbps)\n"
 
436
          "    -pause\tpauses after displaying each pass until key pressed\n"
 
437
          "\nPress Q, Esc or mouse button 1 (within image window, after image\n"
 
438
          "is displayed) to quit.\n"
 
439
          "\n", PROGNAME, strlen(PROGNAME), " ", default_display_exponent,
 
440
          num_bgpat);
 
441
        exit(1);
 
442
    }
 
443
 
 
444
 
 
445
    /* set the title-bar string, but make sure buffer doesn't overflow */
 
446
 
 
447
    alen = strlen(appname);
 
448
    flen = strlen(filename);
 
449
    if (alen + flen + 3 > 1023)
 
450
        sprintf(titlebar, "%s:  ...%s", appname, filename+(alen+flen+6-1023));
 
451
    else
 
452
        sprintf(titlebar, "%s:  %s", appname, filename);
 
453
 
 
454
 
 
455
    /* set some final rpng2_info variables before entering main data loop */
 
456
 
 
457
    if (have_bg) {
 
458
        unsigned r, g, b;   /* this approach quiets compiler warnings */
 
459
 
 
460
        sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
 
461
        rpng2_info.bg_red   = (uch)r;
 
462
        rpng2_info.bg_green = (uch)g;
 
463
        rpng2_info.bg_blue  = (uch)b;
 
464
    } else
 
465
        rpng2_info.need_bgcolor = TRUE;
 
466
 
 
467
    rpng2_info.done = FALSE;
 
468
    rpng2_info.mainprog_init = rpng2_x_init;
 
469
    rpng2_info.mainprog_display_row = rpng2_x_display_row;
 
470
    rpng2_info.mainprog_finish_display = rpng2_x_finish_display;
 
471
 
 
472
 
 
473
    /* OK, this is the fun part:  call readpng2_decode_data() at the start of
 
474
     * the loop to deal with our first buffer of data (read in above to verify
 
475
     * that the file is a PNG image), then loop through the file and continue
 
476
     * calling the same routine to handle each chunk of data.  It in turn
 
477
     * passes the data to libpng, which will invoke one or more of our call-
 
478
     * backs as decoded data become available.  We optionally call sleep() for
 
479
     * one second per iteration to simulate downloading the image via an analog
 
480
     * modem. */
 
481
 
 
482
    for (;;) {
 
483
        Trace((stderr, "about to call readpng2_decode_data()\n"))
 
484
        if (readpng2_decode_data(&rpng2_info, inbuf, incount))
 
485
            ++error;
 
486
        Trace((stderr, "done with readpng2_decode_data()\n"))
 
487
        if (error || feof(infile) || rpng2_info.done)
 
488
            break;
 
489
        if (timing)
 
490
            sleep(1);
 
491
        incount = fread(inbuf, 1, INBUFSIZE, infile);
 
492
    }
 
493
 
 
494
 
 
495
    /* clean up PNG stuff and report any decoding errors */
 
496
 
 
497
    fclose(infile);
 
498
    Trace((stderr, "about to call readpng2_cleanup()\n"))
 
499
    readpng2_cleanup(&rpng2_info);
 
500
 
 
501
    if (error) {
 
502
        fprintf(stderr, PROGNAME ":  libpng error while decoding PNG image\n");
 
503
        exit(3);
 
504
    }
 
505
 
 
506
 
 
507
    /* wait for the user to tell us when to quit */
 
508
 
 
509
    do
 
510
        XNextEvent(display, &e);
 
511
    while (!(e.type == ButtonPress && e.xbutton.button == Button1) &&
 
512
           !(e.type == KeyPress &&    /*  v--- or 1 for shifted keys */
 
513
             ((k = XLookupKeysym(&e.xkey, 0)) == XK_q || k == XK_Escape) ));
 
514
 
 
515
 
 
516
    /* we're done:  clean up all image and X resources and go away */
 
517
 
 
518
    Trace((stderr, "about to call rpng2_x_cleanup()\n"))
 
519
    rpng2_x_cleanup();
 
520
 
 
521
    return 0;
 
522
}
 
523
 
 
524
 
 
525
 
 
526
 
 
527
 
 
528
/* this function is called by readpng2_info_callback() in readpng2.c, which
 
529
 * in turn is called by libpng after all of the pre-IDAT chunks have been
 
530
 * read and processed--i.e., we now have enough info to finish initializing */
 
531
 
 
532
static void rpng2_x_init(void)
 
533
{
 
534
    ulg i;
 
535
    ulg rowbytes = rpng2_info.rowbytes;
 
536
 
 
537
    Trace((stderr, "beginning rpng2_x_init()\n"))
 
538
    Trace((stderr, "  rowbytes = %ld\n", rpng2_info.rowbytes))
 
539
    Trace((stderr, "  width  = %ld\n", rpng2_info.width))
 
540
    Trace((stderr, "  height = %ld\n", rpng2_info.height))
 
541
 
 
542
    rpng2_info.image_data = (uch *)malloc(rowbytes * rpng2_info.height);
 
543
    if (!rpng2_info.image_data) {
 
544
        readpng2_cleanup(&rpng2_info);
 
545
        return;
 
546
    }
 
547
 
 
548
    rpng2_info.row_pointers = (uch **)malloc(rpng2_info.height * sizeof(uch *));
 
549
    if (!rpng2_info.row_pointers) {
 
550
        free(rpng2_info.image_data);
 
551
        rpng2_info.image_data = NULL;
 
552
        readpng2_cleanup(&rpng2_info);
 
553
        return;
 
554
    }
 
555
 
 
556
    for (i = 0;  i < rpng2_info.height;  ++i)
 
557
        rpng2_info.row_pointers[i] = rpng2_info.image_data + i*rowbytes;
 
558
 
 
559
 
 
560
    /* do the basic X initialization stuff, make the window, and fill it with
 
561
     * the user-specified, file-specified or default background color or
 
562
     * pattern */
 
563
 
 
564
    if (rpng2_x_create_window()) {
 
565
        readpng2_cleanup(&rpng2_info);
 
566
        return;
 
567
    }
 
568
}
 
569
 
 
570
 
 
571
 
 
572
 
 
573
 
 
574
static int rpng2_x_create_window(void)
 
575
{
 
576
    ulg bg_red   = rpng2_info.bg_red;
 
577
    ulg bg_green = rpng2_info.bg_green;
 
578
    ulg bg_blue  = rpng2_info.bg_blue;
 
579
    ulg bg_pixel = 0L;
 
580
    ulg attrmask;
 
581
    int need_colormap = FALSE;
 
582
    int screen, pad;
 
583
    uch *xdata;
 
584
    Window root;
 
585
    XEvent e;
 
586
    XGCValues gcvalues;
 
587
    XSetWindowAttributes attr;
 
588
    XSizeHints *size_hints;
 
589
    XTextProperty windowName, *pWindowName = &windowName;
 
590
    XTextProperty iconName, *pIconName = &iconName;
 
591
    XVisualInfo visual_info;
 
592
    XWMHints *wm_hints;
 
593
 
 
594
 
 
595
    Trace((stderr, "beginning rpng2_x_create_window()\n"))
 
596
 
 
597
    screen = DefaultScreen(display);
 
598
    depth = DisplayPlanes(display, screen);
 
599
    root = RootWindow(display, screen);
 
600
 
 
601
#ifdef DEBUG
 
602
    XSynchronize(display, True);
 
603
#endif
 
604
 
 
605
    if (depth != 16 && depth != 24 && depth != 32) {
 
606
        int visuals_matched = 0;
 
607
 
 
608
        Trace((stderr, "default depth is %d:  checking other visuals\n",
 
609
          depth))
 
610
 
 
611
        /* 24-bit first */
 
612
        visual_info.screen = screen;
 
613
        visual_info.depth = 24;
 
614
        visual_list = XGetVisualInfo(display,
 
615
          VisualScreenMask | VisualDepthMask, &visual_info, &visuals_matched);
 
616
        if (visuals_matched == 0) {
 
617
/* GRR:  add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */
 
618
            fprintf(stderr, "default screen depth %d not supported, and no"
 
619
              " 24-bit visuals found\n", depth);
 
620
            return 2;
 
621
        }
 
622
        Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n",
 
623
          visuals_matched))
 
624
        visual = visual_list[0].visual;
 
625
        depth = visual_list[0].depth;
 
626
/*
 
627
        colormap_size = visual_list[0].colormap_size;
 
628
        visual_class = visual->class;
 
629
        visualID = XVisualIDFromVisual(visual);
 
630
 */
 
631
        have_nondefault_visual = TRUE;
 
632
        need_colormap = TRUE;
 
633
    } else {
 
634
        XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info);
 
635
        visual = visual_info.visual;
 
636
    }
 
637
 
 
638
    RMask = visual->red_mask;
 
639
    GMask = visual->green_mask;
 
640
    BMask = visual->blue_mask;
 
641
 
 
642
/* GRR:  add/check 8-bit support */
 
643
    if (depth == 8 || need_colormap) {
 
644
        colormap = XCreateColormap(display, root, visual, AllocNone);
 
645
        if (!colormap) {
 
646
            fprintf(stderr, "XCreateColormap() failed\n");
 
647
            return 2;
 
648
        }
 
649
        have_colormap = TRUE;
 
650
        if (depth == 8)
 
651
            bg_image = FALSE;   /* gradient just wastes palette entries */
 
652
    }
 
653
    if (depth == 15 || depth == 16) {
 
654
        RShift = 15 - rpng2_x_msb(RMask);    /* these are right-shifts */
 
655
        GShift = 15 - rpng2_x_msb(GMask);
 
656
        BShift = 15 - rpng2_x_msb(BMask);
 
657
    } else if (depth > 16) {
 
658
        RShift = rpng2_x_msb(RMask) - 7;     /* these are left-shifts */
 
659
        GShift = rpng2_x_msb(GMask) - 7;
 
660
        BShift = rpng2_x_msb(BMask) - 7;
 
661
    }
 
662
    if (depth >= 15 && (RShift < 0 || GShift < 0 || BShift < 0)) {
 
663
        fprintf(stderr, "rpng2 internal logic error:  negative X shift(s)!\n");
 
664
        return 2;
 
665
    }
 
666
 
 
667
/*---------------------------------------------------------------------------
 
668
    Finally, create the window.
 
669
  ---------------------------------------------------------------------------*/
 
670
 
 
671
    attr.backing_store = Always;
 
672
    attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask;
 
673
    attrmask = CWBackingStore | CWEventMask;
 
674
    if (have_nondefault_visual) {
 
675
        attr.colormap = colormap;
 
676
        attr.background_pixel = 0;
 
677
        attr.border_pixel = 1;
 
678
        attrmask |= CWColormap | CWBackPixel | CWBorderPixel;
 
679
    }
 
680
 
 
681
    window = XCreateWindow(display, root, 0, 0, rpng2_info.width,
 
682
      rpng2_info.height, 0, depth, InputOutput, visual, attrmask, &attr);
 
683
 
 
684
    if (window == None) {
 
685
        fprintf(stderr, "XCreateWindow() failed\n");
 
686
        return 2;
 
687
    } else
 
688
        have_window = TRUE;
 
689
 
 
690
    if (depth == 8)
 
691
        XSetWindowColormap(display, window, colormap);
 
692
 
 
693
    if (!XStringListToTextProperty(&window_name, 1, pWindowName))
 
694
        pWindowName = NULL;
 
695
    if (!XStringListToTextProperty(&icon_name, 1, pIconName))
 
696
        pIconName = NULL;
 
697
 
 
698
    /* OK if either hints allocation fails; XSetWMProperties() allows NULLs */
 
699
 
 
700
    if ((size_hints = XAllocSizeHints()) != NULL) {
 
701
        /* window will not be resizable */
 
702
        size_hints->flags = PMinSize | PMaxSize;
 
703
        size_hints->min_width = size_hints->max_width = (int)rpng2_info.width;
 
704
        size_hints->min_height = size_hints->max_height =
 
705
          (int)rpng2_info.height;
 
706
    }
 
707
 
 
708
    if ((wm_hints = XAllocWMHints()) != NULL) {
 
709
        wm_hints->initial_state = NormalState;
 
710
        wm_hints->input = True;
 
711
     /* wm_hints->icon_pixmap = icon_pixmap; */
 
712
        wm_hints->flags = StateHint | InputHint  /* | IconPixmapHint */ ;
 
713
    }
 
714
 
 
715
    XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0,
 
716
      size_hints, wm_hints, NULL);
 
717
 
 
718
    XMapWindow(display, window);
 
719
 
 
720
    gc = XCreateGC(display, window, 0, &gcvalues);
 
721
 
 
722
/*---------------------------------------------------------------------------
 
723
    Allocate memory for the X- and display-specific version of the image.
 
724
  ---------------------------------------------------------------------------*/
 
725
 
 
726
    if (depth == 24 || depth == 32) {
 
727
        xdata = (uch *)malloc(4*rpng2_info.width*rpng2_info.height);
 
728
        pad = 32;
 
729
    } else if (depth == 16) {
 
730
        xdata = (uch *)malloc(2*rpng2_info.width*rpng2_info.height);
 
731
        pad = 16;
 
732
    } else /* depth == 8 */ {
 
733
        xdata = (uch *)malloc(rpng2_info.width*rpng2_info.height);
 
734
        pad = 8;
 
735
    }
 
736
 
 
737
    if (!xdata) {
 
738
        fprintf(stderr, PROGNAME ":  unable to allocate image memory\n");
 
739
        return 4;
 
740
    }
 
741
 
 
742
    ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
 
743
      (char *)xdata, rpng2_info.width, rpng2_info.height, pad, 0);
 
744
 
 
745
    if (!ximage) {
 
746
        fprintf(stderr, PROGNAME ":  XCreateImage() failed\n");
 
747
        free(xdata);
 
748
        return 3;
 
749
    }
 
750
 
 
751
    /* to avoid testing the byte order every pixel (or doubling the size of
 
752
     * the drawing routine with a giant if-test), we arbitrarily set the byte
 
753
     * order to MSBFirst and let Xlib worry about inverting things on little-
 
754
     * endian machines (e.g., Linux/x86, old VAXen, etc.)--this is not the
 
755
     * most efficient approach (the giant if-test would be better), but in
 
756
     * the interest of clarity, we'll take the easy way out... */
 
757
 
 
758
    ximage->byte_order = MSBFirst;
 
759
 
 
760
/*---------------------------------------------------------------------------
 
761
    Fill window with the specified background color (default is black) or
 
762
    faked "background image" (but latter is disabled if 8-bit; gradients
 
763
    just waste palette entries).
 
764
  ---------------------------------------------------------------------------*/
 
765
 
 
766
    if (bg_image)
 
767
        rpng2_x_load_bg_image();    /* resets bg_image if fails */
 
768
 
 
769
    if (!bg_image) {
 
770
        if (depth == 24 || depth == 32) {
 
771
            bg_pixel = (bg_red   << RShift) |
 
772
                       (bg_green << GShift) |
 
773
                       (bg_blue  << BShift);
 
774
        } else if (depth == 16) {
 
775
            bg_pixel = (((bg_red   << 8) >> RShift) & RMask) |
 
776
                       (((bg_green << 8) >> GShift) & GMask) |
 
777
                       (((bg_blue  << 8) >> BShift) & BMask);
 
778
        } else /* depth == 8 */ {
 
779
 
 
780
            /* GRR:  add 8-bit support */
 
781
 
 
782
        }
 
783
        XSetForeground(display, gc, bg_pixel);
 
784
        XFillRectangle(display, window, gc, 0, 0, rpng2_info.width,
 
785
          rpng2_info.height);
 
786
    }
 
787
 
 
788
/*---------------------------------------------------------------------------
 
789
    Wait for first Expose event to do any drawing, then flush and return.
 
790
  ---------------------------------------------------------------------------*/
 
791
 
 
792
    do
 
793
        XNextEvent(display, &e);
 
794
    while (e.type != Expose || e.xexpose.count);
 
795
 
 
796
    XFlush(display);
 
797
 
 
798
    return 0;
 
799
 
 
800
} /* end function rpng2_x_create_window() */
 
801
 
 
802
 
 
803
 
 
804
 
 
805
 
 
806
static int rpng2_x_load_bg_image(void)
 
807
{
 
808
    uch *src;
 
809
    char *dest;
 
810
    uch r1, r2, g1, g2, b1, b2;
 
811
    uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv;
 
812
    int k, hmax, max;
 
813
    int xidx, yidx, yidx_max = (bgscale-1);
 
814
    int even_odd_vert, even_odd_horiz, even_odd;
 
815
    int invert_gradient2 = (bg[pat].type & 0x08);
 
816
    int invert_column;
 
817
    int ximage_rowbytes = ximage->bytes_per_line;
 
818
    ulg i, row;
 
819
    ulg pixel;
 
820
 
 
821
/*---------------------------------------------------------------------------
 
822
    Allocate buffer for fake background image to be used with transparent
 
823
    images; if this fails, revert to plain background color.
 
824
  ---------------------------------------------------------------------------*/
 
825
 
 
826
    bg_rowbytes = 3 * rpng2_info.width;
 
827
    bg_data = (uch *)malloc(bg_rowbytes * rpng2_info.height);
 
828
    if (!bg_data) {
 
829
        fprintf(stderr, PROGNAME
 
830
          ":  unable to allocate memory for background image\n");
 
831
        bg_image = 0;
 
832
        return 1;
 
833
    }
 
834
 
 
835
/*---------------------------------------------------------------------------
 
836
    Vertical gradients (ramps) in NxN squares, alternating direction and
 
837
    colors (N == bgscale).
 
838
  ---------------------------------------------------------------------------*/
 
839
 
 
840
    if ((bg[pat].type & 0x07) == 0) {
 
841
        uch r1_min  = rgb[bg[pat].rgb1_min].r;
 
842
        uch g1_min  = rgb[bg[pat].rgb1_min].g;
 
843
        uch b1_min  = rgb[bg[pat].rgb1_min].b;
 
844
        uch r2_min  = rgb[bg[pat].rgb2_min].r;
 
845
        uch g2_min  = rgb[bg[pat].rgb2_min].g;
 
846
        uch b2_min  = rgb[bg[pat].rgb2_min].b;
 
847
        int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min;
 
848
        int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min;
 
849
        int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min;
 
850
        int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min;
 
851
        int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min;
 
852
        int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min;
 
853
 
 
854
        for (row = 0;  row < rpng2_info.height;  ++row) {
 
855
            yidx = (int)(row % bgscale);
 
856
            even_odd_vert = (int)((row / bgscale) & 1);
 
857
 
 
858
            r1 = r1_min + (r1_diff * yidx) / yidx_max;
 
859
            g1 = g1_min + (g1_diff * yidx) / yidx_max;
 
860
            b1 = b1_min + (b1_diff * yidx) / yidx_max;
 
861
            r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max;
 
862
            g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max;
 
863
            b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max;
 
864
 
 
865
            r2 = r2_min + (r2_diff * yidx) / yidx_max;
 
866
            g2 = g2_min + (g2_diff * yidx) / yidx_max;
 
867
            b2 = b2_min + (b2_diff * yidx) / yidx_max;
 
868
            r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max;
 
869
            g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max;
 
870
            b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max;
 
871
 
 
872
            dest = (char *)bg_data + row*bg_rowbytes;
 
873
            for (i = 0;  i < rpng2_info.width;  ++i) {
 
874
                even_odd_horiz = (int)((i / bgscale) & 1);
 
875
                even_odd = even_odd_vert ^ even_odd_horiz;
 
876
                invert_column =
 
877
                  (even_odd_horiz && (bg[pat].type & 0x10));
 
878
                if (even_odd == 0) {        /* gradient #1 */
 
879
                    if (invert_column) {
 
880
                        *dest++ = r1_inv;
 
881
                        *dest++ = g1_inv;
 
882
                        *dest++ = b1_inv;
 
883
                    } else {
 
884
                        *dest++ = r1;
 
885
                        *dest++ = g1;
 
886
                        *dest++ = b1;
 
887
                    }
 
888
                } else {                    /* gradient #2 */
 
889
                    if ((invert_column && invert_gradient2) ||
 
890
                        (!invert_column && !invert_gradient2))
 
891
                    {
 
892
                        *dest++ = r2;       /* not inverted or */
 
893
                        *dest++ = g2;       /*  doubly inverted */
 
894
                        *dest++ = b2;
 
895
                    } else {
 
896
                        *dest++ = r2_inv;
 
897
                        *dest++ = g2_inv;   /* singly inverted */
 
898
                        *dest++ = b2_inv;
 
899
                    }
 
900
                }
 
901
            }
 
902
        }
 
903
 
 
904
/*---------------------------------------------------------------------------
 
905
    Soft gradient-diamonds with scale = bgscale.  Code contributed by Adam
 
906
    M. Costello.
 
907
  ---------------------------------------------------------------------------*/
 
908
 
 
909
    } else if ((bg[pat].type & 0x07) == 1) {
 
910
 
 
911
        hmax = (bgscale-1)/2;   /* half the max weight of a color */
 
912
        max = 2*hmax;           /* the max weight of a color */
 
913
 
 
914
        r1 = rgb[bg[pat].rgb1_max].r;
 
915
        g1 = rgb[bg[pat].rgb1_max].g;
 
916
        b1 = rgb[bg[pat].rgb1_max].b;
 
917
        r2 = rgb[bg[pat].rgb2_max].r;
 
918
        g2 = rgb[bg[pat].rgb2_max].g;
 
919
        b2 = rgb[bg[pat].rgb2_max].b;
 
920
 
 
921
        for (row = 0;  row < rpng2_info.height;  ++row) {
 
922
            yidx = (int)(row % bgscale);
 
923
            if (yidx > hmax)
 
924
                yidx = bgscale-1 - yidx;
 
925
            dest = (char *)bg_data + row*bg_rowbytes;
 
926
            for (i = 0;  i < rpng2_info.width;  ++i) {
 
927
                xidx = (int)(i % bgscale);
 
928
                if (xidx > hmax)
 
929
                    xidx = bgscale-1 - xidx;
 
930
                k = xidx + yidx;
 
931
                *dest++ = (k*r1 + (max-k)*r2) / max;
 
932
                *dest++ = (k*g1 + (max-k)*g2) / max;
 
933
                *dest++ = (k*b1 + (max-k)*b2) / max;
 
934
            }
 
935
        }
 
936
 
 
937
/*---------------------------------------------------------------------------
 
938
    Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
 
939
    soids will equal bgscale?].  This one is slow but very cool.  Code con-
 
940
    tributed by Pieter S. van der Meulen (originally in Smalltalk).
 
941
  ---------------------------------------------------------------------------*/
 
942
 
 
943
    } else if ((bg[pat].type & 0x07) == 2) {
 
944
        uch ch;
 
945
        int ii, x, y, hw, hh, grayspot;
 
946
        double freq, rotate, saturate, gray, intensity;
 
947
        double angle=0.0, aoffset=0.0, maxDist, dist;
 
948
        double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t;
 
949
 
 
950
        fprintf(stderr, "%s:  computing radial background...",
 
951
          PROGNAME);
 
952
        fflush(stderr);
 
953
 
 
954
        hh = (int)(rpng2_info.height / 2);
 
955
        hw = (int)(rpng2_info.width / 2);
 
956
 
 
957
        /* variables for radial waves:
 
958
         *   aoffset:  number of degrees to rotate hue [CURRENTLY NOT USED]
 
959
         *   freq:  number of color beams originating from the center
 
960
         *   grayspot:  size of the graying center area (anti-alias)
 
961
         *   rotate:  rotation of the beams as a function of radius
 
962
         *   saturate:  saturation of beams' shape azimuthally
 
963
         */
 
964
        angle = CLIP(angle, 0.0, 360.0);
 
965
        grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw));
 
966
        freq = MAX((double)bg[pat].bg_freq, 0.0);
 
967
        saturate = (double)bg[pat].bg_bsat * 0.1;
 
968
        rotate = (double)bg[pat].bg_brot * 0.1;
 
969
        gray = 0.0;
 
970
        intensity = 0.0;
 
971
        maxDist = (double)((hw*hw) + (hh*hh));
 
972
 
 
973
        for (row = 0;  row < rpng2_info.height;  ++row) {
 
974
            y = (int)(row - hh);
 
975
            dest = (char *)bg_data + row*bg_rowbytes;
 
976
            for (i = 0;  i < rpng2_info.width;  ++i) {
 
977
                x = (int)(i - hw);
 
978
                angle = (x == 0)? PI_2 : atan((double)y / (double)x);
 
979
                gray = (double)MAX(ABS(y), ABS(x)) / grayspot;
 
980
                gray = MIN(1.0, gray);
 
981
                dist = (double)((x*x) + (y*y)) / maxDist;
 
982
                intensity = cos((angle+(rotate*dist*PI)) * freq) *
 
983
                  gray * saturate;
 
984
                intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5;
 
985
                hue = (angle + PI) * INV_PI_360 + aoffset;
 
986
                s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh));
 
987
                s = MIN(MAX(s,0.0), 1.0);
 
988
                v = MIN(MAX(intensity,0.0), 1.0);
 
989
 
 
990
                if (s == 0.0) {
 
991
                    ch = (uch)(v * 255.0);
 
992
                    *dest++ = ch;
 
993
                    *dest++ = ch;
 
994
                    *dest++ = ch;
 
995
                } else {
 
996
                    if ((hue < 0.0) || (hue >= 360.0))
 
997
                        hue -= (((int)(hue / 360.0)) * 360.0);
 
998
                    hue /= 60.0;
 
999
                    ii = (int)hue;
 
1000
                    f = hue - (double)ii;
 
1001
                    p = (1.0 - s) * v;
 
1002
                    q = (1.0 - (s * f)) * v;
 
1003
                    t = (1.0 - (s * (1.0 - f))) * v;
 
1004
                    if      (ii == 0) { red = v; green = t; blue = p; }
 
1005
                    else if (ii == 1) { red = q; green = v; blue = p; }
 
1006
                    else if (ii == 2) { red = p; green = v; blue = t; }
 
1007
                    else if (ii == 3) { red = p; green = q; blue = v; }
 
1008
                    else if (ii == 4) { red = t; green = p; blue = v; }
 
1009
                    else if (ii == 5) { red = v; green = p; blue = q; }
 
1010
                    *dest++ = (uch)(red * 255.0);
 
1011
                    *dest++ = (uch)(green * 255.0);
 
1012
                    *dest++ = (uch)(blue * 255.0);
 
1013
                }
 
1014
            }
 
1015
        }
 
1016
        fprintf(stderr, "done.\n");
 
1017
        fflush(stderr);
 
1018
    }
 
1019
 
 
1020
/*---------------------------------------------------------------------------
 
1021
    Blast background image to display buffer before beginning PNG decode.
 
1022
  ---------------------------------------------------------------------------*/
 
1023
 
 
1024
    if (depth == 24 || depth == 32) {
 
1025
        ulg red, green, blue;
 
1026
 
 
1027
        for (row = 0;  row < rpng2_info.height;  ++row) {
 
1028
            src = bg_data + row*bg_rowbytes;
 
1029
            dest = ximage->data + row*ximage_rowbytes;
 
1030
            for (i = rpng2_info.width;  i > 0;  --i) {
 
1031
                red   = *src++;
 
1032
                green = *src++;
 
1033
                blue  = *src++;
 
1034
                pixel = (red   << RShift) |
 
1035
                        (green << GShift) |
 
1036
                        (blue  << BShift);
 
1037
                /* recall that we set ximage->byte_order = MSBFirst above */
 
1038
                /* GRR BUG:  this assumes bpp == 32, but may be 24: */
 
1039
                *dest++ = (char)((pixel >> 24) & 0xff);
 
1040
                *dest++ = (char)((pixel >> 16) & 0xff);
 
1041
                *dest++ = (char)((pixel >>  8) & 0xff);
 
1042
                *dest++ = (char)( pixel        & 0xff);
 
1043
            }
 
1044
        }
 
1045
 
 
1046
    } else if (depth == 16) {
 
1047
        ush red, green, blue;
 
1048
 
 
1049
        for (row = 0;  row < rpng2_info.height;  ++row) {
 
1050
            src = bg_data + row*bg_rowbytes;
 
1051
            dest = ximage->data + row*ximage_rowbytes;
 
1052
            for (i = rpng2_info.width;  i > 0;  --i) {
 
1053
                red   = ((ush)(*src) << 8);  ++src;
 
1054
                green = ((ush)(*src) << 8);  ++src;
 
1055
                blue  = ((ush)(*src) << 8);  ++src;
 
1056
                pixel = ((red   >> RShift) & RMask) |
 
1057
                        ((green >> GShift) & GMask) |
 
1058
                        ((blue  >> BShift) & BMask);
 
1059
                /* recall that we set ximage->byte_order = MSBFirst above */
 
1060
                *dest++ = (char)((pixel >>  8) & 0xff);
 
1061
                *dest++ = (char)( pixel        & 0xff);
 
1062
            }
 
1063
        }
 
1064
 
 
1065
    } else /* depth == 8 */ {
 
1066
 
 
1067
        /* GRR:  add 8-bit support */
 
1068
 
 
1069
    }
 
1070
 
 
1071
    XPutImage(display, window, gc, ximage, 0, 0, 0, 0, rpng2_info.width,
 
1072
      rpng2_info.height);
 
1073
 
 
1074
    return 0;
 
1075
 
 
1076
} /* end function rpng2_x_load_bg_image() */
 
1077
 
 
1078
 
 
1079
 
 
1080
 
 
1081
 
 
1082
static void rpng2_x_display_row(ulg row)
 
1083
{
 
1084
    uch bg_red   = rpng2_info.bg_red;
 
1085
    uch bg_green = rpng2_info.bg_green;
 
1086
    uch bg_blue  = rpng2_info.bg_blue;
 
1087
    uch *src, *src2=NULL;
 
1088
    char *dest;
 
1089
    uch r, g, b, a;
 
1090
    int ximage_rowbytes = ximage->bytes_per_line;
 
1091
    ulg i, pixel;
 
1092
    static int rows=0, prevpass=(-1);
 
1093
    static ulg firstrow;
 
1094
 
 
1095
/*---------------------------------------------------------------------------
 
1096
    rows and firstrow simply track how many rows (and which ones) have not
 
1097
    yet been displayed; alternatively, we could call XPutImage() for every
 
1098
    row and not bother with the records-keeping.
 
1099
  ---------------------------------------------------------------------------*/
 
1100
 
 
1101
    Trace((stderr, "beginning rpng2_x_display_row()\n"))
 
1102
 
 
1103
    if (rpng2_info.pass != prevpass) {
 
1104
        if (pause_after_pass && rpng2_info.pass > 0) {
 
1105
            XEvent e;
 
1106
            KeySym k;
 
1107
 
 
1108
            fprintf(stderr,
 
1109
              "%s:  end of pass %d of 7; click in image window to continue\n",
 
1110
              PROGNAME, prevpass + 1);
 
1111
            do
 
1112
                XNextEvent(display, &e);
 
1113
            while (!(e.type == ButtonPress && e.xbutton.button == Button1)
 
1114
                   && !(e.type == KeyPress &&
 
1115
                   ((k = XLookupKeysym(&e.xkey, 0)) == XK_q
 
1116
                    || k == XK_Escape) )) ;
 
1117
        }
 
1118
        fprintf(stderr, "%s:  pass %d of 7\r", PROGNAME, rpng2_info.pass + 1);
 
1119
        fflush(stderr);
 
1120
        prevpass = rpng2_info.pass;
 
1121
    }
 
1122
 
 
1123
    if (rows == 0)
 
1124
        firstrow = row;   /* first row that is not yet displayed */
 
1125
 
 
1126
    ++rows;   /* count of rows received but not yet displayed */
 
1127
 
 
1128
/*---------------------------------------------------------------------------
 
1129
    Aside from the use of the rpng2_info struct, the lack of an outer loop
 
1130
    (over rows) and moving the XPutImage() call outside the "if (depth)"
 
1131
    tests, this routine is identical to rpng_x_display_image() in the non-
 
1132
    progressive version of the program.
 
1133
  ---------------------------------------------------------------------------*/
 
1134
 
 
1135
    if (depth == 24 || depth == 32) {
 
1136
        ulg red, green, blue;
 
1137
 
 
1138
        src = rpng2_info.image_data + row*rpng2_info.rowbytes;
 
1139
        if (bg_image)
 
1140
            src2 = bg_data + row*bg_rowbytes;
 
1141
        dest = ximage->data + row*ximage_rowbytes;
 
1142
        if (rpng2_info.channels == 3) {
 
1143
            for (i = rpng2_info.width;  i > 0;  --i) {
 
1144
                red   = *src++;
 
1145
                green = *src++;
 
1146
                blue  = *src++;
 
1147
                pixel = (red   << RShift) |
 
1148
                        (green << GShift) |
 
1149
                        (blue  << BShift);
 
1150
                /* recall that we set ximage->byte_order = MSBFirst above */
 
1151
                /* GRR BUG:  this assumes bpp == 32, but may be 24: */
 
1152
                *dest++ = (char)((pixel >> 24) & 0xff);
 
1153
                *dest++ = (char)((pixel >> 16) & 0xff);
 
1154
                *dest++ = (char)((pixel >>  8) & 0xff);
 
1155
                *dest++ = (char)( pixel        & 0xff);
 
1156
            }
 
1157
        } else /* if (rpng2_info.channels == 4) */ {
 
1158
            for (i = rpng2_info.width;  i > 0;  --i) {
 
1159
                r = *src++;
 
1160
                g = *src++;
 
1161
                b = *src++;
 
1162
                a = *src++;
 
1163
                if (bg_image) {
 
1164
                    bg_red   = *src2++;
 
1165
                    bg_green = *src2++;
 
1166
                    bg_blue  = *src2++;
 
1167
                }
 
1168
                if (a == 255) {
 
1169
                    red   = r;
 
1170
                    green = g;
 
1171
                    blue  = b;
 
1172
                } else if (a == 0) {
 
1173
                    red   = bg_red;
 
1174
                    green = bg_green;
 
1175
                    blue  = bg_blue;
 
1176
                } else {
 
1177
                    /* this macro (from png.h) composites the foreground
 
1178
                     * and background values and puts the result into the
 
1179
                     * first argument */
 
1180
                    alpha_composite(red,   r, a, bg_red);
 
1181
                    alpha_composite(green, g, a, bg_green);
 
1182
                    alpha_composite(blue,  b, a, bg_blue);
 
1183
                }
 
1184
                pixel = (red   << RShift) |
 
1185
                        (green << GShift) |
 
1186
                        (blue  << BShift);
 
1187
                /* recall that we set ximage->byte_order = MSBFirst above */
 
1188
                /* GRR BUG:  this assumes bpp == 32, but may be 24: */
 
1189
                *dest++ = (char)((pixel >> 24) & 0xff);
 
1190
                *dest++ = (char)((pixel >> 16) & 0xff);
 
1191
                *dest++ = (char)((pixel >>  8) & 0xff);
 
1192
                *dest++ = (char)( pixel        & 0xff);
 
1193
            }
 
1194
        }
 
1195
 
 
1196
    } else if (depth == 16) {
 
1197
        ush red, green, blue;
 
1198
 
 
1199
        src = rpng2_info.row_pointers[row];
 
1200
        if (bg_image)
 
1201
            src2 = bg_data + row*bg_rowbytes;
 
1202
        dest = ximage->data + row*ximage_rowbytes;
 
1203
        if (rpng2_info.channels == 3) {
 
1204
            for (i = rpng2_info.width;  i > 0;  --i) {
 
1205
                red   = ((ush)(*src) << 8);
 
1206
                ++src;
 
1207
                green = ((ush)(*src) << 8);
 
1208
                ++src;
 
1209
                blue  = ((ush)(*src) << 8);
 
1210
                ++src;
 
1211
                pixel = ((red   >> RShift) & RMask) |
 
1212
                        ((green >> GShift) & GMask) |
 
1213
                        ((blue  >> BShift) & BMask);
 
1214
                /* recall that we set ximage->byte_order = MSBFirst above */
 
1215
                *dest++ = (char)((pixel >>  8) & 0xff);
 
1216
                *dest++ = (char)( pixel        & 0xff);
 
1217
            }
 
1218
        } else /* if (rpng2_info.channels == 4) */ {
 
1219
            for (i = rpng2_info.width;  i > 0;  --i) {
 
1220
                r = *src++;
 
1221
                g = *src++;
 
1222
                b = *src++;
 
1223
                a = *src++;
 
1224
                if (bg_image) {
 
1225
                    bg_red   = *src2++;
 
1226
                    bg_green = *src2++;
 
1227
                    bg_blue  = *src2++;
 
1228
                }
 
1229
                if (a == 255) {
 
1230
                    red   = ((ush)r << 8);
 
1231
                    green = ((ush)g << 8);
 
1232
                    blue  = ((ush)b << 8);
 
1233
                } else if (a == 0) {
 
1234
                    red   = ((ush)bg_red   << 8);
 
1235
                    green = ((ush)bg_green << 8);
 
1236
                    blue  = ((ush)bg_blue  << 8);
 
1237
                } else {
 
1238
                    /* this macro (from png.h) composites the foreground
 
1239
                     * and background values and puts the result back into
 
1240
                     * the first argument (== fg byte here:  safe) */
 
1241
                    alpha_composite(r, r, a, bg_red);
 
1242
                    alpha_composite(g, g, a, bg_green);
 
1243
                    alpha_composite(b, b, a, bg_blue);
 
1244
                    red   = ((ush)r << 8);
 
1245
                    green = ((ush)g << 8);
 
1246
                    blue  = ((ush)b << 8);
 
1247
                }
 
1248
                pixel = ((red   >> RShift) & RMask) |
 
1249
                        ((green >> GShift) & GMask) |
 
1250
                        ((blue  >> BShift) & BMask);
 
1251
                /* recall that we set ximage->byte_order = MSBFirst above */
 
1252
                *dest++ = (char)((pixel >>  8) & 0xff);
 
1253
                *dest++ = (char)( pixel        & 0xff);
 
1254
            }
 
1255
        }
 
1256
 
 
1257
    } else /* depth == 8 */ {
 
1258
 
 
1259
        /* GRR:  add 8-bit support */
 
1260
 
 
1261
    }
 
1262
 
 
1263
 
 
1264
/*---------------------------------------------------------------------------
 
1265
    Display after every 16 rows or when on one of last two rows.  (Region
 
1266
    may include previously displayed lines due to interlacing--i.e., not
 
1267
    contiguous.  Also, second-to-last row is final one in interlaced images
 
1268
    with odd number of rows.)  For demos, flush (and delay) after every 16th
 
1269
    row so "sparse" passes don't go twice as fast.
 
1270
  ---------------------------------------------------------------------------*/
 
1271
 
 
1272
    if (demo_timing && (row - firstrow >= 16 || row >= rpng2_info.height-2)) {
 
1273
        XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0,
 
1274
          (int)firstrow, rpng2_info.width, row - firstrow + 1);
 
1275
        XFlush(display);
 
1276
        rows = 0;
 
1277
        usleep(usleep_duration);
 
1278
    } else
 
1279
    if (!demo_timing && ((rows & 0xf) == 0 || row >= rpng2_info.height-2)) {
 
1280
        XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0,
 
1281
          (int)firstrow, rpng2_info.width, row - firstrow + 1);
 
1282
        XFlush(display);
 
1283
        rows = 0;
 
1284
    }
 
1285
 
 
1286
}
 
1287
 
 
1288
 
 
1289
 
 
1290
 
 
1291
 
 
1292
static void rpng2_x_finish_display(void)
 
1293
{
 
1294
    Trace((stderr, "beginning rpng2_x_finish_display()\n"))
 
1295
 
 
1296
    /* last row has already been displayed by rpng2_x_display_row(), so we
 
1297
     * have nothing to do here except set a flag and let the user know that
 
1298
     * the image is done */
 
1299
 
 
1300
    rpng2_info.done = TRUE;
 
1301
    printf(
 
1302
      "Done.  Press Q, Esc or mouse button 1 (within image window) to quit.\n");
 
1303
    fflush(stdout);
 
1304
}
 
1305
 
 
1306
 
 
1307
 
 
1308
 
 
1309
 
 
1310
static void rpng2_x_cleanup(void)
 
1311
{
 
1312
    if (bg_image && bg_data) {
 
1313
        free(bg_data);
 
1314
        bg_data = NULL;
 
1315
    }
 
1316
 
 
1317
    if (rpng2_info.image_data) {
 
1318
        free(rpng2_info.image_data);
 
1319
        rpng2_info.image_data = NULL;
 
1320
    }
 
1321
 
 
1322
    if (rpng2_info.row_pointers) {
 
1323
        free(rpng2_info.row_pointers);
 
1324
        rpng2_info.row_pointers = NULL;
 
1325
    }
 
1326
 
 
1327
    if (ximage) {
 
1328
        if (ximage->data) {
 
1329
            free(ximage->data);           /* we allocated it, so we free it */
 
1330
            ximage->data = (char *)NULL;  /*  instead of XDestroyImage() */
 
1331
        }
 
1332
        XDestroyImage(ximage);
 
1333
        ximage = NULL;
 
1334
    }
 
1335
 
 
1336
    XFreeGC(display, gc);
 
1337
 
 
1338
    if (have_window)
 
1339
        XDestroyWindow(display, window);
 
1340
 
 
1341
    if (have_colormap)
 
1342
        XFreeColormap(display, colormap);
 
1343
 
 
1344
    if (have_nondefault_visual)
 
1345
        XFree(visual_list);
 
1346
}
 
1347
 
 
1348
 
 
1349
 
 
1350
 
 
1351
 
 
1352
static int rpng2_x_msb(ulg u32val)
 
1353
{
 
1354
    int i;
 
1355
 
 
1356
    for (i = 31;  i >= 0;  --i) {
 
1357
        if (u32val & 0x80000000L)
 
1358
            break;
 
1359
        u32val <<= 1;
 
1360
    }
 
1361
    return i;
 
1362
}