xwd.c revision b3307321
1/* $Xorg: xwd.c,v 1.5 2001/02/09 02:06:03 xorgcvs Exp $ */ 2 3/* 4 5Copyright 1987, 1998 The Open Group 6 7Permission to use, copy, modify, distribute, and sell this software and its 8documentation for any purpose is hereby granted without fee, provided that 9the above copyright notice appear in all copies and that both that 10copyright notice and this permission notice appear in supporting 11documentation. 12 13The above copyright notice and this permission notice shall be included in 14all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 23Except as contained in this notice, the name of The Open Group shall not be 24used in advertising or otherwise to promote the sale, use or other dealings 25in this Software without prior written authorization from The Open Group. 26 27*/ 28/* $XFree86: xc/programs/xwd/xwd.c,v 3.11 2002/09/16 18:06:21 eich Exp $ */ 29 30/* 31 * xwd.c MIT Project Athena, X Window system window raster image dumper. 32 * 33 * This program will dump a raster image of the contents of a window into a 34 * file for output on graphics printers or for other uses. 35 * 36 * Author: Tony Della Fera, DEC 37 * 17-Jun-85 38 * 39 * Modification history: 40 * 41 * 11/14/86 Bill Wyatt, Smithsonian Astrophysical Observatory 42 * - Removed Z format option, changing it to an XY option. Monochrome 43 * windows will always dump in XY format. Color windows will dump 44 * in Z format by default, but can be dumped in XY format with the 45 * -xy option. 46 * 47 * 11/18/86 Bill Wyatt 48 * - VERSION 6 is same as version 5 for monchrome. For colors, the 49 * appropriate number of Color structs are dumped after the header, 50 * which has the number of colors (=0 for monochrome) in place of the 51 * V5 padding at the end. Up to 16-bit displays are supported. I 52 * don't yet know how 24- to 32-bit displays will be handled under 53 * the Version 11 protocol. 54 * 55 * 6/15/87 David Krikorian, MIT Project Athena 56 * - VERSION 7 runs under the X Version 11 servers, while the previous 57 * versions of xwd were are for X Version 10. This version is based 58 * on xwd version 6, and should eventually have the same color 59 * abilities. (Xwd V7 has yet to be tested on a color machine, so 60 * all color-related code is commented out until color support 61 * becomes practical.) 62 */ 63 64/*% 65 *% This is the format for commenting out color-related code until 66 *% color can be supported. 67%*/ 68 69#include <stdio.h> 70#include <errno.h> 71#include <X11/Xos.h> 72#include <stdlib.h> 73 74#include <X11/Xlib.h> 75#include <X11/Xutil.h> 76 77#include <X11/Xmu/WinUtil.h> 78typedef unsigned long Pixel; 79#include "X11/XWDFile.h" 80 81#define FEEP_VOLUME 0 82 83/* Include routines to do parsing */ 84#include "dsimple.h" 85#include "list.h" 86#include "wsutils.h" 87#include "multiVis.h" 88 89#ifdef XKB 90#include <X11/extensions/XKBbells.h> 91#endif 92 93/* Setable Options */ 94 95int format = ZPixmap; 96Bool nobdrs = False; 97Bool on_root = False; 98Bool standard_out = True; 99Bool debug = False; 100Bool silent = False; 101Bool use_installed = False; 102long add_pixel_value = 0; 103 104 105extern int main(int, char **); 106extern void Window_Dump(Window, FILE *); 107extern int Image_Size(XImage *); 108extern int Get_XColors(XWindowAttributes *, XColor **); 109extern void _swapshort(register char *, register unsigned); 110extern void _swaplong(register char *, register unsigned); 111static long parse_long(char *); 112static int Get24bitDirectColors(XColor **); 113static int ReadColors(Visual *, Colormap, XColor **); 114 115 116static long parse_long (s) 117 char *s; 118{ 119 char *fmt = "%lu"; 120 long retval = 0L; 121 int thesign = 1; 122 123 if (s && s[0]) { 124 if (s[0] == '-') s++, thesign = -1; 125 if (s[0] == '0') s++, fmt = "%lo"; 126 if (s[0] == 'x' || s[0] == 'X') s++, fmt = "%lx"; 127 (void) sscanf (s, fmt, &retval); 128 } 129 return (thesign * retval); 130} 131 132int 133main(argc, argv) 134 int argc; 135 char **argv; 136{ 137 register int i; 138 Window target_win; 139 FILE *out_file = stdout; 140 Bool frame_only = False; 141 142 INIT_NAME; 143 144 Setup_Display_And_Screen(&argc, argv); 145 146 /* Get window select on command line, if any */ 147 target_win = Select_Window_Args(&argc, argv); 148 149 for (i = 1; i < argc; i++) { 150 if (!strcmp(argv[i], "-nobdrs")) { 151 nobdrs = True; 152 continue; 153 } 154 if (!strcmp(argv[i], "-debug")) { 155 debug = True; 156 continue; 157 } 158 if (!strcmp(argv[i], "-help")) 159 usage(); 160 if (!strcmp(argv[i], "-out")) { 161 if (++i >= argc) usage(); 162 if (!(out_file = fopen(argv[i], "wb"))) 163 Fatal_Error("Can't open output file as specified."); 164 standard_out = False; 165 continue; 166 } 167 if (!strcmp(argv[i], "-xy")) { 168 format = XYPixmap; 169 continue; 170 } 171 if (!strcmp(argv[i], "-screen")) { 172 on_root = True; 173 continue; 174 } 175 if (!strcmp(argv[i], "-icmap")) { 176 use_installed = True; 177 continue; 178 } 179 if (!strcmp(argv[i], "-add")) { 180 if (++i >= argc) usage(); 181 add_pixel_value = parse_long (argv[i]); 182 continue; 183 } 184 if (!strcmp(argv[i], "-frame")) { 185 frame_only = True; 186 continue; 187 } 188 if (!strcmp(argv[i], "-silent")) { 189 silent = True; 190 continue; 191 } 192 usage(); 193 } 194#ifdef WIN32 195 if (standard_out) 196 _setmode(fileno(out_file), _O_BINARY); 197#endif 198 199 /* 200 * Let the user select the target window. 201 */ 202 if (!target_win) { 203 target_win = Select_Window(dpy); 204 } 205 206 if (target_win != None && !frame_only) { 207 Window root; 208 int dummyi; 209 unsigned int dummy; 210 211 if (XGetGeometry (dpy, target_win, &root, &dummyi, &dummyi, 212 &dummy, &dummy, &dummy, &dummy) && 213 target_win != root) { 214 target_win = XmuClientWindow (dpy, target_win); 215 } 216 } 217 218 219 /* 220 * Dump it! 221 */ 222 Window_Dump(target_win, out_file); 223 224 XCloseDisplay(dpy); 225 if (fclose(out_file)) { 226 perror("xwd"); 227 exit(1); 228 } 229 exit(0); 230} 231 232static int 233Get24bitDirectColors(colors) 234XColor **colors ; 235{ 236 int i , ncolors = 256 ; 237 XColor *tcol ; 238 239 *colors = tcol = (XColor *)malloc(sizeof(XColor) * ncolors) ; 240 241 for(i=0 ; i < ncolors ; i++) 242 { 243 tcol[i].pixel = i << 16 | i << 8 | i ; 244 tcol[i].red = tcol[i].green = tcol[i].blue = i << 8 | i ; 245 } 246 247 return ncolors ; 248} 249 250 251/* 252 * Window_Dump: dump a window to a file which must already be open for 253 * writting. 254 */ 255 256void 257Window_Dump(window, out) 258 Window window; 259 FILE *out; 260{ 261 unsigned long swaptest = 1; 262 XColor *colors; 263 unsigned buffer_size; 264 int win_name_size; 265 int header_size; 266 int ncolors, i; 267 char *win_name; 268 Bool got_win_name; 269 XWindowAttributes win_info; 270 XImage *image; 271 int absx, absy, x, y; 272 unsigned width, height; 273 int dwidth, dheight; 274 int bw; 275 Window dummywin; 276 XWDFileHeader header; 277 XWDColor xwdcolor; 278 279 int transparentOverlays , multiVis; 280 int numVisuals; 281 XVisualInfo *pVisuals; 282 int numOverlayVisuals; 283 OverlayInfo *pOverlayVisuals; 284 int numImageVisuals; 285 XVisualInfo **pImageVisuals; 286 list_ptr vis_regions; /* list of regions to read from */ 287 list_ptr vis_image_regions ; 288 Visual vis_h,*vis ; 289 int allImage = 0 ; 290 291 /* 292 * Inform the user not to alter the screen. 293 */ 294 if (!silent) { 295#ifdef XKB 296 XkbStdBell(dpy,None,50,XkbBI_Wait); 297#else 298 XBell(dpy,FEEP_VOLUME); 299#endif 300 XFlush(dpy); 301 } 302 303 /* 304 * Get the parameters of the window being dumped. 305 */ 306 if (debug) outl("xwd: Getting target window information.\n"); 307 if(!XGetWindowAttributes(dpy, window, &win_info)) 308 Fatal_Error("Can't get target window attributes."); 309 310 /* handle any frame window */ 311 if (!XTranslateCoordinates (dpy, window, RootWindow (dpy, screen), 0, 0, 312 &absx, &absy, &dummywin)) { 313 fprintf (stderr, 314 "%s: unable to translate window coordinates (%d,%d)\n", 315 program_name, absx, absy); 316 exit (1); 317 } 318 win_info.x = absx; 319 win_info.y = absy; 320 width = win_info.width; 321 height = win_info.height; 322 bw = 0; 323 324 if (!nobdrs) { 325 absx -= win_info.border_width; 326 absy -= win_info.border_width; 327 bw = win_info.border_width; 328 width += (2 * bw); 329 height += (2 * bw); 330 } 331 dwidth = DisplayWidth (dpy, screen); 332 dheight = DisplayHeight (dpy, screen); 333 334 335 /* clip to window */ 336 if (absx < 0) width += absx, absx = 0; 337 if (absy < 0) height += absy, absy = 0; 338 if (absx + width > dwidth) width = dwidth - absx; 339 if (absy + height > dheight) height = dheight - absy; 340 341 XFetchName(dpy, window, &win_name); 342 if (!win_name || !win_name[0]) { 343 win_name = "xwdump"; 344 got_win_name = False; 345 } else { 346 got_win_name = True; 347 } 348 349 /* sizeof(char) is included for the null string terminator. */ 350 win_name_size = strlen(win_name) + sizeof(char); 351 352 /* 353 * Snarf the pixmap with XGetImage. 354 */ 355 356 x = absx - win_info.x; 357 y = absy - win_info.y; 358 359 multiVis = GetMultiVisualRegions(dpy,RootWindow(dpy, screen), 360 absx, absy, 361 width, height,&transparentOverlays,&numVisuals, &pVisuals, 362 &numOverlayVisuals,&pOverlayVisuals,&numImageVisuals, 363 &pImageVisuals,&vis_regions,&vis_image_regions,&allImage) ; 364 if (on_root || multiVis) 365 { 366 if(!multiVis) 367 image = XGetImage (dpy, RootWindow(dpy, screen), absx, absy, 368 width, height, AllPlanes, format); 369 else 370 image = ReadAreaToImage(dpy, RootWindow(dpy, screen), absx, absy, 371 width, height, 372 numVisuals,pVisuals,numOverlayVisuals,pOverlayVisuals, 373 numImageVisuals, pImageVisuals,vis_regions, 374 vis_image_regions,format,allImage); 375 } 376 else 377 image = XGetImage (dpy, window, x, y, width, height, AllPlanes, format); 378 if (!image) { 379 fprintf (stderr, "%s: unable to get image at %dx%d+%d+%d\n", 380 program_name, width, height, x, y); 381 exit (1); 382 } 383 384 if (add_pixel_value != 0) XAddPixel (image, add_pixel_value); 385 386 /* 387 * Determine the pixmap size. 388 */ 389 buffer_size = Image_Size(image); 390 391 if (debug) outl("xwd: Getting Colors.\n"); 392 393 if( !multiVis) 394 { 395 ncolors = Get_XColors(&win_info, &colors); 396 vis = win_info.visual ; 397 } 398 else 399 { 400 ncolors = Get24bitDirectColors(&colors) ; 401 initFakeVisual(&vis_h) ; 402 vis = &vis_h ; 403 } 404 /* 405 * Inform the user that the image has been retrieved. 406 */ 407 if (!silent) { 408#ifdef XKB 409 XkbStdBell(dpy,window,FEEP_VOLUME,XkbBI_Proceed); 410 XkbStdBell(dpy,window,FEEP_VOLUME,XkbBI_RepeatingLastBell); 411#else 412 XBell(dpy, FEEP_VOLUME); 413 XBell(dpy, FEEP_VOLUME); 414#endif 415 XFlush(dpy); 416 } 417 418 /* 419 * Calculate header size. 420 */ 421 if (debug) outl("xwd: Calculating header size.\n"); 422 header_size = SIZEOF(XWDheader) + win_name_size; 423 424 /* 425 * Write out header information. 426 */ 427 if (debug) outl("xwd: Constructing and dumping file header.\n"); 428 header.header_size = (CARD32) header_size; 429 header.file_version = (CARD32) XWD_FILE_VERSION; 430 header.pixmap_format = (CARD32) format; 431 header.pixmap_depth = (CARD32) image->depth; 432 header.pixmap_width = (CARD32) image->width; 433 header.pixmap_height = (CARD32) image->height; 434 header.xoffset = (CARD32) image->xoffset; 435 header.byte_order = (CARD32) image->byte_order; 436 header.bitmap_unit = (CARD32) image->bitmap_unit; 437 header.bitmap_bit_order = (CARD32) image->bitmap_bit_order; 438 header.bitmap_pad = (CARD32) image->bitmap_pad; 439 header.bits_per_pixel = (CARD32) image->bits_per_pixel; 440 header.bytes_per_line = (CARD32) image->bytes_per_line; 441 /**** 442 header.visual_class = (CARD32) win_info.visual->class; 443 header.red_mask = (CARD32) win_info.visual->red_mask; 444 header.green_mask = (CARD32) win_info.visual->green_mask; 445 header.blue_mask = (CARD32) win_info.visual->blue_mask; 446 header.bits_per_rgb = (CARD32) win_info.visual->bits_per_rgb; 447 header.colormap_entries = (CARD32) win_info.visual->map_entries; 448 *****/ 449 header.visual_class = (CARD32) vis->class; 450 header.red_mask = (CARD32) vis->red_mask; 451 header.green_mask = (CARD32) vis->green_mask; 452 header.blue_mask = (CARD32) vis->blue_mask; 453 header.bits_per_rgb = (CARD32) vis->bits_per_rgb; 454 header.colormap_entries = (CARD32) vis->map_entries; 455 456 header.ncolors = ncolors; 457 header.window_width = (CARD32) win_info.width; 458 header.window_height = (CARD32) win_info.height; 459 header.window_x = absx; 460 header.window_y = absy; 461 header.window_bdrwidth = (CARD32) win_info.border_width; 462 463 if (*(char *) &swaptest) { 464 _swaplong((char *) &header, sizeof(header)); 465 for (i = 0; i < ncolors; i++) { 466 _swaplong((char *) &colors[i].pixel, sizeof(CARD32)); 467 _swapshort((char *) &colors[i].red, 3 * sizeof(short)); 468 } 469 } 470 471 if (fwrite((char *)&header, SIZEOF(XWDheader), 1, out) != 1 || 472 fwrite(win_name, win_name_size, 1, out) != 1) { 473 perror("xwd"); 474 exit(1); 475 } 476 477 /* 478 * Write out the color maps, if any 479 */ 480 481 if (debug) outl("xwd: Dumping %d colors.\n", ncolors); 482 for (i = 0; i < ncolors; i++) { 483 xwdcolor.pixel = colors[i].pixel; 484 xwdcolor.red = colors[i].red; 485 xwdcolor.green = colors[i].green; 486 xwdcolor.blue = colors[i].blue; 487 xwdcolor.flags = colors[i].flags; 488 if (fwrite((char *) &xwdcolor, SIZEOF(XWDColor), 1, out) != 1) { 489 perror("xwd"); 490 exit(1); 491 } 492 } 493 494 /* 495 * Write out the buffer. 496 */ 497 if (debug) outl("xwd: Dumping pixmap. bufsize=%d\n",buffer_size); 498 499 /* 500 * This copying of the bit stream (data) to a file is to be replaced 501 * by an Xlib call which hasn't been written yet. It is not clear 502 * what other functions of xwd will be taken over by this (as yet) 503 * non-existant X function. 504 */ 505 if (fwrite(image->data, (int) buffer_size, 1, out) != 1) { 506 perror("xwd"); 507 exit(1); 508 } 509 510 /* 511 * free the color buffer. 512 */ 513 514 if(debug && ncolors > 0) outl("xwd: Freeing colors.\n"); 515 if(ncolors > 0) free(colors); 516 517 /* 518 * Free window name string. 519 */ 520 if (debug) outl("xwd: Freeing window name string.\n"); 521 if (got_win_name) XFree(win_name); 522 523 /* 524 * Free image 525 */ 526 XDestroyImage(image); 527} 528 529/* 530 * Report the syntax for calling xwd. 531 */ 532void 533usage() 534{ 535 fprintf (stderr, 536"usage: %s [-display host:dpy] [-debug] [-help] %s [-nobdrs] [-out <file>]", 537 program_name, "[{-root|-id <id>|-name <name>}]"); 538 fprintf (stderr, " [-xy] [-add value] [-frame]\n"); 539 exit(1); 540} 541 542 543/* 544 * Determine the pixmap size. 545 */ 546 547int Image_Size(image) 548 XImage *image; 549{ 550 if (image->format != ZPixmap) 551 return(image->bytes_per_line * image->height * image->depth); 552 553 return(image->bytes_per_line * image->height); 554} 555 556#define lowbit(x) ((x) & (~(x) + 1)) 557 558static int 559ReadColors(vis,cmap,colors) 560Visual *vis ; 561Colormap cmap ; 562XColor **colors ; 563{ 564 int i,ncolors ; 565 566 ncolors = vis->map_entries; 567 568 if (!(*colors = (XColor *) malloc (sizeof(XColor) * ncolors))) 569 Fatal_Error("Out of memory!"); 570 571 if (vis->class == DirectColor || 572 vis->class == TrueColor) { 573 Pixel red, green, blue, red1, green1, blue1; 574 575 red = green = blue = 0; 576 red1 = lowbit(vis->red_mask); 577 green1 = lowbit(vis->green_mask); 578 blue1 = lowbit(vis->blue_mask); 579 for (i=0; i<ncolors; i++) { 580 (*colors)[i].pixel = red|green|blue; 581 (*colors)[i].pad = 0; 582 red += red1; 583 if (red > vis->red_mask) 584 red = 0; 585 green += green1; 586 if (green > vis->green_mask) 587 green = 0; 588 blue += blue1; 589 if (blue > vis->blue_mask) 590 blue = 0; 591 } 592 } else { 593 for (i=0; i<ncolors; i++) { 594 (*colors)[i].pixel = i; 595 (*colors)[i].pad = 0; 596 } 597 } 598 599 XQueryColors(dpy, cmap, *colors, ncolors); 600 601 return(ncolors); 602} 603 604/* 605 * Get the XColors of all pixels in image - returns # of colors 606 */ 607int Get_XColors(win_info, colors) 608 XWindowAttributes *win_info; 609 XColor **colors; 610{ 611 int i, ncolors; 612 Colormap cmap = win_info->colormap; 613 614 if (use_installed) 615 /* assume the visual will be OK ... */ 616 cmap = XListInstalledColormaps(dpy, win_info->root, &i)[0]; 617 if (!cmap) 618 return(0); 619 ncolors = ReadColors(win_info->visual,cmap,colors) ; 620 return ncolors ; 621} 622 623void 624_swapshort (bp, n) 625 register char *bp; 626 register unsigned n; 627{ 628 register char c; 629 register char *ep = bp + n; 630 631 while (bp < ep) { 632 c = *bp; 633 *bp = *(bp + 1); 634 bp++; 635 *bp++ = c; 636 } 637} 638 639void 640_swaplong (bp, n) 641 register char *bp; 642 register unsigned n; 643{ 644 register char c; 645 register char *ep = bp + n; 646 647 while (bp < ep) { 648 c = bp[3]; 649 bp[3] = bp[0]; 650 bp[0] = c; 651 c = bp[2]; 652 bp[2] = bp[1]; 653 bp[1] = c; 654 bp += 4; 655 } 656} 657