rnd-19970921-src
[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);
783     old_image = *image;
784     new_image = XCreateImage(display,visual,depth,
785                              ZPixmap,0,data,width,height,8,0);
786     if (!new_image)
787       return(GIF_NoMemory);
788
789     if (old_image->depth == 8 && new_image->depth == 4)
790     {
791       /* speedup for the most common format change */
792
793       register byte *sptr = (byte *)old_image->data;
794       register byte *dptr = (byte *)new_image->data;
795
796       for (dwy=1; dwy<=height; dwy++)
797       {
798         for (dwx=1; dwx<width; dwx+=2)
799         {
800           *dptr = (*sptr) | (*(sptr+1)<<4);
801           dptr++;
802           sptr+=2;
803         }
804         if (width & 1)
805         {
806           /* if extra pixal at end of line, just move it */
807           *dptr = *sptr;
808           sptr++; dptr++;
809         }
810       }
811     }
812     else        /* other format change than 8 bit -> 4 bit */
813     {
814       register unsigned long pixel_value;
815
816       for (dwx=0; dwx<width; dwx++)
817       {
818         for (dwy=0; dwy<height; dwy++)
819         {
820           pixel_value = XGetPixel(old_image, dwx, dwy);
821           XPutPixel(new_image, dwx, dwy, pixel_value);
822         }
823       }
824     }
825
826     free(old_image->data);
827     old_image->data = NULL;
828     XDestroyImage(old_image);
829
830     *image = new_image;
831   }
832
833   return(GIF_Success);
834 }
835
836
837 static unsigned long be2long(unsigned char *be) /* big-endian -> long int */
838 {
839   return((be[0]<<24) | (be[1]<<16) | (be[2]<<8) | be[3]);
840 }
841
842 static unsigned short be2short(unsigned char *be) /* big-endian -> short int */
843 {
844   return((be[0]<<8) | be[1]);
845 }
846
847 static struct IFF_ILBM_BMHD *ConvertBMHD(unsigned char *header_data)
848 {
849   struct IFF_ILBM_BMHD_big_endian *bmhd_be;
850   struct IFF_ILBM_BMHD *bmhd;
851
852   bmhd_be = (struct IFF_ILBM_BMHD_big_endian *)header_data;
853   bmhd = (struct IFF_ILBM_BMHD *)malloc(sizeof(struct IFF_ILBM_BMHD));
854   if (!bmhd)
855     return(NULL);
856
857   bmhd->Width = be2short(bmhd_be->Width);
858   bmhd->Height = be2short(bmhd_be->Height);
859   bmhd->LeftEdge = be2short(bmhd_be->LeftEdge);
860   bmhd->TopEdge = be2short(bmhd_be->TopEdge);
861   bmhd->Depth = (int)bmhd_be->Depth;
862   bmhd->Mask = (int)bmhd_be->Mask;
863   bmhd->Compression = (int)bmhd_be->Compression;
864   bmhd->pad1 = bmhd_be->pad1;
865   bmhd->transparentColor = be2short(bmhd_be->transparentColor);
866   bmhd->xAspect = (int)bmhd_be->xAspect;
867   bmhd->yAspect = (int)bmhd_be->yAspect;
868   bmhd->pageWidth = be2short(bmhd_be->pageWidth);
869   bmhd->pageHeight = be2short(bmhd_be->pageHeight);
870
871   return(bmhd);
872 }
873
874 static unsigned char MSBitFirst2LSBitFirst(unsigned char msb_byte)
875 {
876   unsigned char lsb_byte = 0;
877   int i;
878
879   for(i=7;i>=0;i--)
880   {
881     lsb_byte |= (msb_byte & 1) << i;
882     msb_byte >>= 1;
883   }
884
885   return(lsb_byte);
886 }
887
888 int Read_ILBM_to_Bitmap(Display *display, char *filename, Pixmap *pixmap)
889 {
890   Pixmap new_pixmap = 0;
891   int screen = DefaultScreen(display);
892   Drawable root = RootWindow(display,screen);
893   struct IFF_ILBM_FORM_big_endian *form_header;
894   struct IFF_ILBM_BMHD *bitmap_header;
895   unsigned long file_len, body_len;
896   unsigned char *file_data, *bitmap_data;
897   unsigned char *file_ptr, *bitmap_ptr, *body_ptr;
898   unsigned char byte_count, byte_value;
899   int i,x,y,z;
900   int width, height, depth;
901   int bytes_per_line, bitmap_size;
902   FILE *file;
903
904   if (!(file = fopen(filename,"r")))
905     return(ILBM_OpenFailed);
906
907   if (fseek(file,0,SEEK_END) < 0)
908   {
909     fclose(file);
910     return(ILBM_ReadFailed);
911   }
912
913   file_len = ftell(file);
914   rewind(file);
915
916   if (!(file_data = (unsigned char *)malloc(file_len)))
917   {
918     fclose(file);
919     return(ILBM_NoMemory);
920   }
921
922   if (fread(file_data,1,file_len,file) != file_len)
923   {
924     free(file_data);
925     fclose(file);
926     return(ILBM_ReadFailed);
927   }
928
929   fclose(file);
930
931   form_header = (struct IFF_ILBM_FORM_big_endian *)file_data;
932
933   if (strncmp(form_header->magic_FORM,"FORM",4) ||
934       file_len != be2long(form_header->chunk_size)+8 ||
935       strncmp(form_header->magic_ILBM,"ILBM",4))
936   {
937 #ifdef DEBUG_ILBM
938       printf("%s: IFF chunk 'FORM' and/or 'ILBM' not found.\n",filename);
939 #endif
940     free(file_data);
941     return(ILBM_FileInvalid);
942   }
943
944   bitmap_header = NULL;
945   body_ptr = NULL;
946   file_ptr = file_data + 12;
947
948   while(file_ptr < (unsigned char *)(file_data + file_len))
949   {
950     if (!strncmp(file_ptr,"BMHD",4))
951     {
952 #ifdef DEBUG_ILBM
953       printf("%s: IFF chunk 'BMHD' found.\n",filename);
954 #endif
955       bitmap_header = ConvertBMHD(file_ptr + 8);
956       file_ptr += be2long(file_ptr + 4) + 8;
957       continue;
958     }
959     else if (!strncmp(file_ptr,"BODY",4))
960     {
961 #ifdef DEBUG_ILBM
962       printf("%s: IFF chunk 'BODY' found.\n",filename);
963 #endif
964       body_ptr = file_ptr + 8;
965       body_len = be2long(file_ptr + 4);
966       file_ptr += be2long(file_ptr + 4) + 8;
967       continue;
968     }
969     else
970     {
971 #ifdef DEBUG_ILBM
972       printf("%s: IFF chunk '%c%c%c%c' found (but not used).\n",filename,
973              file_ptr[0],file_ptr[1],file_ptr[2],file_ptr[3]);
974 #endif
975       /* other chunk not recognized here */
976       file_ptr += be2long(file_ptr + 4) + 8;
977       continue;
978     }
979   }
980
981   if (!bitmap_header || !body_ptr)
982   {
983 #ifdef DEBUG_ILBM
984       printf("%s: IFF chunk 'BMHD' and/or 'BODY' not found.\n",filename);
985 #endif
986     free(file_data);
987     return(ILBM_FileInvalid);
988   }
989
990   width = bitmap_header->Width;
991   height = bitmap_header->Height;
992   depth = bitmap_header->Depth;
993
994 #ifdef DEBUG_ILBM
995   if (depth > 1)
996     printf("%s: %d bitplanes found; using only the first plane.\n",
997            filename,depth);
998 #endif
999
1000   bytes_per_line = ((width + 15) / 16) * 2;
1001   bitmap_size = bytes_per_line * height;
1002
1003   bitmap_data = (char *)malloc(bitmap_size);
1004   if (!bitmap_data)
1005   {
1006     free(file_data);
1007     free(bitmap_header);
1008     return(ILBM_NoMemory);
1009   }
1010
1011   bitmap_ptr = bitmap_data;
1012   for(i=0;i<bitmap_size;i++)
1013     *bitmap_ptr++ = 0;
1014
1015   for(y=0;y<height;y++)
1016   {
1017     /* we only read the first bitplane here to create a black/white bitmap */
1018
1019     for(z=0;z<depth;z++)
1020     {
1021       bitmap_ptr = bitmap_data + y * bytes_per_line;
1022       x = 0;
1023
1024       if (!bitmap_header->Compression)
1025       {
1026         while(x++ < bytes_per_line)
1027           *bitmap_ptr++ |= MSBitFirst2LSBitFirst(*body_ptr++);
1028       }
1029       else
1030       {
1031         while(x < bytes_per_line)
1032         {
1033           byte_count = *body_ptr++;
1034
1035           if (byte_count <= 128)
1036           {
1037             for(i=0;i<byte_count+1;i++)
1038               *bitmap_ptr++ |= MSBitFirst2LSBitFirst(*body_ptr++);
1039             x += byte_count + 1;
1040           }
1041           else
1042           {
1043             byte_value = *body_ptr++;
1044             for(i=0;i<257-byte_count;i++)
1045               *bitmap_ptr++ |= MSBitFirst2LSBitFirst(byte_value);
1046             x += 257 - byte_count;
1047           }
1048         }
1049       }
1050     }
1051   }
1052
1053   bitmap_ptr = bitmap_data;
1054   for(i=0;i<bitmap_size;i++)
1055     *bitmap_ptr++ ^= 0xff;
1056
1057   new_pixmap = XCreateBitmapFromData(display,root,bitmap_data,width,height);
1058
1059   free(file_data);
1060   free(bitmap_data);
1061   free(bitmap_header);
1062
1063   if (!new_pixmap)
1064     return(ILBM_NoMemory);
1065
1066   *pixmap = new_pixmap;
1067   return(ILBM_Success);
1068 }