rnd-19981118-1
[rocksndiamonds.git] / src / gfxload.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  gfxload.c                                               *
12 ***********************************************************/
13
14 #ifndef MSDOS
15 #include "gfxload.h"
16
17
18
19
20
21
22 extern Window           window;
23 extern void Delay(long);
24
25
26
27
28
29
30 #ifdef DEBUG
31 /*
32 #define DEBUG_GIF
33 #define DEBUG_ILBM
34 */
35 #endif
36
37 struct IFF_ILBM_FORM_big_endian
38 {
39   char magic_FORM[4];
40   unsigned char chunk_size[4];
41   char magic_ILBM[4];
42 };
43
44 struct IFF_ILBM_BMHD_big_endian
45 {
46   char Width[2], Height[2];
47   char LeftEdge[2], TopEdge[2];
48   char Depth;
49   char Mask;
50   char Compression;
51   char pad1;
52   char transparentColor[2];
53   char xAspect, yAspect;
54   char pageWidth[2], pageHeight[2];
55 };
56
57 struct IFF_ILBM_BMHD
58 {
59   unsigned int Width, Height;
60   int LeftEdge, TopEdge;
61   unsigned int Depth;
62   unsigned int Mask;
63   unsigned int Compression;
64   unsigned char pad1;
65   unsigned int transparentColor;
66   unsigned int xAspect, yAspect;
67   int pageWidth, pageHeight;
68 };
69
70 static int ConvertXImageDepth(Display *, XImage **);
71 static int Read_GIF_to_Pixmap_or_Bitmap(Display *, char *, Pixmap *, int);
72
73 #define READ_GIF_TO_BITMAP      0
74 #define READ_GIF_TO_PIXMAP      1
75
76 int Read_GIF_to_Bitmap(Display *display, char *filename, Pixmap *pixmap)
77 {
78   return(Read_GIF_to_Pixmap_or_Bitmap(display, filename,
79                                       pixmap, READ_GIF_TO_BITMAP));
80 }
81
82 int Read_GIF_to_Pixmap(Display *display, char *filename, Pixmap *pixmap)
83 {
84   return(Read_GIF_to_Pixmap_or_Bitmap(display, filename,
85                                       pixmap, READ_GIF_TO_PIXMAP));
86 }
87
88 int Read_GIF_to_Pixmap_or_Bitmap(Display *display, char *filename,
89                                  Pixmap *pixmap, int mode)
90 {
91   XImage *image = NULL;
92   Pixmap new_pixmap = 0;
93   int return_code;
94
95   *pixmap = 0;
96   return_code = Read_GIF_to_XImage(display, filename, &image);
97   if (return_code != GIF_Success)
98     return(return_code);
99
100   if (image)
101   {
102     int screen = DefaultScreen(display);
103     Drawable root = RootWindow(display,screen);
104     int depth = DefaultDepth(display, screen);
105     int width = image->width;
106     int height = image->height;
107
108     if (mode == READ_GIF_TO_BITMAP)
109     {
110       int i,x,y;
111       unsigned long black_pixel = BlackPixel(display,screen);
112       int bytes_per_line = (width+7) / 8;
113       int size = bytes_per_line * height;
114       char *data, *ptr;
115
116       data = (char *)malloc(size);
117       if (!data)
118         return(GIF_NoMemory);
119
120       ptr = data;
121       for(i=0;i<size;i++)
122         *ptr++ = 0;
123
124       for(y=0;y<height;y++)
125       {
126         for(x=0;x<width;x++)
127         {
128           if (XGetPixel(image,x,y) == black_pixel)
129             data[y * bytes_per_line + x/8] |= (1 << (x%8));
130         }
131       }
132
133       new_pixmap = XCreateBitmapFromData(display,root,data,width,height);
134       free(data);
135
136       if (!new_pixmap)
137         return(GIF_NoMemory);
138     }
139     else
140     {
141       GC gc;
142       XGCValues gcv;
143
144       if (ConvertXImageDepth(display, &image) != GIF_Success)
145         return(GIF_ColorFailed);
146
147       new_pixmap = XCreatePixmap(display,root,width,height,depth);
148
149       if (!new_pixmap)
150         return(GIF_NoMemory);
151
152       gcv.foreground = BlackPixel(display,screen);
153       gcv.background = WhitePixel(display,screen);
154       gc = XCreateGC(display, root, GCForeground | GCBackground, &gcv);
155       XPutImage(display,new_pixmap,gc,image,0,0,0,0,width,height);
156
157       XFreeGC(display, gc);
158     }
159
160     XDestroyImage(image);
161   }
162
163   *pixmap = new_pixmap;
164   return(return_code);
165 }
166
167
168 /*
169  * Read_GIF_to_XImage()  -  based strongly on...
170  *
171  * xgifload.c  -  based strongly on...
172  *
173  * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
174  *
175  * Copyright (c) 1988, 1989 by Patrick J. Naughton
176  *
177  * Author: Patrick J. Naughton
178  * naughton@wind.sun.com
179  *
180  * Permission to use, copy, modify, and distribute this software and its
181  * documentation for any purpose and without fee is hereby granted,
182  * provided that the above copyright notice appear in all copies and that
183  * both that copyright notice and this permission notice appear in
184  * supporting documentation.
185  *
186  * This file is provided AS IS with no warranties of any kind.  The author
187  * shall have no liability with respect to the infringement of copyrights,
188  * trade secrets or any patents by this file or any part thereof.  In no
189  * event will the author be liable for any lost revenue or profits or
190  * other special, indirect and consequential damages.
191  *
192  */
193
194 typedef int boolean;
195 typedef unsigned char byte;
196
197 static int ReadCode(void);
198 static void AddToPixel(byte);
199 static int ColorDicking(Display *);
200
201 #define NEXTBYTE        (*ptr++)
202 #define IMAGESEP        0x2c
203 #define INTERLACEMASK   0x40
204 #define COLORMAPMASK    0x80
205
206 static
207 int BitOffset,                  /* Bit Offset of next code */
208     XC, YC,                     /* Output X and Y coords of current pixel */
209     Pass,                       /* Used by output routine if interlaced pic */
210     OutCount,                   /* Decompressor output 'stack count' */
211     RWidth, RHeight,            /* screen dimensions */
212     Width, Height,              /* image dimensions */
213     LeftOfs, TopOfs,            /* image offset */
214     BitsPerPixel,               /* Bits per pixel, read from GIF header */
215     BytesPerScanline,           /* bytes per scanline in output raster */
216     ColorMapSize,               /* number of colors */
217     Background,                 /* background color */
218     CodeSize,                   /* Code size, read from GIF header */
219     InitCodeSize,               /* Starting code size, used during Clear */
220     Code,                       /* Value returned by ReadCode */
221     MaxCode,                    /* limiting value for current code size */
222     ClearCode,                  /* GIF clear code */
223     EOFCode,                    /* GIF end-of-information code */
224     CurCode, OldCode, InCode,   /* Decompressor variables */
225     FirstFree,                  /* First free code, generated per GIF spec */
226     FreeCode,                   /* Decompressor, next free slot in hash table*/
227     FinChar,                    /* Decompressor variable */
228     BitMask,                    /* AND mask for data size */
229     ReadMask;                   /* Code AND mask for current code size */
230
231 static boolean Interlace, HasColormap;
232
233 static byte *ImageData;         /* The result array */
234 static byte *RawGIF;            /* The heap array to hold it, raw */
235 static byte *Raster;            /* The raster data stream, unblocked */
236
237 /* The color map, read from the GIF header */
238 static byte Red[256], Green[256], Blue[256], used[256];
239 static int  numused;
240
241 extern char *progname;
242
243 static int numcols;
244 static unsigned long cols[256];
245 static XColor defs[256];
246
247 int Read_GIF_to_XImage(Display *display, char *filename, XImage **image)
248 {
249   int filesize;
250   register byte ch, ch1;
251   register byte *ptr, *ptr1;
252   register int i;
253   int screen = DefaultScreen(display);
254   Visual *visual = DefaultVisual(display,screen);
255   XImage *new_image = NULL;
256   char *id = "GIF87a";
257   FILE *file;
258   int Prefix[4096];     /* The hash table used by the decompressor */
259   int Suffix[4096];
260   int OutCode[1025];    /* An output array used by the decompressor */
261
262   BitOffset = XC = YC = Pass = OutCount = 0;
263   *image = NULL;
264
265   if (strcmp(filename,"-")==0)
266   {
267     file = stdin;
268     filename = "<stdin>";
269   }
270   else
271     file = fopen(filename,"r");
272
273   if (!file)
274     return(GIF_OpenFailed);
275
276   /* find the size of the file */
277   fseek(file, 0L, 2);
278   filesize = ftell(file);
279   fseek(file, 0L, 0);
280
281   if (!(ptr = RawGIF = (byte *) malloc(filesize)))
282     return(GIF_NoMemory);
283
284   if (!(Raster = (byte *) malloc(filesize)))
285     return(GIF_NoMemory);
286
287   if (fread(ptr, filesize, 1, file) != 1)
288     return(GIF_ReadFailed);
289
290   if (strncmp(ptr, id, 6))
291     return(GIF_FileInvalid);
292
293   ptr += 6;
294
295   /* Get variables from the GIF screen descriptor */
296
297   ch = NEXTBYTE;
298   RWidth = ch + 0x100 * NEXTBYTE;    /* screen dimensions... not used. */
299   ch = NEXTBYTE;
300   RHeight = ch + 0x100 * NEXTBYTE;
301
302   ch = NEXTBYTE;
303   HasColormap = ((ch & COLORMAPMASK) ? True : False);
304
305   BitsPerPixel = (ch & 7) + 1;
306   numcols = ColorMapSize = 1 << BitsPerPixel;
307   BitMask = ColorMapSize - 1;
308
309   Background = NEXTBYTE;             /* background color... not used. */
310
311   if (NEXTBYTE)              /* supposed to be NULL */
312     return(GIF_FileInvalid);
313
314   /* Read in global colormap. */
315
316   if (HasColormap)
317   {
318     for (i = 0; i < ColorMapSize; i++)
319     {
320       Red[i] = NEXTBYTE;
321       Green[i] = NEXTBYTE;
322       Blue[i] = NEXTBYTE;
323       used[i] = 0;
324     }
325     numused = 0;
326   }
327   else
328   {
329     /* no colormap in GIF file */
330     fprintf(stderr,"%s:  warning!  no colortable in this file.  Winging it.\n",
331             progname);
332     if (!numcols)
333       numcols=256;
334     for (i=0; i<numcols; i++)
335       cols[i] = (unsigned long) i;
336   }
337
338   /* Check for image seperator */
339
340   if (NEXTBYTE != IMAGESEP)
341     return(GIF_FileInvalid);
342
343   /* Now read in values from the image descriptor */
344
345   ch = NEXTBYTE;
346   LeftOfs = ch + 0x100 * NEXTBYTE;
347   ch = NEXTBYTE;
348   TopOfs = ch + 0x100 * NEXTBYTE;
349   ch = NEXTBYTE;
350   Width = ch + 0x100 * NEXTBYTE;
351   ch = NEXTBYTE;
352   Height = ch + 0x100 * NEXTBYTE;
353   Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
354
355 #ifdef DEBUG_GIF
356   fprintf(stderr, "%s:\n", filename);
357   fprintf(stderr, "   %dx%d, %d bpp / %d colors, %sinterlaced\n",
358           Width,Height, BitsPerPixel,ColorMapSize,(Interlace ? "" : "non-"));
359   fprintf(stderr, "   Reading file... ");
360 #endif
361
362   /* Note that I ignore the possible existence of a local color map.
363    * I'm told there aren't many files around that use them, and the spec
364    * says it's defined for future use.  This could lead to an error
365    * reading some files. 
366    */
367
368   /* Start reading the raster data. First we get the intial code size
369    * and compute decompressor constant values, based on this code size.
370    */
371
372   CodeSize = NEXTBYTE;
373   ClearCode = (1 << CodeSize);
374   EOFCode = ClearCode + 1;
375     FreeCode = FirstFree = ClearCode + 2;
376
377   /* The GIF spec has it that the code size is the code size used to
378    * compute the above values is the code size given in the file, but the
379    * code size used in compression/decompression is the code size given in
380    * the file plus one. (thus the ++).
381    */
382
383   CodeSize++;
384   InitCodeSize = CodeSize;
385   MaxCode = (1 << CodeSize);
386   ReadMask = MaxCode - 1;
387
388   /* Read the raster data.  Here we just transpose it from the GIF array
389    * to the Raster array, turning it from a series of blocks into one long
390    * data stream, which makes life much easier for ReadCode().
391    */
392
393   ptr1 = Raster;
394   do
395   {
396     ch = ch1 = NEXTBYTE;
397     while (ch--) *ptr1++ = NEXTBYTE;
398     if ((Raster - ptr1) > filesize)
399       return(GIF_FileInvalid);
400   }
401   while(ch1);
402
403   free(RawGIF);              /* We're done with the raw data now... */
404
405 #ifdef DEBUG_GIF
406   fprintf(stderr, "done\n");
407   fprintf(stderr, "   Decompressing... ");
408 #endif
409
410   /* Allocate the X Image */
411   ImageData = (byte *) malloc(Width*Height);
412   if (!ImageData)
413     return(GIF_NoMemory);
414
415   new_image = XCreateImage(display,visual,8,ZPixmap,0,ImageData,
416                            Width,Height,8,Width);
417   if (!new_image)
418     return(GIF_NoMemory);
419
420   BytesPerScanline = Width;
421
422
423   /* Decompress the file, continuing until you see the GIF EOF code.
424    * One obvious enhancement is to add checking for corrupt files here.
425    */
426
427   Code = ReadCode();
428   while (Code != EOFCode)
429   {
430     /* Clear code sets everything back to its initial value, then reads the
431      * immediately subsequent code as uncompressed data.
432      */
433
434     if (Code == ClearCode)
435     {
436       CodeSize = InitCodeSize;
437       MaxCode = (1 << CodeSize);
438       ReadMask = MaxCode - 1;
439       FreeCode = FirstFree;
440       CurCode = OldCode = Code = ReadCode();
441       FinChar = CurCode & BitMask;
442       AddToPixel(FinChar);
443     }
444     else
445     {
446       /* If not a clear code, then must be data:
447        * save same as CurCode and InCode
448        */
449
450       CurCode = InCode = Code;
451
452       /* If greater or equal to FreeCode, not in the hash table yet;
453        * repeat the last character decoded
454        */
455
456       if (CurCode >= FreeCode)
457       {
458         CurCode = OldCode;
459         OutCode[OutCount++] = FinChar;
460       }
461
462       /* Unless this code is raw data, pursue the chain pointed to by CurCode
463        * through the hash table to its end; each code in the chain puts its
464        * associated output code on the output queue.
465        */
466
467       while (CurCode > BitMask)
468       {
469         if (OutCount > 1024)
470           return(GIF_FileInvalid);
471
472         OutCode[OutCount++] = Suffix[CurCode];
473         CurCode = Prefix[CurCode];
474       }
475
476       /* The last code in the chain is treated as raw data. */
477
478       FinChar = CurCode & BitMask;
479       OutCode[OutCount++] = FinChar;
480
481       /* Now we put the data out to the Output routine.
482        * It's been stacked LIFO, so deal with it that way...
483        */
484
485       for (i = OutCount - 1; i >= 0; i--)
486         AddToPixel(OutCode[i]);
487       OutCount = 0;
488
489       /* Build the hash table on-the-fly. No table is stored in the file. */
490
491       Prefix[FreeCode] = OldCode;
492       Suffix[FreeCode] = FinChar;
493       OldCode = InCode;
494
495       /* Point to the next slot in the table.  If we exceed the current
496        * MaxCode value, increment the code size unless it's already 12.  If it
497        * is, do nothing: the next code decompressed better be CLEAR
498        */
499
500       FreeCode++;
501       if (FreeCode >= MaxCode)
502       {
503         if (CodeSize < 12)
504         {
505           CodeSize++;
506           MaxCode *= 2;
507           ReadMask = (1 << CodeSize) - 1;
508         }
509       }
510     }
511     Code = ReadCode();
512   }
513
514   free(Raster);
515
516 #ifdef DEBUG_GIF
517   fprintf(stderr, "done\n");
518   fprintf(stderr,"   %d colors used\n",numused);
519 #endif
520
521   if (file != stdin)
522     fclose(file);
523
524   if (ColorDicking(display) != GIF_Success)
525     return(GIF_ColorFailed);
526
527   *image = new_image;
528   return(GIF_Success);
529 }
530
531
532 /* Fetch the next code from the raster data stream.  The codes can be
533  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
534  * maintain our location in the Raster array as a BIT Offset.  We compute
535  * the byte Offset into the raster array by dividing this by 8, pick up
536  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
537  * bring the desired code to the bottom, then mask it off and return it. 
538  */
539
540 static int ReadCode()
541 {
542   int RawCode, ByteOffset;
543
544   ByteOffset = BitOffset / 8;
545   RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
546   if (CodeSize >= 8)
547     RawCode += (0x10000 * Raster[ByteOffset + 2]);
548   RawCode >>= (BitOffset % 8);
549   BitOffset += CodeSize;
550   return(RawCode & ReadMask);
551 }
552
553
554 static void AddToPixel(byte Index)
555 {
556   if (YC<Height)
557     *(ImageData + YC * BytesPerScanline + XC) = Index;
558
559   if (!used[Index])
560   {
561     used[Index]=1;
562     numused++;
563   }
564
565   /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
566
567   if (++XC == Width)
568   {
569     /* If a non-interlaced picture, just increment YC to the next scan line. 
570      * If it's interlaced, deal with the interlace as described in the GIF
571      * spec.  Put the decoded scan line out to the screen if we haven't gone
572      * past the bottom of it
573      */
574
575     XC = 0;
576     if (!Interlace)
577       YC++;
578     else
579     {
580       switch (Pass)
581       {
582         case 0:
583           YC += 8;
584           if (YC >= Height)
585           {
586             Pass++;
587             YC = 4;
588           }
589           break;
590
591         case 1:
592           YC += 8;
593           if (YC >= Height)
594           {
595             Pass++;
596             YC = 2;
597           }
598           break;
599
600         case 2:
601           YC += 4;
602           if (YC >= Height)
603           {
604             Pass++;
605             YC = 1;
606           }
607           break;
608
609         case 3:
610           YC += 2;
611           break;
612
613         default:
614           break;
615         }
616     }
617   }
618 }
619
620
621 static int ColorDicking(Display *display)
622 {
623   /* we've got the picture loaded, we know what colors are needed. get 'em */
624
625   register int i,j;
626   static byte lmasks[8] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80};
627   byte lmask, *ptr;
628   int screen = DefaultScreen(display);
629   Colormap cmap = DefaultColormap(display,screen);
630   int dispcells = DisplayCells(display,screen);
631
632   int strip = 0;
633   int nostrip = 0; 
634
635   if (!HasColormap)
636     return(GIF_Success);
637   /* no need to allocate any colors if no colormap in GIF file */
638
639   /* Allocate the X colors for this picture */
640
641   if (nostrip)
642   {
643     /* nostrip was set.  try REAL hard to do it */
644     for (i=j=0; i<numcols; i++)
645     {
646       if (used[i])
647       {
648         defs[i].red   = Red[i]<<8;
649         defs[i].green = Green[i]<<8;
650         defs[i].blue  = Blue[i]<<8;
651         defs[i].flags = DoRed | DoGreen | DoBlue;
652         if (!XAllocColor(display,cmap,&defs[i]))
653         { 
654           j++;
655           defs[i].pixel = 0xffff;
656         }
657         cols[i] = defs[i].pixel;
658       }
659     }
660
661     if (j)
662     {
663       /* failed to pull it off */
664
665       XColor ctab[256];
666       int dc;
667
668       dc = (dispcells<256) ? dispcells : 256;
669
670       fprintf(stderr,
671               "failed to allocate %d out of %d colors.  Trying extra hard.\n",
672               j,numused);
673
674       /* read in the color table */
675       for (i=0; i<dc; i++)
676         ctab[i].pixel = i;
677       XQueryColors(display,cmap,ctab,dc);
678                 
679       /* run through the used colors.  any used color that has a pixel
680          value of 0xffff wasn't allocated.  for such colors, run through
681          the entire X colormap and pick the closest color */
682
683       for (i=0; i<numcols; i++)
684         if (used[i] && cols[i]==0xffff)
685         {
686           /* an unallocated pixel */
687
688           int d, mdist, close;
689           unsigned long r,g,b;
690
691           mdist = 100000;   close = -1;
692           r =  Red[i];
693           g =  Green[i];
694           b =  Blue[i];
695           for (j=0; j<dc; j++)
696           {
697             d = abs(r - (ctab[j].red>>8)) +
698               abs(g - (ctab[j].green>>8)) +
699                 abs(b - (ctab[j].blue>>8));
700             if (d<mdist)
701             {
702               mdist=d;
703               close=j;
704             }
705           }
706
707           if (close<0)
708             return(GIF_ColorFailed);
709
710           bcopy(&defs[close],&defs[i],sizeof(XColor));
711           cols[i] = ctab[close].pixel;
712         }
713     }  /* end 'failed to pull it off' */
714   }
715   else
716   {
717     /* strip wasn't set, do the best auto-strip */
718
719     j = 0;
720     while (strip<8)
721     {
722       lmask = lmasks[strip];
723       for (i=0; i<numcols; i++)
724       {
725         if (used[i])
726         {
727           defs[i].red   = (Red[i]  &lmask)<<8;
728           defs[i].green = (Green[i]&lmask)<<8;
729           defs[i].blue  = (Blue[i] &lmask)<<8;
730           defs[i].flags = DoRed | DoGreen | DoBlue;
731           if (!XAllocColor(display,cmap,&defs[i]))
732             break;
733           cols[i] = defs[i].pixel;
734         }
735       }
736
737       if (i<numcols)
738       {
739         /* failed */
740         strip++;
741         j++;
742         for (i--; i>=0; i--)
743           if (used[i])
744             XFreeColors(display,cmap,cols+i,1,0L);
745       }
746       else
747         break;
748     }
749
750 #ifdef DEBUG_GIF
751     if (j && strip<8)
752       fprintf(stderr,"%s: stripped %d bits\n",progname,strip);
753 #endif
754
755     if (strip==8)
756     {
757       fprintf(stderr,"UTTERLY failed to allocate the desired colors.\n");
758       for (i=0; i<numcols; i++) cols[i]=i;
759     }
760   }
761
762   ptr = ImageData;
763   for (i=0; i<Height; i++)
764     for (j=0; j<Width; j++,ptr++) 
765       *ptr = (byte) cols[*ptr];
766
767   return(GIF_Success);
768 }
769
770
771 /******************************************************************************
772  *  This makes sure the display's depth is the same as the
773  * depth of the default 8 bit image.  If not, we build a new image
774  * that has the correct depth.  This works on the fact that
775  * the color mapper has already changed every pixel value in the
776  * image into the proper number of bits (to fit into the pallet)
777  * so we can just chop down the number of bits.
778  *   This changes the global variable 'expImage' if necessary.
779  */
780
781 static int ConvertXImageDepth(Display *display, XImage **image)
782 {
783   int screen = DefaultScreen(display);
784   int depth = DefaultDepth(display, screen);
785
786
787
788
789
790
791   printf("ConvertXImageDepth:\n");
792   printf("(*image)->depth == %d\n",
793          (*image)->depth);
794   printf("DefaultDepth(display, screen) == %d\n",
795          DefaultDepth(display, screen));
796
797
798
799
800   if ((*image)->depth != depth)
801   {
802     XImage *old_image, *new_image;
803
804     Visual *visual = DefaultVisual(display,screen);
805
806     int width = (*image)->width;
807     int height = (*image)->height;
808     register int dwx, dwy;
809     byte *data;
810
811
812
813
814
815     printf("ConvertXImageDepth: ---------> CONVERTING...\n");
816
817
818
819
820
821
822     data = (byte *)malloc(width * height * depth);
823     old_image = *image;
824
825 #if 1
826     new_image = XCreateImage(display,visual,depth,
827                              ZPixmap,0,data,width,height,8,0);
828 #else
829     new_image = XGetImage(display,RootWindow(display,screen),
830                           0,0,width,height,0xffffffff,ZPixmap);
831 #endif
832
833     if (!new_image)
834       return(GIF_NoMemory);
835
836     if (old_image->depth == 8 && new_image->depth == 4)
837     {
838       /* speedup for the most common format change */
839
840       register byte *sptr = (byte *)old_image->data;
841       register byte *dptr = (byte *)new_image->data;
842
843       for (dwy=1; dwy<=height; dwy++)
844       {
845         for (dwx=1; dwx<width; dwx+=2)
846         {
847           *dptr = (*sptr) | (*(sptr+1)<<4);
848           dptr++;
849           sptr+=2;
850         }
851         if (width & 1)
852         {
853           /* if extra pixal at end of line, just move it */
854           *dptr = *sptr;
855           sptr++; dptr++;
856         }
857       }
858     }
859     else        /* other format change than 8 bit -> 4 bit */
860     {
861       unsigned long pixel_value;
862
863       for (dwx=0; dwx<width; dwx++)
864       {
865         for (dwy=0; dwy<height; dwy++)
866         {
867           pixel_value = XGetPixel(old_image, dwx, dwy);
868
869           if (pixel_value > 0xff)
870             printf("pixel = %lx", pixel_value);
871
872           XPutPixel(new_image, dwx, dwy, pixel_value);
873         }
874       }
875     }
876
877     free(old_image->data);
878     old_image->data = NULL;
879     XDestroyImage(old_image);
880
881     *image = new_image;
882   }
883
884   return(GIF_Success);
885 }
886
887
888 static unsigned long be2long(unsigned char *be) /* big-endian -> long int */
889 {
890   return((be[0]<<24) | (be[1]<<16) | (be[2]<<8) | be[3]);
891 }
892
893 static unsigned short be2short(unsigned char *be) /* big-endian -> short int */
894 {
895   return((be[0]<<8) | be[1]);
896 }
897
898 static struct IFF_ILBM_BMHD *ConvertBMHD(unsigned char *header_data)
899 {
900   struct IFF_ILBM_BMHD_big_endian *bmhd_be;
901   struct IFF_ILBM_BMHD *bmhd;
902
903   bmhd_be = (struct IFF_ILBM_BMHD_big_endian *)header_data;
904   bmhd = (struct IFF_ILBM_BMHD *)malloc(sizeof(struct IFF_ILBM_BMHD));
905   if (!bmhd)
906     return(NULL);
907
908   bmhd->Width = be2short(bmhd_be->Width);
909   bmhd->Height = be2short(bmhd_be->Height);
910   bmhd->LeftEdge = be2short(bmhd_be->LeftEdge);
911   bmhd->TopEdge = be2short(bmhd_be->TopEdge);
912   bmhd->Depth = (int)bmhd_be->Depth;
913   bmhd->Mask = (int)bmhd_be->Mask;
914   bmhd->Compression = (int)bmhd_be->Compression;
915   bmhd->pad1 = bmhd_be->pad1;
916   bmhd->transparentColor = be2short(bmhd_be->transparentColor);
917   bmhd->xAspect = (int)bmhd_be->xAspect;
918   bmhd->yAspect = (int)bmhd_be->yAspect;
919   bmhd->pageWidth = be2short(bmhd_be->pageWidth);
920   bmhd->pageHeight = be2short(bmhd_be->pageHeight);
921
922   return(bmhd);
923 }
924
925 static unsigned char MSBitFirst2LSBitFirst(unsigned char msb_byte)
926 {
927   unsigned char lsb_byte = 0;
928   int i;
929
930   for(i=7;i>=0;i--)
931   {
932     lsb_byte |= (msb_byte & 1) << i;
933     msb_byte >>= 1;
934   }
935
936   return(lsb_byte);
937 }
938
939 int Read_ILBM_to_Bitmap(Display *display, char *filename, Pixmap *pixmap)
940 {
941   Pixmap new_pixmap = 0;
942   int screen = DefaultScreen(display);
943   Drawable root = RootWindow(display,screen);
944   struct IFF_ILBM_FORM_big_endian *form_header;
945   struct IFF_ILBM_BMHD *bitmap_header;
946   unsigned long file_len, body_len;
947   unsigned char *file_data, *bitmap_data;
948   unsigned char *file_ptr, *bitmap_ptr, *body_ptr;
949   unsigned char byte_count, byte_value;
950   int i,x,y,z;
951   int width, height, depth;
952   int bytes_per_line, bitmap_size;
953   FILE *file;
954
955   if (!(file = fopen(filename,"r")))
956     return(ILBM_OpenFailed);
957
958   if (fseek(file,0,SEEK_END) < 0)
959   {
960     fclose(file);
961     return(ILBM_ReadFailed);
962   }
963
964   file_len = ftell(file);
965   rewind(file);
966
967   if (!(file_data = (unsigned char *)malloc(file_len)))
968   {
969     fclose(file);
970     return(ILBM_NoMemory);
971   }
972
973   if (fread(file_data,1,file_len,file) != file_len)
974   {
975     free(file_data);
976     fclose(file);
977     return(ILBM_ReadFailed);
978   }
979
980   fclose(file);
981
982   form_header = (struct IFF_ILBM_FORM_big_endian *)file_data;
983
984   if (strncmp(form_header->magic_FORM,"FORM",4) ||
985       file_len != be2long(form_header->chunk_size)+8 ||
986       strncmp(form_header->magic_ILBM,"ILBM",4))
987   {
988 #ifdef DEBUG_ILBM
989       printf("%s: IFF chunk 'FORM' and/or 'ILBM' not found.\n",filename);
990 #endif
991     free(file_data);
992     return(ILBM_FileInvalid);
993   }
994
995   bitmap_header = NULL;
996   body_ptr = NULL;
997   file_ptr = file_data + 12;
998
999   while(file_ptr < (unsigned char *)(file_data + file_len))
1000   {
1001     if (!strncmp(file_ptr,"BMHD",4))
1002     {
1003 #ifdef DEBUG_ILBM
1004       printf("%s: IFF chunk 'BMHD' found.\n",filename);
1005 #endif
1006       bitmap_header = ConvertBMHD(file_ptr + 8);
1007       file_ptr += be2long(file_ptr + 4) + 8;
1008       continue;
1009     }
1010     else if (!strncmp(file_ptr,"BODY",4))
1011     {
1012 #ifdef DEBUG_ILBM
1013       printf("%s: IFF chunk 'BODY' found.\n",filename);
1014 #endif
1015       body_ptr = file_ptr + 8;
1016       body_len = be2long(file_ptr + 4);
1017       file_ptr += be2long(file_ptr + 4) + 8;
1018       continue;
1019     }
1020     else
1021     {
1022 #ifdef DEBUG_ILBM
1023       printf("%s: IFF chunk '%c%c%c%c' found (but not used).\n",filename,
1024              file_ptr[0],file_ptr[1],file_ptr[2],file_ptr[3]);
1025 #endif
1026       /* other chunk not recognized here */
1027       file_ptr += be2long(file_ptr + 4) + 8;
1028       continue;
1029     }
1030   }
1031
1032   if (!bitmap_header || !body_ptr)
1033   {
1034 #ifdef DEBUG_ILBM
1035       printf("%s: IFF chunk 'BMHD' and/or 'BODY' not found.\n",filename);
1036 #endif
1037     free(file_data);
1038     return(ILBM_FileInvalid);
1039   }
1040
1041   width = bitmap_header->Width;
1042   height = bitmap_header->Height;
1043   depth = bitmap_header->Depth;
1044
1045 #ifdef DEBUG_ILBM
1046   if (depth > 1)
1047     printf("%s: %d bitplanes found; using only the first plane.\n",
1048            filename,depth);
1049 #endif
1050
1051   bytes_per_line = ((width + 15) / 16) * 2;
1052   bitmap_size = bytes_per_line * height;
1053
1054   bitmap_data = (char *)malloc(bitmap_size);
1055   if (!bitmap_data)
1056   {
1057     free(file_data);
1058     free(bitmap_header);
1059     return(ILBM_NoMemory);
1060   }
1061
1062   bitmap_ptr = bitmap_data;
1063   for(i=0;i<bitmap_size;i++)
1064     *bitmap_ptr++ = 0;
1065
1066   for(y=0;y<height;y++)
1067   {
1068     /* we only read the first bitplane here to create a black/white bitmap */
1069
1070     for(z=0;z<depth;z++)
1071     {
1072       bitmap_ptr = bitmap_data + y * bytes_per_line;
1073       x = 0;
1074
1075       if (!bitmap_header->Compression)
1076       {
1077         while(x++ < bytes_per_line)
1078           *bitmap_ptr++ |= MSBitFirst2LSBitFirst(*body_ptr++);
1079       }
1080       else
1081       {
1082         while(x < bytes_per_line)
1083         {
1084           byte_count = *body_ptr++;
1085
1086           if (byte_count <= 128)
1087           {
1088             for(i=0;i<byte_count+1;i++)
1089               *bitmap_ptr++ |= MSBitFirst2LSBitFirst(*body_ptr++);
1090             x += byte_count + 1;
1091           }
1092           else
1093           {
1094             byte_value = *body_ptr++;
1095             for(i=0;i<257-byte_count;i++)
1096               *bitmap_ptr++ |= MSBitFirst2LSBitFirst(byte_value);
1097             x += 257 - byte_count;
1098           }
1099         }
1100       }
1101     }
1102   }
1103
1104   bitmap_ptr = bitmap_data;
1105   for(i=0;i<bitmap_size;i++)
1106     *bitmap_ptr++ ^= 0xff;
1107
1108   new_pixmap = XCreateBitmapFromData(display,root,bitmap_data,width,height);
1109
1110   free(file_data);
1111   free(bitmap_data);
1112   free(bitmap_header);
1113
1114   if (!new_pixmap)
1115     return(ILBM_NoMemory);
1116
1117   *pixmap = new_pixmap;
1118   return(ILBM_Success);
1119 }
1120 #endif