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