1 /*---------------------------------------------------------------------------
\r
3 rpng - simple PNG display program rpng-x.c
\r
5 This program decodes and displays PNG images, with gamma correction and
\r
6 optionally with a user-specified background color (in case the image has
\r
7 transparency). It is very nearly the most basic PNG viewer possible.
\r
8 This version is for the X Window System (tested by author under Unix and
\r
9 by Martin Zinser under OpenVMS; may work under OS/2 with some tweaking).
\r
12 - 8-bit (colormapped) X support
\r
13 - use %.1023s to simplify truncation of title-bar string?
\r
15 ---------------------------------------------------------------------------
\r
18 - 1.01: initial public release
\r
19 - 1.02: modified to allow abbreviated options; fixed long/ulong mis-
\r
20 match; switched to png_jmpbuf() macro
\r
21 - 1.10: added support for non-default visuals; fixed X pixel-conversion
\r
22 - 1.11: added extra set of parentheses to png_jmpbuf() macro; fixed
\r
23 command-line parsing bug
\r
24 - 1.12: fixed some small X memory leaks (thanks to François Petitjean)
\r
25 - 1.13: fixed XFreeGC() crash bug (thanks to Patrick Welche)
\r
26 - 1.14: added support for X resources (thanks to Gerhard Niklasch)
\r
27 - 2.00: dual-licensed (added GNU GPL)
\r
28 - 2.01: fixed improper display of usage screen on PNG error(s)
\r
30 ---------------------------------------------------------------------------
\r
32 Copyright (c) 1998-2008 Greg Roelofs. All rights reserved.
\r
34 This software is provided "as is," without warranty of any kind,
\r
35 express or implied. In no event shall the author or contributors
\r
36 be held liable for any damages arising in any way from the use of
\r
39 The contents of this file are DUAL-LICENSED. You may modify and/or
\r
40 redistribute this software according to the terms of one of the
\r
41 following two licenses (at your option):
\r
44 LICENSE 1 ("BSD-like with advertising clause"):
\r
46 Permission is granted to anyone to use this software for any purpose,
\r
47 including commercial applications, and to alter it and redistribute
\r
48 it freely, subject to the following restrictions:
\r
50 1. Redistributions of source code must retain the above copyright
\r
51 notice, disclaimer, and this list of conditions.
\r
52 2. Redistributions in binary form must reproduce the above copyright
\r
53 notice, disclaimer, and this list of conditions in the documenta-
\r
54 tion and/or other materials provided with the distribution.
\r
55 3. All advertising materials mentioning features or use of this
\r
56 software must display the following acknowledgment:
\r
58 This product includes software developed by Greg Roelofs
\r
59 and contributors for the book, "PNG: The Definitive Guide,"
\r
60 published by O'Reilly and Associates.
\r
63 LICENSE 2 (GNU GPL v2 or later):
\r
65 This program is free software; you can redistribute it and/or modify
\r
66 it under the terms of the GNU General Public License as published by
\r
67 the Free Software Foundation; either version 2 of the License, or
\r
68 (at your option) any later version.
\r
70 This program is distributed in the hope that it will be useful,
\r
71 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
72 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
73 GNU General Public License for more details.
\r
75 You should have received a copy of the GNU General Public License
\r
76 along with this program; if not, write to the Free Software Foundation,
\r
77 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
79 ---------------------------------------------------------------------------*/
\r
81 #define PROGNAME "rpng-x"
\r
82 #define LONGNAME "Simple PNG Viewer for X"
\r
83 #define VERSION "2.01 of 16 March 2008"
\r
84 #define RESNAME "rpng" /* our X resource application name */
\r
85 #define RESCLASS "Rpng" /* our X resource class name */
\r
91 #include <X11/Xlib.h>
\r
92 #include <X11/Xutil.h>
\r
93 #include <X11/Xos.h>
\r
94 #include <X11/keysym.h>
\r
96 /* #define DEBUG : this enables the Trace() macros */
\r
98 #include "readpng.h" /* typedefs, common macros, readpng prototypes */
\r
101 /* could just include png.h, but this macro is the only thing we need
\r
102 * (name and typedefs changed to local versions); note that side effects
\r
103 * only happen with alpha (which could easily be avoided with
\r
104 * "ush acopy = (alpha);") */
\r
106 #define alpha_composite(composite, fg, alpha, bg) { \
\r
107 ush temp = ((ush)(fg)*(ush)(alpha) + \
\r
108 (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \
\r
109 (composite) = (uch)((temp + (temp >> 8)) >> 8); \
\r
113 /* local prototypes */
\r
114 static int rpng_x_create_window(void);
\r
115 static int rpng_x_display_image(void);
\r
116 static void rpng_x_cleanup(void);
\r
117 static int rpng_x_msb(ulg u32val);
\r
120 static char titlebar[1024], *window_name = titlebar;
\r
121 static char *appname = LONGNAME;
\r
122 static char *icon_name = PROGNAME;
\r
123 static char *res_name = RESNAME;
\r
124 static char *res_class = RESCLASS;
\r
125 static char *filename;
\r
126 static FILE *infile;
\r
128 static char *bgstr;
\r
129 static uch bg_red=0, bg_green=0, bg_blue=0;
\r
131 static double display_exponent;
\r
133 static ulg image_width, image_height, image_rowbytes;
\r
134 static int image_channels;
\r
135 static uch *image_data;
\r
137 /* X-specific variables */
\r
138 static char *displayname;
\r
139 static XImage *ximage;
\r
140 static Display *display;
\r
142 static Visual *visual;
\r
143 static XVisualInfo *visual_list;
\r
144 static int RShift, GShift, BShift;
\r
145 static ulg RMask, GMask, BMask;
\r
146 static Window window;
\r
148 static Colormap colormap;
\r
150 static int have_nondefault_visual = FALSE;
\r
151 static int have_colormap = FALSE;
\r
152 static int have_window = FALSE;
\r
153 static int have_gc = FALSE;
\r
155 ulg numcolors=0, pixels[256];
\r
156 ush reds[256], greens[256], blues[256];
\r
162 int main(int argc, char **argv)
\r
168 int rc, alen, flen;
\r
170 int have_bg = FALSE;
\r
171 double LUT_exponent; /* just the lookup table */
\r
172 double CRT_exponent = 2.2; /* just the monitor */
\r
173 double default_display_exponent; /* whole display system */
\r
178 displayname = (char *)NULL;
\r
179 filename = (char *)NULL;
\r
182 /* First set the default value for our display-system exponent, i.e.,
\r
183 * the product of the CRT exponent and the exponent corresponding to
\r
184 * the frame-buffer's lookup table (LUT), if any. This is not an
\r
185 * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
\r
186 * ones), but it should cover 99% of the current possibilities. */
\r
189 LUT_exponent = 1.0 / 2.2;
\r
191 if (some_next_function_that_returns_gamma(&next_gamma))
\r
192 LUT_exponent = 1.0 / next_gamma;
\r
195 LUT_exponent = 1.0 / 1.7;
\r
196 /* there doesn't seem to be any documented function to get the
\r
197 * "gamma" value, so we do it the hard way */
\r
198 infile = fopen("/etc/config/system.glGammaVal", "r");
\r
202 fgets(tmpline, 80, infile);
\r
204 sgi_gamma = atof(tmpline);
\r
205 if (sgi_gamma > 0.0)
\r
206 LUT_exponent = 1.0 / sgi_gamma;
\r
208 #elif defined(Macintosh)
\r
209 LUT_exponent = 1.8 / 2.61;
\r
211 if (some_mac_function_that_returns_gamma(&mac_gamma))
\r
212 LUT_exponent = mac_gamma / 2.61;
\r
215 LUT_exponent = 1.0; /* assume no LUT: most PCs */
\r
218 /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
\r
219 default_display_exponent = LUT_exponent * CRT_exponent;
\r
222 /* If the user has set the SCREEN_GAMMA environment variable as suggested
\r
223 * (somewhat imprecisely) in the libpng documentation, use that; otherwise
\r
224 * use the default value we just calculated. Either way, the user may
\r
225 * override this via a command-line option. */
\r
227 if ((p = getenv("SCREEN_GAMMA")) != NULL)
\r
228 display_exponent = atof(p);
\r
230 display_exponent = default_display_exponent;
\r
233 /* Now parse the command line for options and the PNG filename. */
\r
235 while (*++argv && !error) {
\r
236 if (!strncmp(*argv, "-display", 2)) {
\r
240 displayname = *argv;
\r
241 } else if (!strncmp(*argv, "-gamma", 2)) {
\r
245 display_exponent = atof(*argv);
\r
246 if (display_exponent <= 0.0)
\r
249 } else if (!strncmp(*argv, "-bgcolor", 2)) {
\r
254 if (strlen(bgstr) != 7 || bgstr[0] != '#')
\r
260 if (**argv != '-') {
\r
262 if (argv[1]) /* shouldn't be any more args after filename */
\r
265 ++error; /* not expecting any other options */
\r
273 /* print usage screen if any errors up to this point */
\r
276 fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname);
\r
277 readpng_version_info();
\r
278 fprintf(stderr, "\n"
\r
279 "Usage: %s [-display xdpy] [-gamma exp] [-bgcolor bg] file.png\n"
\r
280 " xdpy\tname of the target X display (e.g., ``hostname:0'')\n"
\r
281 " exp \ttransfer-function exponent (``gamma'') of the display\n"
\r
282 "\t\t system in floating-point format (e.g., ``%.1f''); equal\n"
\r
283 "\t\t to the product of the lookup-table exponent (varies)\n"
\r
284 "\t\t and the CRT exponent (usually 2.2); must be positive\n"
\r
285 " bg \tdesired background color in 7-character hex RGB format\n"
\r
286 "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n"
\r
287 "\t\t used with transparent images\n"
\r
288 "\nPress Q, Esc or mouse button 1 (within image window, after image\n"
\r
289 "is displayed) to quit.\n"
\r
290 "\n", PROGNAME, default_display_exponent);
\r
295 if (!(infile = fopen(filename, "rb"))) {
\r
296 fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename);
\r
299 if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) {
\r
302 fprintf(stderr, PROGNAME
\r
303 ": [%s] is not a PNG file: incorrect signature\n",
\r
307 fprintf(stderr, PROGNAME
\r
308 ": [%s] has bad IHDR (libpng longjmp)\n", filename);
\r
311 fprintf(stderr, PROGNAME ": insufficient memory\n");
\r
314 fprintf(stderr, PROGNAME
\r
315 ": unknown readpng_init() error\n");
\r
320 display = XOpenDisplay(displayname);
\r
322 readpng_cleanup(TRUE);
\r
323 fprintf(stderr, PROGNAME ": can't open X display [%s]\n",
\r
324 displayname? displayname : "default");
\r
334 fprintf(stderr, PROGNAME ": aborting.\n");
\r
339 /* set the title-bar string, but make sure buffer doesn't overflow */
\r
341 alen = strlen(appname);
\r
342 flen = strlen(filename);
\r
343 if (alen + flen + 3 > 1023)
\r
344 sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023));
\r
346 sprintf(titlebar, "%s: %s", appname, filename);
\r
349 /* if the user didn't specify a background color on the command line,
\r
350 * check for one in the PNG file--if not, the initialized values of 0
\r
351 * (black) will be used */
\r
354 unsigned r, g, b; /* this approach quiets compiler warnings */
\r
356 sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
\r
360 } else if (readpng_get_bgcolor(&bg_red, &bg_green, &bg_blue) > 1) {
\r
361 readpng_cleanup(TRUE);
\r
362 fprintf(stderr, PROGNAME
\r
363 ": libpng error while checking for background color\n");
\r
368 /* do the basic X initialization stuff, make the window and fill it
\r
369 * with the background color */
\r
371 if (rpng_x_create_window())
\r
375 /* decode the image, all at once */
\r
377 Trace((stderr, "calling readpng_get_image()\n"))
\r
378 image_data = readpng_get_image(display_exponent, &image_channels,
\r
380 Trace((stderr, "done with readpng_get_image()\n"))
\r
383 /* done with PNG file, so clean up to minimize memory usage (but do NOT
\r
384 * nuke image_data!) */
\r
386 readpng_cleanup(FALSE);
\r
390 fprintf(stderr, PROGNAME ": unable to decode PNG image\n");
\r
395 /* display image (composite with background if requested) */
\r
397 Trace((stderr, "calling rpng_x_display_image()\n"))
\r
398 if (rpng_x_display_image()) {
\r
402 Trace((stderr, "done with rpng_x_display_image()\n"))
\r
405 /* wait for the user to tell us when to quit */
\r
408 "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n");
\r
412 XNextEvent(display, &e);
\r
413 while (!(e.type == ButtonPress && e.xbutton.button == Button1) &&
\r
414 !(e.type == KeyPress && /* v--- or 1 for shifted keys */
\r
415 ((k = XLookupKeysym(&e.xkey, 0)) == XK_q || k == XK_Escape) ));
\r
418 /* OK, we're done: clean up all image and X resources and go away */
\r
429 static int rpng_x_create_window(void)
\r
432 int need_colormap = FALSE;
\r
438 XGCValues gcvalues;
\r
439 XSetWindowAttributes attr;
\r
440 XTextProperty windowName, *pWindowName = &windowName;
\r
441 XTextProperty iconName, *pIconName = &iconName;
\r
442 XVisualInfo visual_info;
\r
443 XSizeHints *size_hints;
\r
444 XWMHints *wm_hints;
\r
445 XClassHint *class_hints;
\r
448 screen = DefaultScreen(display);
\r
449 depth = DisplayPlanes(display, screen);
\r
450 root = RootWindow(display, screen);
\r
453 XSynchronize(display, True);
\r
457 /* GRR: add 8-bit support */
\r
458 if (/* depth != 8 && */ depth != 16 && depth != 24 && depth != 32) {
\r
460 "screen depth %d not supported (only 16-, 24- or 32-bit TrueColor)\n",
\r
465 XMatchVisualInfo(display, screen, depth,
\r
466 (depth == 8)? PseudoColor : TrueColor, &visual_info);
\r
467 visual = visual_info.visual;
\r
469 if (depth != 16 && depth != 24 && depth != 32) {
\r
470 int visuals_matched = 0;
\r
472 Trace((stderr, "default depth is %d: checking other visuals\n",
\r
476 visual_info.screen = screen;
\r
477 visual_info.depth = 24;
\r
478 visual_list = XGetVisualInfo(display,
\r
479 VisualScreenMask | VisualDepthMask, &visual_info, &visuals_matched);
\r
480 if (visuals_matched == 0) {
\r
481 /* GRR: add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */
\r
482 fprintf(stderr, "default screen depth %d not supported, and no"
\r
483 " 24-bit visuals found\n", depth);
\r
486 Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n",
\r
488 visual = visual_list[0].visual;
\r
489 depth = visual_list[0].depth;
\r
491 colormap_size = visual_list[0].colormap_size;
\r
492 visual_class = visual->class;
\r
493 visualID = XVisualIDFromVisual(visual);
\r
495 have_nondefault_visual = TRUE;
\r
496 need_colormap = TRUE;
\r
498 XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info);
\r
499 visual = visual_info.visual;
\r
503 RMask = visual->red_mask;
\r
504 GMask = visual->green_mask;
\r
505 BMask = visual->blue_mask;
\r
507 /* GRR: add/check 8-bit support */
\r
508 if (depth == 8 || need_colormap) {
\r
509 colormap = XCreateColormap(display, root, visual, AllocNone);
\r
511 fprintf(stderr, "XCreateColormap() failed\n");
\r
514 have_colormap = TRUE;
\r
516 if (depth == 15 || depth == 16) {
\r
517 RShift = 15 - rpng_x_msb(RMask); /* these are right-shifts */
\r
518 GShift = 15 - rpng_x_msb(GMask);
\r
519 BShift = 15 - rpng_x_msb(BMask);
\r
520 } else if (depth > 16) {
\r
521 #define NO_24BIT_MASKS
\r
522 #ifdef NO_24BIT_MASKS
\r
523 RShift = rpng_x_msb(RMask) - 7; /* these are left-shifts */
\r
524 GShift = rpng_x_msb(GMask) - 7;
\r
525 BShift = rpng_x_msb(BMask) - 7;
\r
527 RShift = 7 - rpng_x_msb(RMask); /* these are right-shifts, too */
\r
528 GShift = 7 - rpng_x_msb(GMask);
\r
529 BShift = 7 - rpng_x_msb(BMask);
\r
532 if (depth >= 15 && (RShift < 0 || GShift < 0 || BShift < 0)) {
\r
533 fprintf(stderr, "rpng internal logic error: negative X shift(s)!\n");
\r
537 /*---------------------------------------------------------------------------
\r
538 Finally, create the window.
\r
539 ---------------------------------------------------------------------------*/
\r
541 attr.backing_store = Always;
\r
542 attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask;
\r
543 attrmask = CWBackingStore | CWEventMask;
\r
544 if (have_nondefault_visual) {
\r
545 attr.colormap = colormap;
\r
546 attr.background_pixel = 0;
\r
547 attr.border_pixel = 1;
\r
548 attrmask |= CWColormap | CWBackPixel | CWBorderPixel;
\r
551 window = XCreateWindow(display, root, 0, 0, image_width, image_height, 0,
\r
552 depth, InputOutput, visual, attrmask, &attr);
\r
554 if (window == None) {
\r
555 fprintf(stderr, "XCreateWindow() failed\n");
\r
558 have_window = TRUE;
\r
561 XSetWindowColormap(display, window, colormap);
\r
563 if (!XStringListToTextProperty(&window_name, 1, pWindowName))
\r
564 pWindowName = NULL;
\r
565 if (!XStringListToTextProperty(&icon_name, 1, pIconName))
\r
568 /* OK if any hints allocation fails; XSetWMProperties() allows NULLs */
\r
570 if ((size_hints = XAllocSizeHints()) != NULL) {
\r
571 /* window will not be resizable */
\r
572 size_hints->flags = PMinSize | PMaxSize;
\r
573 size_hints->min_width = size_hints->max_width = (int)image_width;
\r
574 size_hints->min_height = size_hints->max_height = (int)image_height;
\r
577 if ((wm_hints = XAllocWMHints()) != NULL) {
\r
578 wm_hints->initial_state = NormalState;
\r
579 wm_hints->input = True;
\r
580 /* wm_hints->icon_pixmap = icon_pixmap; */
\r
581 wm_hints->flags = StateHint | InputHint /* | IconPixmapHint */ ;
\r
584 if ((class_hints = XAllocClassHint()) != NULL) {
\r
585 class_hints->res_name = res_name;
\r
586 class_hints->res_class = res_class;
\r
589 XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0,
\r
590 size_hints, wm_hints, class_hints);
\r
592 /* various properties and hints no longer needed; free memory */
\r
594 XFree(pWindowName->value);
\r
596 XFree(pIconName->value);
\r
602 XFree(class_hints);
\r
604 XMapWindow(display, window);
\r
606 gc = XCreateGC(display, window, 0, &gcvalues);
\r
609 /*---------------------------------------------------------------------------
\r
610 Fill window with the specified background color.
\r
611 ---------------------------------------------------------------------------*/
\r
613 if (depth == 24 || depth == 32) {
\r
614 bg_pixel = ((ulg)bg_red << RShift) |
\r
615 ((ulg)bg_green << GShift) |
\r
616 ((ulg)bg_blue << BShift);
\r
617 } else if (depth == 16) {
\r
618 bg_pixel = ((((ulg)bg_red << 8) >> RShift) & RMask) |
\r
619 ((((ulg)bg_green << 8) >> GShift) & GMask) |
\r
620 ((((ulg)bg_blue << 8) >> BShift) & BMask);
\r
621 } else /* depth == 8 */ {
\r
623 /* GRR: add 8-bit support */
\r
627 XSetForeground(display, gc, bg_pixel);
\r
628 XFillRectangle(display, window, gc, 0, 0, image_width, image_height);
\r
630 /*---------------------------------------------------------------------------
\r
631 Wait for first Expose event to do any drawing, then flush.
\r
632 ---------------------------------------------------------------------------*/
\r
635 XNextEvent(display, &e);
\r
636 while (e.type != Expose || e.xexpose.count);
\r
640 /*---------------------------------------------------------------------------
\r
641 Allocate memory for the X- and display-specific version of the image.
\r
642 ---------------------------------------------------------------------------*/
\r
644 if (depth == 24 || depth == 32) {
\r
645 xdata = (uch *)malloc(4*image_width*image_height);
\r
647 } else if (depth == 16) {
\r
648 xdata = (uch *)malloc(2*image_width*image_height);
\r
650 } else /* depth == 8 */ {
\r
651 xdata = (uch *)malloc(image_width*image_height);
\r
656 fprintf(stderr, PROGNAME ": unable to allocate image memory\n");
\r
660 ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
\r
661 (char *)xdata, image_width, image_height, pad, 0);
\r
664 fprintf(stderr, PROGNAME ": XCreateImage() failed\n");
\r
669 /* to avoid testing the byte order every pixel (or doubling the size of
\r
670 * the drawing routine with a giant if-test), we arbitrarily set the byte
\r
671 * order to MSBFirst and let Xlib worry about inverting things on little-
\r
672 * endian machines (like Linux/x86, old VAXen, etc.)--this is not the most
\r
673 * efficient approach (the giant if-test would be better), but in the
\r
674 * interest of clarity, we take the easy way out... */
\r
676 ximage->byte_order = MSBFirst;
\r
680 } /* end function rpng_x_create_window() */
\r
686 static int rpng_x_display_image(void)
\r
691 ulg i, row, lastrow = 0;
\r
693 int ximage_rowbytes = ximage->bytes_per_line;
\r
694 /* int bpp = ximage->bits_per_pixel; */
\r
697 Trace((stderr, "beginning display loop (image_channels == %d)\n",
\r
699 Trace((stderr, " (width = %ld, rowbytes = %ld, ximage_rowbytes = %d)\n",
\r
700 image_width, image_rowbytes, ximage_rowbytes))
\r
701 Trace((stderr, " (bpp = %d)\n", ximage->bits_per_pixel))
\r
702 Trace((stderr, " (byte_order = %s)\n", ximage->byte_order == MSBFirst?
\r
703 "MSBFirst" : (ximage->byte_order == LSBFirst? "LSBFirst" : "unknown")))
\r
705 if (depth == 24 || depth == 32) {
\r
706 ulg red, green, blue;
\r
708 for (lastrow = row = 0; row < image_height; ++row) {
\r
709 src = image_data + row*image_rowbytes;
\r
710 dest = ximage->data + row*ximage_rowbytes;
\r
711 if (image_channels == 3) {
\r
712 for (i = image_width; i > 0; --i) {
\r
716 #ifdef NO_24BIT_MASKS
\r
717 pixel = (red << RShift) |
\r
718 (green << GShift) |
\r
720 /* recall that we set ximage->byte_order = MSBFirst above */
\r
721 /* GRR BUG: this assumes bpp == 32, but may be 24: */
\r
722 *dest++ = (char)((pixel >> 24) & 0xff);
\r
723 *dest++ = (char)((pixel >> 16) & 0xff);
\r
724 *dest++ = (char)((pixel >> 8) & 0xff);
\r
725 *dest++ = (char)( pixel & 0xff);
\r
727 red = (RShift < 0)? red << (-RShift) : red >> RShift;
\r
728 green = (GShift < 0)? green << (-GShift) : green >> GShift;
\r
729 blue = (BShift < 0)? blue << (-BShift) : blue >> BShift;
\r
730 pixel = (red & RMask) | (green & GMask) | (blue & BMask);
\r
731 /* recall that we set ximage->byte_order = MSBFirst above */
\r
732 *dest++ = (char)((pixel >> 24) & 0xff);
\r
733 *dest++ = (char)((pixel >> 16) & 0xff);
\r
734 *dest++ = (char)((pixel >> 8) & 0xff);
\r
735 *dest++ = (char)( pixel & 0xff);
\r
738 } else /* if (image_channels == 4) */ {
\r
739 for (i = image_width; i > 0; --i) {
\r
748 } else if (a == 0) {
\r
753 /* this macro (from png.h) composites the foreground
\r
754 * and background values and puts the result into the
\r
755 * first argument */
\r
756 alpha_composite(red, r, a, bg_red);
\r
757 alpha_composite(green, g, a, bg_green);
\r
758 alpha_composite(blue, b, a, bg_blue);
\r
760 pixel = (red << RShift) |
\r
761 (green << GShift) |
\r
763 /* recall that we set ximage->byte_order = MSBFirst above */
\r
764 *dest++ = (char)((pixel >> 24) & 0xff);
\r
765 *dest++ = (char)((pixel >> 16) & 0xff);
\r
766 *dest++ = (char)((pixel >> 8) & 0xff);
\r
767 *dest++ = (char)( pixel & 0xff);
\r
770 /* display after every 16 lines */
\r
771 if (((row+1) & 0xf) == 0) {
\r
772 XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
\r
773 (int)lastrow, image_width, 16);
\r
779 } else if (depth == 16) {
\r
780 ush red, green, blue;
\r
782 for (lastrow = row = 0; row < image_height; ++row) {
\r
783 src = image_data + row*image_rowbytes;
\r
784 dest = ximage->data + row*ximage_rowbytes;
\r
785 if (image_channels == 3) {
\r
786 for (i = image_width; i > 0; --i) {
\r
787 red = ((ush)(*src) << 8);
\r
789 green = ((ush)(*src) << 8);
\r
791 blue = ((ush)(*src) << 8);
\r
793 pixel = ((red >> RShift) & RMask) |
\r
794 ((green >> GShift) & GMask) |
\r
795 ((blue >> BShift) & BMask);
\r
796 /* recall that we set ximage->byte_order = MSBFirst above */
\r
797 *dest++ = (char)((pixel >> 8) & 0xff);
\r
798 *dest++ = (char)( pixel & 0xff);
\r
800 } else /* if (image_channels == 4) */ {
\r
801 for (i = image_width; i > 0; --i) {
\r
807 red = ((ush)r << 8);
\r
808 green = ((ush)g << 8);
\r
809 blue = ((ush)b << 8);
\r
810 } else if (a == 0) {
\r
811 red = ((ush)bg_red << 8);
\r
812 green = ((ush)bg_green << 8);
\r
813 blue = ((ush)bg_blue << 8);
\r
815 /* this macro (from png.h) composites the foreground
\r
816 * and background values and puts the result back into
\r
817 * the first argument (== fg byte here: safe) */
\r
818 alpha_composite(r, r, a, bg_red);
\r
819 alpha_composite(g, g, a, bg_green);
\r
820 alpha_composite(b, b, a, bg_blue);
\r
821 red = ((ush)r << 8);
\r
822 green = ((ush)g << 8);
\r
823 blue = ((ush)b << 8);
\r
825 pixel = ((red >> RShift) & RMask) |
\r
826 ((green >> GShift) & GMask) |
\r
827 ((blue >> BShift) & BMask);
\r
828 /* recall that we set ximage->byte_order = MSBFirst above */
\r
829 *dest++ = (char)((pixel >> 8) & 0xff);
\r
830 *dest++ = (char)( pixel & 0xff);
\r
833 /* display after every 16 lines */
\r
834 if (((row+1) & 0xf) == 0) {
\r
835 XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
\r
836 (int)lastrow, image_width, 16);
\r
842 } else /* depth == 8 */ {
\r
844 /* GRR: add 8-bit support */
\r
848 Trace((stderr, "calling final XPutImage()\n"))
\r
849 if (lastrow < image_height) {
\r
850 XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
\r
851 (int)lastrow, image_width, image_height-lastrow);
\r
861 static void rpng_x_cleanup(void)
\r
869 if (ximage->data) {
\r
870 free(ximage->data); /* we allocated it, so we free it */
\r
871 ximage->data = (char *)NULL; /* instead of XDestroyImage() */
\r
873 XDestroyImage(ximage);
\r
878 XFreeGC(display, gc);
\r
881 XDestroyWindow(display, window);
\r
884 XFreeColormap(display, colormap);
\r
886 if (have_nondefault_visual)
\r
887 XFree(visual_list);
\r
894 static int rpng_x_msb(ulg u32val)
\r
898 for (i = 31; i >= 0; --i) {
\r
899 if (u32val & 0x80000000L)
\r