Improve single-threaded operation. It's now safe(r?) to close a canvas while it...
[synfig.git] / gtkmm-osx / trunk / libpng-1.2.5 / contrib / gregbook / rpng-x.c
1 /*---------------------------------------------------------------------------
2
3    rpng - simple PNG display program                               rpng-x.c
4
5    This program decodes and displays PNG images, with gamma correction and
6    optionally with a user-specified background color (in case the image has
7    transparency).  It is very nearly the most basic PNG viewer possible.
8    This version is for the X Window System (tested by author under Unix and
9    by Martin Zinser under OpenVMS; may work under OS/2 with some tweaking).
10
11    to do:
12     - 8-bit support
13     - use %.1023s to simplify truncation of title-bar string?
14
15   ---------------------------------------------------------------------------
16
17    Changelog:
18     - 1.01:  initial public release
19     - 1.02:  modified to allow abbreviated options; fixed long/ulong mis-
20               match; switched to png_jmpbuf() macro
21     - 1.10:  added support for non-default visuals; fixed X pixel-conversion
22     - 1.11:  added extra set of parentheses to png_jmpbuf() macro; fixed
23               command-line parsing bug
24     - 1.12:  fixed small X memory leak (thanks to Francois Petitjean)
25     - 1.13:  fixed XFreeGC() crash bug
26
27   ---------------------------------------------------------------------------
28
29       Copyright (c) 1998-2001 Greg Roelofs.  All rights reserved.
30
31       This software is provided "as is," without warranty of any kind,
32       express or implied.  In no event shall the author or contributors
33       be held liable for any damages arising in any way from the use of
34       this software.
35
36       Permission is granted to anyone to use this software for any purpose,
37       including commercial applications, and to alter it and redistribute
38       it freely, subject to the following restrictions:
39
40       1. Redistributions of source code must retain the above copyright
41          notice, disclaimer, and this list of conditions.
42       2. Redistributions in binary form must reproduce the above copyright
43          notice, disclaimer, and this list of conditions in the documenta-
44          tion and/or other materials provided with the distribution.
45       3. All advertising materials mentioning features or use of this
46          software must display the following acknowledgment:
47
48             This product includes software developed by Greg Roelofs
49             and contributors for the book, "PNG: The Definitive Guide,"
50             published by O'Reilly and Associates.
51
52   ---------------------------------------------------------------------------*/
53
54 #define PROGNAME  "rpng-x"
55 #define LONGNAME  "Simple PNG Viewer for X"
56 #define VERSION   "1.13 of 16 August 2001"
57
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <time.h>
62 #include <X11/Xlib.h>
63 #include <X11/Xutil.h>
64 #include <X11/Xos.h>
65 #include <X11/keysym.h>
66
67 /* #define DEBUG  :  this enables the Trace() macros */
68
69 #include "readpng.h"   /* typedefs, common macros, readpng prototypes */
70
71
72 /* could just include png.h, but this macro is the only thing we need
73  * (name and typedefs changed to local versions); note that side effects
74  * only happen with alpha (which could easily be avoided with
75  * "ush acopy = (alpha);") */
76
77 #define alpha_composite(composite, fg, alpha, bg) {               \
78     ush temp = ((ush)(fg)*(ush)(alpha) +                          \
79                 (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128);  \
80     (composite) = (uch)((temp + (temp >> 8)) >> 8);               \
81 }
82
83
84 /* local prototypes */
85 static int  rpng_x_create_window(void);
86 static int  rpng_x_display_image(void);
87 static void rpng_x_cleanup(void);
88 static int  rpng_x_msb(ulg u32val);
89
90
91 static char titlebar[1024], *window_name = titlebar;
92 static char *appname = LONGNAME;
93 static char *icon_name = PROGNAME;
94 static char *filename;
95 static FILE *infile;
96
97 static char *bgstr;
98 static uch bg_red=0, bg_green=0, bg_blue=0;
99
100 static double display_exponent;
101
102 static ulg image_width, image_height, image_rowbytes;
103 static int image_channels;
104 static uch *image_data;
105
106 /* X-specific variables */
107 static char *displayname;
108 static XImage *ximage;
109 static Display *display;
110 static int depth;
111 static Visual *visual;
112 static XVisualInfo *visual_list;
113 static int RShift, GShift, BShift;
114 static ulg RMask, GMask, BMask;
115 static Window window;
116 static GC gc;
117 static Colormap colormap;
118
119 static int have_nondefault_visual = FALSE;
120 static int have_colormap = FALSE;
121 static int have_window = FALSE;
122 static int have_gc = FALSE;
123 /*
124 ulg numcolors=0, pixels[256];
125 ush reds[256], greens[256], blues[256];
126  */
127
128
129
130
131 int main(int argc, char **argv)
132 {
133 #ifdef sgi
134     char tmpline[80];
135 #endif
136     char *p;
137     int rc, alen, flen;
138     int error = 0;
139     int have_bg = FALSE;
140     double LUT_exponent;               /* just the lookup table */
141     double CRT_exponent = 2.2;         /* just the monitor */
142     double default_display_exponent;   /* whole display system */
143     XEvent e;
144     KeySym k;
145
146
147     displayname = (char *)NULL;
148     filename = (char *)NULL;
149
150
151     /* First set the default value for our display-system exponent, i.e.,
152      * the product of the CRT exponent and the exponent corresponding to
153      * the frame-buffer's lookup table (LUT), if any.  This is not an
154      * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
155      * ones), but it should cover 99% of the current possibilities. */
156
157 #if defined(NeXT)
158     LUT_exponent = 1.0 / 2.2;
159     /*
160     if (some_next_function_that_returns_gamma(&next_gamma))
161         LUT_exponent = 1.0 / next_gamma;
162      */
163 #elif defined(sgi)
164     LUT_exponent = 1.0 / 1.7;
165     /* there doesn't seem to be any documented function to get the
166      * "gamma" value, so we do it the hard way */
167     infile = fopen("/etc/config/system.glGammaVal", "r");
168     if (infile) {
169         double sgi_gamma;
170
171         fgets(tmpline, 80, infile);
172         fclose(infile);
173         sgi_gamma = atof(tmpline);
174         if (sgi_gamma > 0.0)
175             LUT_exponent = 1.0 / sgi_gamma;
176     }
177 #elif defined(Macintosh)
178     LUT_exponent = 1.8 / 2.61;
179     /*
180     if (some_mac_function_that_returns_gamma(&mac_gamma))
181         LUT_exponent = mac_gamma / 2.61;
182      */
183 #else
184     LUT_exponent = 1.0;   /* assume no LUT:  most PCs */
185 #endif
186
187     /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
188     default_display_exponent = LUT_exponent * CRT_exponent;
189
190
191     /* If the user has set the SCREEN_GAMMA environment variable as suggested
192      * (somewhat imprecisely) in the libpng documentation, use that; otherwise
193      * use the default value we just calculated.  Either way, the user may
194      * override this via a command-line option. */
195
196     if ((p = getenv("SCREEN_GAMMA")) != NULL)
197         display_exponent = atof(p);
198     else
199         display_exponent = default_display_exponent;
200
201
202     /* Now parse the command line for options and the PNG filename. */
203
204     while (*++argv && !error) {
205         if (!strncmp(*argv, "-display", 2)) {
206             if (!*++argv)
207                 ++error;
208             else
209                 displayname = *argv;
210         } else if (!strncmp(*argv, "-gamma", 2)) {
211             if (!*++argv)
212                 ++error;
213             else {
214                 display_exponent = atof(*argv);
215                 if (display_exponent <= 0.0)
216                     ++error;
217             }
218         } else if (!strncmp(*argv, "-bgcolor", 2)) {
219             if (!*++argv)
220                 ++error;
221             else {
222                 bgstr = *argv;
223                 if (strlen(bgstr) != 7 || bgstr[0] != '#')
224                     ++error; 
225                 else 
226                     have_bg = TRUE;
227             }
228         } else {
229             if (**argv != '-') {
230                 filename = *argv;
231                 if (argv[1])   /* shouldn't be any more args after filename */
232                     ++error;
233             } else
234                 ++error;   /* not expecting any other options */
235         }
236     }
237
238     if (!filename) {
239         ++error;
240     } else if (!(infile = fopen(filename, "rb"))) {
241         fprintf(stderr, PROGNAME ":  can't open PNG file [%s]\n", filename);
242         ++error;
243     } else {
244         if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) {
245             switch (rc) {
246                 case 1:
247                     fprintf(stderr, PROGNAME
248                       ":  [%s] is not a PNG file: incorrect signature\n",
249                       filename);
250                     break;
251                 case 2:
252                     fprintf(stderr, PROGNAME
253                       ":  [%s] has bad IHDR (libpng longjmp)\n",
254                       filename);
255                     break;
256                 case 4:
257                     fprintf(stderr, PROGNAME ":  insufficient memory\n");
258                     break;
259                 default:
260                     fprintf(stderr, PROGNAME
261                       ":  unknown readpng_init() error\n");
262                     break;
263             }
264             ++error;
265         } else {
266             display = XOpenDisplay(displayname);
267             if (!display) {
268                 readpng_cleanup(TRUE);
269                 fprintf(stderr, PROGNAME ":  can't open X display [%s]\n",
270                   displayname? displayname : "default");
271                 ++error;
272             }
273         }
274         if (error)
275             fclose(infile);
276     }
277
278
279     /* usage screen */
280
281     if (error) {
282         fprintf(stderr, "\n%s %s:  %s\n", PROGNAME, VERSION, appname);
283         readpng_version_info();
284         fprintf(stderr, "\n"
285           "Usage:  %s [-display xdpy] [-gamma exp] [-bgcolor bg] file.png\n"
286           "    xdpy\tname of the target X display (e.g., ``hostname:0'')\n"
287           "    exp \ttransfer-function exponent (``gamma'') of the display\n"
288           "\t\t  system in floating-point format (e.g., ``%.1f''); equal\n"
289           "\t\t  to the product of the lookup-table exponent (varies)\n"
290           "\t\t  and the CRT exponent (usually 2.2); must be positive\n"
291           "    bg  \tdesired background color in 7-character hex RGB format\n"
292           "\t\t  (e.g., ``#ff7700'' for orange:  same as HTML colors);\n"
293           "\t\t  used with transparent images\n"
294           "\nPress Q, Esc or mouse button 1 (within image window, after image\n"
295           "is displayed) to quit.\n"
296           "\n", PROGNAME, default_display_exponent);
297         exit(1);
298     }
299
300
301     /* set the title-bar string, but make sure buffer doesn't overflow */
302
303     alen = strlen(appname);
304     flen = strlen(filename);
305     if (alen + flen + 3 > 1023)
306         sprintf(titlebar, "%s:  ...%s", appname, filename+(alen+flen+6-1023));
307     else
308         sprintf(titlebar, "%s:  %s", appname, filename);
309
310
311     /* if the user didn't specify a background color on the command line,
312      * check for one in the PNG file--if not, the initialized values of 0
313      * (black) will be used */
314
315     if (have_bg) {
316         unsigned r, g, b;   /* this approach quiets compiler warnings */
317
318         sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
319         bg_red   = (uch)r;
320         bg_green = (uch)g;
321         bg_blue  = (uch)b;
322     } else if (readpng_get_bgcolor(&bg_red, &bg_green, &bg_blue) > 1) {
323         readpng_cleanup(TRUE);
324         fprintf(stderr, PROGNAME
325           ":  libpng error while checking for background color\n");
326         exit(2);
327     }
328
329
330     /* do the basic X initialization stuff, make the window and fill it
331      * with the background color */
332
333     if (rpng_x_create_window())
334         exit(2);
335
336
337     /* decode the image, all at once */
338
339     Trace((stderr, "calling readpng_get_image()\n"))
340     image_data = readpng_get_image(display_exponent, &image_channels,
341       &image_rowbytes);
342     Trace((stderr, "done with readpng_get_image()\n"))
343
344
345     /* done with PNG file, so clean up to minimize memory usage (but do NOT
346      * nuke image_data!) */
347
348     readpng_cleanup(FALSE);
349     fclose(infile);
350
351     if (!image_data) {
352         fprintf(stderr, PROGNAME ":  unable to decode PNG image\n");
353         exit(3);
354     }
355
356
357     /* display image (composite with background if requested) */
358
359     Trace((stderr, "calling rpng_x_display_image()\n"))
360     if (rpng_x_display_image()) {
361         free(image_data);
362         exit(4);
363     }
364     Trace((stderr, "done with rpng_x_display_image()\n"))
365
366
367     /* wait for the user to tell us when to quit */
368
369     printf(
370       "Done.  Press Q, Esc or mouse button 1 (within image window) to quit.\n");
371     fflush(stdout);
372
373     do
374         XNextEvent(display, &e);
375     while (!(e.type == ButtonPress && e.xbutton.button == Button1) &&
376            !(e.type == KeyPress &&    /*  v--- or 1 for shifted keys */
377              ((k = XLookupKeysym(&e.xkey, 0)) == XK_q || k == XK_Escape) ));
378
379
380     /* OK, we're done:  clean up all image and X resources and go away */
381
382     rpng_x_cleanup();
383
384     return 0;
385 }
386
387
388
389
390
391 static int rpng_x_create_window(void)
392 {
393     uch *xdata;
394     int need_colormap = FALSE;
395     int screen, pad;
396     ulg bg_pixel = 0L;
397     ulg attrmask;
398     Window root;
399     XEvent e;
400     XGCValues gcvalues;
401     XSetWindowAttributes attr;
402     XSizeHints *size_hints;
403     XTextProperty windowName, *pWindowName = &windowName;
404     XTextProperty iconName, *pIconName = &iconName;
405     XVisualInfo visual_info;
406     XWMHints *wm_hints;
407
408
409     screen = DefaultScreen(display);
410     depth = DisplayPlanes(display, screen);
411     root = RootWindow(display, screen);
412
413 #ifdef DEBUG
414     XSynchronize(display, True);
415 #endif
416
417 #if 0
418 /* GRR:  add 8-bit support */
419     if (/* depth != 8 && */ depth != 16 && depth != 24 && depth != 32) {
420         fprintf(stderr,
421           "screen depth %d not supported (only 16-, 24- or 32-bit TrueColor)\n",
422           depth);
423         return 2;
424     }
425
426     XMatchVisualInfo(display, screen, depth,
427       (depth == 8)? PseudoColor : TrueColor, &visual_info);
428     visual = visual_info.visual;
429 #else
430     if (depth != 16 && depth != 24 && depth != 32) {
431         int visuals_matched = 0;
432
433         Trace((stderr, "default depth is %d:  checking other visuals\n",
434           depth))
435
436         /* 24-bit first */
437         visual_info.screen = screen;
438         visual_info.depth = 24;
439         visual_list = XGetVisualInfo(display,
440           VisualScreenMask | VisualDepthMask, &visual_info, &visuals_matched);
441         if (visuals_matched == 0) {
442 /* GRR:  add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */
443             fprintf(stderr, "default screen depth %d not supported, and no"
444               " 24-bit visuals found\n", depth);
445             return 2;
446         }
447         Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n",
448           visuals_matched))
449         visual = visual_list[0].visual;
450         depth = visual_list[0].depth;
451 /*
452         colormap_size = visual_list[0].colormap_size;
453         visual_class = visual->class;
454         visualID = XVisualIDFromVisual(visual);
455  */
456         have_nondefault_visual = TRUE;
457         need_colormap = TRUE;
458     } else {
459         XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info);
460         visual = visual_info.visual;
461     }
462 #endif
463
464     RMask = visual->red_mask;
465     GMask = visual->green_mask;
466     BMask = visual->blue_mask;
467
468 /* GRR:  add/check 8-bit support */
469     if (depth == 8 || need_colormap) {
470         colormap = XCreateColormap(display, root, visual, AllocNone);
471         if (!colormap) {
472             fprintf(stderr, "XCreateColormap() failed\n");
473             return 2;
474         }
475         have_colormap = TRUE;
476     }
477     if (depth == 15 || depth == 16) {
478         RShift = 15 - rpng_x_msb(RMask);    /* these are right-shifts */
479         GShift = 15 - rpng_x_msb(GMask);
480         BShift = 15 - rpng_x_msb(BMask);
481     } else if (depth > 16) {
482 #define NO_24BIT_MASKS
483 #ifdef NO_24BIT_MASKS
484         RShift = rpng_x_msb(RMask) - 7;     /* these are left-shifts */
485         GShift = rpng_x_msb(GMask) - 7;
486         BShift = rpng_x_msb(BMask) - 7;
487 #else
488         RShift = 7 - rpng_x_msb(RMask);     /* these are right-shifts, too */
489         GShift = 7 - rpng_x_msb(GMask);
490         BShift = 7 - rpng_x_msb(BMask);
491 #endif
492     }
493     if (depth >= 15 && (RShift < 0 || GShift < 0 || BShift < 0)) {
494         fprintf(stderr, "rpng internal logic error:  negative X shift(s)!\n");
495         return 2;
496     }
497
498 /*---------------------------------------------------------------------------
499     Finally, create the window.
500   ---------------------------------------------------------------------------*/
501
502     attr.backing_store = Always;
503     attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask;
504     attrmask = CWBackingStore | CWEventMask;
505     if (have_nondefault_visual) {
506         attr.colormap = colormap;
507         attr.background_pixel = 0;
508         attr.border_pixel = 1;
509         attrmask |= CWColormap | CWBackPixel | CWBorderPixel;
510     }
511
512     window = XCreateWindow(display, root, 0, 0, image_width, image_height, 0,
513       depth, InputOutput, visual, attrmask, &attr);
514
515     if (window == None) {
516         fprintf(stderr, "XCreateWindow() failed\n");
517         return 2;
518     } else
519         have_window = TRUE;
520
521     if (depth == 8)
522         XSetWindowColormap(display, window, colormap);
523
524     if (!XStringListToTextProperty(&window_name, 1, pWindowName))
525         pWindowName = NULL;
526     if (!XStringListToTextProperty(&icon_name, 1, pIconName))
527         pIconName = NULL;
528
529     /* OK if either hints allocation fails; XSetWMProperties() allows NULLs */
530
531     if ((size_hints = XAllocSizeHints()) != NULL) {
532         /* window will not be resizable */
533         size_hints->flags = PMinSize | PMaxSize;
534         size_hints->min_width = size_hints->max_width = (int)image_width;
535         size_hints->min_height = size_hints->max_height = (int)image_height;
536     }
537
538     if ((wm_hints = XAllocWMHints()) != NULL) {
539         wm_hints->initial_state = NormalState;
540         wm_hints->input = True;
541      /* wm_hints->icon_pixmap = icon_pixmap; */
542         wm_hints->flags = StateHint | InputHint  /* | IconPixmapHint */ ;
543     }
544
545     XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0,
546       size_hints, wm_hints, NULL);
547
548     /* various properties and hints no longer needed; free memory */
549     if (pWindowName)
550        XFree(pWindowName->value);
551     if (pIconName)
552        XFree(pIconName->value);
553     if (size_hints)
554         XFree(size_hints);
555     if (wm_hints)
556        XFree(wm_hints);
557
558     XMapWindow(display, window);
559
560     gc = XCreateGC(display, window, 0, &gcvalues);
561     have_gc = TRUE;
562
563 /*---------------------------------------------------------------------------
564     Fill window with the specified background color.
565   ---------------------------------------------------------------------------*/
566
567     if (depth == 24 || depth == 32) {
568         bg_pixel = ((ulg)bg_red   << RShift) |
569                    ((ulg)bg_green << GShift) |
570                    ((ulg)bg_blue  << BShift);
571     } else if (depth == 16) {
572         bg_pixel = ((((ulg)bg_red   << 8) >> RShift) & RMask) |
573                    ((((ulg)bg_green << 8) >> GShift) & GMask) |
574                    ((((ulg)bg_blue  << 8) >> BShift) & BMask);
575     } else /* depth == 8 */ {
576
577         /* GRR:  add 8-bit support */
578
579     }
580
581     XSetForeground(display, gc, bg_pixel);
582     XFillRectangle(display, window, gc, 0, 0, image_width, image_height);
583
584 /*---------------------------------------------------------------------------
585     Wait for first Expose event to do any drawing, then flush.
586   ---------------------------------------------------------------------------*/
587
588     do
589         XNextEvent(display, &e);
590     while (e.type != Expose || e.xexpose.count);
591
592     XFlush(display);
593
594 /*---------------------------------------------------------------------------
595     Allocate memory for the X- and display-specific version of the image.
596   ---------------------------------------------------------------------------*/
597
598     if (depth == 24 || depth == 32) {
599         xdata = (uch *)malloc(4*image_width*image_height);
600         pad = 32;
601     } else if (depth == 16) {
602         xdata = (uch *)malloc(2*image_width*image_height);
603         pad = 16;
604     } else /* depth == 8 */ {
605         xdata = (uch *)malloc(image_width*image_height);
606         pad = 8;
607     }
608
609     if (!xdata) {
610         fprintf(stderr, PROGNAME ":  unable to allocate image memory\n");
611         return 4;
612     }
613
614     ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
615       (char *)xdata, image_width, image_height, pad, 0);
616
617     if (!ximage) {
618         fprintf(stderr, PROGNAME ":  XCreateImage() failed\n");
619         free(xdata);
620         return 3;
621     }
622
623     /* to avoid testing the byte order every pixel (or doubling the size of
624      * the drawing routine with a giant if-test), we arbitrarily set the byte
625      * order to MSBFirst and let Xlib worry about inverting things on little-
626      * endian machines (like Linux/x86, old VAXen, etc.)--this is not the most
627      * efficient approach (the giant if-test would be better), but in the
628      * interest of clarity, we take the easy way out... */
629
630     ximage->byte_order = MSBFirst;
631
632     return 0;
633
634 } /* end function rpng_x_create_window() */
635
636
637
638
639
640 static int rpng_x_display_image(void)
641 {
642     uch *src;
643     char *dest;
644     uch r, g, b, a;
645     ulg i, row, lastrow = 0;
646     ulg pixel;
647     int ximage_rowbytes = ximage->bytes_per_line;
648 /*  int bpp = ximage->bits_per_pixel;  */
649
650
651     Trace((stderr, "beginning display loop (image_channels == %d)\n",
652       image_channels))
653     Trace((stderr, "   (width = %ld, rowbytes = %ld, ximage_rowbytes = %d)\n",
654       image_width, image_rowbytes, ximage_rowbytes))
655     Trace((stderr, "   (bpp = %d)\n", ximage->bits_per_pixel))
656     Trace((stderr, "   (byte_order = %s)\n", ximage->byte_order == MSBFirst?
657       "MSBFirst" : (ximage->byte_order == LSBFirst? "LSBFirst" : "unknown")))
658
659     if (depth == 24 || depth == 32) {
660         ulg red, green, blue;
661
662         for (lastrow = row = 0;  row < image_height;  ++row) {
663             src = image_data + row*image_rowbytes;
664             dest = ximage->data + row*ximage_rowbytes;
665             if (image_channels == 3) {
666                 for (i = image_width;  i > 0;  --i) {
667                     red   = *src++;
668                     green = *src++;
669                     blue  = *src++;
670 #ifdef NO_24BIT_MASKS
671                     pixel = (red   << RShift) |
672                             (green << GShift) |
673                             (blue  << BShift);
674                     /* recall that we set ximage->byte_order = MSBFirst above */
675                     /* GRR BUG:  this assumes bpp == 32, but may be 24: */
676                     *dest++ = (char)((pixel >> 24) & 0xff);
677                     *dest++ = (char)((pixel >> 16) & 0xff);
678                     *dest++ = (char)((pixel >>  8) & 0xff);
679                     *dest++ = (char)( pixel        & 0xff);
680 #else
681                     red   = (RShift < 0)? red   << (-RShift) : red   >> RShift;
682                     green = (GShift < 0)? green << (-GShift) : green >> GShift;
683                     blue  = (BShift < 0)? blue  << (-BShift) : blue  >> BShift;
684                     pixel = (red & RMask) | (green & GMask) | (blue & BMask);
685                     /* recall that we set ximage->byte_order = MSBFirst above */
686                     *dest++ = (char)((pixel >> 24) & 0xff);
687                     *dest++ = (char)((pixel >> 16) & 0xff);
688                     *dest++ = (char)((pixel >>  8) & 0xff);
689                     *dest++ = (char)( pixel        & 0xff);
690 #endif
691                 }
692             } else /* if (image_channels == 4) */ {
693                 for (i = image_width;  i > 0;  --i) {
694                     r = *src++;
695                     g = *src++;
696                     b = *src++;
697                     a = *src++;
698                     if (a == 255) {
699                         red   = r;
700                         green = g;
701                         blue  = b;
702                     } else if (a == 0) {
703                         red   = bg_red;
704                         green = bg_green;
705                         blue  = bg_blue;
706                     } else {
707                         /* this macro (from png.h) composites the foreground
708                          * and background values and puts the result into the
709                          * first argument */
710                         alpha_composite(red,   r, a, bg_red);
711                         alpha_composite(green, g, a, bg_green);
712                         alpha_composite(blue,  b, a, bg_blue);
713                     }
714                     pixel = (red   << RShift) |
715                             (green << GShift) |
716                             (blue  << BShift);
717                     /* recall that we set ximage->byte_order = MSBFirst above */
718                     *dest++ = (char)((pixel >> 24) & 0xff);
719                     *dest++ = (char)((pixel >> 16) & 0xff);
720                     *dest++ = (char)((pixel >>  8) & 0xff);
721                     *dest++ = (char)( pixel        & 0xff);
722                 }
723             }
724             /* display after every 16 lines */
725             if (((row+1) & 0xf) == 0) {
726                 XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
727                   (int)lastrow, image_width, 16);
728                 XFlush(display);
729                 lastrow = row + 1;
730             }
731         }
732
733     } else if (depth == 16) {
734         ush red, green, blue;
735
736         for (lastrow = row = 0;  row < image_height;  ++row) {
737             src = image_data + row*image_rowbytes;
738             dest = ximage->data + row*ximage_rowbytes;
739             if (image_channels == 3) {
740                 for (i = image_width;  i > 0;  --i) {
741                     red   = ((ush)(*src) << 8);
742                     ++src;
743                     green = ((ush)(*src) << 8);
744                     ++src;
745                     blue  = ((ush)(*src) << 8);
746                     ++src;
747                     pixel = ((red   >> RShift) & RMask) |
748                             ((green >> GShift) & GMask) |
749                             ((blue  >> BShift) & BMask);
750                     /* recall that we set ximage->byte_order = MSBFirst above */
751                     *dest++ = (char)((pixel >>  8) & 0xff);
752                     *dest++ = (char)( pixel        & 0xff);
753                 }
754             } else /* if (image_channels == 4) */ {
755                 for (i = image_width;  i > 0;  --i) {
756                     r = *src++;
757                     g = *src++;
758                     b = *src++;
759                     a = *src++;
760                     if (a == 255) {
761                         red   = ((ush)r << 8);
762                         green = ((ush)g << 8);
763                         blue  = ((ush)b << 8);
764                     } else if (a == 0) {
765                         red   = ((ush)bg_red   << 8);
766                         green = ((ush)bg_green << 8);
767                         blue  = ((ush)bg_blue  << 8);
768                     } else {
769                         /* this macro (from png.h) composites the foreground
770                          * and background values and puts the result back into
771                          * the first argument (== fg byte here:  safe) */
772                         alpha_composite(r, r, a, bg_red);
773                         alpha_composite(g, g, a, bg_green);
774                         alpha_composite(b, b, a, bg_blue);
775                         red   = ((ush)r << 8);
776                         green = ((ush)g << 8);
777                         blue  = ((ush)b << 8);
778                     }
779                     pixel = ((red   >> RShift) & RMask) |
780                             ((green >> GShift) & GMask) |
781                             ((blue  >> BShift) & BMask);
782                     /* recall that we set ximage->byte_order = MSBFirst above */
783                     *dest++ = (char)((pixel >>  8) & 0xff);
784                     *dest++ = (char)( pixel        & 0xff);
785                 }
786             }
787             /* display after every 16 lines */
788             if (((row+1) & 0xf) == 0) {
789                 XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
790                   (int)lastrow, image_width, 16);
791                 XFlush(display);
792                 lastrow = row + 1;
793             }
794         }
795
796     } else /* depth == 8 */ {
797
798         /* GRR:  add 8-bit support */
799
800     }
801
802     Trace((stderr, "calling final XPutImage()\n"))
803     if (lastrow < image_height) {
804         XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
805           (int)lastrow, image_width, image_height-lastrow);
806         XFlush(display);
807     }
808
809     return 0;
810 }
811
812
813
814
815 static void rpng_x_cleanup(void)
816 {
817     if (image_data) {
818         free(image_data);
819         image_data = NULL;
820     }
821
822     if (ximage) {
823         if (ximage->data) {
824             free(ximage->data);           /* we allocated it, so we free it */
825             ximage->data = (char *)NULL;  /*  instead of XDestroyImage() */
826         }
827         XDestroyImage(ximage);
828         ximage = NULL;
829     }
830
831     if (have_gc)
832         XFreeGC(display, gc);
833
834     if (have_window)
835         XDestroyWindow(display, window);
836
837     if (have_colormap)
838         XFreeColormap(display, colormap);
839
840     if (have_nondefault_visual)
841         XFree(visual_list);
842 }
843
844
845
846
847
848 static int rpng_x_msb(ulg u32val)
849 {
850     int i;
851
852     for (i = 31;  i >= 0;  --i) {
853         if (u32val & 0x80000000L)
854             break;
855         u32val <<= 1;
856     }
857     return i;
858 }