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