source: rtems-graphics-toolkit/libpng-1.5.11/contrib/gregbook/rpng-x.c @ 248419a

Last change on this file since 248419a was 248419a, checked in by Sebastian Huber <sebastian.huber@…>, on 07/12/12 at 07:28:02

Update libpng from 1.2.41 to 1.5.11

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