OSDN Git Service

・#26997 DTXViewer023 のソースコード一式を追加。変更点は以下の通り。
[dtxmania/dtxmania.git] / @libpngソリューション / lpng157 / contrib / gregbook / rpng-x.c
1 /*---------------------------------------------------------------------------\r
2 \r
3    rpng - simple PNG display program                               rpng-x.c\r
4 \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
10 \r
11    to do:\r
12     - 8-bit (colormapped) X support\r
13     - use %.1023s to simplify truncation of title-bar string?\r
14 \r
15   ---------------------------------------------------------------------------\r
16 \r
17    Changelog:\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
29 \r
30   ---------------------------------------------------------------------------\r
31 \r
32       Copyright (c) 1998-2008 Greg Roelofs.  All rights reserved.\r
33 \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
37       this software.\r
38 \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
42 \r
43 \r
44       LICENSE 1 ("BSD-like with advertising clause"):\r
45 \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
49 \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
57 \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
61 \r
62 \r
63       LICENSE 2 (GNU GPL v2 or later):\r
64 \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
69 \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
74 \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
78 \r
79   ---------------------------------------------------------------------------*/\r
80 \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
86 \r
87 #include <stdio.h>\r
88 #include <stdlib.h>\r
89 #include <string.h>\r
90 #include <time.h>\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
95 \r
96 /* #define DEBUG  :  this enables the Trace() macros */\r
97 \r
98 #include "readpng.h"   /* typedefs, common macros, readpng prototypes */\r
99 \r
100 \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
105 \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
110 }\r
111 \r
112 \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
118 \r
119 \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
127 \r
128 static char *bgstr;\r
129 static uch bg_red=0, bg_green=0, bg_blue=0;\r
130 \r
131 static double display_exponent;\r
132 \r
133 static ulg image_width, image_height, image_rowbytes;\r
134 static int image_channels;\r
135 static uch *image_data;\r
136 \r
137 /* X-specific variables */\r
138 static char *displayname;\r
139 static XImage *ximage;\r
140 static Display *display;\r
141 static int depth;\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
147 static GC gc;\r
148 static Colormap colormap;\r
149 \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
154 /*\r
155 ulg numcolors=0, pixels[256];\r
156 ush reds[256], greens[256], blues[256];\r
157  */\r
158 \r
159 \r
160 \r
161 \r
162 int main(int argc, char **argv)\r
163 {\r
164 #ifdef sgi\r
165     char tmpline[80];\r
166 #endif\r
167     char *p;\r
168     int rc, alen, flen;\r
169     int error = 0;\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
174     XEvent e;\r
175     KeySym k;\r
176 \r
177 \r
178     displayname = (char *)NULL;\r
179     filename = (char *)NULL;\r
180 \r
181 \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
187 \r
188 #if defined(NeXT)\r
189     LUT_exponent = 1.0 / 2.2;\r
190     /*\r
191     if (some_next_function_that_returns_gamma(&next_gamma))\r
192         LUT_exponent = 1.0 / next_gamma;\r
193      */\r
194 #elif defined(sgi)\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
199     if (infile) {\r
200         double sgi_gamma;\r
201 \r
202         fgets(tmpline, 80, infile);\r
203         fclose(infile);\r
204         sgi_gamma = atof(tmpline);\r
205         if (sgi_gamma > 0.0)\r
206             LUT_exponent = 1.0 / sgi_gamma;\r
207     }\r
208 #elif defined(Macintosh)\r
209     LUT_exponent = 1.8 / 2.61;\r
210     /*\r
211     if (some_mac_function_that_returns_gamma(&mac_gamma))\r
212         LUT_exponent = mac_gamma / 2.61;\r
213      */\r
214 #else\r
215     LUT_exponent = 1.0;   /* assume no LUT:  most PCs */\r
216 #endif\r
217 \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
220 \r
221 \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
226 \r
227     if ((p = getenv("SCREEN_GAMMA")) != NULL)\r
228         display_exponent = atof(p);\r
229     else\r
230         display_exponent = default_display_exponent;\r
231 \r
232 \r
233     /* Now parse the command line for options and the PNG filename. */\r
234 \r
235     while (*++argv && !error) {\r
236         if (!strncmp(*argv, "-display", 2)) {\r
237             if (!*++argv)\r
238                 ++error;\r
239             else\r
240                 displayname = *argv;\r
241         } else if (!strncmp(*argv, "-gamma", 2)) {\r
242             if (!*++argv)\r
243                 ++error;\r
244             else {\r
245                 display_exponent = atof(*argv);\r
246                 if (display_exponent <= 0.0)\r
247                     ++error;\r
248             }\r
249         } else if (!strncmp(*argv, "-bgcolor", 2)) {\r
250             if (!*++argv)\r
251                 ++error;\r
252             else {\r
253                 bgstr = *argv;\r
254                 if (strlen(bgstr) != 7 || bgstr[0] != '#')\r
255                     ++error;\r
256                 else\r
257                     have_bg = TRUE;\r
258             }\r
259         } else {\r
260             if (**argv != '-') {\r
261                 filename = *argv;\r
262                 if (argv[1])   /* shouldn't be any more args after filename */\r
263                     ++error;\r
264             } else\r
265                 ++error;   /* not expecting any other options */\r
266         }\r
267     }\r
268 \r
269     if (!filename)\r
270         ++error;\r
271 \r
272 \r
273     /* print usage screen if any errors up to this point */\r
274 \r
275     if (error) {\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
291         exit(1);\r
292     }\r
293 \r
294 \r
295     if (!(infile = fopen(filename, "rb"))) {\r
296         fprintf(stderr, PROGNAME ":  can't open PNG file [%s]\n", filename);\r
297         ++error;\r
298     } else {\r
299         if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) {\r
300             switch (rc) {\r
301                 case 1:\r
302                     fprintf(stderr, PROGNAME\r
303                       ":  [%s] is not a PNG file: incorrect signature\n",\r
304                       filename);\r
305                     break;\r
306                 case 2:\r
307                     fprintf(stderr, PROGNAME\r
308                       ":  [%s] has bad IHDR (libpng longjmp)\n", filename);\r
309                     break;\r
310                 case 4:\r
311                     fprintf(stderr, PROGNAME ":  insufficient memory\n");\r
312                     break;\r
313                 default:\r
314                     fprintf(stderr, PROGNAME\r
315                       ":  unknown readpng_init() error\n");\r
316                     break;\r
317             }\r
318             ++error;\r
319         } else {\r
320             display = XOpenDisplay(displayname);\r
321             if (!display) {\r
322                 readpng_cleanup(TRUE);\r
323                 fprintf(stderr, PROGNAME ":  can't open X display [%s]\n",\r
324                   displayname? displayname : "default");\r
325                 ++error;\r
326             }\r
327         }\r
328         if (error)\r
329             fclose(infile);\r
330     }\r
331 \r
332 \r
333     if (error) {\r
334         fprintf(stderr, PROGNAME ":  aborting.\n");\r
335         exit(2);\r
336     }\r
337 \r
338 \r
339     /* set the title-bar string, but make sure buffer doesn't overflow */\r
340 \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
345     else\r
346         sprintf(titlebar, "%s:  %s", appname, filename);\r
347 \r
348 \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
352 \r
353     if (have_bg) {\r
354         unsigned r, g, b;   /* this approach quiets compiler warnings */\r
355 \r
356         sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);\r
357         bg_red   = (uch)r;\r
358         bg_green = (uch)g;\r
359         bg_blue  = (uch)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
364         exit(2);\r
365     }\r
366 \r
367 \r
368     /* do the basic X initialization stuff, make the window and fill it\r
369      * with the background color */\r
370 \r
371     if (rpng_x_create_window())\r
372         exit(2);\r
373 \r
374 \r
375     /* decode the image, all at once */\r
376 \r
377     Trace((stderr, "calling readpng_get_image()\n"))\r
378     image_data = readpng_get_image(display_exponent, &image_channels,\r
379       &image_rowbytes);\r
380     Trace((stderr, "done with readpng_get_image()\n"))\r
381 \r
382 \r
383     /* done with PNG file, so clean up to minimize memory usage (but do NOT\r
384      * nuke image_data!) */\r
385 \r
386     readpng_cleanup(FALSE);\r
387     fclose(infile);\r
388 \r
389     if (!image_data) {\r
390         fprintf(stderr, PROGNAME ":  unable to decode PNG image\n");\r
391         exit(3);\r
392     }\r
393 \r
394 \r
395     /* display image (composite with background if requested) */\r
396 \r
397     Trace((stderr, "calling rpng_x_display_image()\n"))\r
398     if (rpng_x_display_image()) {\r
399         free(image_data);\r
400         exit(4);\r
401     }\r
402     Trace((stderr, "done with rpng_x_display_image()\n"))\r
403 \r
404 \r
405     /* wait for the user to tell us when to quit */\r
406 \r
407     printf(\r
408       "Done.  Press Q, Esc or mouse button 1 (within image window) to quit.\n");\r
409     fflush(stdout);\r
410 \r
411     do\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
416 \r
417 \r
418     /* OK, we're done:  clean up all image and X resources and go away */\r
419 \r
420     rpng_x_cleanup();\r
421 \r
422     return 0;\r
423 }\r
424 \r
425 \r
426 \r
427 \r
428 \r
429 static int rpng_x_create_window(void)\r
430 {\r
431     uch *xdata;\r
432     int need_colormap = FALSE;\r
433     int screen, pad;\r
434     ulg bg_pixel = 0L;\r
435     ulg attrmask;\r
436     Window root;\r
437     XEvent e;\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
446 \r
447 \r
448     screen = DefaultScreen(display);\r
449     depth = DisplayPlanes(display, screen);\r
450     root = RootWindow(display, screen);\r
451 \r
452 #ifdef DEBUG\r
453     XSynchronize(display, True);\r
454 #endif\r
455 \r
456 #if 0\r
457 /* GRR:  add 8-bit support */\r
458     if (/* depth != 8 && */ depth != 16 && depth != 24 && depth != 32) {\r
459         fprintf(stderr,\r
460           "screen depth %d not supported (only 16-, 24- or 32-bit TrueColor)\n",\r
461           depth);\r
462         return 2;\r
463     }\r
464 \r
465     XMatchVisualInfo(display, screen, depth,\r
466       (depth == 8)? PseudoColor : TrueColor, &visual_info);\r
467     visual = visual_info.visual;\r
468 #else\r
469     if (depth != 16 && depth != 24 && depth != 32) {\r
470         int visuals_matched = 0;\r
471 \r
472         Trace((stderr, "default depth is %d:  checking other visuals\n",\r
473           depth))\r
474 \r
475         /* 24-bit first */\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
484             return 2;\r
485         }\r
486         Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n",\r
487           visuals_matched))\r
488         visual = visual_list[0].visual;\r
489         depth = visual_list[0].depth;\r
490 /*\r
491         colormap_size = visual_list[0].colormap_size;\r
492         visual_class = visual->class;\r
493         visualID = XVisualIDFromVisual(visual);\r
494  */\r
495         have_nondefault_visual = TRUE;\r
496         need_colormap = TRUE;\r
497     } else {\r
498         XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info);\r
499         visual = visual_info.visual;\r
500     }\r
501 #endif\r
502 \r
503     RMask = visual->red_mask;\r
504     GMask = visual->green_mask;\r
505     BMask = visual->blue_mask;\r
506 \r
507 /* GRR:  add/check 8-bit support */\r
508     if (depth == 8 || need_colormap) {\r
509         colormap = XCreateColormap(display, root, visual, AllocNone);\r
510         if (!colormap) {\r
511             fprintf(stderr, "XCreateColormap() failed\n");\r
512             return 2;\r
513         }\r
514         have_colormap = TRUE;\r
515     }\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
526 #else\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
530 #endif\r
531     }\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
534         return 2;\r
535     }\r
536 \r
537 /*---------------------------------------------------------------------------\r
538     Finally, create the window.\r
539   ---------------------------------------------------------------------------*/\r
540 \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
549     }\r
550 \r
551     window = XCreateWindow(display, root, 0, 0, image_width, image_height, 0,\r
552       depth, InputOutput, visual, attrmask, &attr);\r
553 \r
554     if (window == None) {\r
555         fprintf(stderr, "XCreateWindow() failed\n");\r
556         return 2;\r
557     } else\r
558         have_window = TRUE;\r
559 \r
560     if (depth == 8)\r
561         XSetWindowColormap(display, window, colormap);\r
562 \r
563     if (!XStringListToTextProperty(&window_name, 1, pWindowName))\r
564         pWindowName = NULL;\r
565     if (!XStringListToTextProperty(&icon_name, 1, pIconName))\r
566         pIconName = NULL;\r
567 \r
568     /* OK if any hints allocation fails; XSetWMProperties() allows NULLs */\r
569 \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
575     }\r
576 \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
582     }\r
583 \r
584     if ((class_hints = XAllocClassHint()) != NULL) {\r
585         class_hints->res_name = res_name;\r
586         class_hints->res_class = res_class;\r
587     }\r
588 \r
589     XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0,\r
590       size_hints, wm_hints, class_hints);\r
591 \r
592     /* various properties and hints no longer needed; free memory */\r
593     if (pWindowName)\r
594        XFree(pWindowName->value);\r
595     if (pIconName)\r
596        XFree(pIconName->value);\r
597     if (size_hints)\r
598         XFree(size_hints);\r
599     if (wm_hints)\r
600        XFree(wm_hints);\r
601     if (class_hints)\r
602        XFree(class_hints);\r
603 \r
604     XMapWindow(display, window);\r
605 \r
606     gc = XCreateGC(display, window, 0, &gcvalues);\r
607     have_gc = TRUE;\r
608 \r
609 /*---------------------------------------------------------------------------\r
610     Fill window with the specified background color.\r
611   ---------------------------------------------------------------------------*/\r
612 \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
622 \r
623         /* GRR:  add 8-bit support */\r
624 \r
625     }\r
626 \r
627     XSetForeground(display, gc, bg_pixel);\r
628     XFillRectangle(display, window, gc, 0, 0, image_width, image_height);\r
629 \r
630 /*---------------------------------------------------------------------------\r
631     Wait for first Expose event to do any drawing, then flush.\r
632   ---------------------------------------------------------------------------*/\r
633 \r
634     do\r
635         XNextEvent(display, &e);\r
636     while (e.type != Expose || e.xexpose.count);\r
637 \r
638     XFlush(display);\r
639 \r
640 /*---------------------------------------------------------------------------\r
641     Allocate memory for the X- and display-specific version of the image.\r
642   ---------------------------------------------------------------------------*/\r
643 \r
644     if (depth == 24 || depth == 32) {\r
645         xdata = (uch *)malloc(4*image_width*image_height);\r
646         pad = 32;\r
647     } else if (depth == 16) {\r
648         xdata = (uch *)malloc(2*image_width*image_height);\r
649         pad = 16;\r
650     } else /* depth == 8 */ {\r
651         xdata = (uch *)malloc(image_width*image_height);\r
652         pad = 8;\r
653     }\r
654 \r
655     if (!xdata) {\r
656         fprintf(stderr, PROGNAME ":  unable to allocate image memory\n");\r
657         return 4;\r
658     }\r
659 \r
660     ximage = XCreateImage(display, visual, depth, ZPixmap, 0,\r
661       (char *)xdata, image_width, image_height, pad, 0);\r
662 \r
663     if (!ximage) {\r
664         fprintf(stderr, PROGNAME ":  XCreateImage() failed\n");\r
665         free(xdata);\r
666         return 3;\r
667     }\r
668 \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
675 \r
676     ximage->byte_order = MSBFirst;\r
677 \r
678     return 0;\r
679 \r
680 } /* end function rpng_x_create_window() */\r
681 \r
682 \r
683 \r
684 \r
685 \r
686 static int rpng_x_display_image(void)\r
687 {\r
688     uch *src;\r
689     char *dest;\r
690     uch r, g, b, a;\r
691     ulg i, row, lastrow = 0;\r
692     ulg pixel;\r
693     int ximage_rowbytes = ximage->bytes_per_line;\r
694 /*  int bpp = ximage->bits_per_pixel;  */\r
695 \r
696 \r
697     Trace((stderr, "beginning display loop (image_channels == %d)\n",\r
698       image_channels))\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
704 \r
705     if (depth == 24 || depth == 32) {\r
706         ulg red, green, blue;\r
707 \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
713                     red   = *src++;\r
714                     green = *src++;\r
715                     blue  = *src++;\r
716 #ifdef NO_24BIT_MASKS\r
717                     pixel = (red   << RShift) |\r
718                             (green << GShift) |\r
719                             (blue  << BShift);\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
726 #else\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
736 #endif\r
737                 }\r
738             } else /* if (image_channels == 4) */ {\r
739                 for (i = image_width;  i > 0;  --i) {\r
740                     r = *src++;\r
741                     g = *src++;\r
742                     b = *src++;\r
743                     a = *src++;\r
744                     if (a == 255) {\r
745                         red   = r;\r
746                         green = g;\r
747                         blue  = b;\r
748                     } else if (a == 0) {\r
749                         red   = bg_red;\r
750                         green = bg_green;\r
751                         blue  = bg_blue;\r
752                     } else {\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
759                     }\r
760                     pixel = (red   << RShift) |\r
761                             (green << GShift) |\r
762                             (blue  << BShift);\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
768                 }\r
769             }\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
774                 XFlush(display);\r
775                 lastrow = row + 1;\r
776             }\r
777         }\r
778 \r
779     } else if (depth == 16) {\r
780         ush red, green, blue;\r
781 \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
788                     ++src;\r
789                     green = ((ush)(*src) << 8);\r
790                     ++src;\r
791                     blue  = ((ush)(*src) << 8);\r
792                     ++src;\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
799                 }\r
800             } else /* if (image_channels == 4) */ {\r
801                 for (i = image_width;  i > 0;  --i) {\r
802                     r = *src++;\r
803                     g = *src++;\r
804                     b = *src++;\r
805                     a = *src++;\r
806                     if (a == 255) {\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
814                     } else {\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
824                     }\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
831                 }\r
832             }\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
837                 XFlush(display);\r
838                 lastrow = row + 1;\r
839             }\r
840         }\r
841 \r
842     } else /* depth == 8 */ {\r
843 \r
844         /* GRR:  add 8-bit support */\r
845 \r
846     }\r
847 \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
852         XFlush(display);\r
853     }\r
854 \r
855     return 0;\r
856 }\r
857 \r
858 \r
859 \r
860 \r
861 static void rpng_x_cleanup(void)\r
862 {\r
863     if (image_data) {\r
864         free(image_data);\r
865         image_data = NULL;\r
866     }\r
867 \r
868     if (ximage) {\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
872         }\r
873         XDestroyImage(ximage);\r
874         ximage = NULL;\r
875     }\r
876 \r
877     if (have_gc)\r
878         XFreeGC(display, gc);\r
879 \r
880     if (have_window)\r
881         XDestroyWindow(display, window);\r
882 \r
883     if (have_colormap)\r
884         XFreeColormap(display, colormap);\r
885 \r
886     if (have_nondefault_visual)\r
887         XFree(visual_list);\r
888 }\r
889 \r
890 \r
891 \r
892 \r
893 \r
894 static int rpng_x_msb(ulg u32val)\r
895 {\r
896     int i;\r
897 \r
898     for (i = 31;  i >= 0;  --i) {\r
899         if (u32val & 0x80000000L)\r
900             break;\r
901         u32val <<= 1;\r
902     }\r
903     return i;\r
904 }\r