1 /*
2
3 Copyright 1985, 1986, 1988, 1998 The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from 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
46 static Atom wm_protocols;
47 static Atom wm_delete_window;
48 static int split;
49
50 static char *progname;
51
52 static Bool Read(char *ptr, int size, int nitems, FILE *stream);
53 static void putImage(Display *dpy, Window image_win, GC gc,
54 XImage *out_image, int x, int y, int w, int h);
55 static 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);
59 static void Latin1Upper(char *s);
60 static void Extract_Plane(XImage *in_image, XImage *out_image, int plane);
61 static int EffectiveSize(XVisualInfo *vinfo);
62 static int VisualRank(int class);
63 static int IsGray(Display *dpy, XStandardColormap *stdmap);
64 static void Do_StdGray(Display *dpy, XStandardColormap *stdmap, int ncolors,
65 XColor *colors, XImage *in_image, XImage *out_image);
66 static void Do_StdCol(Display *dpy, XStandardColormap *stdmap, int ncolors,
67 XColor *colors, XImage *in_image, XImage *out_image);
68 static Colormap CopyColormapAndFree(Display *dpy, Colormap colormap);
69 static void Do_Pseudo(Display *dpy, Colormap *colormap, int ncolors,
70 XColor *colors, XImage *in_image, XImage *out_image);
71 static void Do_Direct(Display *dpy, XWDFileHeader *header, Colormap *colormap,
72 int ncolors, XColor *colors,
73 XImage *in_image, XImage *out_image, XVisualInfo *vinfo);
74 static unsigned int Image_Size(XImage *image);
75 static void Error(const char *string) _X_NORETURN;
76 static void _swapshort(char *bp, unsigned int n);
77 static void _swaplong(char *bp, unsigned int n);
78 static void DumpHeader(const XWDFileHeader *header, const char *win_name);
79
80 static void _X_NORETURN _X_COLD
usage(const char * errmsg)81 usage(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
96 static Bool
Read(char * ptr,int size,int nitems,FILE * stream)97 Read(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
110 int
main(int argc,char * argv[])111 main(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 < 1)
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
704 static void
putImage(Display * dpy,Window image_win,GC gc,XImage * out_image,int x,int y,int w,int h)705 putImage(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
728 typedef short Position;
729 typedef unsigned short Dimension;
730 typedef unsigned long Pixel;
731
732 #define roundint(x) (int)((x) + 0.5)
733
734 typedef struct {
735 Position *x, *y;
736 Dimension *width, *height;
737 } Table;
738
739 static void
putScaledImage(Display * display,Drawable d,GC gc,XImage * src_image,int exp_x,int exp_y,unsigned int exp_width,unsigned int exp_height,unsigned int dest_width,unsigned dest_height)740 putScaledImage(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
856 static void
Latin1Upper(char * s)857 Latin1Upper(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
873 static void
Extract_Plane(XImage * in_image,XImage * out_image,int plane)874 Extract_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
884 static int
EffectiveSize(XVisualInfo * vinfo)885 EffectiveSize(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
893 static int
VisualRank(int class)894 VisualRank(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
914 static int
IsGray(Display * dpy,XStandardColormap * stdmap)915 IsGray(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
924 static void
Do_StdGray(Display * dpy,XStandardColormap * stdmap,int ncolors,XColor * colors,XImage * in_image,XImage * out_image)925 Do_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
949 static void
Do_StdCol(Display * dpy,XStandardColormap * stdmap,int ncolors,XColor * colors,XImage * in_image,XImage * out_image)950 Do_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
973 static Colormap
CopyColormapAndFree(Display * dpy,Colormap colormap)974 CopyColormapAndFree(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
983 static void
Do_Pseudo(Display * dpy,Colormap * colormap,int ncolors,XColor * colors,XImage * in_image,XImage * out_image)984 Do_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
1007 static void
Do_Direct(Display * dpy,XWDFileHeader * header,Colormap * colormap,int ncolors,XColor * colors,XImage * in_image,XImage * out_image,XVisualInfo * vinfo)1008 Do_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
1152 static unsigned int
Image_Size(XImage * image)1153 Image_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
1161 static void
Error(const char * string)1162 Error(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
1172 static void
_swapshort(char * bp,unsigned int n)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
1186 static void
_swaplong(char * bp,unsigned int n)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
1206 static void
DumpHeader(const XWDFileHeader * header,const char * win_name)1207 DumpHeader(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