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