Bringing libpng-1.5.10 into the main branch
[AROS.git] / workbench / libs / png / contrib / gregbook / rpng-x.c
blob6d10e1b84ed3cb63a8070017066a317715cbbd50
1 /*---------------------------------------------------------------------------
3 rpng - simple PNG display program rpng-x.c
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).
11 to do:
12 - 8-bit (colormapped) X support
13 - use %.1023s to simplify truncation of title-bar string?
15 ---------------------------------------------------------------------------
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)
30 ---------------------------------------------------------------------------
32 Copyright (c) 1998-2008 Greg Roelofs. All rights reserved.
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.
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):
44 LICENSE 1 ("BSD-like with advertising clause"):
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:
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:
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.
63 LICENSE 2 (GNU GPL v2 or later):
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.
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.
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
79 ---------------------------------------------------------------------------*/
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 */
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>
96 /* #define DEBUG : this enables the Trace() macros */
98 #include "readpng.h" /* typedefs, common macros, readpng prototypes */
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);") */
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); \
113 /* local prototypes */
114 static int rpng_x_create_window(void);
115 static int rpng_x_display_image(void);
116 static void rpng_x_cleanup(void);
117 static int rpng_x_msb(ulg u32val);
120 static char titlebar[1024], *window_name = titlebar;
121 static char *appname = LONGNAME;
122 static char *icon_name = PROGNAME;
123 static char *res_name = RESNAME;
124 static char *res_class = RESCLASS;
125 static char *filename;
126 static FILE *infile;
128 static char *bgstr;
129 static uch bg_red=0, bg_green=0, bg_blue=0;
131 static double display_exponent;
133 static ulg image_width, image_height, image_rowbytes;
134 static int image_channels;
135 static uch *image_data;
137 /* X-specific variables */
138 static char *displayname;
139 static XImage *ximage;
140 static Display *display;
141 static int depth;
142 static Visual *visual;
143 static XVisualInfo *visual_list;
144 static int RShift, GShift, BShift;
145 static ulg RMask, GMask, BMask;
146 static Window window;
147 static GC gc;
148 static Colormap colormap;
150 static int have_nondefault_visual = FALSE;
151 static int have_colormap = FALSE;
152 static int have_window = FALSE;
153 static int have_gc = FALSE;
155 ulg numcolors=0, pixels[256];
156 ush reds[256], greens[256], blues[256];
162 int main(int argc, char **argv)
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;
178 displayname = (char *)NULL;
179 filename = (char *)NULL;
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. */
188 #if defined(NeXT)
189 LUT_exponent = 1.0 / 2.2;
191 if (some_next_function_that_returns_gamma(&next_gamma))
192 LUT_exponent = 1.0 / next_gamma;
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;
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;
208 #elif defined(Macintosh)
209 LUT_exponent = 1.8 / 2.61;
211 if (some_mac_function_that_returns_gamma(&mac_gamma))
212 LUT_exponent = mac_gamma / 2.61;
214 #else
215 LUT_exponent = 1.0; /* assume no LUT: most PCs */
216 #endif
218 /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
219 default_display_exponent = LUT_exponent * CRT_exponent;
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. */
227 if ((p = getenv("SCREEN_GAMMA")) != NULL)
228 display_exponent = atof(p);
229 else
230 display_exponent = default_display_exponent;
233 /* Now parse the command line for options and the PNG filename. */
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;
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;
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 */
269 if (!filename)
270 ++error;
273 /* print usage screen if any errors up to this point */
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);
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;
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;
328 if (error)
329 fclose(infile);
333 if (error) {
334 fprintf(stderr, PROGNAME ": aborting.\n");
335 exit(2);
339 /* set the title-bar string, but make sure buffer doesn't overflow */
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);
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 */
353 if (have_bg) {
354 unsigned r, g, b; /* this approach quiets compiler warnings */
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);
368 /* do the basic X initialization stuff, make the window and fill it
369 * with the background color */
371 if (rpng_x_create_window())
372 exit(2);
375 /* decode the image, all at once */
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"))
383 /* done with PNG file, so clean up to minimize memory usage (but do NOT
384 * nuke image_data!) */
386 readpng_cleanup(FALSE);
387 fclose(infile);
389 if (!image_data) {
390 fprintf(stderr, PROGNAME ": unable to decode PNG image\n");
391 exit(3);
395 /* display image (composite with background if requested) */
397 Trace((stderr, "calling rpng_x_display_image()\n"))
398 if (rpng_x_display_image()) {
399 free(image_data);
400 exit(4);
402 Trace((stderr, "done with rpng_x_display_image()\n"))
405 /* wait for the user to tell us when to quit */
407 printf(
408 "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n");
409 fflush(stdout);
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) ));
418 /* OK, we're done: clean up all image and X resources and go away */
420 rpng_x_cleanup();
422 return 0;
429 static int rpng_x_create_window(void)
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;
448 screen = DefaultScreen(display);
449 depth = DisplayPlanes(display, screen);
450 root = RootWindow(display, screen);
452 #ifdef DEBUG
453 XSynchronize(display, True);
454 #endif
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;
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;
472 Trace((stderr, "default depth is %d: checking other visuals\n",
473 depth))
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;
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;
491 colormap_size = visual_list[0].colormap_size;
492 visual_class = visual->class;
493 visualID = XVisualIDFromVisual(visual);
495 have_nondefault_visual = TRUE;
496 need_colormap = TRUE;
497 } else {
498 XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info);
499 visual = visual_info.visual;
501 #endif
503 RMask = visual->red_mask;
504 GMask = visual->green_mask;
505 BMask = visual->blue_mask;
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;
514 have_colormap = TRUE;
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
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;
537 /*---------------------------------------------------------------------------
538 Finally, create the window.
539 ---------------------------------------------------------------------------*/
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;
551 window = XCreateWindow(display, root, 0, 0, image_width, image_height, 0,
552 depth, InputOutput, visual, attrmask, &attr);
554 if (window == None) {
555 fprintf(stderr, "XCreateWindow() failed\n");
556 return 2;
557 } else
558 have_window = TRUE;
560 if (depth == 8)
561 XSetWindowColormap(display, window, colormap);
563 if (!XStringListToTextProperty(&window_name, 1, pWindowName))
564 pWindowName = NULL;
565 if (!XStringListToTextProperty(&icon_name, 1, pIconName))
566 pIconName = NULL;
568 /* OK if any hints allocation fails; XSetWMProperties() allows NULLs */
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;
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 */ ;
584 if ((class_hints = XAllocClassHint()) != NULL) {
585 class_hints->res_name = res_name;
586 class_hints->res_class = res_class;
589 XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0,
590 size_hints, wm_hints, class_hints);
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);
604 XMapWindow(display, window);
606 gc = XCreateGC(display, window, 0, &gcvalues);
607 have_gc = TRUE;
609 /*---------------------------------------------------------------------------
610 Fill window with the specified background color.
611 ---------------------------------------------------------------------------*/
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 */ {
623 /* GRR: add 8-bit support */
627 XSetForeground(display, gc, bg_pixel);
628 XFillRectangle(display, window, gc, 0, 0, image_width, image_height);
630 /*---------------------------------------------------------------------------
631 Wait for first Expose event to do any drawing, then flush.
632 ---------------------------------------------------------------------------*/
635 XNextEvent(display, &e);
636 while (e.type != Expose || e.xexpose.count);
638 XFlush(display);
640 /*---------------------------------------------------------------------------
641 Allocate memory for the X- and display-specific version of the image.
642 ---------------------------------------------------------------------------*/
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;
655 if (!xdata) {
656 fprintf(stderr, PROGNAME ": unable to allocate image memory\n");
657 return 4;
660 ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
661 (char *)xdata, image_width, image_height, pad, 0);
663 if (!ximage) {
664 fprintf(stderr, PROGNAME ": XCreateImage() failed\n");
665 free(xdata);
666 return 3;
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... */
676 ximage->byte_order = MSBFirst;
678 return 0;
680 } /* end function rpng_x_create_window() */
686 static int rpng_x_display_image(void)
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; */
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")))
705 if (depth == 24 || depth == 32) {
706 ulg red, green, blue;
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
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);
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);
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;
779 } else if (depth == 16) {
780 ush red, green, blue;
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);
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);
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);
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;
842 } else /* depth == 8 */ {
844 /* GRR: add 8-bit support */
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);
855 return 0;
861 static void rpng_x_cleanup(void)
863 if (image_data) {
864 free(image_data);
865 image_data = NULL;
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() */
873 XDestroyImage(ximage);
874 ximage = NULL;
877 if (have_gc)
878 XFreeGC(display, gc);
880 if (have_window)
881 XDestroyWindow(display, window);
883 if (have_colormap)
884 XFreeColormap(display, colormap);
886 if (have_nondefault_visual)
887 XFree(visual_list);
894 static int rpng_x_msb(ulg u32val)
896 int i;
898 for (i = 31; i >= 0; --i) {
899 if (u32val & 0x80000000L)
900 break;
901 u32val <<= 1;
903 return i;