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