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