xwud.c revision ec318dbf
1/* 2 3Copyright 1985, 1986, 1988, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27*/ 28 29/* xwud - marginally useful raster image undumper */ 30 31#ifdef HAVE_CONFIG_H 32#include "config.h" 33#endif 34 35#include <X11/Xos.h> 36#include <X11/Xlib.h> 37#include <X11/Xutil.h> 38#include <X11/Xatom.h> 39#include <stdio.h> 40#include <X11/XWDFile.h> 41#define XK_LATIN1 42#include <X11/keysymdef.h> 43#include <errno.h> 44#include <stdlib.h> 45 46static Atom wm_protocols; 47static Atom wm_delete_window; 48static int split; 49 50static char *progname; 51 52static Bool Read(char *ptr, int size, int nitems, FILE *stream); 53static void putImage(Display *dpy, Window image_win, GC gc, 54 XImage *out_image, int x, int y, int w, int h); 55static void putScaledImage(Display *display, Drawable d, GC gc, 56 XImage *src_image, int exp_x, int exp_y, 57 unsigned int exp_width, unsigned int exp_height, 58 unsigned int dest_width, unsigned dest_height); 59static void Latin1Upper(char *s); 60static void Extract_Plane(XImage *in_image, XImage *out_image, int plane); 61static int EffectiveSize(XVisualInfo *vinfo); 62static int VisualRank(int class); 63static int IsGray(Display *dpy, XStandardColormap *stdmap); 64static void Do_StdGray(Display *dpy, XStandardColormap *stdmap, int ncolors, 65 XColor *colors, XImage *in_image, XImage *out_image); 66static void Do_StdCol(Display *dpy, XStandardColormap *stdmap, int ncolors, 67 XColor *colors, XImage *in_image, XImage *out_image); 68static Colormap CopyColormapAndFree(Display *dpy, Colormap colormap); 69static void Do_Pseudo(Display *dpy, Colormap *colormap, int ncolors, 70 XColor *colors, XImage *in_image, XImage *out_image); 71static void Do_Direct(Display *dpy, XWDFileHeader *header, Colormap *colormap, 72 int ncolors, XColor *colors, 73 XImage *in_image, XImage *out_image, XVisualInfo *vinfo); 74static unsigned int Image_Size(XImage *image); 75static void Error(const char *string) _X_NORETURN; 76static void _swapshort(char *bp, unsigned int n); 77static void _swaplong(char *bp, unsigned int n); 78static void DumpHeader(const XWDFileHeader *header, const char *win_name); 79 80static void _X_NORETURN _X_COLD 81usage(const char *errmsg) 82{ 83 if (errmsg != NULL) 84 fprintf (stderr, "%s: %s\n\n", progname, errmsg); 85 86 fprintf(stderr, "usage: %s %s", 87 progname, 88 " [-in <file>] [-noclick] [-geometry <geom>] [-display <display>]\n" 89 " [-new] [-std <maptype>] [-raw] [-vis <vis-type-or-id>]\n" 90 " [-help] [-rv] [-plane <number>] [-fg <color>] [-bg <color>]\n" 91 " [-scale] [-dumpheader] [-version]\n" 92 ); 93 exit(1); 94} 95 96static Bool 97Read(char *ptr, int size, int nitems, FILE *stream) 98{ 99 size *= nitems; 100 while (size) { 101 nitems = fread(ptr, 1, size, stream); 102 if (nitems <= 0) 103 return False; 104 size -= nitems; 105 ptr += nitems; 106 } 107 return True; 108} 109 110int 111main(int argc, char *argv[]) 112{ 113 Display *dpy; 114 int screen; 115 register int i; 116 XImage in_image_struct; 117 XImage *in_image, *out_image; 118 XSetWindowAttributes attributes; 119 XVisualInfo vinfo, *vinfos; 120 long mask; 121 register char *buffer; 122 unsigned long swaptest = 1; 123 int count, stdcnt; 124 unsigned buffer_size; 125 int win_name_size; 126 int ncolors; 127 char *file_name = NULL; 128 char *win_name; 129 Bool inverse = False, rawbits = False, newmap = False; 130 Bool onclick = True; 131 Bool scale = False; 132 int plane = -1; 133 char *std = NULL; 134 char *vis = NULL; 135 char *display_name = NULL; 136 char *fgname = NULL; 137 char *bgname = NULL; 138 char *geom = NULL; 139 int gbits = 0; 140 XSizeHints hints; 141 XTextProperty textprop; 142 XClassHint class_hint; 143 XColor *colors = NULL, color, igncolor; 144 Window image_win; 145 Colormap colormap; 146 XEvent event; 147 register XExposeEvent *expose = (XExposeEvent *)&event; 148 GC gc; 149 XGCValues gc_val; 150 XWDFileHeader header; 151 XWDColor xwdcolor; 152 FILE *in_file = stdin; 153 char *map_name; 154 Atom map_prop; 155 XStandardColormap *stdmaps, *stdmap = NULL; 156 char c; 157 int win_width, win_height; 158 Bool dump_header = False; 159 160 progname = argv[0]; 161 162 for (i = 1; i < argc; i++) { 163 if (strcmp(argv[i], "-bg") == 0) { 164 if (++i >= argc) usage("-bg requires an argument"); 165 bgname = argv[i]; 166 continue; 167 } 168 if (strcmp(argv[i], "-display") == 0) { 169 if (++i >= argc) usage("-display requires an argument"); 170 display_name = argv[i]; 171 continue; 172 } 173 if (strcmp(argv[i], "-dumpheader") == 0) { 174 dump_header = True; 175 continue; 176 } 177 if (strcmp(argv[i], "-fg") == 0) { 178 if (++i >= argc) usage("-fg requires an argument"); 179 fgname = argv[i]; 180 continue; 181 } 182 if (strcmp(argv[i], "-geometry") == 0) { 183 if (++i >= argc) usage("-geometry requires an argument"); 184 geom = argv[i]; 185 continue; 186 } 187 if (strcmp(argv[i], "-help") == 0) { 188 usage(NULL); 189 } 190 if (strcmp(argv[i], "-in") == 0) { 191 if (++i >= argc) usage("-in requires an argument"); 192 file_name = argv[i]; 193 continue; 194 } 195 if (strcmp(argv[i], "-inverse") == 0) { /* for compatibility */ 196 inverse = True; 197 continue; 198 } 199 if (strcmp(argv[i], "-new") == 0) { 200 newmap = True; 201 if (std) usage("-new cannot be specified with -std"); 202 continue; 203 } 204 if (strcmp(argv[i], "-noclick") == 0) { 205 onclick = False; 206 continue; 207 } 208 if (strcmp(argv[i], "-plane") == 0) { 209 if (++i >= argc) usage("-plane requires an argument"); 210 plane = atoi(argv[i]); 211 continue; 212 } 213 if (strcmp(argv[i], "-raw") == 0) { 214 rawbits = True; 215 if (std) usage("-new cannot be specified with -std"); 216 continue; 217 } 218 if (strcmp(argv[i], "-rv") == 0) { 219 inverse = True; 220 continue; 221 } 222 if (strcmp(argv[i], "-scale") == 0) { 223 scale = True; 224 continue; 225 } 226 if (strcmp(argv[i], "-split") == 0) { 227 split = True; 228 continue; 229 } 230 if (strcmp(argv[i], "-std") == 0) { 231 if (++i >= argc) usage("-std requires an argument"); 232 std = argv[i]; 233 if (newmap || rawbits) 234 usage("-std cannot be specified with -raw or -new"); 235 continue; 236 } 237 if (strcmp(argv[i], "-vis") == 0) { 238 if (++i >= argc) usage("-vis requires an argument"); 239 vis = argv[i]; 240 continue; 241 } 242 if (strcmp(argv[i], "-version") == 0) { 243 puts(PACKAGE_STRING); 244 exit(0); 245 } 246 fprintf (stderr, "%s: unrecognized argument '%s'\n\n", 247 progname, argv[i]); 248 usage(NULL); 249 } 250 251 if (file_name) { 252 in_file = fopen(file_name, "rb"); 253 if (in_file == NULL) 254 Error("Can't open input file as specified."); 255 } 256#ifdef WIN32 257 else 258 _setmode(fileno(in_file), _O_BINARY); 259#endif 260 261 dpy = XOpenDisplay(display_name); 262 if (dpy == NULL) { 263 fprintf(stderr, "%s: unable to open display \"%s\"\n", 264 progname, XDisplayName(display_name)); 265 exit(1); 266 } 267 screen = DefaultScreen(dpy); 268 269 /* 270 * Read in header information. 271 */ 272 if(!Read((char *)&header, SIZEOF(XWDheader), 1, in_file)) 273 Error("Unable to read dump file header."); 274 275 if (*(char *) &swaptest) 276 _swaplong((char *) &header, SIZEOF(XWDheader)); 277 278 /* check to see if the dump file is in the proper format */ 279 if (header.file_version != XWD_FILE_VERSION) { 280 fprintf(stderr,"xwud: XWD file format version mismatch."); 281 Error("exiting."); 282 } 283 if (header.header_size < SIZEOF(XWDheader)) { 284 fprintf(stderr,"xwud: XWD header size is too small."); 285 Error("exiting."); 286 } 287 288 /* alloc window name */ 289 win_name_size = (header.header_size - SIZEOF(XWDheader)); 290 if (win_name_size < 0) 291 Error("win_name_size"); 292 if((win_name = malloc((unsigned) win_name_size + 6)) == NULL) 293 Error("Can't malloc window name storage."); 294 strcpy(win_name, "xwud: "); 295 296 /* read in window name */ 297 if(!Read(win_name + 6, sizeof(char), win_name_size, in_file)) 298 Error("Unable to read window name from dump file."); 299 (win_name + 6)[win_name_size - 1] = 0; 300 301 if (dump_header) { 302 DumpHeader(&header, win_name); 303 exit(0); 304 } 305 306 /* initialize the input image */ 307 308 in_image = &in_image_struct; 309 in_image->depth = header.pixmap_depth; 310 in_image->format = header.pixmap_format; 311 in_image->xoffset = header.xoffset; 312 in_image->data = NULL; 313 in_image->width = header.pixmap_width; 314 in_image->height = header.pixmap_height; 315 in_image->bitmap_pad = header.bitmap_pad; 316 in_image->bytes_per_line = header.bytes_per_line; 317 in_image->byte_order = header.byte_order; 318 in_image->bitmap_unit = header.bitmap_unit; 319 in_image->bitmap_bit_order = header.bitmap_bit_order; 320 in_image->bits_per_pixel = header.bits_per_pixel; 321 in_image->red_mask = header.red_mask; 322 in_image->green_mask = header.green_mask; 323 in_image->blue_mask = header.blue_mask; 324 if (!XInitImage(in_image)) 325 Error("Invalid input image header data."); 326 327 /* read in the color map buffer */ 328 if((ncolors = header.ncolors)) { 329 colors = (XColor *)malloc((unsigned) ncolors * sizeof(XColor)); 330 if (!colors) 331 Error("Can't malloc color table"); 332 for (i = 0; i < ncolors; i++) { 333 if(!Read((char *) &xwdcolor, SIZEOF(XWDColor), 1, in_file)) 334 Error("Unable to read color map from dump file."); 335 colors[i].pixel = xwdcolor.pixel; 336 colors[i].red = xwdcolor.red; 337 colors[i].green = xwdcolor.green; 338 colors[i].blue = xwdcolor.blue; 339 colors[i].flags = xwdcolor.flags; 340 } 341 if (*(char *) &swaptest) { 342 for (i = 0; i < ncolors; i++) { 343 _swaplong((char *) &colors[i].pixel, sizeof(long)); 344 _swapshort((char *) &colors[i].red, 3 * sizeof(short)); 345 } 346 } 347 } 348 else 349 /* no color map exists, turn on the raw option */ 350 rawbits = True; 351 352 /* alloc the pixel buffer */ 353 buffer_size = Image_Size(in_image); 354 if((buffer = malloc(buffer_size)) == NULL) 355 Error("Can't malloc data buffer."); 356 357 /* read in the image data */ 358 if (!Read(buffer, sizeof(char), (int)buffer_size, in_file)) 359 Error("Unable to read pixmap from dump file."); 360 361 /* close the input file */ 362 (void) fclose(in_file); 363 364 if (plane >= in_image->depth) 365 Error("plane number exceeds image depth"); 366 if ((in_image->format == XYPixmap) && (plane >= 0)) { 367 buffer += in_image->bytes_per_line * in_image->height * 368 (in_image->depth - (plane + 1)); 369 in_image->depth = 1; 370 ncolors = 0; 371 } 372 if (in_image->bits_per_pixel == 1 && in_image->depth == 1) { 373 in_image->format = XYBitmap; 374 newmap = False; 375 rawbits = True; 376 } 377 in_image->data = buffer; 378 379 if (std) { 380 map_name = malloc(strlen(std) + 9); 381 strcpy(map_name, "RGB_"); 382 strcat(map_name, std); 383 strcat(map_name, "_MAP"); 384 Latin1Upper(map_name); 385 map_prop = XInternAtom(dpy, map_name, True); 386 if (!map_prop || !XGetRGBColormaps(dpy, RootWindow(dpy, screen), 387 &stdmaps, &stdcnt, map_prop)) 388 Error("specified standard colormap does not exist"); 389 } 390 vinfo.screen = screen; 391 mask = VisualScreenMask; 392 if (vis) 393 { 394 char *vt = strdup(vis); 395 Latin1Upper(vt); 396 if (strcmp(vt, "STATICGRAY") == 0) { 397 vinfo.class = StaticGray; 398 mask |= VisualClassMask; 399 } else if (strcmp(vt, "GRAYSCALE") == 0) { 400 vinfo.class = GrayScale; 401 mask |= VisualClassMask; 402 } else if (strcmp(vt, "STATICCOLOR") == 0) { 403 vinfo.class = StaticColor; 404 mask |= VisualClassMask; 405 } else if (strcmp(vt, "PSEUDOCOLOR") == 0) { 406 vinfo.class = PseudoColor; 407 mask |= VisualClassMask; 408 } else if (strcmp(vt, "DIRECTCOLOR") == 0) { 409 vinfo.class = DirectColor; 410 mask |= VisualClassMask; 411 } else if (strcmp(vt, "TRUECOLOR") == 0) { 412 vinfo.class = TrueColor; 413 mask |= VisualClassMask; 414 } else if (strcmp(vt, "MATCH") == 0) { 415 vinfo.class = header.visual_class; 416 mask |= VisualClassMask; 417 } else if (strcmp(vt, "DEFAULT") == 0) { 418 vinfo.visualid= XVisualIDFromVisual(DefaultVisual(dpy, screen)); 419 mask |= VisualIDMask; 420 } else { 421 vinfo.visualid = 0; 422 mask |= VisualIDMask; 423 sscanf(vis, "0x%lx", &vinfo.visualid); 424 if (!vinfo.visualid) 425 sscanf(vis, "%lu", &vinfo.visualid); 426 if (!vinfo.visualid) 427 Error("invalid visual specifier"); 428 } 429 } 430 if (rawbits && (in_image->depth > 1) && (plane < 0)) { 431 vinfo.depth = in_image->depth; 432 mask |= VisualDepthMask; 433 } 434 vinfos = XGetVisualInfo(dpy, mask, &vinfo, &count); 435 if (count == 0) 436 Error("no matching visual found"); 437 438 /* find a workable visual */ 439 if (std) { 440 stdmap = &stdmaps[0]; 441 if (mask & VisualIDMask) { 442 for (i = 0; i < stdcnt; i++) { 443 if (stdmaps[i].visualid == vinfo.visualid) { 444 stdmap = &stdmaps[i]; 445 break; 446 } 447 } 448 if (stdmap->visualid != vinfo.visualid) 449 Error("no standard colormap matching specified visual"); 450 } 451 for (i = 0; i < count; i++) { 452 if (stdmap->visualid == vinfos[i].visualid) { 453 vinfo = vinfos[i]; 454 break; 455 } 456 } 457 } else if ((in_image->depth == 1) || 458 ((in_image->format == ZPixmap) && (plane >= 0)) || 459 rawbits) { 460 vinfo = vinfos[0]; 461 if (!(mask & VisualIDMask)) { 462 for (i = 0; i < count; i++) { 463 if ((vinfos[i].visualid == 464 XVisualIDFromVisual(DefaultVisual(dpy, screen))) && 465 (vinfos[i].depth == DefaultDepth(dpy, screen))) { 466 vinfo = vinfos[i]; 467 break; 468 } 469 } 470 } 471 } else { 472 /* get best visual */ 473 vinfo = vinfos[0]; 474 for (i = 0; i < count; i++) { 475 int z1, z2; 476 z2 = EffectiveSize(&vinfos[i]); 477 if ((z2 >= ncolors) && 478 (vinfos[i].depth == in_image->depth) && 479 (vinfos[i].class == header.visual_class)) 480 { 481 vinfo = vinfos[i]; 482 break; 483 } 484 z1 = EffectiveSize(&vinfo); 485 if ((z2 > z1) || 486 ((z2 == z1) && 487 (VisualRank(vinfos[i].class) >= VisualRank(vinfo.class)))) 488 vinfo = vinfos[i]; 489 } 490 if ((newmap || (vinfo.visual != DefaultVisual(dpy, screen))) && 491 (vinfo.class != StaticGray) && 492 (vinfo.class != StaticColor) && 493 (vinfo.class == header.visual_class) && 494 (vinfo.depth == in_image->depth) && 495 ((vinfo.class == PseudoColor) || 496 (vinfo.class == GrayScale) || 497 ((vinfo.red_mask == header.red_mask) && 498 (vinfo.green_mask == header.green_mask) && 499 (vinfo.blue_mask == header.blue_mask)))) { 500 rawbits = True; 501 newmap = True; 502 } 503 } 504 505 /* get the appropriate colormap */ 506 if (newmap && (vinfo.class & 1) && 507 (vinfo.depth == in_image->depth) && 508 (vinfo.class == header.visual_class) && 509 (vinfo.colormap_size >= ncolors) && 510 (vinfo.red_mask == header.red_mask) && 511 (vinfo.green_mask == header.green_mask) && 512 (vinfo.blue_mask == header.blue_mask)) { 513 colormap = XCreateColormap(dpy, RootWindow(dpy, screen), vinfo.visual, 514 AllocAll); 515 if (ncolors) { 516 for (i = 0; i < ncolors; i++) 517 colors[i].flags = DoRed|DoGreen|DoBlue; 518 XStoreColors(dpy, colormap, colors, ncolors); 519 } 520 } else if (std) { 521 colormap = stdmap->colormap; 522 } else { 523 if (!newmap && (vinfo.visual == DefaultVisual(dpy, screen))) 524 colormap = DefaultColormap(dpy, screen); 525 else 526 colormap = XCreateColormap(dpy, RootWindow(dpy, screen), 527 vinfo.visual, AllocNone); 528 newmap = False; 529 } 530 531 /* create the output image */ 532 if ((in_image->format == ZPixmap) && (plane >= 0)) { 533 out_image = XCreateImage(dpy, vinfo.visual, 1, 534 XYBitmap, 0, NULL, 535 in_image->width, in_image->height, 536 XBitmapPad(dpy), 0); 537 out_image->data = malloc(Image_Size(out_image)); 538 Extract_Plane(in_image, out_image, plane); 539 ncolors = 0; 540 } else if (rawbits || newmap) { 541 out_image = in_image; 542 } else { 543 out_image = XCreateImage(dpy, vinfo.visual, vinfo.depth, 544 (vinfo.depth == 1) ? XYBitmap : 545 in_image->format, 546 in_image->xoffset, NULL, 547 in_image->width, in_image->height, 548 XBitmapPad(dpy), 0); 549 out_image->data = malloc(Image_Size(out_image)); 550 if (std) { 551 if (!stdmap->green_max && !stdmap->blue_max && IsGray(dpy, stdmap)) 552 Do_StdGray(dpy, stdmap, ncolors, colors, in_image, out_image); 553 else 554 Do_StdCol(dpy, stdmap, ncolors, colors, in_image, out_image); 555 } else if ((header.visual_class == TrueColor) || 556 (header.visual_class == DirectColor)) 557 Do_Direct(dpy, &header, &colormap, ncolors, colors, 558 in_image, out_image, &vinfo); 559 else 560 Do_Pseudo(dpy, &colormap, ncolors, colors, in_image, out_image); 561 } 562 563 if (out_image->depth == 1) { 564 if (fgname && 565 XAllocNamedColor(dpy, colormap, fgname, &color, &igncolor)) 566 gc_val.foreground = color.pixel; 567 else if ((ncolors == 2) && XAllocColor(dpy, colormap, &colors[1])) 568 gc_val.foreground = colors[1].pixel; 569 else 570 gc_val.foreground = BlackPixel (dpy, screen); 571 if (bgname && 572 XAllocNamedColor(dpy, colormap, bgname, &color, &igncolor)) 573 gc_val.background = color.pixel; 574 else if ((ncolors == 2) && XAllocColor(dpy, colormap, &colors[0])) 575 gc_val.background = colors[0].pixel; 576 else 577 gc_val.background = WhitePixel (dpy, screen); 578 if (inverse) { 579 unsigned long tmp; 580 tmp = gc_val.foreground; 581 gc_val.foreground = gc_val.background; 582 gc_val.background = tmp; 583 } 584 } else { 585 gc_val.background = XGetPixel(out_image, 0, 0); 586 gc_val.foreground = 0; 587 } 588 589 attributes.background_pixel = gc_val.background; 590 attributes.border_pixel = gc_val.background; 591 if (scale) 592 attributes.bit_gravity = ForgetGravity; 593 else 594 attributes.bit_gravity = NorthWestGravity; 595 attributes.event_mask = ButtonPressMask|ButtonReleaseMask|KeyPressMask| 596 ExposureMask; 597 if (scale) 598 attributes.event_mask |= StructureNotifyMask; 599 attributes.colormap = colormap; 600 601 hints.x = header.window_x; 602 hints.y = header.window_y; 603 hints.width = out_image->width; 604 hints.height = out_image->height; 605 if (geom) 606 gbits = XParseGeometry(geom, &hints.x, &hints.y, 607 (unsigned int *)&hints.width, 608 (unsigned int *)&hints.height); 609 hints.flags = ((gbits & (XValue|YValue)) ? USPosition : 0) | 610 ((gbits & (HeightValue|WidthValue)) ? USSize : PSize); 611 if (!scale) { 612 hints.flags |= PMaxSize; 613 hints.max_width = (hints.width > out_image->width) ? 614 hints.width : out_image->width; 615 hints.max_height = (hints.height > out_image->height) ? 616 hints.height : out_image->height; 617 } 618 if ((gbits & XValue) && (gbits & XNegative)) 619 hints.x += DisplayWidth(dpy, screen) - hints.width; 620 if ((gbits & YValue) && (gbits & YNegative)) 621 hints.y += DisplayHeight(dpy, screen) - hints.height; 622 623 /* create the image window */ 624 image_win = XCreateWindow(dpy, RootWindow(dpy, screen), 625 hints.x, hints.y, hints.width, hints.height, 626 0, vinfo.depth, InputOutput, vinfo.visual, 627 CWBorderPixel|CWBackPixel|CWColormap|CWEventMask|CWBitGravity, 628 &attributes); 629 win_width = hints.width; 630 win_height = hints.height; 631 632 /* Setup for ICCCM delete window. */ 633 wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); 634 wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 635 (void) XSetWMProtocols (dpy, image_win, &wm_delete_window, 1); 636 637 textprop.value = (unsigned char *) win_name; 638 textprop.encoding = XA_STRING; 639 textprop.format = 8; 640 textprop.nitems = strlen(win_name); 641 class_hint.res_name = (char *)NULL; 642 class_hint.res_class = "Xwud"; 643 /* set standard properties */ 644 XSetWMProperties(dpy, image_win, &textprop, (XTextProperty *)NULL, 645 argv, argc, &hints, (XWMHints *)NULL, &class_hint); 646 647 /* map the image window */ 648 XMapWindow(dpy, image_win); 649 650 gc = XCreateGC (dpy, image_win, GCForeground|GCBackground, &gc_val); 651 652 while (1) { 653 /* wait on mouse input event to terminate */ 654 XNextEvent(dpy, &event); 655 switch(event.type) { 656 case ClientMessage: 657 if (event.xclient.message_type == wm_protocols && 658 event.xclient.data.l[0] == wm_delete_window) { 659 XCloseDisplay(dpy); 660 exit(0); /* ICCCM delete window */ 661 } 662 break; 663 case ButtonPress: 664 break; 665 case ButtonRelease: 666 if (onclick) { 667 XCloseDisplay(dpy); 668 exit(0); 669 } 670 break; 671 case KeyPress: 672 i = XLookupString(&event.xkey, &c, 1, NULL, NULL); 673 if ((i == 1) && ((c == 'q') || (c == 'Q') || (c == '\03'))) { 674 XCloseDisplay(dpy); 675 exit(0); 676 } 677 break; 678 case ConfigureNotify: 679 win_width = event.xconfigure.width; 680 win_height = event.xconfigure.height; 681 break; 682 case Expose: 683 if (scale) 684 putScaledImage(dpy, image_win, gc, out_image, 685 expose->x, expose->y, 686 expose->width, expose->height, 687 win_width, win_height); 688 else if ((expose->x < out_image->width) && 689 (expose->y < out_image->height)) { 690 if ((out_image->width - expose->x) < expose->width) 691 expose->width = out_image->width - expose->x; 692 if ((out_image->height - expose->y) < expose->height) 693 expose->height = out_image->height - expose->y; 694 putImage(dpy, image_win, gc, out_image, 695 expose->x, expose->y, 696 expose->width, expose->height); 697 } 698 break; 699 } 700 } 701 exit(0); 702} 703 704static void 705putImage(Display *dpy, Window image_win, GC gc, XImage *out_image, 706 int x, int y, int w, int h) 707{ 708#define SPLIT_SIZE 100 709 int t_x, t_y, t_w, t_h; 710 if (split) { 711 for (t_y = y; t_y < y + h; t_y += t_h) { 712 t_h = SPLIT_SIZE; 713 if (t_y + t_h > y + h) 714 t_h = y + h - t_y; 715 for (t_x = x; t_x < x + w; t_x += t_w) { 716 t_w = SPLIT_SIZE; 717 if (t_x + t_w > x + w) 718 t_w = x + w - t_x; 719 XPutImage(dpy, image_win, gc, out_image, 720 t_x, t_y, t_x, t_y, t_w, t_h); 721 } 722 } 723 } else { 724 XPutImage (dpy, image_win, gc, out_image, x, y, x, y, w, h); 725 } 726} 727 728typedef short Position; 729typedef unsigned short Dimension; 730typedef unsigned long Pixel; 731 732#define roundint(x) (int)((x) + 0.5) 733 734typedef struct { 735 Position *x, *y; 736 Dimension *width, *height; 737} Table; 738 739static void 740putScaledImage(Display *display, Drawable d, GC gc, XImage *src_image, 741 int exp_x, int exp_y, 742 unsigned int exp_width, unsigned int exp_height, 743 unsigned int dest_width, unsigned dest_height) 744{ 745 XImage *dest_image; 746 Position x, y, min_y, max_y, exp_max_y, src_x, src_max_x, src_y; 747 Dimension w, h, strip_height; 748 Table table; 749 Pixel pixel; 750 double ratio_x, ratio_y; 751 Bool fast8; 752 753 if (dest_width == src_image->width && dest_height == src_image->height) { 754 /* same for x and y, just send it out */ 755 XPutImage(display, d, gc, src_image, exp_x, exp_y, 756 exp_x, exp_y, exp_width, exp_height); 757 return; 758 } 759 760 ratio_x = (double)dest_width / (double)src_image->width; 761 ratio_y = (double)dest_height / (double)src_image->height; 762 763 src_x = exp_x / ratio_x; 764 if (src_x >= src_image->width) 765 src_x = src_image->width - 1; 766 src_y = exp_y / ratio_y; 767 if (src_y >= src_image->height) 768 src_y = src_image->height - 1; 769 exp_max_y = exp_y + exp_height; 770 src_max_x = roundint((exp_x + exp_width) / ratio_x) + 1; 771 if (src_max_x > src_image->width) 772 src_max_x = src_image->width; 773 774 strip_height = 65536 / roundint(ratio_x * src_image->bytes_per_line); 775 if (strip_height == 0) 776 strip_height = 1; 777 if (strip_height > exp_height) 778 strip_height = exp_height; 779 780 h = strip_height + roundint(ratio_y); 781 dest_image = XCreateImage(display, 782 DefaultVisualOfScreen( 783 DefaultScreenOfDisplay(display)), 784 src_image->depth, src_image->format, 785 0, NULL, 786 dest_width, h, 787 src_image->bitmap_pad, 0); 788 dest_image->data = malloc(dest_image->bytes_per_line * h); 789 fast8 = (src_image->depth == 8 && src_image->bits_per_pixel == 8 && 790 dest_image->bits_per_pixel == 8 && src_image->format == ZPixmap); 791 792 table.x = (Position *) malloc(sizeof(Position) * (src_image->width + 1)); 793 table.y = (Position *) malloc(sizeof(Position) * (src_image->height + 1)); 794 table.width = (Dimension *) malloc(sizeof(Dimension) * src_image->width); 795 table.height = (Dimension *) malloc(sizeof(Dimension)*src_image->height); 796 797 table.x[0] = 0; 798 for (x = 1; x <= src_image->width; x++) { 799 table.x[x] = roundint(ratio_x * x); 800 table.width[x - 1] = table.x[x] - table.x[x - 1]; 801 } 802 803 table.y[0] = 0; 804 for (y = 1; y <= src_image->height; y++) { 805 table.y[y] = roundint(ratio_y * y); 806 table.height[y - 1] = table.y[y] - table.y[y - 1]; 807 } 808 809 for (min_y = table.y[src_y]; min_y < exp_max_y; min_y = table.y[y]) { 810 max_y = min_y + strip_height; 811 if (max_y > exp_max_y) { 812 strip_height = exp_max_y - min_y; 813 max_y = exp_max_y; 814 } 815 for (y = src_y; table.y[y] < max_y; y++) { 816 if (table.y[y] < min_y) 817 continue; 818 if (fast8) { 819 for (x = src_x; x < src_max_x; x++) { 820 pixel = ((unsigned char *)src_image->data) 821 [y * src_image->bytes_per_line + x]; 822 for (h = 0; h < table.height[y]; h++) { 823 memset(dest_image->data + 824 (table.y[y] + h - min_y) * 825 dest_image->bytes_per_line + table.x[x], 826 pixel, table.width[x]); 827 } 828 } 829 } else { 830 for (x = src_x; x < src_max_x; x++) { 831 pixel = XGetPixel(src_image, x, y); 832 for (h = 0; h < table.height[y]; h++) { 833 for (w = 0; w < table.width[x]; w++) 834 XPutPixel(dest_image, 835 table.x[x] + w, 836 table.y[y] + h - min_y, 837 pixel); 838 } 839 } 840 } 841 } 842 XPutImage(display, d, gc, dest_image, exp_x, 0, 843 exp_x, min_y, exp_width, table.y[y] - min_y); 844 if (y >= src_image->height) 845 break; 846 } 847 848 XFree((char *)table.x); 849 XFree((char *)table.y); 850 XFree((char *)table.width); 851 XFree((char *)table.height); 852 853 XDestroyImage(dest_image); 854} 855 856static void 857Latin1Upper(char *s) 858{ 859 unsigned char *str = (unsigned char *)s; 860 unsigned char c; 861 862 for (; (c = *str); str++) 863 { 864 if ((c >= XK_a) && (c <= XK_z)) 865 *str = c - (XK_a - XK_A); 866 else if ((c >= XK_agrave) && (c <= XK_odiaeresis)) 867 *str = c - (XK_agrave - XK_Agrave); 868 else if ((c >= XK_oslash) && (c <= XK_thorn)) 869 *str = c - (XK_oslash - XK_Ooblique); 870 } 871} 872 873static void 874Extract_Plane(XImage *in_image, XImage *out_image, int plane) 875{ 876 register int x, y; 877 878 for (y = 0; y < in_image->height; y++) 879 for (x = 0; x < in_image->width; x++) 880 XPutPixel(out_image, x, y, 881 (XGetPixel(in_image, x, y) >> plane) & 1); 882} 883 884static int 885EffectiveSize(XVisualInfo *vinfo) 886{ 887 if ((vinfo->class == DirectColor) || (vinfo->class == TrueColor)) 888 return (vinfo->red_mask | vinfo->green_mask | vinfo->blue_mask) + 1; 889 else 890 return vinfo->colormap_size; 891} 892 893static int 894VisualRank(int class) 895{ 896 switch (class) { 897 case PseudoColor: 898 return 5; 899 case TrueColor: 900 return 4; 901 case DirectColor: 902 return 3; 903 case StaticColor: 904 return 2; 905 case GrayScale: 906 return 1; 907 case StaticGray: 908 return 0; 909 } 910 /* NOTREACHED */ 911 return -1; 912} 913 914static int 915IsGray(Display *dpy, XStandardColormap *stdmap) 916{ 917 XColor color; 918 919 color.pixel = stdmap->base_pixel + (stdmap->red_max * stdmap->red_mult); 920 XQueryColor(dpy, stdmap->colormap, &color); 921 return (color.green || color.blue); 922} 923 924static void 925Do_StdGray(Display *dpy, XStandardColormap *stdmap, 926 int ncolors, XColor *colors, XImage *in_image, XImage *out_image) 927{ 928 register int i, x, y; 929 register XColor *color; 930 unsigned lim; 931 932 lim = stdmap->red_max + 1; 933 for (i = 0, color = colors; i < ncolors; i++, color++) 934 color->pixel = stdmap->base_pixel + 935 (((((int)(30L * color->red + 936 59L * color->green + 937 11L * color->blue) / 100) 938 * lim) >> 16) * stdmap->red_mult); 939 for (y = 0; y < in_image->height; y++) { 940 for (x = 0; x < in_image->width; x++) { 941 XPutPixel(out_image, x, y, 942 colors[XGetPixel(in_image, x, y)].pixel); 943 } 944 } 945} 946 947#define MapVal(val,lim,mult) ((((val * lim) + 32768) / 65535) * mult) 948 949static void 950Do_StdCol(Display *dpy, XStandardColormap *stdmap, 951 int ncolors, XColor *colors, XImage *in_image, XImage *out_image) 952{ 953 register int i, x, y; 954 register XColor *color; 955 unsigned limr, limg, limb; 956 957 limr = stdmap->red_max; 958 limg = stdmap->green_max; 959 limb = stdmap->blue_max; 960 for (i = 0, color = colors; i < ncolors; i++, color++) 961 color->pixel = stdmap->base_pixel + 962 MapVal(color->red, limr, stdmap->red_mult) + 963 MapVal(color->green, limg, stdmap->green_mult) + 964 MapVal(color->blue, limb, stdmap->blue_mult); 965 for (y = 0; y < in_image->height; y++) { 966 for (x = 0; x < in_image->width; x++) { 967 XPutPixel(out_image, x, y, 968 colors[XGetPixel(in_image, x, y)].pixel); 969 } 970 } 971} 972 973static Colormap 974CopyColormapAndFree(Display *dpy, Colormap colormap) 975{ 976 if (colormap == DefaultColormap(dpy, DefaultScreen(dpy))) 977 return XCopyColormapAndFree(dpy, colormap); 978 Error("Visual type is not large enough to hold all colors of the image."); 979 /*NOTREACHED*/ 980 return (Colormap)0; 981} 982 983static void 984Do_Pseudo(Display *dpy, Colormap *colormap, 985 int ncolors, XColor *colors, XImage *in_image, XImage *out_image) 986{ 987 register int i, x, y; 988 register XColor *color; 989 990 for (i = 0; i < ncolors; i++) 991 colors[i].flags = 0; 992 for (y = 0; y < in_image->height; y++) { 993 for (x = 0; x < in_image->width; x++) { 994 color = &colors[XGetPixel(in_image, x, y)]; 995 if (!color->flags) { 996 color->flags = DoRed | DoGreen | DoBlue; 997 if (!XAllocColor(dpy, *colormap, color)) { 998 *colormap = CopyColormapAndFree(dpy, *colormap); 999 XAllocColor(dpy, *colormap, color); 1000 } 1001 } 1002 XPutPixel(out_image, x, y, color->pixel); 1003 } 1004 } 1005} 1006 1007static void 1008Do_Direct(Display *dpy, XWDFileHeader *header, Colormap *colormap, 1009 int ncolors, XColor *colors, XImage *in_image, XImage *out_image, 1010 XVisualInfo *vinfo) 1011{ 1012 register int x, y; 1013 XColor color; 1014 unsigned long rmask, gmask, bmask; 1015 unsigned long ormask, ogmask, obmask; 1016 unsigned long rshift = 0, gshift = 0, bshift = 0; 1017 unsigned long orshift = 0, ogshift = 0, obshift = 0; 1018 int i; 1019 unsigned long pix, xpix; 1020 unsigned long *pixels, *rpixels; 1021 1022 rmask = header->red_mask; 1023 while (!(rmask & 1)) { 1024 rmask >>= 1; 1025 rshift++; 1026 } 1027 gmask = header->green_mask; 1028 while (!(gmask & 1)) { 1029 gmask >>= 1; 1030 gshift++; 1031 } 1032 bmask = header->blue_mask; 1033 while (!(bmask & 1)) { 1034 bmask >>= 1; 1035 bshift++; 1036 } 1037 if (in_image->depth <= 12) { 1038 pix = 1 << in_image->depth; 1039 pixels = (unsigned long *)malloc(sizeof(unsigned long) * pix); 1040 if (pixels == NULL) 1041 Error("Unable to allocate memory for pixel conversion"); 1042 for (i = 0; i < pix; i++) 1043 pixels[i] = ~0L; 1044 color.flags = DoRed | DoGreen | DoBlue; 1045 for (y = 0; y < in_image->height; y++) { 1046 for (x = 0; x < in_image->width; x++) { 1047 pix = XGetPixel(in_image, x, y); 1048 if ((color.pixel = pixels[pix]) == ~0L) { 1049 color.red = (pix >> rshift) & rmask; 1050 color.green = (pix >> gshift) & gmask; 1051 color.blue = (pix >> bshift) & bmask; 1052 if (ncolors) { 1053 color.red = colors[color.red].red; 1054 color.green = colors[color.green].green; 1055 color.blue = colors[color.blue].blue; 1056 } else { 1057 color.red = (((unsigned long)color.red * 65535) / 1058 rmask); 1059 color.green = (((unsigned long)color.green * 65535) / 1060 gmask); 1061 color.blue = (((unsigned long)color.blue * 65535) / 1062 bmask); 1063 } 1064 if (!XAllocColor(dpy, *colormap, &color)) { 1065 *colormap = CopyColormapAndFree(dpy, *colormap); 1066 XAllocColor(dpy, *colormap, &color); 1067 } 1068 pixels[pix] = color.pixel; 1069 } 1070 XPutPixel(out_image, x, y, color.pixel); 1071 } 1072 } 1073 free(pixels); 1074 } else if (header->visual_class == TrueColor && 1075 vinfo->class == TrueColor) { 1076 ormask = vinfo->red_mask; 1077 while (!(ormask & 1)) { 1078 ormask >>= 1; 1079 orshift++; 1080 } 1081 ogmask = vinfo->green_mask; 1082 while (!(ogmask & 1)) { 1083 ogmask >>= 1; 1084 ogshift++; 1085 } 1086 obmask = vinfo->blue_mask; 1087 while (!(obmask & 1)) { 1088 obmask >>= 1; 1089 obshift++; 1090 } 1091 for (y = 0; y < in_image->height; y++) { 1092 for (x = 0; x < in_image->width; x++) { 1093 pix = XGetPixel(in_image, x, y); 1094 xpix = (((((pix >> rshift) & rmask) * 65535 / rmask) 1095 * ormask / 65535) << orshift) | 1096 (((((pix >> gshift) & gmask) * 65535 / gmask) 1097 * ogmask / 65535) << ogshift) | 1098 (((((pix >> bshift) & bmask) * 65535 / bmask) 1099 * obmask / 65535) << obshift); 1100 XPutPixel(out_image, x, y, xpix); 1101 } 1102 } 1103 } else { 1104 if (header->visual_class == TrueColor) 1105 ncolors = 0; 1106 pix = 1 << 12; 1107 pixels = (unsigned long *)malloc(sizeof(unsigned long) * pix); 1108 rpixels = (unsigned long *)malloc(sizeof(unsigned long) * pix); 1109 if ((pixels == NULL) || (rpixels == NULL)) 1110 Error("Unable to allocate memory for pixel conversion"); 1111 for (i = 0; i < pix; i++) { 1112 pixels[i] = ~0L; 1113 rpixels[i] = ~0L; 1114 } 1115 color.flags = DoRed | DoGreen | DoBlue; 1116 for (y = 0; y < in_image->height; y++) { 1117 for (x = 0; x < in_image->width; x++) { 1118 pix = XGetPixel(in_image, x, y); 1119 xpix = ((pix >> 12) ^ pix) & ((1 << 12) - 1); 1120 if (((color.pixel = pixels[xpix]) == ~0L) || 1121 (rpixels[xpix] != pix)) { 1122 color.red = (pix >> rshift) & rmask; 1123 color.green = (pix >> gshift) & gmask; 1124 color.blue = (pix >> bshift) & bmask; 1125 if (ncolors) { 1126 color.red = colors[color.red].red; 1127 color.green = colors[color.green].green; 1128 color.blue = colors[color.blue].blue; 1129 } else { 1130 color.red = (((unsigned long)color.red * 65535) / 1131 rmask); 1132 color.green = (((unsigned long)color.green * 65535) / 1133 gmask); 1134 color.blue = (((unsigned long)color.blue * 65535) / 1135 bmask); 1136 } 1137 if (!XAllocColor(dpy, *colormap, &color)) { 1138 *colormap = CopyColormapAndFree(dpy, *colormap); 1139 XAllocColor(dpy, *colormap, &color); 1140 } 1141 pixels[xpix] = color.pixel; 1142 rpixels[xpix] = pix; 1143 } 1144 XPutPixel(out_image, x, y, color.pixel); 1145 } 1146 } 1147 free(pixels); 1148 free(rpixels); 1149 } 1150} 1151 1152static unsigned int 1153Image_Size(XImage *image) 1154{ 1155 if (image->format != ZPixmap) 1156 return(image->bytes_per_line * image->height * image->depth); 1157 1158 return((unsigned)image->bytes_per_line * image->height); 1159} 1160 1161static void 1162Error(const char *string) 1163{ 1164 fprintf(stderr, "xwud: Error => %s\n", string); 1165 if (errno != 0) { 1166 perror("xwud"); 1167 fprintf(stderr, "\n"); 1168 } 1169 exit(1); 1170} 1171 1172static void 1173_swapshort(char *bp, unsigned int n) 1174{ 1175 register char c; 1176 register char *ep = bp + n; 1177 1178 while (bp < ep) { 1179 c = *bp; 1180 *bp = *(bp + 1); 1181 bp++; 1182 *bp++ = c; 1183 } 1184} 1185 1186static void 1187_swaplong(char *bp, unsigned int n) 1188{ 1189 register char c; 1190 register char *ep = bp + n; 1191 register char *sp; 1192 1193 while (bp < ep) { 1194 sp = bp + 3; 1195 c = *sp; 1196 *sp = *bp; 1197 *bp++ = c; 1198 sp = bp + 1; 1199 c = *sp; 1200 *sp = *bp; 1201 *bp++ = c; 1202 bp += 2; 1203 } 1204} 1205 1206static void 1207DumpHeader(const XWDFileHeader *header, const char *win_name) 1208{ 1209 printf("window name: %s\n", win_name); 1210 printf("sizeof(XWDheader): %d\n", (int)sizeof(*header)); 1211 printf("header size: %d\n", (int)header->header_size); 1212 printf("file version: %d\n", (int)header->file_version); 1213 printf("pixmap format: %d\n", (int)header->pixmap_format); 1214 printf("pixmap depth: %d\n", (int)header->pixmap_depth); 1215 printf("pixmap width: %d\n", (int)header->pixmap_width); 1216 printf("pixmap height: %d\n", (int)header->pixmap_height); 1217 printf("x offset: %d\n", (int)header->xoffset); 1218 printf("byte order: %d\n", (int)header->byte_order); 1219 printf("bitmap unit: %d\n", (int)header->bitmap_unit); 1220 printf("bitmap bit order: %d\n", (int)header->bitmap_bit_order); 1221 printf("bitmap pad: %d\n", (int)header->bitmap_pad); 1222 printf("bits per pixel: %d\n", (int)header->bits_per_pixel); 1223 printf("bytes per line: %d\n", (int)header->bytes_per_line); 1224 printf("visual class: %d\n", (int)header->visual_class); 1225 printf("red mask: %d\n", (int)header->red_mask); 1226 printf("green mask: %d\n", (int)header->green_mask); 1227 printf("blue mask: %d\n", (int)header->blue_mask); 1228 printf("bits per rgb: %d\n", (int)header->bits_per_rgb); 1229 printf("colormap entries: %d\n", (int)header->colormap_entries); 1230 printf("num colors: %d\n", (int)header->ncolors); 1231 printf("window width: %d\n", (int)header->window_width); 1232 printf("window height: %d\n", (int)header->window_height); 1233 printf("window x: %d\n", (int)header->window_x); 1234 printf("window y: %d\n", (int)header->window_y); 1235 printf("border width: %d\n", (int)header->window_bdrwidth); 1236} 1237 1238