VirtualBox

source: vbox/trunk/src/libs/libpng-1.2.8/contrib/gregbook/rpng2-x.c@ 11115

Last change on this file since 11115 was 6395, checked in by vboxsync, 17 years ago

export libpng and zlib so Windows and OS/2 build cleanly.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette