Mercurial > fife-parpg
comparison ext/libpng-1.2.29/contrib/gregbook/rpng-x.c @ 0:4a0efb7baf70
* Datasets becomes the new trunk and retires after that :-)
author | mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Sun, 29 Jun 2008 18:44:17 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4a0efb7baf70 |
---|---|
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 */ | |
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); | |
118 | |
119 | |
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; | |
127 | |
128 static char *bgstr; | |
129 static uch bg_red=0, bg_green=0, bg_blue=0; | |
130 | |
131 static double display_exponent; | |
132 | |
133 static ulg image_width, image_height, image_rowbytes; | |
134 static int image_channels; | |
135 static uch *image_data; | |
136 | |
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; | |
149 | |
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; | |
154 /* | |
155 ulg numcolors=0, pixels[256]; | |
156 ush reds[256], greens[256], blues[256]; | |
157 */ | |
158 | |
159 | |
160 | |
161 | |
162 int 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 | |
429 static 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 | |
686 static 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 | |
861 static 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 | |
894 static 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 } |