xwd.c revision afe13c8e
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 77typedef unsigned long Pixel; 78#include "X11/XWDFile.h" 79 80#define FEEP_VOLUME 0 81 82/* Include routines to do parsing */ 83#include "dsimple.h" 84#include "list.h" 85#include "wsutils.h" 86#include "multiVis.h" 87 88#ifdef XKB 89#include <X11/extensions/XKBbells.h> 90#endif 91 92/* Setable Options */ 93 94int format = ZPixmap; 95Bool nobdrs = False; 96Bool on_root = False; 97Bool standard_out = True; 98Bool debug = False; 99Bool silent = False; 100Bool use_installed = False; 101long add_pixel_value = 0; 102 103 104extern int main(int, char **); 105extern void Window_Dump(Window, FILE *); 106extern int Image_Size(XImage *); 107extern int Get_XColors(XWindowAttributes *, XColor **); 108extern void _swapshort(register char *, register unsigned); 109extern void _swaplong(register char *, register unsigned); 110static long parse_long(char *); 111static int Get24bitDirectColors(XColor **); 112static int ReadColors(Visual *, Colormap, XColor **); 113 114 115static long parse_long (s) 116 char *s; 117{ 118 char *fmt = "%lu"; 119 long retval = 0L; 120 int thesign = 1; 121 122 if (s && s[0]) { 123 if (s[0] == '-') s++, thesign = -1; 124 if (s[0] == '0') s++, fmt = "%lo"; 125 if (s[0] == 'x' || s[0] == 'X') s++, fmt = "%lx"; 126 (void) sscanf (s, fmt, &retval); 127 } 128 return (thesign * retval); 129} 130 131int 132main(argc, argv) 133 int argc; 134 char **argv; 135{ 136 register int i; 137 Window target_win; 138 FILE *out_file = stdout; 139 Bool frame_only = False; 140 141 INIT_NAME; 142 143 Setup_Display_And_Screen(&argc, argv); 144 145 /* Get window select on command line, if any */ 146 target_win = Select_Window_Args(&argc, argv); 147 148 for (i = 1; i < argc; i++) { 149 if (!strcmp(argv[i], "-nobdrs")) { 150 nobdrs = True; 151 continue; 152 } 153 if (!strcmp(argv[i], "-debug")) { 154 debug = True; 155 continue; 156 } 157 if (!strcmp(argv[i], "-help")) 158 usage(); 159 if (!strcmp(argv[i], "-out")) { 160 if (++i >= argc) usage(); 161 if (!(out_file = fopen(argv[i], "wb"))) 162 Fatal_Error("Can't open output file as specified."); 163 standard_out = False; 164 continue; 165 } 166 if (!strcmp(argv[i], "-xy")) { 167 format = XYPixmap; 168 continue; 169 } 170 if (!strcmp(argv[i], "-screen")) { 171 on_root = True; 172 continue; 173 } 174 if (!strcmp(argv[i], "-icmap")) { 175 use_installed = True; 176 continue; 177 } 178 if (!strcmp(argv[i], "-add")) { 179 if (++i >= argc) usage(); 180 add_pixel_value = parse_long (argv[i]); 181 continue; 182 } 183 if (!strcmp(argv[i], "-frame")) { 184 frame_only = True; 185 continue; 186 } 187 if (!strcmp(argv[i], "-silent")) { 188 silent = True; 189 continue; 190 } 191 usage(); 192 } 193#ifdef WIN32 194 if (standard_out) 195 _setmode(fileno(out_file), _O_BINARY); 196#endif 197 198 /* 199 * Let the user select the target window. 200 */ 201 if (target_win == None) 202 target_win = Select_Window(dpy, !frame_only); 203 204 /* 205 * Dump it! 206 */ 207 Window_Dump(target_win, out_file); 208 209 XCloseDisplay(dpy); 210 if (fclose(out_file)) { 211 perror("xwd"); 212 exit(1); 213 } 214 exit(0); 215} 216 217static int 218Get24bitDirectColors(colors) 219XColor **colors ; 220{ 221 int i , ncolors = 256 ; 222 XColor *tcol ; 223 224 *colors = tcol = (XColor *)malloc(sizeof(XColor) * ncolors) ; 225 226 for(i=0 ; i < ncolors ; i++) 227 { 228 tcol[i].pixel = i << 16 | i << 8 | i ; 229 tcol[i].red = tcol[i].green = tcol[i].blue = i << 8 | i ; 230 } 231 232 return ncolors ; 233} 234 235 236/* 237 * Window_Dump: dump a window to a file which must already be open for 238 * writting. 239 */ 240 241void 242Window_Dump(window, out) 243 Window window; 244 FILE *out; 245{ 246 unsigned long swaptest = 1; 247 XColor *colors; 248 unsigned buffer_size; 249 int win_name_size; 250 int header_size; 251 int ncolors, i; 252 char *win_name; 253 Bool got_win_name; 254 XWindowAttributes win_info; 255 XImage *image; 256 int absx, absy, x, y; 257 unsigned width, height; 258 int dwidth, dheight; 259 int bw; 260 Window dummywin; 261 XWDFileHeader header; 262 XWDColor xwdcolor; 263 264 int transparentOverlays , multiVis; 265 int numVisuals; 266 XVisualInfo *pVisuals; 267 int numOverlayVisuals; 268 OverlayInfo *pOverlayVisuals; 269 int numImageVisuals; 270 XVisualInfo **pImageVisuals; 271 list_ptr vis_regions; /* list of regions to read from */ 272 list_ptr vis_image_regions ; 273 Visual vis_h,*vis ; 274 int allImage = 0 ; 275 276 /* 277 * Inform the user not to alter the screen. 278 */ 279 if (!silent) { 280#ifdef XKB 281 XkbStdBell(dpy,None,50,XkbBI_Wait); 282#else 283 XBell(dpy,FEEP_VOLUME); 284#endif 285 XFlush(dpy); 286 } 287 288 /* 289 * Get the parameters of the window being dumped. 290 */ 291 if (debug) outl("xwd: Getting target window information.\n"); 292 if(!XGetWindowAttributes(dpy, window, &win_info)) 293 Fatal_Error("Can't get target window attributes."); 294 295 /* handle any frame window */ 296 if (!XTranslateCoordinates (dpy, window, RootWindow (dpy, screen), 0, 0, 297 &absx, &absy, &dummywin)) { 298 fprintf (stderr, 299 "%s: unable to translate window coordinates (%d,%d)\n", 300 program_name, absx, absy); 301 exit (1); 302 } 303 win_info.x = absx; 304 win_info.y = absy; 305 width = win_info.width; 306 height = win_info.height; 307 bw = 0; 308 309 if (!nobdrs) { 310 absx -= win_info.border_width; 311 absy -= win_info.border_width; 312 bw = win_info.border_width; 313 width += (2 * bw); 314 height += (2 * bw); 315 } 316 dwidth = DisplayWidth (dpy, screen); 317 dheight = DisplayHeight (dpy, screen); 318 319 320 /* clip to window */ 321 if (absx < 0) width += absx, absx = 0; 322 if (absy < 0) height += absy, absy = 0; 323 if (absx + width > dwidth) width = dwidth - absx; 324 if (absy + height > dheight) height = dheight - absy; 325 326 XFetchName(dpy, window, &win_name); 327 if (!win_name || !win_name[0]) { 328 win_name = "xwdump"; 329 got_win_name = False; 330 } else { 331 got_win_name = True; 332 } 333 334 /* sizeof(char) is included for the null string terminator. */ 335 win_name_size = strlen(win_name) + sizeof(char); 336 337 /* 338 * Snarf the pixmap with XGetImage. 339 */ 340 341 x = absx - win_info.x; 342 y = absy - win_info.y; 343 344 multiVis = GetMultiVisualRegions(dpy,RootWindow(dpy, screen), 345 absx, absy, 346 width, height,&transparentOverlays,&numVisuals, &pVisuals, 347 &numOverlayVisuals,&pOverlayVisuals,&numImageVisuals, 348 &pImageVisuals,&vis_regions,&vis_image_regions,&allImage) ; 349 if (on_root || multiVis) 350 { 351 if(!multiVis) 352 image = XGetImage (dpy, RootWindow(dpy, screen), absx, absy, 353 width, height, AllPlanes, format); 354 else 355 image = ReadAreaToImage(dpy, RootWindow(dpy, screen), absx, absy, 356 width, height, 357 numVisuals,pVisuals,numOverlayVisuals,pOverlayVisuals, 358 numImageVisuals, pImageVisuals,vis_regions, 359 vis_image_regions,format,allImage); 360 } 361 else 362 image = XGetImage (dpy, window, x, y, width, height, AllPlanes, format); 363 if (!image) { 364 fprintf (stderr, "%s: unable to get image at %dx%d+%d+%d\n", 365 program_name, width, height, x, y); 366 exit (1); 367 } 368 369 if (add_pixel_value != 0) XAddPixel (image, add_pixel_value); 370 371 /* 372 * Determine the pixmap size. 373 */ 374 buffer_size = Image_Size(image); 375 376 if (debug) outl("xwd: Getting Colors.\n"); 377 378 if( !multiVis) 379 { 380 ncolors = Get_XColors(&win_info, &colors); 381 vis = win_info.visual ; 382 } 383 else 384 { 385 ncolors = Get24bitDirectColors(&colors) ; 386 initFakeVisual(&vis_h) ; 387 vis = &vis_h ; 388 } 389 /* 390 * Inform the user that the image has been retrieved. 391 */ 392 if (!silent) { 393#ifdef XKB 394 XkbStdBell(dpy,window,FEEP_VOLUME,XkbBI_Proceed); 395 XkbStdBell(dpy,window,FEEP_VOLUME,XkbBI_RepeatingLastBell); 396#else 397 XBell(dpy, FEEP_VOLUME); 398 XBell(dpy, FEEP_VOLUME); 399#endif 400 XFlush(dpy); 401 } 402 403 /* 404 * Calculate header size. 405 */ 406 if (debug) outl("xwd: Calculating header size.\n"); 407 header_size = SIZEOF(XWDheader) + win_name_size; 408 409 /* 410 * Write out header information. 411 */ 412 if (debug) outl("xwd: Constructing and dumping file header.\n"); 413 header.header_size = (CARD32) header_size; 414 header.file_version = (CARD32) XWD_FILE_VERSION; 415 header.pixmap_format = (CARD32) format; 416 header.pixmap_depth = (CARD32) image->depth; 417 header.pixmap_width = (CARD32) image->width; 418 header.pixmap_height = (CARD32) image->height; 419 header.xoffset = (CARD32) image->xoffset; 420 header.byte_order = (CARD32) image->byte_order; 421 header.bitmap_unit = (CARD32) image->bitmap_unit; 422 header.bitmap_bit_order = (CARD32) image->bitmap_bit_order; 423 header.bitmap_pad = (CARD32) image->bitmap_pad; 424 header.bits_per_pixel = (CARD32) image->bits_per_pixel; 425 header.bytes_per_line = (CARD32) image->bytes_per_line; 426 /**** 427 header.visual_class = (CARD32) win_info.visual->class; 428 header.red_mask = (CARD32) win_info.visual->red_mask; 429 header.green_mask = (CARD32) win_info.visual->green_mask; 430 header.blue_mask = (CARD32) win_info.visual->blue_mask; 431 header.bits_per_rgb = (CARD32) win_info.visual->bits_per_rgb; 432 header.colormap_entries = (CARD32) win_info.visual->map_entries; 433 *****/ 434 header.visual_class = (CARD32) vis->class; 435 header.red_mask = (CARD32) vis->red_mask; 436 header.green_mask = (CARD32) vis->green_mask; 437 header.blue_mask = (CARD32) vis->blue_mask; 438 header.bits_per_rgb = (CARD32) vis->bits_per_rgb; 439 header.colormap_entries = (CARD32) vis->map_entries; 440 441 header.ncolors = ncolors; 442 header.window_width = (CARD32) win_info.width; 443 header.window_height = (CARD32) win_info.height; 444 header.window_x = absx; 445 header.window_y = absy; 446 header.window_bdrwidth = (CARD32) win_info.border_width; 447 448 if (*(char *) &swaptest) { 449 _swaplong((char *) &header, sizeof(header)); 450 for (i = 0; i < ncolors; i++) { 451 _swaplong((char *) &colors[i].pixel, sizeof(CARD32)); 452 _swapshort((char *) &colors[i].red, 3 * sizeof(short)); 453 } 454 } 455 456 if (fwrite((char *)&header, SIZEOF(XWDheader), 1, out) != 1 || 457 fwrite(win_name, win_name_size, 1, out) != 1) { 458 perror("xwd"); 459 exit(1); 460 } 461 462 /* 463 * Write out the color maps, if any 464 */ 465 466 if (debug) outl("xwd: Dumping %d colors.\n", ncolors); 467 for (i = 0; i < ncolors; i++) { 468 xwdcolor.pixel = colors[i].pixel; 469 xwdcolor.red = colors[i].red; 470 xwdcolor.green = colors[i].green; 471 xwdcolor.blue = colors[i].blue; 472 xwdcolor.flags = colors[i].flags; 473 if (fwrite((char *) &xwdcolor, SIZEOF(XWDColor), 1, out) != 1) { 474 perror("xwd"); 475 exit(1); 476 } 477 } 478 479 /* 480 * Write out the buffer. 481 */ 482 if (debug) outl("xwd: Dumping pixmap. bufsize=%d\n",buffer_size); 483 484 /* 485 * This copying of the bit stream (data) to a file is to be replaced 486 * by an Xlib call which hasn't been written yet. It is not clear 487 * what other functions of xwd will be taken over by this (as yet) 488 * non-existant X function. 489 */ 490 if (fwrite(image->data, (int) buffer_size, 1, out) != 1) { 491 perror("xwd"); 492 exit(1); 493 } 494 495 /* 496 * free the color buffer. 497 */ 498 499 if(debug && ncolors > 0) outl("xwd: Freeing colors.\n"); 500 if(ncolors > 0) free(colors); 501 502 /* 503 * Free window name string. 504 */ 505 if (debug) outl("xwd: Freeing window name string.\n"); 506 if (got_win_name) XFree(win_name); 507 508 /* 509 * Free image 510 */ 511 XDestroyImage(image); 512} 513 514/* 515 * Report the syntax for calling xwd. 516 */ 517void 518usage() 519{ 520 fprintf (stderr, 521"usage: %s [-display host:dpy] [-debug] [-help] %s [-nobdrs] [-out <file>]", 522 program_name, "[{-root|-id <id>|-name <name>}]"); 523 fprintf (stderr, " [-xy] [-add value] [-frame]\n"); 524 exit(1); 525} 526 527 528/* 529 * Determine the pixmap size. 530 */ 531 532int Image_Size(image) 533 XImage *image; 534{ 535 if (image->format != ZPixmap) 536 return(image->bytes_per_line * image->height * image->depth); 537 538 return(image->bytes_per_line * image->height); 539} 540 541#define lowbit(x) ((x) & (~(x) + 1)) 542 543static int 544ReadColors(vis,cmap,colors) 545Visual *vis ; 546Colormap cmap ; 547XColor **colors ; 548{ 549 int i,ncolors ; 550 551 ncolors = vis->map_entries; 552 553 if (!(*colors = (XColor *) malloc (sizeof(XColor) * ncolors))) 554 Fatal_Error("Out of memory!"); 555 556 if (vis->class == DirectColor || 557 vis->class == TrueColor) { 558 Pixel red, green, blue, red1, green1, blue1; 559 560 red = green = blue = 0; 561 red1 = lowbit(vis->red_mask); 562 green1 = lowbit(vis->green_mask); 563 blue1 = lowbit(vis->blue_mask); 564 for (i=0; i<ncolors; i++) { 565 (*colors)[i].pixel = red|green|blue; 566 (*colors)[i].pad = 0; 567 red += red1; 568 if (red > vis->red_mask) 569 red = 0; 570 green += green1; 571 if (green > vis->green_mask) 572 green = 0; 573 blue += blue1; 574 if (blue > vis->blue_mask) 575 blue = 0; 576 } 577 } else { 578 for (i=0; i<ncolors; i++) { 579 (*colors)[i].pixel = i; 580 (*colors)[i].pad = 0; 581 } 582 } 583 584 XQueryColors(dpy, cmap, *colors, ncolors); 585 586 return(ncolors); 587} 588 589/* 590 * Get the XColors of all pixels in image - returns # of colors 591 */ 592int Get_XColors(win_info, colors) 593 XWindowAttributes *win_info; 594 XColor **colors; 595{ 596 int i, ncolors; 597 Colormap cmap = win_info->colormap; 598 599 if (use_installed) 600 /* assume the visual will be OK ... */ 601 cmap = XListInstalledColormaps(dpy, win_info->root, &i)[0]; 602 if (!cmap) 603 return(0); 604 ncolors = ReadColors(win_info->visual,cmap,colors) ; 605 return ncolors ; 606} 607 608void 609_swapshort (bp, n) 610 register char *bp; 611 register unsigned n; 612{ 613 register char c; 614 register char *ep = bp + n; 615 616 while (bp < ep) { 617 c = *bp; 618 *bp = *(bp + 1); 619 bp++; 620 *bp++ = c; 621 } 622} 623 624void 625_swaplong (bp, n) 626 register char *bp; 627 register unsigned n; 628{ 629 register char c; 630 register char *ep = bp + n; 631 632 while (bp < ep) { 633 c = bp[3]; 634 bp[3] = bp[0]; 635 bp[0] = c; 636 c = bp[2]; 637 bp[2] = bp[1]; 638 bp[1] = c; 639 bp += 4; 640 } 641} 642