1 /*
2  *  This file is part of the XForms library package.
3  *
4  *  XForms is free software; you can redistribute it and/or modify it
5  *  under the terms of the GNU Lesser General Public License as
6  *  published by the Free Software Foundation; either version 2.1, or
7  *  (at your option) any later version.
8  *
9  *  XForms is distributed in the hope that it will be useful, but
10  *  WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public License
15  *  along with XForms.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 
19 /*
20  *  This file is part of the XForms library package.
21  *  Copyright (c) 1993, 1998-2002  By T.C. Zhao
22  *  All rights reserved.
23  *
24  * BUGS: delay & input not handled
25  *
26  * "The Graphics Interchange Format(c) is the Copyright property of
27  *  CompuServ Incorporated. GIF(sm) is a Service Mark property of
28  *  CompuServ Incorporated.
29  *
30  *   Signature
31  *   screen descriptor
32  *   global map
33  *   image descriptor   --- 1
34  *   raster             --- 2
35  *   terminator
36  *
37  *  1 & 2 can be repeated.
38  */
39 
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43 
44 #include "include/forms.h"
45 #include "flimage.h"
46 #include "flimage_int.h"
47 
48 #define IMAGESEP      0x2C  /* ',' */
49 
50 
51 /***************************************
52  ***************************************/
53 
54 static int
GIF_identify(FILE * fp)55 GIF_identify( FILE * fp )
56 {
57     char buf[ 7 ];
58 
59     if ( fread( buf, 1, 6, fp ) != 6 )
60         return 0;
61     rewind( fp );
62     return    buf[ 0 ] == 'G'
63            && buf[ 1 ] == 'I'
64            && buf[ 2 ] == 'F'
65            && buf[ 5 ] == 'a';
66 }
67 
68 static int read_descriptor_block( FL_IMAGE * im );
69 static int skip_extension( FILE * fp,
70                            FL_IMAGE * );
71 static void read_map( FL_IMAGE * );
72 
73 
74 /* plain text extension */
75 
76 typedef struct
77 {
78     char str[ 512 ];
79     int  x,
80          y;
81     int cw,
82         ch;
83     int tw,
84         th;
85     int tran;
86     int bc,
87         tc;
88 } GIFTEXT;
89 
90 /* graphics control extension */
91 
92 typedef struct
93 {
94     int tran;
95     int delay;
96     int input;
97     int tran_col;
98 } GIFGCNTL;
99 
100 #define MAXGIFTEXT 5
101 
102 typedef struct
103 {
104     int      interlace;
105     int      lsx,
106              lsy;
107     int      bkcolor;
108     int      aspect;
109     int      cur_total;
110     int      globalmap;
111     GIFGCNTL gc;
112     int      ctext;
113     GIFTEXT  giftext[ MAXGIFTEXT ];
114 } SPEC;
115 
116 static int GIF_next( FL_IMAGE * );
117 
118 
119 /***************************************
120  ***************************************/
121 
122 static int
GIF_description(FL_IMAGE * im)123 GIF_description( FL_IMAGE * im )
124 {
125     unsigned char buf[ 15 ];
126     FILE *fp = im->fpin;
127     SPEC *sp = fl_calloc( 1, sizeof *sp );
128 
129     im->io_spec = sp;
130     im->spec_size = sizeof *sp;
131 
132     im->next_frame = GIF_next;
133     sp->gc.tran = 0;
134 
135     /* identify should've already checked signature. */
136 
137     if (    fread( buf, 1, 6, fp ) != 6
138          || fread( buf, 1, 7, fp ) != 7 )
139     {
140         flimage_error( im, "%s: error while reading gif file", im->infile );
141         return -1;
142     }
143 
144     sp->lsx = buf[ 0 ] + ( buf[ 1 ] << 8 );
145     sp->lsy = buf[ 2 ] + ( buf[ 3 ] << 8 );
146 
147     sp->globalmap = buf[ 4 ] & 0x80;
148     im->map_len = 1 << ( 1 + ( buf[ 4 ] & 0x07 ) );
149     flimage_getcolormap( im );
150     sp->bkcolor = buf[ 5 ];
151     sp->aspect = buf[ 6 ] ?
152                  ( int ) ( 1000.0 * ( buf[ 6 ] + 15 ) / 64.0 ) : 1000;
153 
154     /* err= buf[4] & 0x08; */
155 
156     if ( sp->globalmap )
157         read_map( im );
158 
159     return read_descriptor_block( im );
160 }
161 
162 
163 /***************************************
164  ***************************************/
165 
166 static void
read_map(FL_IMAGE * im)167 read_map( FL_IMAGE * im )
168 {
169     int i;
170 
171     for ( i = 0; i < im->map_len; i++ )
172     {
173         im->red_lut[   i ] = getc( im->fpin );
174         im->green_lut[ i ] = getc( im->fpin );
175         im->blue_lut[  i ] = getc( im->fpin );
176     }
177 }
178 
179 
180 /***************************************
181  ***************************************/
182 
183 static void
write_map(FL_IMAGE * im,int n)184 write_map( FL_IMAGE * im,
185            int        n )
186 {
187     int i;
188 
189     for ( i = 0; i < im->map_len; i++ )
190     {
191         putc( im->red_lut[   i ], im->fpout );
192         putc( im->green_lut[ i ], im->fpout );
193         putc( im->blue_lut[  i ], im->fpout );
194     }
195 
196     for ( ; i < n; i++ )
197     {
198         putc( 0, im->fpout );
199         putc( 0, im->fpout );
200         putc( 0, im->fpout );
201     }
202 }
203 
204 
205 /***************************************
206  ***************************************/
207 
208 static void
generate_header_info(FL_IMAGE * im)209 generate_header_info( FL_IMAGE *im )
210 {
211    SPEC *sp = im->io_spec;
212    char buf[ 128 ];
213 
214    if ( ! im->info && ! ( im->info = fl_malloc( 1024 ) ) )
215        return;
216 
217    sprintf( im->info, "Size=(%d x %d)\n", im->w, im->h );
218    sprintf( buf,"Colors=%d\nGlobalmap=%d\n", im->map_len, sp->globalmap );
219    strcat( im->info,buf );
220    sprintf( buf,"Aspect=%d\nInterlace=%d\n", sp->aspect, sp->interlace );
221    strcat( im->info, buf );
222    sprintf( buf,"Offset=(%d %d)\n", im->wx, im->wy );
223    strcat( im->info, buf );
224 }
225 
226 
227 /***************************************
228  ***************************************/
229 
230 static int
read_descriptor_block(FL_IMAGE * im)231 read_descriptor_block( FL_IMAGE * im )
232 {
233     int local_map,
234         inbyte;
235     FILE *fp = im->fpin;
236     SPEC *sp = im->io_spec;
237 
238     /* Read the extension if any, and do nothing about it until get the image
239        separator */
240 
241     if ( skip_extension( fp, im ) != IMAGESEP )
242     {
243         flimage_error( im, "%s: no separator or BadBlockMarker", im->infile );
244         return -1;
245     }
246 
247     /* offset relative to lsx and lsy */
248 
249     im->wx = fli_fget2LSBF( fp );
250     im->wy = fli_fget2LSBF( fp );
251 
252     /* True image size */
253 
254     im->w = fli_fget2LSBF( fp );
255     im->h = fli_fget2LSBF( fp );
256 
257     if ( sp->lsx < im->w || sp->lsy < im->h )
258     {
259         M_info( "", "Bad screen description. LX=%d W=%d LY=%d H=%d",
260                 sp->lsx, im->w, sp->lsy, im->h );
261         sp->lsx = im->w;
262         sp->lsy = im->h;
263     }
264 
265     inbyte = getc( fp );
266     sp->interlace = ( inbyte & 0x40 ) != 0;
267     local_map = ( inbyte & 0x80 );
268 
269     if ( ! sp->globalmap && !local_map )
270     {
271         M_err( "GIFDescriptor", "%s: No ColorMap", im->infile );
272         /* return -1; *//* might want to continue */
273     }
274 
275     /* If local map, replace the global map */
276 
277     if ( local_map )
278     {
279         local_map = ( inbyte & 0x07 ) + 1;
280         im->map_len = 1 << local_map;
281         flimage_getcolormap( im );
282         read_map( im );
283     }
284 
285     /* Handle transparency */
286 
287     if ( sp->gc.tran && sp->gc.tran_col < im->map_len )
288         im->tran_index = sp->gc.tran_col;
289 
290     if ( im->setup->header_info )
291         generate_header_info( im );
292 
293     return 0;
294 }
295 
296 
297 #define Badfread( a, b, c, d )    ( fread( a, b, c, d ) != ( c ) )
298 #define Badfwrite( a, b, c, d )   ( fwrite( a, b, c, d ) != ( c ) )
299 
300 
301 /***************************************
302  ***************************************/
303 
304 static void
convert_gif_text(FL_IMAGE * im)305 convert_gif_text( FL_IMAGE * im )
306 {
307     SPEC *sp = im->io_spec;
308     GIFTEXT *p = sp->giftext,
309             *ps = p + sp->ctext;
310     unsigned int tcol,
311                  bcol;
312     int x,
313         y;
314     int fsize;
315 
316     while ( p < ps )
317     {
318         int tc = p->tc,
319             bc = p->bc;
320 
321         if ( ! p->str[ 0 ] )
322             continue;
323 
324         /* gif text size is given in pixels, convert to point. 1pixel = 0.75pt
325            for a typical screen */
326 
327         if ( ( fsize = ( int ) ( FL_min( p->cw, p->ch ) * 0.75 ) ) < 6 )
328             fsize = 6;
329         else if ( fsize > 24 )
330             fsize = 24;
331 
332         /* convert text position to image based */
333 
334         x = p->x - im->wx;
335         y = p->y - im->wy;
336 
337         tcol = FL_PACK3( im->red_lut[ tc ], im->green_lut[ tc ],
338                          im->blue_lut[ tc ] );
339         bcol = FL_PACK3( im->red_lut[ bc ], im->green_lut[ bc ],
340                          im->blue_lut[ bc ] );
341 
342         flimage_add_text( im, p->str, strlen( p->str ), 0, fsize, tcol, bcol,
343                           ! p->tran, x, y, 0 );
344         p++;
345     }
346 }
347 
348 
349 /******************* local functions ******************/
350 
351 static int readextension( FILE *,
352                           FL_IMAGE * );
353 static int next_lineno( int,
354                         int,
355                         int );
356 static int process_lzw_code( FL_IMAGE *,
357                              int );
358 static void outputline( FL_IMAGE *,
359                         unsigned char * );
360 
361 
362 /****************** decoder variables ******************/
363 
364 static const unsigned int gif_codemask[ ] =
365 {
366     0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f,
367     0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff
368 };
369 
370 
371 /***************************************
372  * ouptut line simply copies one scanline at a time to the master
373  * image structure, taking into account the possibility of
374  * interlacing
375  ***************************************/
376 
377 static void
outputline(FL_IMAGE * im,unsigned char * line)378 outputline( FL_IMAGE      * im,
379             unsigned char * line )
380 {
381     unsigned short *po;
382     unsigned char *pi = line;
383     SPEC *sp = im->io_spec;
384     static int lines;
385     int k;
386 
387     if ( sp->cur_total == 0 )   /* first entry */
388         lines = 0;
389 
390     /* figure out the real row  number if interlace */
391 
392     k = next_lineno( lines, im->h, sp->interlace );
393 
394     sp->cur_total += im->w;
395 
396     /* stop to avoid buffer overrun if k is bad */
397 
398     if ( k >= im->h )
399         return;
400 
401     for ( po = im->ci[ k ], line += im->w; pi < line; )
402         *po++ = *pi++;
403 
404     im->completed = ++lines;
405     if ( ! ( im->completed & FLIMAGE_REPFREQ ) )
406         im->visual_cue( im, "Reading GIF" );
407 }
408 
409 
410 /***************************************
411  * Get a single data block
412  ***************************************/
413 
414 static int
getblock(FILE * fp,char * buf)415 getblock( FILE * fp,
416           char * buf )
417 {
418     int count;
419 
420     if ( ( count = getc( fp ) ) != EOF && count != 0 )
421         count = fread( buf, 1, count, fp );
422     return count;
423 }
424 
425 
426 #define EXTENSION     0x21  /* '!'  introducer  */
427 #define GIFEXT_PT     0x01  /* plain text       */
428 #define GIFEXT_APP    0xFF  /* application      */
429 #define GIFEXT_GC     0xF9  /* graphics control */
430 #define GIFEXT_COM    0xFE  /* comment          */
431 #define TRAILER       0x3b
432 
433 
434 /***************************************
435  *  As long as we are not doing the extension, print it out to stderr
436  ***************************************/
437 
438 static int
readextension(FILE * fp,FL_IMAGE * im)439 readextension( FILE     * fp,
440                FL_IMAGE * im )
441 {
442     SPEC *sp = im->io_spec;
443     int count = 0,
444         label;
445     char buf[ 258 ];
446     const char *f = "GIF_ext";
447     GIFTEXT *t = sp->giftext + sp->ctext;
448 
449     label = getc( fp );
450 
451     switch ( label )
452     {
453         case GIFEXT_PT :        /* plain text extension */
454             M_info( 0, "%s: PlainText Extension", im->infile );
455             if ( getc( fp ) != 12 )
456             {
457                 flimage_error( im, "%s: bad PlainText extension", im->infile );
458                 return EOF;
459             }
460 
461             t->x  = fli_fget2LSBF( fp );    /* left wrt left edge of ls  */
462             t->y  = fli_fget2LSBF( fp );
463             t->tw = fli_fget2LSBF( fp );    /* total width  */
464             t->th = fli_fget2LSBF( fp );    /* total width  */
465             t->cw = fgetc( fp );    /* cell width   */
466             t->ch = fgetc( fp );    /* cell height  */
467             t->tc = fgetc( fp );    /* text color   */
468             t->bc = fgetc( fp );    /* bk color     */
469             t->tran = sp->gc.tran;
470 
471             t->str[ 0 ] = '\0';
472             while ( ( count = getblock( fp, buf ) ) != 0 && count != EOF )
473             {
474                 buf[ count ] = '\0';
475                 M_info( 0, buf );
476                 if ( strlen( t->str ) + count > sizeof t->str )
477                     count = sizeof t->str - strlen( t->str ) - 1;
478                 strncat( t->str, buf, count );
479             }
480             sp->ctext++;
481             break;
482 
483         case GIFEXT_COM :       /* a comment extension */
484             M_info( 0, "%s:Comment Extension", im->infile );
485             while ( ( count = getblock( fp, buf ) ) != 0 && count != EOF )
486             {
487                 buf[ count ] = '\0';
488                 flimage_add_comments( im, buf, count );
489             }
490             break;
491 
492         case GIFEXT_GC :        /* graphics control     */
493             M_info( 0, "%s:GraphicsControl extension", im->infile );
494             while ( ( count = getblock( fp, buf ) ) != 0 && count != EOF )
495             {
496                 sp->gc.tran = buf[ 0 ] & 1;
497                 sp->gc.input = buf[ 0 ] & 2;
498                 sp->gc.delay = 10 * ( buf[ 0 ] + ( buf[ 1 ] << 8 ) );
499                 if ( sp->gc.tran )
500                     sp->gc.tran_col = buf[ 3 ];
501             }
502             break;
503 
504         case GIFEXT_APP :       /* application extension */
505             M_info( 0, "%s:ApplicationExtension", im->infile );
506             if ( getc( fp ) != 11 ) /* block length */
507                 M_warn( "GifExt", "wrong block length" );
508             if ( fread( buf, 1, 8, fp ) != 8 )
509                 return EOF;
510             buf[ 8 ] = '\0';
511             M_info( 0, buf );
512             if ( fread( buf, 1, 3, fp ) != 3 )
513                 return EOF;
514             while ( ( count = getblock( fp, buf ) ) != 0 && count != EOF )
515             {
516                 buf[ count ] = '\0';
517                 M_info( 0, buf );
518             }
519             break;
520 
521         default :
522             M_err( f, "%s: Bogus extension byte 0x%02x", im->infile, label );
523             break;
524     }
525 
526     return count;
527 }
528 
529 
530 /***************************************
531  ***************************************/
532 
533 static int
skip_extension(FILE * fp,FL_IMAGE * im)534 skip_extension( FILE     * fp,
535                 FL_IMAGE * im )
536 {
537     int pchar,
538         err = 0;
539 
540     while ( ! err && ( pchar = getc( fp ) ) != EOF && pchar != IMAGESEP )
541     {
542         switch ( pchar )
543         {
544             case '\0' :
545             case TRAILER :
546                 break;
547 
548             case EXTENSION :
549                 err = readextension( fp, im );
550                 break;
551 
552             default :
553                 M_warn( "GIFextension", "%s: Bogus byte 0x%02x",
554                         im->infile, pchar );
555                 return EOF;
556         }
557     }
558 
559     return err ? EOF : pchar;
560 }
561 
562 
563 #define LZW_INIT          9000
564 
565 
566 static int bpp,
567            ClearCode,
568            EOFCode,
569            CodeSize;
570 
571 #include <ctype.h>
572 
573 static unsigned char * lhead,
574                      *lbuf,
575                      *stackp;   /* local buffers */
576 
577 
578 /***************************************
579  ***************************************/
580 
581 static int
GIF_load(FL_IMAGE * im)582 GIF_load( FL_IMAGE * im )
583 {
584     int bits = 0,
585         err,
586         count,
587         code = -1;
588     unsigned int datum = 0;
589     unsigned char *ch,
590                   buf[ 257 ];
591     SPEC *sp = im->io_spec;
592     const char *func = "GIFReadPix";
593     FILE *fp = im->fpin;
594 
595     sp->ctext = 0;
596 
597     CodeSize = getc( fp );
598     if ( CodeSize > 8 || CodeSize < 2 )
599     {
600         flimage_error( im, "Load: Bad CodeSize %d(%s)", CodeSize, im->infile );
601         return -1;
602     }
603 
604     /* initialize the decompressor */
605 
606     err = sp->cur_total = 0;
607     process_lzw_code( im, LZW_INIT );
608 
609     while ( ! err && ( count = getc( fp ) ) != EOF && count > 0 )
610     {
611         err = Badfread( buf, 1, ( size_t )count, fp );
612         for ( ch = buf; count-- > 0; ch++ )
613         {
614             datum += *ch << bits;
615             bits += 8;
616             while ( bits >= CodeSize && ! err )
617             {
618                 code = datum & gif_codemask[ CodeSize ];
619                 datum >>= CodeSize;
620                 bits -= CodeSize;
621                 err = code == EOFCode || process_lzw_code( im, code );
622             }
623         }
624 
625         /* EOFcode is not exactly an errr */
626 
627         if ( err && code == EOFCode )
628             err = 0;
629 
630         if ( code != EOFCode && sp->cur_total > (long) im->w * im->h )
631         {
632             flimage_error( im, "%s: Raster full before EOI", im->infile );
633             err = 1;
634         }
635     }
636 
637     if ( ! err )
638     {
639         if ( ( code = getc( fp ) ) == EXTENSION )
640         {
641             ungetc( code, fp );
642             while (    ( code = skip_extension( fp, im ) ) != EOF
643                     && code != IMAGESEP )
644                 /* empty */ ;
645         }
646 
647         if ( code == IMAGESEP )
648         {
649             im->more = 1;
650             ungetc( IMAGESEP, fp );
651         }
652         else if (    code != EOF
653                   && fread( buf, 1, 50, fp )
654                   && getc( fp ) != EOF )
655         {
656             M_info( func, "%s: Garbage(> 50bytes) at end", im->infile );
657         }
658     }
659 
660     count = sp->cur_total / im->w;
661 
662     /* final check: get pixels that are decoded but yet to be output */
663 
664     if ( count < im->h )
665     {
666         int leftover;
667         leftover = lbuf - lhead;
668 
669         M_warn( func, "total %ld should be %d", sp->cur_total + leftover,
670                 im->w * im->h );
671 
672         if ( leftover )
673             outputline( im, lhead );
674     }
675 
676     /* if more than 1/4 image is read, return positive value so that driver
677        will try to display it.  */
678 
679     convert_gif_text( im );
680 
681     return count >= im->h / 4 ? count : -1;
682 }
683 
684 
685 /***************************************
686  * process_lzw_code - Process a compression code.  "clear" resets the
687  * code table. Otherwise make a new code table entry, and output the
688  * bytes associated with the code.
689  *
690  * Based on gifpaste by Kipp Hickman @ Silicon Graphics
691  ***************************************/
692 
693 #define OUTPIX( c )    ( *lbuf++ = ( c ) )
694 #define MC_SIZE        4097
695 
696 
697 /***************************************
698  * if we've got more than one scanline, output
699  ***************************************/
700 
701 static void
flush_buffer(FL_IMAGE * im)702 flush_buffer( FL_IMAGE * im )
703 {
704     int incode;
705 
706     incode = lbuf - lhead;
707 
708     if ( incode >= im->w )
709     {
710         int i;
711 
712         lbuf = lhead;
713 
714         while ( incode >= im->w )
715         {
716             outputline( im, lbuf );
717             incode -= im->w;
718             lbuf += im->w;
719         }
720 
721         /* copy the left over */
722 
723         for ( i = 0; i < incode; i++ )
724             lhead[ i ] = *lbuf++;
725         lbuf = lhead + incode;
726     }
727 }
728 
729 
730 /***************************************
731  ***************************************/
732 
733 static int
process_lzw_code(FL_IMAGE * im,int code)734 process_lzw_code( FL_IMAGE * im,
735                   int        code )
736 {
737     int incode;
738     static unsigned char firstchar;
739     static unsigned char stack[ MC_SIZE ];
740     static int avail,
741                oldcode;
742     static unsigned char suffix[ MC_SIZE ];
743     static unsigned short prefix[ MC_SIZE ];
744 
745     if ( code == LZW_INIT )
746     {
747         lbuf = lhead = fl_realloc( lhead, im->w + 1 + 4096 );
748 
749         bpp = CodeSize;
750         ClearCode = 1 << bpp;
751         EOFCode = ClearCode + 1;
752         CodeSize = bpp + 1;
753 
754         for ( incode = ClearCode; --incode >= 0; )
755         {
756             *( suffix + incode ) = incode;
757             *( prefix + incode ) = 0;
758         }
759 
760         avail = ClearCode + 2;
761         oldcode = -1;
762         stackp = stack;
763         return lbuf ? 0 : -1;
764     }
765 
766     if ( code == ClearCode )
767     {
768         CodeSize = bpp + 1;
769         avail = ClearCode + 2;
770         oldcode = -1;
771         return 0;
772     }
773 
774     /* this is possible only if the image file is corrupt */
775 
776     if ( code > avail || code < 0 )
777     {
778         flimage_error( im, "GIFLZW(%s): Bad code 0x%04x", im->infile, code );
779         return -1;
780     }
781 
782     if ( oldcode == -1 )
783     {
784         OUTPIX( suffix[ code ] );
785         firstchar = oldcode = code;
786 
787         /* Clive Stubbings.
788          * There is the posibility of an image with just alternate
789          * single code bytes and resets. I know thats really dumb,
790          * but I found one and it took a long time to work out why
791          * it crashed...
792          * So flush the buffer before it overuns. */
793 
794         flush_buffer( im );
795         return 0;
796     }
797 
798     incode = code;
799     if ( code == avail )
800     {               /* the first code is always < avail */
801         *stackp++ = firstchar;
802         code = oldcode;
803     }
804 
805     while ( code > ClearCode )
806     {
807         *stackp++ = suffix[ code ];
808         code = prefix[ code ];
809     }
810 
811     if ( avail >= 4096 )
812     {
813         flimage_error( im, "GIFLZW(%s): BadBlock--TableFull", im->infile );
814         return -1;
815     }
816 
817     *stackp++ = firstchar = suffix[ code ];
818     prefix[ avail ] = oldcode;
819     suffix[ avail ] = firstchar;
820 
821     avail++;
822     if ( ( avail & gif_codemask[ CodeSize ] ) == 0 && avail < 4096 )
823         CodeSize++;
824 
825     oldcode = incode;
826 
827     do
828     {
829         OUTPIX( *--stackp );
830     }
831     while ( stackp > stack );
832 
833     /* if we've got more than one scanline, output */
834 
835     flush_buffer( im );
836 
837     return 0;
838 }
839 
840 
841 /***************************************
842  ***************************************/
843 
844 static int
GIF_next(FL_IMAGE * im)845 GIF_next( FL_IMAGE * im )
846 {
847     int ow = im->w,
848         oh = im->h;
849     int ret;
850 
851     read_descriptor_block( im );
852 
853     /* It would seem from the doc that it is possible new image could be
854        larger than last one */
855 
856     if ( ow != im->w || oh != im->h )
857         flimage_getmem( im );
858 
859 #if 0
860     del_text( );
861 #endif
862 
863     im->more = 0;       /* gif_load will do turn it on if more */
864     im->modified = 1;
865 
866     ret = GIF_load( im );
867 
868     return ret;
869 }
870 
871 /******************* END of DECODER ****************************}*****/
872 
873 
874 /***************************************
875  * Given GIF sequence no. i, starting from 0, figure out the image
876  * sequence number. If interlaced, the sequence will be independent
877  * of i, sort of a bug, but for this application, it is perfectly ok.
878  ***************************************/
879 
880 static int
next_lineno(int i,int h,int interlace)881 next_lineno( int i,
882              int h,
883              int interlace )
884 {
885     static const int steps[ 5 ] = { 8, 8, 4, 2, 0 };
886     static const int start[ 5 ] = { 0, 4, 2, 1, 0 };
887     static int pass,
888                sofar,
889                current;
890     int line;
891 
892     /* init for each image */
893 
894     if ( i == 0 )
895         pass = sofar = current = 0;
896 
897     line = i;           /* unless interlace */
898 
899     if ( interlace )
900     {
901         line = current;
902         if ( ( current += steps[pass] ) >= h )
903             current = start[ ++pass ];
904     }
905 
906     sofar++;
907 
908     return line;
909 }
910 
911 
912 /********************************************************************
913  * GIF encoding routine.
914  * Original code
915  ********************************************************************/
916 
917 /************************************************************
918  * Write image to a disk file in GIF format.
919  ************************************************************/
920 
921 /* current char, cchar, must be of signed type, and code and prefix must be
922  * at least 12 bits long. */
923 
924 typedef struct strspace_
925 {
926     struct strspace_ * next;            /* link          */
927     int                code;            /* emit code     */
928     int                cchar;           /* current char */
929 } Strtab;
930 
931 typedef struct
932 {
933     int prefix,
934         cchar,
935         code;
936 } WorkStr;
937 
938 #define  MAXTABL  4097
939 
940 static Strtab *strtab[ MAXTABL ],
941                strspace[ MAXTABL ];
942 
943 
944 /**************************************************************
945  * Check if current string is already in the string table
946  **************************************************************/
947 
948 static int
in_table(WorkStr * cstr)949 in_table( WorkStr * cstr )
950 {
951     Strtab *p = strtab[ cstr->prefix ];
952 
953     for ( ; p && p->cchar != cstr->cchar; p = p->next )
954         /* empty */ ;
955 
956     return p ? p->code : -1;
957 }
958 
959 #define USE_TAB_FUNC
960 
961 
962 /*
963  * A macro and function are supplied to insert a string into the
964  * string table.
965  */
966 
967 #ifdef USE_TAB_FUNC
968 
969 /***************************************
970  ***************************************/
971 
972 static void
addto_table(WorkStr * cstr,int code)973 addto_table( WorkStr * cstr,
974              int       code )
975 {
976     Strtab *p = &strspace[ code ];
977 
978     p->code = code;
979     p->cchar = cstr->cchar;
980     p->next = strtab[ cstr->prefix ];
981     strtab[ cstr->prefix ] = p;
982 }
983 
984 #else
985 
986 #define  addto_table(cstr, ccode )                         \
987     do {                                                   \
988         Strtab *p = &strspace[ ccode ];                    \
989         p->code = ccode;                                   \
990         p->cchar = cstr->cchar;                            \
991         p->next = strtab[ cstr->prefix ];                  \
992         strtab[ cstr->prefix ] = p;                        \
993    } while( 0 )
994 #endif
995 
996 
997 static void output_lzw_code( unsigned int,
998                              FILE * );
999 static void init_table( int,
1000                         FILE * );
1001 #if 0
1002 static unsigned short * get_scan_line( FL_IMAGE *,
1003                                        int );
1004 #endif
1005 
1006 static int interlace;
1007 
1008 
1009 /***************************************
1010  ***************************************/
1011 
1012 void
flimage_gif_output_options(int inter)1013 flimage_gif_output_options( int inter )
1014 {
1015     interlace = inter;
1016 }
1017 
1018 
1019 /***************************************
1020  * for now, only write max 255 chars
1021  ***************************************/
1022 
1023 static void
write_gif_comments(FILE * fp,const char * str)1024 write_gif_comments( FILE       * fp,
1025                     const char * str )
1026 {
1027     char s[ 256 ];
1028     const char *p = str;
1029     int len,
1030         k = strlen( str );
1031 
1032     for ( len = 0; p < str + k; p += len )
1033     {
1034         strncpy( s, p, 255 );
1035         s[ 255 ] = '\0';
1036         len = strlen( s );
1037         putc( EXTENSION, fp );
1038         fputc( GIFEXT_COM, fp );
1039         putc( len, fp );
1040         fwrite( s, 1, len, fp );
1041         putc( 0, fp );
1042     }
1043 }
1044 
1045 
1046 /***************************************
1047  ***************************************/
1048 
1049 static int
write_descriptor(FL_IMAGE * im)1050 write_descriptor( FL_IMAGE * im )
1051 {
1052     unsigned char buf[ 10 ];
1053     FILE *ffp = im->fpout;
1054 
1055     if ( im->app_background >= 0 )
1056     {
1057         int tran = flimage_get_closest_color_from_map( im, im->app_background );
1058 
1059         buf[ 0 ] = GIFEXT_GC;
1060         buf[ 1 ] = 4;       /* count */
1061         buf[ 2 ] = 0x1;
1062         buf[ 3 ] = 0;
1063         buf[ 4 ] = 0;
1064         buf[ 5 ] = tran;
1065         buf[ 6 ] = 0;       /* end of block */
1066         putc( EXTENSION, ffp );
1067         fwrite( buf, 1, 7, ffp );
1068     }
1069 
1070     /* image descriptions  */
1071 
1072     buf[ 0 ] = IMAGESEP;
1073     buf[ 1 ] = buf[ 2 ] = buf[ 3 ] = buf[ 4 ] = 0;  /* offsets         */
1074     if ( Badfwrite( buf, 1, 5, ffp ) )
1075         return -1;
1076 
1077     /* raster dimensions */
1078 
1079     fli_fput2LSBF( im->w, ffp );
1080     fli_fput2LSBF( im->h, ffp );
1081 
1082     /* local_gifmap, interlace, etc. only set interlace if requested */
1083 
1084     putc( interlace ? 0x40 : 0, ffp );
1085     return 0;
1086 }
1087 
1088 
1089 /***************************************
1090  * write the image description
1091  ***************************************/
1092 
1093 static int
write_desc(FL_IMAGE * im,FILE * ffp)1094 write_desc( FL_IMAGE * im,
1095             FILE     * ffp )
1096 {
1097     int packed;
1098 
1099     /* get bits per pixel first */
1100 
1101     bpp = 0;
1102     while ( im->map_len > 1 << bpp )
1103         bpp++;
1104 
1105     if ( bpp < 1 || bpp > 8 )
1106     {
1107         M_err( "GIF_dump", "%s: Bad bpp=%d", im->outfile, bpp );
1108         bpp = 1;
1109     }
1110 
1111     if ( Badfwrite("GIF89a", 1, 6, ffp ) )
1112     {
1113         M_err( "GIF_dump", im->outfile );
1114         return -1;
1115     }
1116 
1117     /* always write the same logical screen/image size  */
1118 
1119     fli_fput2LSBF( im->w, ffp );
1120     fli_fput2LSBF( im->h, ffp );
1121 
1122     packed =   0x80                  /* always output global map */
1123              + ( ( bpp - 1 ) << 4 )  /* cr. does not mean much   */
1124              + ( bpp - 1 );          /* bits_per_pixel-1         */
1125     putc( packed, ffp );
1126     putc( 0, ffp );
1127     putc( 0, ffp );     /* bk color and aspect ratio */
1128 
1129     /* global color map.  Entries must be 2^N */
1130 
1131     write_map( im, 1 << bpp );
1132 
1133     if ( im->comments )
1134         write_gif_comments( ffp, im->comments );
1135 
1136     return 0;
1137 }
1138 
1139 
1140 /*******************************************************************
1141  * The encoder
1142  *******************************************************************/
1143 
1144 /***************************************
1145  ***************************************/
1146 
1147 static int
write_pixels(FL_IMAGE * im)1148 write_pixels( FL_IMAGE * im )
1149 {
1150     int j, code,
1151         ccode;
1152     unsigned short *scan,
1153                    *ss;
1154     WorkStr *cstr;
1155     int colors;
1156     WorkStr workstring;
1157     FILE *fp = im->fpout;
1158 
1159     /* IMPORTANT: number of colors handed to this routine might not be 2^n,
1160        need to make it so to fool the encoder (colors-1 need to be full bits) */
1161 
1162     colors = 1 << bpp;
1163 
1164     /* min bpp by definition is no smaller than 2 */
1165 
1166     if ( bpp < 2 )
1167         bpp = 2;        /* initial codesize */
1168     putc( bpp, fp );
1169 
1170     ClearCode = 1 << bpp;   /* set clear and end codes */
1171     EOFCode = ClearCode + 1;
1172     CodeSize = bpp + 1;     /* start encoding */
1173 
1174     init_table( colors, fp );   /* initialize the LZW tables */
1175     cstr = &workstring;
1176     ccode = EOFCode + 1;
1177     cstr->prefix = -1;
1178 
1179     /* start raster stream. Old way of doing things, that is as soon as we
1180        get 4095, a clearcode is emitted. */
1181 
1182     for ( j = 0; j < im->h; j++ )
1183     {
1184         scan = im->ci[ next_lineno( j, im->h, interlace ) ];
1185 
1186         for ( ss = scan + im->w; scan < ss; scan++ )
1187         {
1188             cstr->cchar = *scan & ( colors - 1 );
1189             if ( cstr->prefix >= 0 )
1190             {
1191                 if ( ( code = in_table( cstr ) ) >= 0 )
1192                     cstr->prefix = code;
1193                 else
1194                 {
1195                     addto_table( cstr, ccode );
1196                     output_lzw_code( cstr->prefix, fp );
1197                     cstr->prefix = cstr->cchar;
1198 
1199                     if ( ccode >= 1 << CodeSize )
1200                         CodeSize++;
1201                     ccode++;
1202 
1203                     if ( ccode >= 4096 )
1204                     {
1205                         output_lzw_code( cstr->prefix, fp );
1206                         init_table( colors, fp );
1207                         ccode = EOFCode + 1;
1208                         cstr->prefix = -1;
1209                     }
1210                 }
1211             }
1212             else
1213             {           /* root entry */
1214                 cstr->prefix = cstr->code = cstr->cchar;
1215             }
1216         }
1217     }
1218 
1219     output_lzw_code( cstr->prefix, fp );
1220     output_lzw_code( EOFCode, fp );
1221     putc( 0, fp );      /* end block  */
1222 
1223     return fflush( fp );
1224 }
1225 
1226 
1227 /***************************************
1228  ***************************************/
1229 
1230 static int
GIF_write(FL_IMAGE * sim)1231 GIF_write( FL_IMAGE * sim )
1232 {
1233     int err = 0;
1234     FL_IMAGE *im;
1235 
1236     if ( write_desc( sim, sim->fpout ) < 0 )
1237         return -1;
1238 
1239     for ( err = 0, im = sim; !err && im; im = im->next )
1240     {
1241         im->fpout = sim->fpout;
1242         err = write_descriptor( im ) < 0 || write_pixels( im ) < 0;
1243         if ( im != sim )
1244             im->fpout = 0;
1245     }
1246 
1247     putc( ';', sim->fpout );    /* end stream */
1248     fflush( sim->fpout );
1249 
1250     return err ? -1 : 0;
1251 }
1252 
1253 
1254 /***************************************
1255  ***************************************/
1256 
1257 static void
init_table(int rootlen,FILE * fp)1258 init_table( int    rootlen,
1259             FILE * fp )
1260 {
1261     int i;
1262     Strtab *sp = strspace;
1263 
1264     output_lzw_code( ClearCode, fp );
1265 
1266     CodeSize = bpp + 1;
1267 
1268     for ( i = 0; i < rootlen; i++, sp++ )
1269     {
1270         sp->next = 0;
1271         sp->code = i;
1272         sp->cchar = -1;
1273         strtab[ i ] = sp;
1274     }
1275 
1276     for ( ; i < MAXTABL; i++, sp++ )
1277         strtab[ i ] = sp->next = 0;
1278 }
1279 
1280 
1281 /*******************************************************************
1282  * Packing and output an LZW code(bpp+1 to 12 bits long).
1283  *
1284  * Note: accum must be at least 19 bits long. accum and bits must be
1285  * re-initialized when EOFCode is written out.
1286  *******************************************************************/
1287 
1288 static void
output_lzw_code(unsigned int code,FILE * fp)1289 output_lzw_code( unsigned int   code,
1290                  FILE         * fp )
1291 {
1292     static unsigned int bytes,
1293                         bits;
1294     static unsigned char bbuf[ 255 + 3 ];
1295     static unsigned long accum;
1296     unsigned char *ch;
1297 
1298     accum &= gif_codemask[ bits ];
1299     accum |= code << bits;
1300     bits += CodeSize;
1301 
1302     ch = bbuf + bytes;
1303     bytes += bits >> 3;
1304 
1305     while ( bits >= 8 )
1306     {
1307         bits -= 8;
1308         *ch++ = ( unsigned char ) ( accum & 255 );
1309         accum >>= 8;
1310     }
1311 
1312     if ( bytes >= 254 || ( int ) code == EOFCode )
1313     {
1314         if ( ( int ) code == EOFCode && bits )
1315         {
1316             *ch = ( unsigned char ) ( accum & 255 );
1317             bytes++;
1318             bits = accum = 0;
1319         }
1320 
1321         putc(bytes, fp);
1322         fwrite( bbuf, 1, bytes, fp );
1323         bytes = 0;
1324     }
1325 }
1326 
1327 
1328 /***************************************
1329  ***************************************/
1330 
1331 void
flimage_enable_gif(void)1332 flimage_enable_gif( void )
1333 {
1334     flimage_add_format( "CompuServ GIF", "gif", "gif",
1335                         FL_IMAGE_CI,
1336                         GIF_identify,
1337                         GIF_description,
1338                         GIF_load,
1339                         GIF_write);
1340 }
1341 
1342 
1343 /*
1344  * Local variables:
1345  * tab-width: 4
1346  * indent-tabs-mode: nil
1347  * End:
1348  */
1349