dtcm: make it build
[oweals/cde.git] / cde / lib / DtHelp / GifUtils.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  * $XConsortium: GifUtils.c /main/5 1996/05/07 13:21:42 drk $
25  * Copyright (c) 1993 HAL Computer Systems International, Ltd.
26  * All rights reserved.  Unpublished -- rights reserved under
27  * the Copyright Laws of the United States.  USE OF A COPYRIGHT
28  * NOTICE IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION
29  * OR DISCLOSURE.
30  * 
31  * THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND TRADE
32  * SECRETS OF HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.  USE,
33  * DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE
34  * PRIOR EXPRESS WRITTEN PERMISSION OF HAL COMPUTER SYSTEMS
35  * INTERNATIONAL, LTD.
36  * 
37  *                         RESTRICTED RIGHTS LEGEND
38  * Use, duplication, or disclosure by the Government is subject
39  * to the restrictions as set forth in subparagraph (c)(l)(ii)
40  * of the Rights in Technical Data and Computer Software clause
41  * at DFARS 252.227-7013.
42  *
43  *          HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.
44  *                  1315 Dell Avenue
45  *                  Campbell, CA  95008
46  * 
47  */
48
49
50 /* +-------------------------------------------------------------------+ */
51 /* | Portions lifted from giftoppm.c (pbmplus version 10dec91)         | */
52 /* |                                                                   | */
53 /* | Copyright 1990, David Koblas.                                     | */
54 /* |   Permission to use, copy, modify, and distribute this software   | */
55 /* |   and its documentation for any purpose and without fee is hereby | */
56 /* |   granted, provided that the above copyright notice appear in all | */
57 /* |   copies and that both that copyright notice and this permission  | */
58 /* |   notice appear in supporting documentation.  This software is    | */
59 /* |   provided "as is" without express or implied warranty.           | */
60 /* +-------------------------------------------------------------------+ */
61
62 #define C_Gif
63 #define L_Graphics
64 #define C_MessageMgr
65 #define L_Managers
66
67 /* include files */
68 #include <stdio.h>
69 #include <stdarg.h>
70 #include <stdlib.h>
71 #include <string.h>
72 #include <math.h>
73 #include <assert.h>
74 #include <Xm/XmPrivate.h>
75 #include "GifUtilsI.h"
76
77 #ifndef __STDC__
78 #define debug1(s, x)  s <<  "x" << " = " << (x) << "\n"
79 #else
80 #define debug1(s, x)  s << #x << " = " << (x) << "\n"
81 #endif
82
83 #define MAX_GHANDS 16   /* maximum # of GRAF handles */
84
85 #define PPM_ASSIGN(p,red,grn,blu) (p) = ((pixel) (red) << 20) | ((pixel) (grn) << 10) | (pixel) (blu)
86 #define PPM_GETR(p) (((p) & 0x3ff00000) >> 20)
87 #define PPM_GETG(p) (((p) & 0xffc00) >> 10)
88 #define PPM_GETB(p) ((p) & 0x3ff)
89
90 #define MAXCOLORMAPSIZE         256
91
92 #define TRUE    1
93 #define FALSE   0
94
95 #define CM_RED          0
96 #define CM_GREEN        1
97 #define CM_BLUE         2
98
99 #define MAX_LWZ_BITS            12
100
101 #define INTERLACE               0x40
102 #define LOCALCOLORMAP   0x80
103 #define BitSet(byte, bit)       (((byte) & (bit)) == (bit))
104
105 #define LM_to_uint(a,b)                 (((b)<<8)|(a))
106
107 typedef struct {
108         unsigned int    Width;
109         unsigned int    Height;
110         unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
111         unsigned int    BitPixel;
112         unsigned int    ColorResolution;
113         unsigned int    Background;
114         unsigned int    AspectRatio;
115 } GifScreenType;
116
117 typedef struct {
118         int     transparent;
119         int     delayTime;
120         int     inputFlag;
121         int     disposal;
122 } Gif89Type;
123
124 /*
125  * This structure holds variables that were formerly global or static
126  * within a function in the original giftoppm code.  They have been
127  * moved into this object to ensure thread re-entrancy of the routines
128  * that use them.  A unique instance of this object is created for each
129  * thread and passed to the appropriate routines.
130  */
131 typedef struct {
132         /* Formerly global variables */
133         GifScreenType    GifScreen;
134         Gif89Type        Gif89;
135         int              ZeroDataBlock;
136         /* Formerly static variables declared in DoExtension */
137         char             ext_buf[256];
138         /* Formerly static variables declared in GetCode */
139         unsigned char    buf[280];
140         int              curbit, lastbit, done, last_byte;
141         /* Formerly static variables declared in LWZReadByte*/
142         int              fresh;
143         int              code_size, set_code_size;
144         int              max_code, max_code_size;
145         int              firstcode, oldcode;
146         int              clear_code, end_code;
147         int              table[2][(1<< MAX_LWZ_BITS)];
148         int              stack[(1<<(MAX_LWZ_BITS))*2], *sp;
149 } GifState;
150
151 /*********************/
152 static void
153 _gif_error( char *format, ... )
154 {
155     va_list args;
156
157     va_start( args, format );
158
159     fprintf( stderr, "GifObject: " );
160     (void) vfprintf( stderr, format, args );
161     fputc( '\n', stderr );
162     va_end( args );
163     /*  throw (Exception()); */
164 #if 0
165     abort();
166 #endif
167 }
168
169 /*********************/
170 static void
171 _gif_message( char *format, ... )
172 {
173     va_list args;
174
175     va_start( args, format );
176
177     fprintf( stderr, "GifObject: " );
178     (void) vfprintf( stderr, format, args );
179     fputc( '\n', stderr );
180     va_end( args );
181 }
182
183 /*********************/
184 static pixel **
185 _gif_allocarray( int cols, int rows, int size )
186 {
187     char** its;
188     int i;
189
190     its = (char**) malloc( rows * sizeof(char*) );
191     if ( its == (char**) 0 )
192         _gif_error( "out of memory allocating an array", 0 );
193     its[0] = (char*) malloc( rows * cols * size );
194     if ( its[0] == (char*) 0 )
195         _gif_error( "out of memory allocating an array", 0 );
196     for ( i = 1; i < rows; ++i )
197         its[i] = &(its[0][i * cols * size]);
198     return (pixel **)its;
199 }
200
201 /*********************/
202 static int
203 GetDataBlock(byte **inbuf, unsigned char *buf, GifState *g)
204 {
205     unsigned char    count;
206
207     count = (*inbuf)[0];
208     (*inbuf)++;
209
210     g->ZeroDataBlock = count == 0;
211
212     if (count) {
213         memcpy (buf, *inbuf, count);
214         *inbuf += count;
215     }
216
217     return count;
218 }
219
220 /*********************/
221 static int
222 ReadColorMap(byte **inbuf, int number, unsigned char buffer[3][MAXCOLORMAPSIZE])
223 {
224     int              i;
225     unsigned char    *rgb;
226
227     for (i = 0; i < number; ++i) {
228         rgb = (unsigned char *)*inbuf;
229         *inbuf += 3;
230
231         buffer[CM_RED][i] = rgb[0] ;
232         buffer[CM_GREEN][i] = rgb[1] ;
233         buffer[CM_BLUE][i] = rgb[2] ;
234     }
235     return FALSE;
236 }
237
238 /*********************/
239 static int
240 DoExtension(byte **inbuf, int label, GifState *g)
241 {
242     char           *str;
243     char           *buf = g->ext_buf;
244
245     switch (label) {
246     case 0x01:        /* Plain Text Extension */
247         str = "Plain Text Extension";
248         break;
249     case 0xff:        /* Application Extension */
250         str = "Application Extension";
251         break;
252     case 0xfe:        /* Comment Extension */
253         str = "Comment Extension";
254         while (GetDataBlock(inbuf, (unsigned char*) buf, g) != 0) {
255 #ifdef DEBUG
256             _gif_message("gif comment: %s", buf );
257 #endif
258         }
259         return FALSE;
260     case 0xf9:        /* Graphic Control Extension */
261         str = "Graphic Control Extension";
262         (void) GetDataBlock(inbuf, (unsigned char*) buf, g);
263         g->Gif89.disposal    = (buf[0] >> 2) & 0x7;
264         g->Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
265         g->Gif89.delayTime   = LM_to_uint(buf[1], buf[2]);
266         if ((buf[0] & 0x1) != 0)
267             g->Gif89.transparent = buf[3];
268
269         while (GetDataBlock(inbuf, (unsigned char*) buf, g) != 0)
270             ;
271         return FALSE;
272     default:
273         str = buf;
274         sprintf(buf, "UNKNOWN (0x%02x)", label);
275         break;
276     }
277
278 #ifdef DEBUG
279     _gif_message("got a '%s' extension", str );
280 #endif
281
282     while (GetDataBlock(inbuf, (unsigned char*) buf, g) != 0)
283         ;
284
285     return FALSE;
286 }
287
288 /*********************/
289 static int
290 GetCode(byte **inbuf, int code_size, int flag, GifState *g)
291 {
292     int            i, j, ret;
293     unsigned char  count;
294     unsigned char  *buf = g->buf;
295
296     if (flag) {
297         for (i = 0; i < 280; i++)
298                 buf[i] = 0;
299         g->last_byte = 0;
300         g->curbit = 0;
301         g->lastbit = 0;
302         g->done = FALSE;
303         return 0;
304     }
305
306     if ( (g->curbit+code_size) >= g->lastbit) {
307         if (g->done) {
308             if (g->curbit >= g->lastbit)
309                 _gif_error("ran off the end of my bits", 0 );
310             return -1;
311         }
312         if (g->last_byte) {
313                 buf[0] = buf[g->last_byte-2];
314                 buf[1] = buf[g->last_byte-1];
315         }
316
317         if ((count = GetDataBlock(inbuf, &buf[2], g)) == 0)
318             g->done = TRUE;
319
320         g->last_byte = 2 + count;
321         g->curbit = (g->curbit - g->lastbit) + 16;
322         g->lastbit = (2+count)*8 ;
323     }
324
325     ret = 0;
326     for (i = g->curbit, j = 0; j < code_size; ++i, ++j)
327         ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
328
329     g->curbit += code_size;
330
331     return ret;
332 }
333
334 /*********************/
335 static int
336 LWZReadByte(byte **inbuf, int flag, int input_code_size, GifState *g)
337 {
338     int        code, incode;
339     int    i;
340
341     if (flag) {
342         g->set_code_size = input_code_size;
343         g->code_size = g->set_code_size+1;
344         g->clear_code = 1 << g->set_code_size ;
345         g->end_code = g->clear_code + 1;
346         g->max_code_size = 2*g->clear_code;
347         g->max_code = g->clear_code+2;
348
349         GetCode(inbuf, 0, TRUE, g);
350         
351         g->fresh = TRUE;
352
353         for (i = 0; i < g->clear_code; ++i) {
354             g->table[0][i] = 0;
355             g->table[1][i] = i;
356         }
357         for (; i < (1<<MAX_LWZ_BITS); ++i)
358             g->table[0][i] = g->table[1][0] = 0;
359
360         g->sp = g->stack;
361
362         return 0;
363     } else if (g->fresh) {
364        g->fresh = FALSE;
365         do {
366             g->firstcode = g->oldcode =
367                 GetCode(inbuf, g->code_size, FALSE, g);
368         } while (g->firstcode == g->clear_code);
369         return g->firstcode;
370     }
371
372     if (g->sp > g->stack)
373         return *--(g->sp);
374
375     while ((code = GetCode(inbuf, g->code_size, FALSE, g)) >= 0) {
376         if (code == g->clear_code) {
377             for (i = 0; i < g->clear_code; ++i) {
378                 g->table[0][i] = 0;
379                 g->table[1][i] = i;
380             }
381             for (; i < (1<<MAX_LWZ_BITS); ++i)
382                 g->table[0][i] = g->table[1][i] = 0;
383             g->code_size = g->set_code_size+1;
384             g->max_code_size = 2*g->clear_code;
385             g->max_code = g->clear_code+2;
386             g->sp = g->stack;
387             g->firstcode = g->oldcode =
388                     GetCode(inbuf, g->code_size, FALSE, g);
389             return g->firstcode;
390         } else if (code == g->end_code) {
391             int        count;
392             unsigned char    buf[260];
393
394             if (g->ZeroDataBlock)
395                 return -2;
396
397             while ((count = GetDataBlock(inbuf, buf, g)) > 0)
398                 ;
399
400 #ifdef DEBUG
401             if (count != 0)
402                 _gif_message("missing EOD in data stream (common occurence)");
403 #endif
404             return -2;
405         }
406
407         incode = code;
408
409         if (code >= g->max_code) {
410             *(g->sp)++ = g->firstcode;
411             code = g->oldcode;
412         }
413
414         while (code >= g->clear_code) {
415             *(g->sp++) = g->table[1][code];
416             if (code == g->table[0][code])
417                 _gif_error("circular table entry BIG ERROR", 0);
418             code = g->table[0][code];
419         }
420
421         *(g->sp)++ = g->firstcode = g->table[1][code];
422
423         if ((code = g->max_code) <(1<<MAX_LWZ_BITS)) {
424             g->table[0][code] = g->oldcode;
425             g->table[1][code] = g->firstcode;
426             ++(g->max_code);
427             if ((g->max_code >= g->max_code_size) &&
428                 (g->max_code_size < (1<<MAX_LWZ_BITS))) {
429                 g->max_code_size *= 2;
430                 ++(g->code_size);
431             }
432         }
433
434         g->oldcode = incode;
435
436         if (g->sp > g->stack)
437             return *--(g->sp);
438     }
439     return code;
440 }
441
442 /*********************/
443 pixel **
444 ReadImage(byte **inbuf, int len, int height, unsigned char cmap[3][MAXCOLORMAPSIZE], int interlace, int ignore, GifState *g)
445 {
446     unsigned char    c;    
447     int              v;
448     int              xpos = 0, ypos = 0, pass = 0;
449     pixel            **image;
450
451     /*
452     **  Initialize the Compression routines
453     */
454     c = (*inbuf)[0];
455     (*inbuf)++;
456
457     if (LWZReadByte(inbuf, TRUE, c, g) < 0)
458         _gif_error("error reading image", 0 );
459
460     /*
461     **  If this is an "uninteresting picture" ignore it.
462     */
463     if (ignore) {
464 #ifdef DEBUG
465         _gif_message("skipping image..." );
466 #endif
467         while (LWZReadByte(inbuf, FALSE, c, g) >= 0)
468             ;
469         return NULL;
470     }
471
472     if ((image = _gif_allocarray(len, height, sizeof(pixel))) == NULL)
473         _gif_error("couldn't alloc space for image", 0 );
474
475 #ifdef DEBUG
476     _gif_message("reading %d by %d%s GIF image",
477                  len, height, interlace ? " interlaced" : "" );
478 #endif
479
480     while ((v = LWZReadByte(inbuf,FALSE,c, g)) >= 0 ) {
481         PPM_ASSIGN(image[ypos][xpos], cmap[CM_RED][v],
482                     cmap[CM_GREEN][v], cmap[CM_BLUE][v]);
483
484         ++xpos;
485         if (xpos == len) {
486             xpos = 0;
487             if (interlace) {
488                 switch (pass) {
489                 case 0:
490                 case 1:
491                     ypos += 8; break;
492                 case 2:
493                     ypos += 4; break;
494                 case 3:
495                     ypos += 2; break;
496                 }
497
498                 if (ypos >= height) {
499                     ++pass;
500                     switch (pass) {
501                     case 1:
502                         ypos = 4; break;
503                     case 2:
504                         ypos = 2; break;
505                     case 3:
506                         ypos = 1; break;
507                     default:
508                         goto fini;
509                     }
510                 }
511             } else {
512                 ++ypos;
513             }
514         }
515         if (ypos >= height)
516             break;
517     }
518
519 fini:
520 #ifdef DEBUG
521     if (LWZReadByte(inbuf,FALSE,c, g)>=0)
522         _gif_message("too much input data, ignoring extra...");
523 #endif
524     return image;
525
526 }
527
528
529 /* ////////////////////////////////////////////////////////////
530 // class constructor
531 // ////////////////////////////////////////////////////////// */
532
533 enum _DtGrLoadStatus InitGifObject (
534     GifObj               *go, 
535     Display              *dpy, 
536     Drawable             drawable,
537     Screen               *screen,
538     int                  depth,
539     Colormap             colormap,
540     Visual               *visual,
541     GC                   gc,
542     enum _DtGrColorModel colorModel, 
543     Boolean              allowReducedColors)
544 {
545     int r, g, b, i, visualsMatched;
546     XVisualInfo vTemplate, *visualList;
547
548     /* 
549     ** Initialize structure values
550     */
551     go->bits_per_pixel = 2;
552     go->colors_per_pixel = (int) pow (2, go->bits_per_pixel);
553     go->total_colors = (int) pow (go->colors_per_pixel, 3);
554     go->f_color_map_constructed = 0;
555     go->f_total_greys = 2;
556     go->f_ximage    = NULL;
557     go->f_dpy       = dpy;
558     go->f_drawable  = drawable;
559     go->f_screen    = XScreenNumberOfScreen(screen);
560     go->f_dft_depth = depth;
561     go->f_cmap      = colormap;
562     go->f_gc        = gc;
563     go->f_visual    = visual;
564     go->f_ncells    = DisplayCells(go->f_dpy, go->f_screen);
565     go->f_nplanes   = DisplayPlanes(go->f_dpy,go->f_screen);
566     go->f_white     = WhitePixel(go->f_dpy, go->f_screen); 
567     go->f_black     = BlackPixel(go->f_dpy, go->f_screen);
568     go->f_allow_reduced_colors = allowReducedColors;
569     go->f_color_reduction_used = FALSE;
570
571     /*
572     ** Initialize color allocation fields according to the color model
573     ** specified by the caller.
574     */
575     switch (colorModel)
576     {
577         case _DtGrCOLOR:
578              go->f_do_visual = DO_COLOR;
579              go->f_init_total_greys = 32;
580              break;
581         case _DtGrGRAY_SCALE:
582              go->f_do_visual = DO_GREY;
583              go->f_init_total_greys = 32;
584              break;
585         case _DtGrBITONAL:
586              go->f_do_visual = DO_GREY;
587              go->f_init_total_greys = 2;
588              break;
589         default:
590             /* Should never get here */
591              go->f_do_visual = DO_COLOR;
592              go->f_init_total_greys = 32;
593     }
594
595     /* Return if the colormap is already allocated */
596     if ( go->f_color_map_constructed )
597         return (_DtGrSUCCESS);
598
599     /* find the visual class code */
600
601     vTemplate.screen = go->f_screen;
602     vTemplate.depth = go->f_dft_depth;
603
604     visualList = XGetVisualInfo( go->f_dpy, 
605                                  VisualScreenMask | VisualDepthMask,
606                                  &vTemplate, &visualsMatched );
607
608     /* Return failure if we can't find a matching visual */
609     if ( visualsMatched == 0 ) 
610         return (_DtGrCONVERT_FAILURE);
611
612     go->f_visual_class = StaticGray;
613
614     for ( i=0; i<visualsMatched; i++ ) 
615     {
616         if ( visualList[i].visual == go->f_visual ) 
617         {
618             go->f_visual_class = visualList[i].class;
619             break;
620         }
621     }
622
623     XFree(visualList);
624
625     /* Construct a 4x4x4 color cube */
626     i = 0;
627     for (r = 0; r < go->colors_per_pixel; r++)
628         for (g = 0; g < go->colors_per_pixel; g++)
629            for (b = 0; b < go->colors_per_pixel; b++)
630            {
631                go->GifCMap[i].red   = ((r * 65535)/(go->colors_per_pixel - 1));
632                go->GifCMap[i].green = ((g * 65535)/(go->colors_per_pixel - 1));
633                go->GifCMap[i].blue  = ((b * 65535)/(go->colors_per_pixel - 1));
634                i++;
635            }
636
637     /* 
638     ** Allocate X pixels, either color or greyscale values depending upon
639     ** visual class and color model.
640     */
641     switch ( go->f_visual_class ) 
642     {
643         case StaticGray:
644         case GrayScale:
645         case StaticColor:
646         {
647             /*
648             ** Return failure if caller is insisting on color and this
649             ** visual can't provide it.
650             */
651             if ((colorModel == _DtGrCOLOR) && !allowReducedColors)
652                 return (_DtGrCOLOR_FAILED);
653
654             if ( allocate_greys(go) != 0 )
655                 return (_DtGrCOLOR_FAILED);
656
657             break;
658         }
659
660         case PseudoColor:
661         case DirectColor:
662         case TrueColor:
663         {
664            if (colorModel == _DtGrCOLOR)
665            {
666                if ( allocate_colors(go) != 0 )
667                    return (_DtGrCOLOR_FAILED);
668            }
669            else
670            {
671                if ( allocate_greys(go) != 0 )
672                    return (_DtGrCOLOR_FAILED);
673            }
674            break;
675         }
676
677         default:
678             return (_DtGrCONVERT_FAILURE);
679     }
680
681     /*
682     ** Colors successfully allocated, return status code indicating
683     ** whether we had to fallback to a degraded color model.
684     */
685     if (go->f_color_reduction_used)
686         return (_DtGrCOLOR_REDUCE);
687     else
688         return (_DtGrSUCCESS);
689 }
690
691 /* /////////////////////////////////////////////////////////////////
692 // class destructor
693 // /////////////////////////////////////////////////////////////// */
694
695 void DeleteGifObjectResources(GifObj *g)
696 {
697 }
698
699 int allocate_colors(GifObj *g)
700 {
701     int i, j;
702     /*return allocate_greys(); // use this to test grey-scale */
703
704    XColor color;
705    unsigned long* colors;
706
707    color.flags = DoRed | DoGreen | DoBlue;
708
709    for (i = 0; i < g->total_colors; i++) {
710
711       color.red   = g->GifCMap[i].red;
712       color.green = g->GifCMap[i].green;
713       color.blue  = g->GifCMap[i].blue;
714     
715       /*printf ("Allocating %3d: ", i); */
716       if ( !XAllocColor (g->f_dpy, g->f_cmap, &color) ) {
717
718           /*puts ("FAILED!!!"); */
719          colors = (unsigned long *) malloc (sizeof(unsigned long)  * i);
720          for (j = 0; j < i; j++)
721            colors[j] = g->GifCMap[j].pixel;
722
723          /*cerr << "Xfree in allocate_colors(): " << i << "\n"; */
724          XFreeColors (g->f_dpy, g->f_cmap, colors, i, 0);
725
726          free(colors);
727
728          /* fallback to greys */
729          if (g->f_allow_reduced_colors)
730          {
731              g->f_color_reduction_used = TRUE;
732              return allocate_greys(g);
733          }
734          else
735              return (_DtGrCOLOR_FAILED);
736       }
737
738       /*fprintf(stderr, "i=%d pixel=%d\n", i, color.pixel);*/
739
740       /*printf ("@ %d\n", color.pixel); */
741       g->GifCMap[i].pixel = color.pixel;
742     }
743
744    g->f_do_visual = DO_COLOR;
745    g->f_color_map_constructed = 1;
746
747    return 0;
748 }
749
750 int allocate_greys(GifObj *g)
751 {
752    XColor color;
753    int i, j;
754    unsigned long* colors;
755
756    color.flags = DoRed | DoGreen | DoBlue;
757
758    for ( i=0; i<g->total_colors; i++ ) {
759
760 /*
761 debug1(cerr, i);
762 debug1(cerr, GifCMap[i].red);
763 debug1(cerr, GifCMap[i].green);
764 debug1(cerr, GifCMap[i].blue);
765 debug1(cerr, 0.299 * GifCMap[i].red + 0.587 * GifCMap[i].green +
766                                          0.114 * GifCMap[i].blue);
767 debug1(cerr, GifCMap[i].grey);
768 */
769
770       g->GifCMap[i].grey = (unsigned short)(0.299 * g->GifCMap[i].red +     
771                                          0.587 * g->GifCMap[i].green +     
772                                          0.114 * g->GifCMap[i].blue);     
773    }
774
775 /*   
776    if ( StaticColor == g->f_visual_class ||
777         TrueColor == g->f_visual_class ) 
778 */
779    if ( StaticColor == g->f_visual_class)
780    {
781       g->f_do_visual = DO_GREY;
782       g->f_total_greys = 2;
783       return 0;
784    }
785
786
787    for ( g->f_total_greys=g->f_init_total_greys; g->f_total_greys>=2; 
788          g->f_total_greys/=2 ) 
789    {
790       /*fprintf(stderr, "f_total_greys = %d\n", g->f_total_greys); */
791
792       /*
793       ** Return failure if we're about to downgrade from greyscale
794       ** to dithered monochrome and we don't allow reduced colors.
795       */ 
796       if ((g->f_total_greys == 2) && (g->f_init_total_greys > 2) &&
797           (!g->f_allow_reduced_colors))
798           return -1;
799
800       for (i = 0; i<g->f_total_greys; i++) {
801
802          color.red = 
803          color.green = 
804          color.blue  = (i*65535)/(g->f_total_greys - 1);
805    
806          /*fprintf (stderr, "Allocating %3d: ", i);*/
807          if ( !XAllocColor (g->f_dpy, g->f_cmap, &color) ) {
808
809              /*fprintf(stderr, "alloc Grey FAILED!!!");*/
810             colors = (unsigned long *) malloc (sizeof(unsigned long)  * i);
811             for (j = 0; j < i; j++)
812               colors[j] = g->GifGMap[j];
813
814             /*cerr << "Xfree in allocate_greys()\n"; */
815             XFreeColors (g->f_dpy, g->f_cmap, colors, i, 0);
816
817             free(colors);
818      
819             break;
820          }
821
822          /*printf ("@ %d\n", color.pixel); */
823          g->GifGMap[i] = color.pixel;
824       }
825
826       if ( i == g->f_total_greys ) {
827
828 /*
829 for ( int l=0; l<i; l++ )
830 cerr << "GifGMap[l]= " << GifGMap[l] << "\n";
831 */
832
833          g->f_color_map_constructed = 1;
834          g->f_do_visual = DO_GREY;
835          /* If greyscape was downgraded to bitonal, record the fact */
836          if ((g->f_total_greys == 2) && (g->f_init_total_greys > 2))
837              g->f_color_reduction_used = TRUE;
838          return 0;
839       }
840    }
841
842    return -1;
843 }
844
845 /* ////////////////////////////////////////////////////////////
846 // Free allocated raw image data
847 // ////////////////////////////////////////////////////////// */
848
849 void
850 free_raw_image( pixel **image )
851 {
852     free( (char *)image[0] );
853     free( (char *)image );
854 }
855
856 /* ////////////////////////////////////////////////////////////
857 // Decompress GIF data into raw bytes
858 // ////////////////////////////////////////////////////////// */
859
860 pixel **
861 create_raw_image( byte *inbuf, unsigned int buflen, int *width, int *height, int imageNumber )
862 {
863     unsigned char    *buf;
864     unsigned char    *start_of_buf = inbuf;
865     unsigned char    c;
866     unsigned char    localColorMap[3][MAXCOLORMAPSIZE];
867     int              useGlobalColormap;
868     int              bitPixel;
869     int              imageCount = 0;
870     char             version[4];
871     pixel            **image;
872     GifState         g;
873
874     /* Initialize the GIF state object */
875     g.Gif89.transparent = g.Gif89.delayTime = g.Gif89.inputFlag = -1;
876     g.Gif89.disposal = 0;
877     g.ZeroDataBlock = FALSE;
878     g.fresh = FALSE;
879
880     /*  XXXSWM -- hack */
881     if (buflen < 13) {
882         fprintf (stderr, "Not GIF Data, buffer too small\n");
883         return NULL;
884     }
885
886     buf = (unsigned char *)inbuf;
887     inbuf += 6;
888
889     if (strncmp((const char *)buf,"GIF",3) != 0) {
890         fprintf( stderr, "GifObject: not GIF data\n" );
891         return NULL;
892     }
893
894     strncpy(version, (const char *)(buf + 3), 3);
895     version[3] = '\0';
896
897     if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
898         fprintf (stderr, "bad version number, not '87a' or '89a'\n" );
899         return NULL;
900     }
901
902     buf = (unsigned char *)inbuf;
903     inbuf += 7;
904
905     g.GifScreen.Width           = LM_to_uint(buf[0],buf[1]);
906     g.GifScreen.Height          = LM_to_uint(buf[2],buf[3]);
907     g.GifScreen.BitPixel        = 2<<(buf[4]&0x07);
908     g.GifScreen.ColorResolution = (((buf[4]&0x70)>>3)+1);
909     g.GifScreen.Background      = buf[5];
910     g.GifScreen.AspectRatio     = buf[6];
911
912     if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
913         if (ReadColorMap(&inbuf,g.GifScreen.BitPixel,g.GifScreen.ColorMap)) {
914             fprintf (stderr, "error reading global colormap\n" );
915             return NULL;
916         }
917     }
918
919     if (g.GifScreen.AspectRatio != 0 && g.GifScreen.AspectRatio != 49) {
920         float    r;
921         r = ( (float) g.GifScreen.AspectRatio + 15.0 ) / 64.0;
922 #ifdef DEBUG
923         _gif_message("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'",
924             r < 1.0 ? 'x' : 'y',
925             r < 1.0 ? 1.0 / r : r );
926 #endif
927     }
928
929     image = NULL;
930
931     for (;;) {
932         if (inbuf - start_of_buf >= buflen) {
933             fprintf (stderr, "Premature EOF in GIF data\n");
934             return NULL;
935         }
936         c = inbuf[0];
937         inbuf++;
938
939         if (c == ';') {        /* GIF terminator */
940             if (imageCount < imageNumber)
941                 _gif_error("only %d image%s found in file",
942                      imageCount, imageCount>1?"s":"" );
943             return image;
944         }
945
946         if (c == '!') {     /* Extension */
947             if (inbuf - start_of_buf >= buflen) {
948                 fprintf  (stderr, "Premature EOF in GIF data\n");
949                 return NULL;
950             }
951             c = inbuf[0];
952             inbuf++;
953             DoExtension(&inbuf, c, &g);
954             continue;
955         }
956
957         if (c != ',') {        /* Not a valid start character */
958 #ifdef DEBUG
959             _gif_message("bogus character 0x%02x, ignoring", (int) c );
960 #endif
961             continue;
962         }
963
964         ++imageCount;
965
966         buf = (unsigned char *)inbuf;
967         inbuf += 9;
968
969         useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
970
971         bitPixel = 1<<((buf[8]&0x07)+1);
972
973         *width = LM_to_uint(buf[4],buf[5]);
974         *height = LM_to_uint(buf[6],buf[7]);
975
976         if (! useGlobalColormap) {
977             if (ReadColorMap(&inbuf, bitPixel, localColorMap))
978                 _gif_error("error reading local colormap", 0 );
979             image = ReadImage(&inbuf, *width, *height, localColorMap,
980                        BitSet(buf[8], INTERLACE), imageCount != imageNumber,
981                        &g);
982         } else {
983             image = ReadImage(&inbuf, *width, *height, g.GifScreen.ColorMap,
984                        BitSet(buf[8], INTERLACE), imageCount != imageNumber,
985                        &g);
986         }
987
988     }
989 }
990
991 /* ////////////////////////////////////////////////////////////
992 // Create X pixmap from raw image data
993 // ////////////////////////////////////////////////////////// */
994
995 /* from "Computer Graphics" by Foley, VanDam, Feiner, Hughes */
996 /*       2nd edition */
997 static int dither_8X8[8][8] = 
998 {
999  { 0,  32,  8, 40,  2, 34, 10, 42 },
1000  { 48, 16, 56, 24, 50, 18, 58, 26 },
1001  { 42, 44,  4, 36, 14, 46,  6, 38 },
1002  { 60, 28, 52, 20, 62, 30, 54, 22 },
1003  { 3,  35, 11, 43,  1, 33,  9, 41 },
1004  { 51, 19, 59, 27, 49, 17, 57, 25 },
1005  { 15, 47,  7, 39, 13, 45,  5, 37 },
1006  { 63, 31, 55, 23, 61, 29, 53, 21 }
1007 };
1008
1009 /*static int dither_6X6[6][6] =
1010 //{
1011 // { 24, 32, 16, 26, 34, 18},
1012 // {  4,  0, 12,  6, 2,  14},
1013 // { 20,  8, 28, 22, 10, 30},
1014 // { 27, 35, 19, 25, 33, 17},
1015 // {  7,  3, 15,  5,  1, 13},
1016 // { 23, 11, 31, 21,  9, 29}
1017 //};
1018 */
1019
1020 /*
1021 static int dither_4X4[4][4] = 
1022 {
1023  { 0, 8, 2, 10 },
1024  { 12, 4, 14, 6},
1025  { 3, 11, 1, 9},
1026  { 15, 7, 13, 5}
1027 };
1028
1029
1030 static int dither_3X3[3][3] = 
1031 {
1032  { 6, 8, 4 },
1033  { 1, 0, 3},
1034  { 5, 2, 7}
1035 };
1036
1037
1038 static int dither_2X2[2][2] = 
1039 {
1040  { 0, 2 },
1041  { 3, 1}
1042 };
1043 */
1044
1045 /*static int dither_matrix_sz = 2; */
1046 /*static int dither_matrix_sz = 4; */
1047 /*static int dither_matrix_sz = 3; */
1048 static int dither_matrix_sz = 8;
1049
1050 /* call XListPixFormat() to get bits/pix and pads ? */
1051 Pixmap
1052 create_pixmap( GifObj *g, pixel **image, int width, int height, Pixel fg, Pixel bg, float ratio)
1053 {
1054   int nullCount = (4 - (width % 4)) & 0x03;
1055   int ximWidth = width + nullCount; 
1056   byte *ximData = 0;
1057   pixel *ipp = *image;
1058   int spacing;
1059   long pixval;
1060   int x, y;
1061   int index;
1062   Pixmap pm;
1063   int scaledWidth, scaledHeight;
1064
1065   if ( g->f_nplanes > 8 )
1066      ximData = (byte *) malloc(ximWidth * height * 4 );
1067   else
1068      ximData = (byte *) malloc(ximWidth * height );
1069
1070   if (!ximData) {
1071     fprintf(stderr, "Could not allocate ximage data\n");
1072     return None;
1073   }
1074
1075   /* Monochrome */
1076   if (g->f_nplanes == 1)
1077      g->f_ximage = XCreateImage(g->f_dpy, g->f_visual, g->f_nplanes, XYPixmap,
1078                           0, (char *)ximData, width, height, 32, 0);
1079   /* 8 bit color */
1080   /*else if (g->f_nplanes == 8) */
1081
1082   /* non-mono display */
1083   else  
1084      g->f_ximage = XCreateImage(g->f_dpy, g->f_visual, g->f_nplanes, ZPixmap,
1085                           0, (char *)ximData, width, height, 32, 0);
1086
1087   if (!g->f_ximage) {
1088     fprintf(stderr, "XCreateImage failed\n");
1089     return None;
1090   }
1091
1092
1093 /* RGB to Pixel Conversion */
1094
1095   if ( g->f_total_greys == 2 ) 
1096      spacing = 65536 / (dither_matrix_sz * dither_matrix_sz);
1097   else
1098      spacing = 65536 / g->f_total_greys;
1099
1100 /*cerr << "spacing" << spacing << "\n"; */
1101
1102   for (y=0; y < height; y++) {
1103     for (x=0; x < width; x++) {
1104       pixval = (long)*ipp; 
1105
1106 /*      XColor cellDef; */
1107 /*      cellDef.red   = (short)PPM_GETR(pixval);    */
1108 /*      cellDef.green = (short)PPM_GETG(pixval);    */
1109 /*      cellDef.blue  = (short)PPM_GETB(pixval);    */
1110
1111           index = (((short)PPM_GETR(pixval))/64)*16 +
1112                   (((short)PPM_GETG(pixval))/64)*4  +
1113                   ((short)PPM_GETB(pixval))/64;
1114
1115 /*fprintf(stderr, "grey= %d, grey/space=%d\n", g->GifCMap[index].grey, g->GifCMap[index].grey / spacing);*/
1116       switch (g->f_do_visual) {
1117         case DO_GREY:
1118
1119          switch ( g->f_total_greys ) {
1120           case 2:
1121
1122 /*cerr << "index=" << index << "\n"; */
1123 /*cerr << "GifCMap[index].grey" << GifCMap[index].grey << "\n"; */
1124 /*cerr << "GifCMap[index].grey/spacing" << GifCMap[index].grey / spacing << "\n"; */
1125
1126             if ( dither_8X8[x%dither_matrix_sz][y%dither_matrix_sz] < g->GifCMap[index].grey / spacing ) {
1127                XPutPixel(g->f_ximage,x,y,g->f_white);
1128             } else {
1129                XPutPixel(g->f_ximage,x,y,g->f_black);
1130             }
1131
1132             break;
1133
1134
1135          default:
1136 /*cerr << GifCMap[index].grey / spacing << " "; */
1137
1138            XPutPixel(g->f_ximage,x,y, g->GifGMap[g->GifCMap[index].grey / spacing]);
1139          }
1140          
1141          break;
1142
1143
1144         case DO_COLOR:
1145 #ifdef FLOOD
1146 fprintf(stderr, "%03d %03d %03d -- %03d %03d %03d ",
1147 (short)PPM_GETR(pixval),(short)PPM_GETG(pixval),(short)PPM_GETB(pixval),
1148 g->GifCMap[index].red>>8, g->GifCMap[index].green>>8, g->GifCMap[index].blue>>8
1149                             );
1150 if ((short)PPM_GETR(pixval) != (GifCMap[index].red>>8) || 
1151     (short)PPM_GETG(pixval) != (GifCMap[index].green>>8) || 
1152     (short)PPM_GETB(pixval) != (GifCMap[index].blue>>8))
1153   puts (" *");
1154 else
1155   puts (" -"); 
1156 #endif
1157
1158
1159              XPutPixel(g->f_ximage,x,y, g->GifCMap[index].pixel);
1160 /*
1161          switch ( g->f_visual_class ) {
1162           case StaticColor:
1163           case PseudoColor:
1164              XPutPixel(g->f_ximage,x,y, g->GifCMap[index].pixel);
1165              break;
1166
1167           case TrueColor:
1168           case DirectColor:
1169              break;
1170
1171          }
1172 */
1173
1174        }
1175
1176       ipp++;
1177     }
1178     for (x=width;x<ximWidth;x++)
1179       XPutPixel(g->f_ximage,x,y,bg);   /* padding */
1180   }
1181
1182   scaledWidth = width * ratio + 0.5;
1183   scaledHeight = height * ratio + 0.5;
1184   if (scaledWidth == 0)
1185       scaledWidth = 1;
1186   if (scaledHeight == 0)
1187      scaledHeight = 1; 
1188   pm = XCreatePixmap(g->f_dpy,g->f_drawable,
1189                      scaledWidth,scaledHeight,
1190                      g->f_nplanes);
1191
1192   if (!pm) {
1193     fprintf(stderr, "could not create pixmap\n");
1194     return None;
1195   }
1196
1197   _XmPutScaledImage (g->f_dpy,pm,g->f_gc,g->f_ximage,
1198                      0,0,0,0,width,height,
1199                      scaledWidth,scaledHeight);
1200
1201   XDestroyImage(g->f_ximage);
1202   g->f_ximage = NULL;
1203   
1204   return(pm);
1205 }
1206
1207
1208 /* /////////////////////////////////////////////////////////////////
1209 // Load pixmap from GIF data
1210 // /////////////////////////////////////////////////////////////// */
1211
1212 Pixmap
1213 gif_to_pixmap(GifObj *g, byte *inbuf, unsigned int buflen, Dimension *w, Dimension *h, Pixel fg, Pixel bg, float ratio)
1214 {
1215   Pixmap pixmap;
1216   pixel  **raw_image;
1217   int    width, height;
1218
1219   /* Create raw image from compress GIF data */
1220   raw_image = create_raw_image (inbuf, buflen, &width, &height, 1);
1221   if (!raw_image) return None;
1222
1223   /* Create X pixmap from raw image data */
1224   pixmap = create_pixmap(g, raw_image, width, height, fg, bg, ratio);
1225
1226   /* Free raw image data */
1227   free_raw_image(raw_image);
1228
1229   /* Set X pixmap dimensions */
1230   *w = (Dimension) width * ratio + 0.5;
1231   *h = (Dimension) height * ratio + 0.5;
1232   if (*w == 0)
1233       *w = 1;
1234   if (*h == 0)
1235       *h = 1;
1236   /* Return X pixmap */
1237   return pixmap;
1238 }