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