1 /*
2  * Copyright 1993, 1994 Liverpool University Computer Science Department
3  *
4  * Permission to use, copy, modify, and distribute this software and its
5  * documentation for any purpose and without fee is hereby granted, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of L.U.C.S. not be used in advertising
9  * or publicity pertaining to distribution of the software without specific,
10  * written prior permission. L.U.C.S. makes no representations about the
11  * suitability of this software for any purpose.  It is provided "as is"
12  * without express or implied warranty.
13  *
14  * FILE NAME:	XbrGfx.c
15  * CREATED:	Wed Oct 27 1993
16  * AUTHOR:	Rik Turnbull (rik@csc.liv.ac.uk)
17  * DESCRIPTION:	Routines to support simple graphics operations.
18  *
19  */
20 
21 /*
22  * (c) Copyright 1989, 1990, 1991, 1992 OPEN SOFTWARE FOUNDATION, INC.
23  * ALL RIGHTS RESERVED
24  *
25  * Based strongly on...
26  *
27  * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun raster image.
28  *
29  * Copyright (c) 1988, 1989 by Patrick J. Naughton
30  *
31  * Author: Patrick J. Naughton
32  * naughton@wind.sun.com
33  *
34  * Permission to use, copy, modify, and distribute this software and its
35  * documentation for any purpose and without fee is hereby granted,
36  * provided that the above copyright notice appear in all copies and that
37  * both that copyright notice and this permission notice appear in
38  * supporting documentation.
39  *
40  * This file is provided AS IS with no warranties of any kind.  The author
41  * shall have no liability with respect to the infringement of copyrights,
42  * trade secrets or any patents by this file or any part thereof.  In no
43  * event will the author be liable for any lost revenue or profits or
44  * other special, indirect and consequential damages.
45  *
46  */
47 
48 #include <stdio.h>
49 #include <stdlib.h> /* for free(), malloc() */
50 #include <string.h>
51 #include <math.h>
52 #include <ctype.h>
53 
54 #include <Xm/Xm.h>
55 
56 #include <X11/Intrinsic.h>
57 #include <X11/Xos.h>
58 #include <X11/Xlib.h>
59 #include <X11/Xutil.h>
60 
61 #include "XbrGfx.h"
62 
63 #define	GIF_EXTENSION	0x21
64 #define	GIF_BLOCKEND	0x00
65 #define	GIF_GFXBLOCK	0xf9
66 #define	GIF_TRANSMASK	0x01
67 
68 #define NEXTBYTE (*ptr++)
69 #define IMAGESEP 0x2c
70 #define INTERLACEMASK 0x40
71 #define COLORMAPMASK 0x80
72 
73 /*****************************************************************************/
74 /* VARIABLES required by all procedures.                                     */
75 /*****************************************************************************/
76 static int XC = 0, YC = 0,	/* Output X and Y coords of current pixel    */
77            Height, Width,       /* Image dimensions                          */
78            BytesPerScanline,    /* Bytes per scanline in output raster       */
79            numused,             /* Colours already used                      */
80            Pass = 0,            /* Used by output routine if interlaced pic  */
81            Interlace,		/* Interlaced image?                         */
82            HasColormap,		/* Global colormap?                          */
83            numcols, strip = 0,  /* Number of colours, Strip colour?          */
84            nostrip = 0,		/* Don't strip colours?                      */
85            alloc = 0;		/* Number of colours allocated               */
86 static unsigned char used[256], /* Colour already used?                      */
87            Red[256],            /* REDs from GIF header                      */
88            Green[256],          /* GREENs from GIF header                    */
89            Blue[256];           /* BLUEs from GIF header                     */
90 unsigned long alloced[256],	/* Allocated colour cells                    */
91            cols[256];           /* Actual colours used                       */
92 XColor defs[256];		/* Colours as XColor types                   */
93 
94 /*****************************************************************************/
95 /* FUNCTION declarations.                                                    */
96 /*****************************************************************************/
97 Pixmap XbrGfxLoadPixmap(Widget, char *, int, int);
98 XBR_IMAGE *XbrGfxGIF(Display *, unsigned char *, int, int, XColor *, char **);
99 static int XbrGfxGetColours(Display *, Colormap , int, unsigned char *, XColor *, int, int);
100 static int XbrGfxReadCode(int *, unsigned char *, int, int);
101 static void XbrGfxAddtoPixel(unsigned char, unsigned char *);
102 Pixmap XbrGfxReadBitmap(Display *, Screen *, GC, char *, int, int);
103 Pixmap XbrGfxLoadBitmap(Widget, char *, int, int, int);
104 unsigned long XbrGfxBestColour(Display *, Colormap, XColor *, int);
105 void XbrGfxBWPixels(Display *, Screen *, Colormap, XColor *, XColor *);
106 unsigned char *XbrGfxParseXBMData(char *, unsigned int *, unsigned int *);
107 unsigned char *XbrGfxXBMtoRaw(unsigned char *, unsigned int, unsigned int);
108 Pixmap XbrGfxSetPixmap(Widget, char *, int, int);
109 void XbrGfxShadow(Widget);
110 
111 /* XbrGfxLoadPixmap:**********************************************************/
112 /* XbrGfxLoadPixmap: Given a bitmap definition and a widget, create a pixmap */
113 /* XbrGfxLoadPixmap: and build the image in the widget.                      */
114 /* XbrGfxLoadPixmap:**********************************************************/
115 
XbrGfxLoadPixmap(Widget w,char * bits,int width,int height)116 Pixmap XbrGfxLoadPixmap(Widget w, char *bits, int width, int height)
117 {
118     XGCValues vals;
119     Pixmap pixmap;
120     GC gc;
121     Display *display = XtDisplay(w);
122     Screen *screen = XtScreen(w);
123     Window root = RootWindowOfScreen(screen);
124 
125     /* Create a GC for drawing the pixmap */
126     XtVaGetValues(w, XmNforeground, &vals.foreground,
127                      XmNbackground, &vals.background,
128                      NULL);
129     gc = XCreateGC(display, root, GCForeground|GCBackground, &vals);
130 
131     /* Change the bitmap to a pixmap */
132     pixmap = XbrGfxReadBitmap(display, screen, gc, bits, width, height);
133 
134     /* Display it */
135     XtVaSetValues(w, XmNlabelType, XmPIXMAP, XmNlabelPixmap, pixmap, NULL);
136 
137     /* Free GC we have finished with */
138     XFreeGC(display, gc);
139 
140     /* OK. */
141     return(pixmap);
142 }
143 
144 /* XbrGfxReadBitmap:**********************************************************/
145 /* XbrGfxReadBitmap: Convert a single plane bitmap to a pixmap.              */
146 /* XbrGfxReadBitmap:**********************************************************/
147 
XbrGfxReadBitmap(Display * display,Screen * screen,GC gc,char * bits,int width,int height)148 Pixmap XbrGfxReadBitmap(Display *display, Screen *screen, GC gc, char *bits,
149                         int width, int height)
150 {
151     Pixmap bitmap, pixmap;
152 
153     /* Create a bitmap from the bits passed in */
154     bitmap = XCreateBitmapFromData(display, RootWindowOfScreen(screen), bits,
155       width, height);
156 
157     /* Create a pixmap with the same dimensions */
158     pixmap = XCreatePixmap(display, RootWindowOfScreen(screen), width, height,
159       DefaultDepthOfScreen(screen));
160 
161     /* Copy the bitmap onto the first plane of the pixmap */
162     XCopyPlane(display, bitmap, pixmap, gc, 0, 0, width, height, 0, 0, 1);
163 
164     /* Finished with the bitmap */
165     XFreePixmap(display, bitmap);
166 
167     /* Done. */
168     return(pixmap);
169 }
170 
171 /* XbrGfxLoadBitmap:**********************************************************/
172 /* XbrGfxLoadBitmap: Use the widget passed in to create a GC, then read in   */
173 /* XbrGfxLoadBitmap: the bitmap.                                             */
174 /* XbrGfxLoadBitmap:**********************************************************/
175 
XbrGfxLoadBitmap(Widget w,char * bits,int width,int height,int inherit)176 Pixmap XbrGfxLoadBitmap(Widget w, char *bits, int width, int height, int inherit)
177 {
178     XGCValues vals;
179     Pixmap pixmap;
180     GC gc;
181     Display *display = XtDisplay(w);
182     Screen *screen = XtScreen(w);
183     Window root = RootWindowOfScreen(screen);
184 
185     /* Get the foreground and background colours of the widget */
186     if(inherit) {
187         XtVaGetValues(w, XmNforeground, &vals.foreground, XmNbackground,
188           &vals.background, NULL);
189     } else {
190         vals.foreground = BlackPixelOfScreen(screen);
191 	vals.background = WhitePixelOfScreen(screen);
192     }
193 
194     /* Create a GC for drawing the pixmap */
195     gc = XCreateGC(display, root, GCForeground|GCBackground, &vals);
196 
197     /* Change the bitmap to a pixmap */
198     pixmap = XbrGfxReadBitmap(display, screen, gc, bits, width, height);
199 
200     /* Free GC we have finished with */
201     XFreeGC(display, gc);
202 
203     /* Return the pixmap */
204     return(pixmap);
205 }
206 
207 /* XbrGfxBestColour:**********************************************************/
208 /* XbrGfxBestColour: Given an XColor with the RGB data filled in, find the   */
209 /* XbrGfxBestColour: closest match for it in the default colormap. Ian Finch */
210 /* XbrGfxBestColour: wrote this. (I think).                                  */
211 /* XbrGfxBestColour:**********************************************************/
212 
XbrGfxBestColour(Display * display,Colormap defmap,XColor * color,int num_colors)213 unsigned long XbrGfxBestColour(Display *display, Colormap defmap, XColor *color,
214                                int num_colors)
215 {
216     static XColor *colormap = NULL;
217     int i, best_match = 0, best_diff = 65535 * 3, colorval;
218 
219     /* NULL parameter passed to indicate we can free our mem */
220     if(color == NULL) {
221         if(colormap) free(colormap);
222         colormap = NULL;
223         return(0);
224     }
225 
226     /* If we have not yet read in the colormap do it */
227     if(!colormap) {
228         if((colormap = (XColor *) malloc(sizeof(XColor) * num_colors)) == NULL)
229             return(0);
230         for(i = 0; i < num_colors; i++)
231             colormap[i].pixel = i;
232         XQueryColors(display, defmap, colormap, num_colors);
233     }
234 
235     /* Try and get a good match */
236     for(i = 0; i < num_colors; i++) {
237         colorval = abs(color->red   - colormap[i].red)   +
238                    abs(color->green - colormap[i].green) +
239                    abs(color->blue  - colormap[i].blue);
240 
241         /* Is it a perfect match */
242         if(colorval == 0) {
243             best_match = i;
244             break;
245         }
246 
247         /* Is it better than the best one so far */
248         if(colorval < best_diff) {
249             best_diff = colorval;
250             best_match = i;
251         }
252     }
253 
254     return(colormap[best_match].pixel);
255 }
256 
257 /* XbrGfxBWPixels:************************************************************/
258 /* XbrGfxBWPixels: Found the black and/or white pixels of the given screen.  */
259 /* XbrGfxBWPixels:************************************************************/
260 
XbrGfxBWPixels(Display * display,Screen * screen,Colormap colourmap,XColor * black,XColor * white)261 void XbrGfxBWPixels(Display *display, Screen *screen, Colormap colourmap,
262                     XColor *black, XColor *white)
263 {
264     if(black != NULL) {
265         black->pixel = BlackPixelOfScreen(screen);
266         XQueryColor(display, colourmap, black);
267     }
268 
269     if(white != NULL) {
270         white->pixel = WhitePixelOfScreen(screen);
271         XQueryColor(display, colourmap, white);
272     }
273 }
274 
275 /* XbrGfxXBMtoRaw:************************************************************/
276 /* XbrGfxXBMtoRaw: Convert XBM data into raw data with RGB colours and an    */
277 /* XbrGfxXBMtoRaw: index into the data.                                      */
278 /* XbrGfxXBMtoRaw:************************************************************/
279 
XbrGfxXBMtoRaw(unsigned char * data,unsigned int width,unsigned int height)280 unsigned char *XbrGfxXBMtoRaw(unsigned char *data, unsigned int width,
281                               unsigned int height)
282 {
283     int alloc_width = ((width+8)/8)*8;
284     int new_width = (alloc_width/8);
285     unsigned char mask = 255>>(alloc_width-width);
286     unsigned char *newdata = (unsigned char *)
287       XtMalloc((alloc_width*height)*sizeof(char));
288     int i, j, k,bit;
289 
290     for(i = new_width-1; i < (new_width*height); i+=new_width) {
291         data[i] = data[i] & mask;
292     }
293 
294     for(i = 0, k = 0; i < (new_width*height); i++, k+=8) {
295         for(j = 0,bit=1; j < 8; j++,bit<<=1) {
296             newdata[k+j] = ((int)(data[i] & bit))/bit ;
297         }
298     }
299 
300     return(newdata);
301 }
302 
303 /* XbrGfxParseXBMData:********************************************************/
304 /* XbrGfxParseXBMData: Given a bitmap file loaded into memory, parse it into */
305 /* XbrGfxParseXBMData: individual data items.                                */
306 /* XbrGfxParseXBMData:********************************************************/
307 
XbrGfxParseXBMData(char * data,unsigned int * retwidth,unsigned int * retheight)308 unsigned char *XbrGfxParseXBMData(char *data, unsigned int *retwidth,
309                                   unsigned int *retheight)
310 {
311     char *ptr, token[50];
312     int done = 0, i = 0, j = 0, width, height;
313     unsigned char val = 0;
314     unsigned char *newdata;
315 
316     /* Try and find the width */
317     if((ptr = strstr(data, "width")) == NULL) {
318         fprintf(stderr, "Could not determine width!\n");
319         exit(1);
320     }
321     while(!isdigit(*ptr)) ptr++;
322     width = atoi(ptr);
323     *retwidth = width;
324     width = (width + 7)/8;
325 
326     /* Try and find the height */
327     if((ptr = strstr(data, "height")) == NULL) {
328         return(NULL);
329     }
330     while(!isdigit(*ptr)) ptr++;
331     height = atoi(ptr);
332     *retheight = height;
333 
334     /* Allocate new data */
335     if((newdata = (unsigned char *) malloc(width * height)) == NULL)
336         return(NULL);
337 
338     /* Jump to first bracket */
339     if((ptr = strchr(data, '{')) == NULL) {
340         free(newdata);
341         return(NULL);
342     }
343 
344     /* Parse a token at a time */
345     while(!done) {
346         ptr++;
347         while(isspace(*ptr)) ptr++;
348 
349         i = 0;
350         while(*ptr != ',' && *ptr != '}' && *ptr != EOF) {
351             token[i++] = *ptr;
352             ptr++;
353         }
354         token[i] = 0;
355         val = (char) strtol(token, (char *)NULL, 16);
356         newdata[j++] = val;
357 
358         if(*ptr == '}' || *ptr == EOF) done = 1;
359     }
360 
361     return(newdata);
362 }
363 
364 /* XbrGfxGIF:*****************************************************************/
365 /* XbrGfxGIF: Load a GIF into a pixmap and return its width, height and the  */
366 /* XbrGfxGIF: colours it allocated.                                          */
367 /* XbrGfxGIF:*****************************************************************/
368 
XbrGfxGIF(Display * display,unsigned char * data,int size,int html,XColor * backcol,char ** errmsg)369 XBR_IMAGE *XbrGfxGIF(Display *display, unsigned char *data, int size, int html,
370                      XColor *backcol, char **errmsg)
371 {
372     register unsigned char  ch, ch1;
373     register unsigned char *ptr, *ptr1;
374     register int   i;
375     unsigned char *raster,	/* The raster data stream, unblocked */
376                   *image;	/* The image data */
377     int BitOffset = 0,		/* Bit Offset of next code */
378     Prefix[4096],               /* Prefix table used for decoding */
379     Suffix[4096],               /* Suffix table used for decoding */
380     OutCode[1025],              /* Hash table used by the decompressor */
381     OutCount = 0,		/* Decompressor output 'stack count' */
382     RWidth, RHeight,		/* screen dimensions */
383     LeftOfs, TopOfs,		/* image offset */
384     BitsPerPixel,		/* Bits per pixel, read from GIF header */
385     ColorMapSize,		/* number of colors */
386     Background,			/* background color */
387     Transparent = 0,		/* Transparent background? */
388     TransparentColour,		/* The colour that is transparent. */
389     CodeSize,			/* Code size, read from GIF header */
390     InitCodeSize,		/* Starting code size, used during Clear */
391     Code,			/* Value returned by XbrGfxReadCode */
392     MaxCode,			/* limiting value for current code size */
393     ClearCode,			/* GIF clear code */
394     EOFCode,			/* GIF end-of-information code */
395     CurCode, OldCode, InCode,	/* Decompressor variables */
396     FirstFree,			/* First free code, generated per GIF spec */
397     FreeCode,			/* Decompressor, next free slot in hash table */
398     FinChar,			/* Decompressor variable */
399     BitMask,			/* AND mask for data size */
400     ReadMask,			/* Code AND mask for current code size */
401     DispCells,			/* Number of display cells */
402     screen;                     /* Default screen of display */
403     Colormap colormap;          /* The colour map the get colours from */
404     XImage *theImage;		/* The image to build up */
405     Visual *theVisual;          /* Screen visual type */
406     XBR_IMAGE *retval;
407     GC gc;
408 
409     DispCells = DisplayCells(display, DefaultScreen(display));
410     colormap = DefaultColormap(display, DefaultScreen(display));
411     theVisual = DefaultVisual(display, DefaultScreen(display));
412     screen = DefaultScreen(display);
413 
414     XC = 0, YC = 0; Pass = 0; alloc = 0;
415 
416     /* Allocate memory for raster data */
417     if((raster = (unsigned char *) malloc(size)) == NULL) {
418         if(errmsg) *errmsg = "Out of memory!";
419         return(NULL);
420     }
421 
422     ptr = data;
423 
424     if(strncmp((char *)ptr, "GIF87a", 6) && strncmp((char *)ptr, "GIF89a", 6)) {
425         if(errmsg) *errmsg = "Not a GIF image!";
426         return(NULL);
427     }
428     ptr += 6;
429 
430     /* Get variables from the GIF screen descriptor */
431     ch = NEXTBYTE;
432     RWidth = ch + 0x100 * NEXTBYTE;
433     ch = NEXTBYTE;
434     RHeight = ch + 0x100 * NEXTBYTE;
435 
436     ch = NEXTBYTE;
437     HasColormap = ((ch & COLORMAPMASK) ? True : False);
438 
439     BitsPerPixel = (ch & 7) + 1;
440     numcols = ColorMapSize = 1 << BitsPerPixel;
441     BitMask = ColorMapSize - 1;
442 
443     Background = NEXTBYTE;
444 
445     /* Supposed to be NULL */
446     if(NEXTBYTE) {
447         if(errmsg) *errmsg = "GIF image corrupt!";
448         return(NULL);
449     }
450 
451     /* Read in global colormap. */
452     if(HasColormap) {
453 	for (i = 0; i < ColorMapSize; i++) {
454 	    Red[i] = NEXTBYTE;
455 	    Green[i] = NEXTBYTE;
456 	    Blue[i] = NEXTBYTE;
457             used[i] = 0;
458 	}
459         numused = 0;
460     }
461     else {
462         if(!numcols) numcols=256;
463         for (i=0; i<numcols; i++)
464             cols[i] = (unsigned long) i;
465     }
466 
467     /* Chomp extensions. */
468     while((ch = NEXTBYTE) == GIF_EXTENSION) {
469         if(NEXTBYTE == GIF_GFXBLOCK) {
470 	    ch = NEXTBYTE;	/* Block size */
471 	    Transparent = ((NEXTBYTE & GIF_TRANSMASK) ? True : False);
472 	    ptr += 2;
473 	    TransparentColour = NEXTBYTE;
474 	    ch = NEXTBYTE;
475 	} else {
476 	    ch = NEXTBYTE;
477 	    ptr += ch;
478 	    while((ch = NEXTBYTE) != GIF_BLOCKEND)
479 		ptr += ch;
480 	}
481     }
482 
483     /* Check for image seperator */
484     if (ch != IMAGESEP) {
485         if(errmsg) *errmsg = "Corrupt GIF file: *no image separator*";
486         return(NULL);
487     }
488 
489     /* Now read in values from the image descriptor */
490     ch = NEXTBYTE;
491     LeftOfs = ch + 0x100 * NEXTBYTE;
492     ch = NEXTBYTE;
493     TopOfs = ch + 0x100 * NEXTBYTE;
494     ch = NEXTBYTE;
495     Width = ch + 0x100 * NEXTBYTE;
496     ch = NEXTBYTE;
497     Height = ch + 0x100 * NEXTBYTE;
498     Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
499 
500 /*
501     xbrimage_resize(Width, Height);
502     xbrimage_dimensions(Width, Height);
503 */
504 
505     /* Note that I ignore the possible existence of a local color map.
506      * I'm told there aren't many files around that use them, and the spec
507      * says it's defined for future use.  This could lead to an error
508      * reading some files.
509      */
510 
511     /* Start reading the raster data. First we get the intial code size
512      * and compute decompressor constant values, based on this code size.
513      */
514     CodeSize = NEXTBYTE;
515     ClearCode = (1 << CodeSize);
516     EOFCode = ClearCode + 1;
517     FreeCode = FirstFree = ClearCode + 2;
518 
519     /* The GIF spec has it that the code size is the code size used to
520      * compute the above values is the code size given in the file, but the
521      * code size used in compression/decompression is the code size given in
522      * the file plus one. (thus the ++).
523      */
524     CodeSize++;
525     InitCodeSize = CodeSize;
526     MaxCode = (1 << CodeSize);
527     ReadMask = MaxCode - 1;
528 
529     /* Read the raster data.  Here we just transpose it from the GIF array
530      * to the raster array, turning it from a series of blocks into one long
531      * data stream, which makes life much easier for XbrGfxReadCode().
532      */
533     ptr1 = raster;
534     do {
535 	ch = ch1 = NEXTBYTE;
536 	while (ch--) *ptr1++ = NEXTBYTE;
537 	if ((raster - ptr1) > size) {
538 	    if(errmsg) *errmsg = "Corrupt GIF file\n*unblock*";
539             return(NULL);
540         }
541     } while(ch1);
542 
543 
544     /* Allocate the X image */
545     image = (unsigned char *) malloc(Width*Height);
546     if (image == NULL) {
547         if(errmsg) *errmsg = "Not enough memory for Ximage!";
548         return(NULL);
549     }
550     if(!html) {
551         theImage = XCreateImage(display,theVisual,8,ZPixmap,0,(char *)image,
552           Width, Height,8,Width);
553 
554         if(theImage == NULL) {
555             if(errmsg) *errmsg = "Unable to create Ximage!";
556              return(NULL);
557        }
558     }
559 
560     BytesPerScanline = Width;
561 
562     /* Decompress the file, continuing until you see the GIF EOF code.
563        One obvious enhancement is to add checking for corrupt files here.
564     */
565     Code = XbrGfxReadCode(&BitOffset, raster, CodeSize, ReadMask);
566     while (Code != EOFCode) {
567 
568         /* Clear code sets everything back to its initial value, then reads the
569           immediately subsequent code as uncompressed data.
570         */
571 	if (Code == ClearCode) {
572 	    CodeSize = InitCodeSize;
573 	    MaxCode = (1 << CodeSize);
574 	    ReadMask = MaxCode - 1;
575 	    FreeCode = FirstFree;
576 	    CurCode = OldCode = Code = XbrGfxReadCode(&BitOffset, raster,
577               CodeSize, ReadMask);
578 	    FinChar = CurCode & BitMask;
579 	    XbrGfxAddtoPixel(FinChar, image);
580 	}
581 	else {
582 
583             /* If not a clear code, then must be data:save same as CurCode and
584                InCode
585             */
586 	    CurCode = InCode = Code;
587 
588             /* If greater or equal to FreeCode, not in the hash table yet;
589                repeat the last character decoded
590             */
591 	    if (CurCode >= FreeCode) {
592 		CurCode = OldCode;
593 		OutCode[OutCount++] = FinChar;
594 	    }
595 
596             /* Unless this code is raw data, pursue the chain pointed to by
597               CurCode through the hash table to its end; each code in the chain
598               puts its associated output code on the output queue.
599             */
600 	    while (CurCode > BitMask) {
601 		if (OutCount > 1024) {
602 		    if(errmsg) *errmsg = "Corrupt GIF file!*OutCount*";
603                     if(!html) XDestroyImage(theImage);
604                     theImage = NULL;
605                     return(NULL);
606                     }
607 		OutCode[OutCount++] = Suffix[CurCode];
608 		CurCode = Prefix[CurCode];
609 	    }
610 
611             /* The last code in the chain is treated as raw data. */
612 	    FinChar = CurCode & BitMask;
613 	    OutCode[OutCount++] = FinChar;
614 
615             /* Now we put the data out to the Output routine.
616                It's been stacked LIFO, so deal with it that way...
617             */
618             for (i = OutCount - 1; i >= 0; i--)
619 		XbrGfxAddtoPixel(OutCode[i], image);
620 	    OutCount = 0;
621 
622             /* Build the hash table on-the-fly. No table is stored in the
623                file.
624             */
625 	    Prefix[FreeCode] = OldCode;
626 	    Suffix[FreeCode] = FinChar;
627 	    OldCode = InCode;
628 
629             /* Point to the next slot in the table.  If we exceed the current
630                MaxCode value, increment the code size unless it's already 12.
631                If it is, do nothing: the next code decompressed better be CLEAR
632             */
633 	    FreeCode++;
634 	    if (FreeCode >= MaxCode) {
635 		if (CodeSize < 12) {
636 		    CodeSize++;
637 		    MaxCode *= 2;
638 		    ReadMask = (1 << CodeSize) - 1;
639 		}
640 	    }
641 	}
642 	Code = XbrGfxReadCode(&BitOffset, raster, CodeSize, ReadMask);
643     }
644 
645     free(raster);
646 /*
647     xbrimage_colours(numused, ColorMapSize);
648 */
649 
650     retval = XtNew(XBR_IMAGE);
651     retval->size = size;
652     retval->width = Width;
653     retval->height = Height;
654     retval->data = (char *)data;
655 
656     if(html) {
657         retval->pixmap = (Pixmap)NULL;
658         retval->num_colors = numcols;
659         retval->reds = (int *) XtMalloc(sizeof(int)*numcols);
660         retval->greens = (int *) XtMalloc(sizeof(int)*numcols);
661         retval->blues = (int *) XtMalloc(sizeof(int)*numcols);
662         for(i = 0; i < numcols; i++) {
663             retval->reds[i] = Red[i] << 8;
664             retval->greens[i] = Green[i] << 8;
665             retval->blues[i] = Blue[i] << 8;
666         }
667 	if(Transparent) {
668 	    retval->reds[TransparentColour] = backcol->red;
669 	    retval->greens[TransparentColour] = backcol->green;
670 	    retval->blues[TransparentColour] = backcol->blue;
671 	}
672         retval->image_data = image;
673         retval->npixels = 0;
674     } else {
675         retval->pixmap = XCreatePixmap(display, DefaultRootWindow(display),
676           Width, Height, DefaultDepth(display, screen));
677         retval->num_colors = numcols;
678         retval->reds = NULL;
679         retval->greens = NULL;
680         retval->blues = NULL;
681         retval->image_data = NULL;
682         if(!XbrGfxGetColours(display, colormap,DispCells, image,backcol,Transparent,TransparentColour)) {
683             if(errmsg) *errmsg = "Error allocating colours!";
684             XDestroyImage(theImage);
685             theImage = NULL;
686             return(NULL);
687         }
688 
689         for(i = 0; i < alloc; i++) {
690             retval->pixels[i] = alloced[i];
691         }
692         retval->npixels = alloc-1;
693 
694         gc = XCreateGC(display, retval->pixmap,  0, NULL);
695         XPutImage(display, retval->pixmap, gc, theImage, 0, 0, 0, 0, Width,
696           Height);
697         XFreeGC(display, gc);
698         XDestroyImage(theImage);
699     }
700 
701     theImage = NULL;
702 
703     return(retval);
704 }
705 
706 
707 /* XbrGfxReadCode:************************************************************/
708 /* XbrGfxReadCode: Fetch the next code from the raster data stream.  The     */
709 /* XbrGfxReadCode: codes can be any length from 3 to 12 bits, packed into    */
710 /* XbrGfxReadCode: 8-bit unsigned chars, so we have to maintain our location */
711 /* XbrGfxReadCode: in the raster array as a BIT Offset.  We compute the      */
712 /* XbrGfxReadCode: unsigned char Offset into the raster array by dividing    */
713 /* XbrGfxReadCode: this by 8, pick upthree unsigned chars, compute the bit   */
714 /* XbrGfxReadCode: Offset into our 24-bit chunk, shift to bring the desired  */
715 /* XbrGfxReadCode: code to the bottom, then mask it off and return it.       */
716 /* XbrGfxReadCode:************************************************************/
717 
XbrGfxReadCode(int * BitOffset,unsigned char * raster,int CodeSize,int ReadMask)718 static int XbrGfxReadCode(int *BitOffset, unsigned char *raster, int CodeSize,
719                     int ReadMask)
720 {
721     int RawCode, ByteOffset;
722 
723     ByteOffset = (*BitOffset) / 8;
724     RawCode = raster[ByteOffset] + (0x100 * raster[ByteOffset + 1]);
725     if (CodeSize >= 8) RawCode += (0x10000 * raster[ByteOffset + 2]);
726     RawCode >>= (*(BitOffset) % 8);
727     (*BitOffset) += CodeSize;
728     return(RawCode & ReadMask);
729 }
730 
731 
732 /* XbrGfxAddtoPixel:**********************************************************/
733 /* XbrGfxAddtoPixel: Add the pixel with the appropriate index into the       */
734 /* XbrGfxAddtoPixel: colour map.                                             */
735 /* XbrGfxAddtoPixel:**********************************************************/
736 
XbrGfxAddtoPixel(unsigned char Index,unsigned char * image)737 static void XbrGfxAddtoPixel(unsigned char Index, unsigned char *image)
738 {
739     register int slider_val;
740 
741     if (YC<Height)
742         *(image + YC * BytesPerScanline + XC) = Index;
743 
744     if (!used[Index]) { used[Index]=1;  numused++; }
745 
746     /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
747     if (++XC == Width) {
748 
749     /* If a non-interlaced picture, just increment YC to the next scan line.
750        If it's interlaced, deal with the interlace as described in the GIF
751        spec.  Put the decoded scan line out to the screen if we haven't gone
752         past the bottom of it
753      */
754 	XC = 0;
755 	if (!Interlace) {
756             YC++;
757             /* slider_val = (int) (((float)YC/(float)Height) * 100.0);
758             xbrimage_slide(slider_val); */
759         }
760 	else {
761 	    switch (Pass) {
762 		case 0:
763 		    YC += 8;
764 		    if (YC >= Height) {
765 			Pass++;
766 			YC = 4;
767 		    }
768 		break;
769 		case 1:
770 		    YC += 8;
771 		    if (YC >= Height) {
772 			Pass++;
773 			YC = 2;
774 		    }
775 		break;
776 		case 2:
777 		    YC += 4;
778 		    if (YC >= Height) {
779 			Pass++;
780 			YC = 1;
781 		    }
782 		break;
783 		case 3:
784 		    YC += 2;
785 		break;
786 		default:
787 		break;
788 	    }
789 	}
790     }
791 }
792 
793 /* XbrGfxGetColours:**********************************************************/
794 /* XbrGfxGetColours: Once we have the colour requirements we can try and     */
795 /* XbrGfxGetColours: get the requested colours from the colourmap.           */
796 /* XbrGfxGetColours:**********************************************************/
797 
XbrGfxGetColours(Display * display,Colormap colormap,int DispCells,unsigned char * image,XColor * backcol,int Transparent,int TransparentColour)798 static int XbrGfxGetColours(Display *display, Colormap colormap, int DispCells,
799                             unsigned char *image, XColor *backcol,
800 			    int Transparent, int TransparentColour)
801 {
802     register int i, j;
803     unsigned char *ptr;
804 
805     /* No need to allocate any colors if no colormap in GIF file */
806     if (!HasColormap) return(1);
807 
808     for(i = 0; i < numcols; i++) {
809 	if(Transparent && i == TransparentColour) {
810 	    cols[i] = backcol->pixel;
811 	} else if(used[i]) {
812             defs[i].red = Red[i] <<8;
813             defs[i].green = Green[i] <<8;
814             defs[i].blue  = Blue[i] <<8;
815             defs[i].flags = DoRed | DoGreen | DoBlue;
816             if(XAllocColor(display, colormap, &defs[i])) {
817                 cols[i] = defs[i].pixel;
818                 alloced[alloc++] = defs[i].pixel;
819             } else {
820                 defs[i].pixel = XbrGfxBestColour(display, colormap, &defs[i],
821                     256);
822                 cols[i] = defs[i].pixel;
823             }
824         }
825     }
826 
827     XbrGfxBestColour(display, colormap, NULL, 256);
828 
829     ptr = image;
830     for (i=0; i<Height; i++)
831         for (j=0; j<Width; j++,ptr++)
832             *ptr = (unsigned char) cols[*ptr];
833 
834     return(1);
835 
836 }
837 
838 /*----------------------------------------------------------------------------
839   XbrGfxSetPixmap()
840   Function to create and set the icon pixmap of a shell.
841   ----------------------------------------------------------------------------*/
XbrGfxSetPixmap(Widget shell,char * bits,int width,int height)842 Pixmap XbrGfxSetPixmap(Widget shell, char *bits, int width, int height)
843 {
844     Pixmap pixmap;
845 
846     pixmap = XbrGfxLoadBitmap(shell, bits, width, height, 0);
847 
848     XtVaSetValues(shell, XmNiconPixmap, pixmap, NULL);
849 
850     return(pixmap);
851 }
852 
853 /*----------------------------------------------------------------------------
854   XbrGfxShadow()
855   Get the shadow colours and set them for the given widget.
856 
857   Widget w	The widget to wreck
858   ----------------------------------------------------------------------------*/
XbrGfxShadow(Widget w)859 void XbrGfxShadow(Widget w)
860 {
861     Pixel background, top_shadow, bottom_shadow;
862     Screen *screen = XtScreen(w);
863 
864     /* Get the background pixel of the widget. */
865     XtVaGetValues(w, XmNbackground, &background, NULL);
866 
867     /* Generate the shadow colours */
868     XmGetColors(screen, DefaultColormapOfScreen(screen), background, NULL,
869 		&top_shadow, &bottom_shadow, NULL);
870 
871     /* Set shadow values. */
872     XtVaSetValues(w, XmNshadowThickness, 2,
873 		     XmNtopShadowColor,  top_shadow,
874 		     XmNbottomShadowColor, bottom_shadow,
875 		     NULL);
876 }
877