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