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