all repos — mgba @ 9de8f084ba55460b02d300c1dd8b8e6c56f691d5

mGBA Game Boy Advance Emulator

src/third-party/libpng/contrib/gregbook/rpng-x.c (view raw)

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