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