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