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