~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Tina4/src/file/gif/gif.c

Version: ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* GIF loader for tina tools.
  2  * loosely based upon ... */
  3 
  4 
  5 /* +-------------------------------------------------------------------+ */
  6 /* | Copyright 1990, David Koblas.                                     | */
  7 /* |   Permission to use, copy, modify, and distribute this software   | */
  8 /* |   and its documentation for any purpose and without fee is hereby | */
  9 /* |   granted, provided that the above copyright notice appear in all | */
 10 /* |   copies and that both that copyright notice and this permission  | */
 11 /* |   notice appear in supporting documentation.  This software is    | */
 12 /* |   provided "as is" without express or implied warranty.           | */
 13 /* +-------------------------------------------------------------------+ */
 14 
 15 /* sam 13.7.1995 */
 16 #include <tina/gif.h>
 17 
 18 int     GetPixel( int x, int y );
 19 void compress( int init_bits, FILE *outfile, ifunptr ReadValue );
 20 void output( code_int code );
 21 void cl_block (void);
 22 void    cl_hash(register count_int hsize);
 23 void    writeerr(void);
 24 void char_init(void);
 25 void char_out( int c );
 26 void    flush_char(void);
 27 
 28 
 29 
 30 
 31 pixel   *Image = NULL;
 32 Imrect  *OpIm   = NULL;
 33 static int      verbose;
 34 int     showComment;
 35 
 36 extern Imrect *ReadGIF(char *fn, int imageNumber)
 37 {
 38         unsigned char   buf[16];
 39         unsigned char   c;
 40         unsigned char   localColorMap[3][MAXCOLORMAPSIZE];
 41         int             useGlobalColormap;
 42         int             bitPixel;
 43         int             imageCount = 0;
 44         char            version[4];
 45         Imrect  *opim=NULL;
 46         FILE    *fd;
 47                 
 48         fd=fopen(fn,"rb");
 49 
 50         if (fd==NULL)
 51         {
 52                 error("GIF:cannot load file.\n",non_fatal);
 53                 return NULL;
 54         }
 55 
 56         if (! ReadOK(fd,buf,6)) {
 57                 error("GIF:error reading magic number\n" , non_fatal);
 58                 return;
 59         }
 60 
 61         if (strncmp(buf,"GIF",3) != 0)
 62         {
 63                 error("GIF:not a GIF file\n", non_fatal );
 64                 return;
 65         }
 66 
 67         strncpy(version, buf + 3, 3);
 68         version[3] = '\0';
 69 
 70         if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0))
 71         {
 72                 error("GIF:bad version number, not '87a' or '89a'\n",non_fatal );
 73                 return;
 74         }
 75 
 76         if (!ReadOK(fd,buf,7))
 77         {
 78                 error("GIF:failed to read screen descriptor", non_fatal );
 79                 return;
 80         }       
 81 
 82         GifScreen.Width           = LM_to_uint(buf[0],buf[1]);
 83         GifScreen.Height          = LM_to_uint(buf[2],buf[3]);
 84         GifScreen.BitPixel        = 2<<(buf[4]&0x07);
 85         GifScreen.ColorResolution = (((buf[4]&0x70)>>3)+1);
 86         GifScreen.Background      = buf[5];
 87         GifScreen.AspectRatio     = buf[6];
 88 
 89         #ifdef DEBUG
 90                 fprintf(stdout, "Found image %dx%d\n", GifScreen.Width,
 91                                                  GifScreen.Height);
 92         #endif
 93 
 94         if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
 95                 if (ReadColorMap(fd,GifScreen.BitPixel,GifScreen.ColorMap))
 96                 {
 97                         error("GIF:error reading global colormap\n", non_fatal );
 98                         return;
 99                 }
100         }
101 
102         if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) {
103                 float   r;
104                 r = ( (float) GifScreen.AspectRatio + 15.0 ) / 64.0;
105                 pm_message("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'" );
106         }
107 
108         for (;;) 
109         {
110                 if (!ReadOK(fd,&c,1))
111                 {
112                         /*error("GIF:EOF1 / read error on image data\n", non_fatal );*/
113                         /* sam. we always get this error ... */
114                         break;
115                 }
116 
117                 if (c == ';') {         /* GIF terminator */
118                         if (imageCount < imageNumber)
119                         {
120                                 error("GIF:too few images found in file", non_fatal);
121                                 return;
122                         }
123                 }
124 
125                 if (c == '!') {         /* Extension */
126                         if (! ReadOK(fd,&c,1))
127                         {
128                                 error("GIF:OF / read error on extention function code\n",non_fatal);
129                                 return;
130                         }
131                         DoExtension(fd, c);
132                         continue;
133                 }
134 
135                 if (c != ',') {         /* Not a valid start character */
136                         pm_message("bogus character 0x%02x, ignoring" );
137                         continue;
138                 }
139 
140                 ++imageCount;
141 
142                 if (! ReadOK(fd,buf,9))
143                 {
144                         error("GIF:couldn't read left/top/width/height\n",non_fatal);
145                         return;
146                 }
147 
148                 useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
149 
150                 bitPixel = 1<<((buf[8]&0x07)+1);
151 
152                 if (! useGlobalColormap) {
153                         if (ReadColorMap(fd, bitPixel, localColorMap))
154                         {
155                                 error("GIF:error reading local colormap\n" , non_fatal);
156                                 return;
157                         }
158                         opim=ReadImage(fd, LM_to_uint(buf[4],buf[5]),
159                                   LM_to_uint(buf[6],buf[7]), localColorMap,
160                                   BitSet(buf[8], INTERLACE), imageCount != imageNumber);
161                 } else {
162                         opim=ReadImage(fd, LM_to_uint(buf[4],buf[5]),
163                                   LM_to_uint(buf[6],buf[7]), GifScreen.ColorMap,
164                                   BitSet(buf[8], INTERLACE), imageCount != imageNumber);
165                 }
166 
167         }
168 
169         return opim;
170 }
171 
172 extern int      ReadColorMap(FILE *fd,int number,unsigned char buffer[3][MAXCOLORMAPSIZE] )
173 {
174         int             i;
175         unsigned char   rgb[3];
176 
177         for (i = 0; i < number; ++i) {
178                 if (! ReadOK(fd, rgb, sizeof(rgb)))
179                 {
180                         error("GIF:bad colormap\n",non_fatal );
181                         return;
182                 }
183 
184                 buffer[CM_RED][i] = rgb[0] ;
185                 buffer[CM_GREEN][i] = rgb[1] ;
186                 buffer[CM_BLUE][i] = rgb[2] ;
187         }
188         return FALSE;
189 }
190 
191 
192 extern int DoExtension(FILE *fd, int label)
193 {
194         static char     buf[256];
195         char            *str;
196 
197         switch (label) {
198         case 0x01:              /* Plain Text Extension */
199                 str = "Plain Text Extension";
200 #ifdef notdef
201                 if (GetDataBlock(fd, (unsigned char*) buf) == 0)
202                         ;
203 
204                 lpos   = LM_to_uint(buf[0], buf[1]);
205                 tpos   = LM_to_uint(buf[2], buf[3]);
206                 width  = LM_to_uint(buf[4], buf[5]);
207                 height = LM_to_uint(buf[6], buf[7]);
208                 cellw  = buf[8];
209                 cellh  = buf[9];
210                 foreground = buf[10];
211                 background = buf[11];
212 
213                 while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
214                         PPM_ASSIGN(image[ypos][xpos],
215                                         cmap[CM_RED][v],
216                                         cmap[CM_GREEN][v],
217                                         cmap[CM_BLUE][v]);
218                         ++index;
219                 }
220 
221                 return FALSE;
222 #else
223                 break;
224 #endif
225         case 0xff:              /* Application Extension */
226                 str = "Application Extension";
227                 break;
228         case 0xfe:              /* Comment Extension */
229                 str = "Comment Extension";
230                 while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
231                         if (showComment)
232                                 pm_message("gif comment: %s" );
233                 }
234                 return FALSE;
235         case 0xf9:              /* Graphic Control Extension */
236                 str = "Graphic Control Extension";
237                 (void) GetDataBlock(fd, (unsigned char*) buf);
238                 Gif89.disposal    = (buf[0] >> 2) & 0x7;
239                 Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
240                 Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
241                 if ((buf[0] & 0x1) != 0)
242                         Gif89.transparent = buf[3];
243 
244                 while (GetDataBlock(fd, (unsigned char*) buf) != 0)
245                         ;
246                 return FALSE;
247         default:
248                 str = buf;
249                 sprintf(buf, "UNKNOWN (0x%02x)", label);
250                 break;
251         }
252 
253         pm_message("got a '%s' extension - please report this to koblas@mips.com" );
254 
255         while (GetDataBlock(fd, (unsigned char*) buf) != 0)
256                 ;
257 
258         return FALSE;
259 }
260 
261 int     ZeroDataBlock = FALSE;
262 
263 extern int GetDataBlock(FILE *fd, unsigned char *buf)
264 {
265         unsigned char   count;
266 
267         if (! ReadOK(fd,&count,1)) {
268                 pm_message("error in getting DataBlock size" );
269                 return -1;
270         }
271 
272         ZeroDataBlock = count == 0;
273 
274         if ((count != 0) && (! ReadOK(fd, buf, count))) {
275                 pm_message("error in reading DataBlock" );
276                 return -1;
277         }
278 
279         return count;
280 }
281 
282 extern int GetCode(FILE *fd, int code_size, int flag)
283 {
284         static unsigned char    buf[280];
285         static int              curbit, lastbit, done, last_byte;
286         int                     i, j, ret;
287         unsigned char           count;
288 
289         if (flag) {
290                 curbit = 0;
291                 lastbit = 0;
292                 done = FALSE;
293                 return 0;
294         }
295 
296         if ( (curbit+code_size) >= lastbit) {
297                 if (done) {
298                         if (curbit >= lastbit)
299                         {
300                                 error("GIF:ran off the end of my bits\n",non_fatal );
301                                 return;
302                         }
303                         return -1;
304                 }
305                 buf[0] = buf[last_byte-2];
306                 buf[1] = buf[last_byte-1];
307 
308                 if ((count = GetDataBlock(fd, &buf[2])) == 0)
309                         done = TRUE;
310 
311                 last_byte = 2 + count;
312                 curbit = (curbit - lastbit) + 16;
313                 lastbit = (2+count)*8 ;
314         }
315 
316         ret = 0;
317         for (i = curbit, j = 0; j < code_size; ++i, ++j)
318                 ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
319 
320         curbit += code_size;
321 
322         return ret;
323 }
324 
325 extern int LWZReadByte(FILE *fd, int flag, int input_code_size)
326 {
327         static int      fresh = FALSE;
328         int             code, incode;
329         static int      code_size, set_code_size;
330         static int      max_code, max_code_size;
331         static int      firstcode, oldcode;
332         static int      clear_code, end_code;
333         static int      table[2][(1<< MAX_LWZ_BITS)];
334         static int      stack[(1<<(MAX_LWZ_BITS))*2], *sp;
335         register int    i;
336 
337         if (flag) {
338                 set_code_size = input_code_size;
339                 code_size = set_code_size+1;
340                 clear_code = 1 << set_code_size ;
341                 end_code = clear_code + 1;
342                 max_code_size = 2*clear_code;
343                 max_code = clear_code+2;
344 
345                 GetCode(fd, 0, TRUE);
346                 
347                 fresh = TRUE;
348 
349                 for (i = 0; i < clear_code; ++i) {
350                         table[0][i] = 0;
351                         table[1][i] = i;
352                 }
353                 for (; i < (1<<MAX_LWZ_BITS); ++i)
354                         table[0][i] = table[1][0] = 0;
355 
356                 sp = stack;
357 
358                 return 0;
359         } else if (fresh) {
360                 fresh = FALSE;
361                 do {
362                         firstcode = oldcode =
363                                 GetCode(fd, code_size, FALSE);
364                 } while (firstcode == clear_code);
365                 return firstcode;
366         }
367 
368         if (sp > stack)
369                 return *--sp;
370 
371         while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
372                 if (code == clear_code) {
373                         for (i = 0; i < clear_code; ++i) {
374                                 table[0][i] = 0;
375                                 table[1][i] = i;
376                         }
377                         for (; i < (1<<MAX_LWZ_BITS); ++i)
378                                 table[0][i] = table[1][i] = 0;
379                         code_size = set_code_size+1;
380                         max_code_size = 2*clear_code;
381                         max_code = clear_code+2;
382                         sp = stack;
383                         firstcode = oldcode =
384                                         GetCode(fd, code_size, FALSE);
385                         return firstcode;
386                 } else if (code == end_code) {
387                         int             count;
388                         unsigned char   buf[260];
389 
390                         if (ZeroDataBlock)
391                                 return -2;
392 
393                         while ((count = GetDataBlock(fd, buf)) > 0)
394                                 ;
395 
396                         if (count != 0)
397                                 pm_message("missing EOD in data stream (common occurence)");
398                         return -2;
399                 }
400 
401                 incode = code;
402 
403                 if (code >= max_code) {
404                         *sp++ = firstcode;
405                         code = oldcode;
406                 }
407 
408                 while (code >= clear_code) {
409                         *sp++ = table[1][code];
410                         if (code == table[0][code])
411                         {
412                                 error("GIF:circular table entry BIG ERROR\n",non_fatal);
413                                 return;
414                         }
415                         code = table[0][code];
416                 }
417 
418                 *sp++ = firstcode = table[1][code];
419 
420                 if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
421                         table[0][code] = oldcode;
422                         table[1][code] = firstcode;
423                         ++max_code;
424                         if ((max_code >= max_code_size) &&
425                                 (max_code_size < (1<<MAX_LWZ_BITS))) {
426                                 max_code_size *= 2;
427                                 ++code_size;
428                         }
429                 }
430 
431                 oldcode = incode;
432 
433                 if (sp > stack)
434                         return *--sp;
435         }
436         return code;
437 }
438 
439 
440 extern Imrect *ReadImage(FILE *fd, int len, int height, 
441                         unsigned char cmap[3][MAXCOLORMAPSIZE], int interlace, int ignore)
442 {
443         unsigned char   c;      
444         int             v;
445         int             xpos = 0, ypos = 0, pass = 0;
446         pixel           **image,pxl;
447         Imrect          *opim;
448 
449         #ifdef DEBUG
450                 long    pix_count=0;
451         #endif
452 
453         /*
454         **  Initialize the Compression routines
455         */
456 
457         #ifdef DEBUG
458                 printf("Reading Image ...\n");
459         #endif
460 
461         if (!ReadOK(fd,&c,1))
462         {
463                 error("GIF:EOF2 / read error on image data\n",non_fatal );
464                 return;
465         }
466 
467         if (LWZReadByte(fd, TRUE, c) < 0)
468         {
469                 error("GIF:error reading image\n", non_fatal );
470                 return;
471         }
472 
473         /*
474         **  If this is an "uninteresting picture" ignore it.
475         */
476         if (ignore) {
477                 if (verbose)
478                         pm_message("skipping image..." );
479 
480                 while (LWZReadByte(fd, FALSE, c) >= 0)
481                         ;
482                 return;
483         }
484 
485         if ((image = ppm_allocarray(len, height)) == NULL)
486         {
487                 error("GIF:couldn't alloc space for image\n", non_fatal );
488                 return;
489         }
490 
491         if (verbose)
492                 pm_message("reading %d by %d%s GIF image" );
493 
494         while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
495                 pxl.r = cmap[CM_RED][v];
496                 pxl.g = cmap[CM_GREEN][v];
497                 pxl.b = cmap[CM_BLUE][v];
498         
499                 image[ypos][xpos].r = pxl.r;
500                 image[ypos][xpos].g = pxl.g;
501                 image[ypos][xpos].b = pxl.b;
502                 
503                 #ifdef DEBUG
504                         pix_count++;
505                 #endif
506                 
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 
540                 if (ypos >= height)
541                         break;
542         }
543 
544 fini:
545         if (LWZReadByte(fd,FALSE,c)>=0)
546                 pm_message("too much input data, ignoring extra...");
547 
548         #ifdef DEBUG
549                 printf("Read %ld pixels \n",pix_count);
550         #endif
551 
552         /* and NOW convert the data to an Imrect */
553         opim= PixelToImrect( image, len, height );
554 
555         free(image);
556 
557         return opim;
558 }
559 
560 
561 Imrect  *PixelToImrect( pixel **image, int width, int height)
562 {
563         Imrect  *opm;
564         pixel   p;
565         int             i,j,pix;
566 
567         #ifdef DEBUG
568                 printf("Converting to imrect ...\n");
569         #endif
570 
571         opm= im_alloc( height,width, NULL, int_v);
572         if (opm==NULL)
573         {
574                 error("GIF: unable to allocate imrect \n", non_fatal);
575                 return NULL;
576         }
577         
578         for (j=0;j<height;j++)
579         {
580                 for (i=0;i<width;i++)
581                 {
582                         p.r = image[j][i].r;
583                         p.g = image[j][i].g;
584                         p.b = image[j][i].b;
585                 
586                         pix = p.r + p.g + p.b;
587                         pix /=3;
588                         IM_PIX_SET( opm, j, i, pix);
589                 }
590         }
591 
592         return opm;
593 }
594 
595 
596 /* sam 13.7.1995 */
597 void    pm_message(char *m)
598 {
599         format("Gif");
600         format(m);
601         format("\n");
602 }
603 
604 
605 FILE    *pm_openr(char *name)
606 {
607         return fopen(name,"rb");
608 }
609 
610 
611 void    pm_close(FILE *fn)
612 {
613         fclose(fn);
614 }
615 
616 char** pm_allocarray( int cols, int rows, int size )
617 {
618         int             i;
619         char    **p;
620 
621         p = (char **) malloc( rows * sizeof(char *));
622         for (i=0;i<rows;i++)
623                 *(p+i) = (char *)malloc(cols * size);
624 
625         return  p;
626 }
627 
628 /* Case-insensitive keyword matcher. */
629 
630 int pm_keymatch( char* str, char* keyword, int minchars )
631 {
632         return strncmp(str,keyword,minchars);
633 }
634 
635 
636 void    gif_write_file(Imrect *opm, char *pn)
637 {
638         int     rows = opm->height,cols = opm->width,i; 
639         int interlace =0;
640         int BitsPerPixel = 8;
641     int Red[MAXCOLORS], Green[MAXCOLORS], Blue[MAXCOLORS];
642 
643         FILE *opf;
644 
645         if ((opf = fopen( pn , "w+b"))==NULL)
646         {
647                 error("gif:Unable to open op file!\n", non_fatal);
648                 return;
649         }
650 
651 
652         /* make up a palette */
653         for (i=0;i<256;i++)
654         {
655                 Red[i]=Green[i]=Blue[i]=i;
656         }
657 
658         OpIm = opm;
659 
660     GIFEncode( opf, cols, rows, interlace, 0, BitsPerPixel, 
661                                 Red, Green, Blue, GetPixel );
662 
663         fclose(opf);
664 }
665 
666 
667 int     GetPixel( int x, int y )
668 {
669         int     v;
670 
671         IM_PIX_GET(OpIm, y, x, v);
672 
673         return v;
674 }
675 
676 
677 /*****************************************************************************
678  *
679  * GIFENCODE.C    - GIF Image compression interface
680  *
681  * GIFEncode( FName, GHeight, GWidth, GInterlace, Background,
682  *            BitsPerPixel, Red, Green, Blue, GetPixel )
683  *
684  *****************************************************************************/
685 
686 #define TRUE 1
687 #define FALSE 0
688 
689 static int Width, Height;
690 static int curx, cury;
691 static long CountDown;
692 static int Pass = 0;
693 static int Interlace;
694 
695 /*
696  * Bump the 'curx' and 'cury' to point to the next pixel
697  */
698 static void
699 BumpPixel(void)
700 {
701         /*
702          * Bump the current X position
703          */
704         ++curx;
705 
706         /*
707          * If we are at the end of a scan line, set curx back to the beginning
708          * If we are interlaced, bump the cury to the appropriate spot,
709          * otherwise, just increment it.
710          */
711         if( curx == Width ) {
712                 curx = 0;
713 
714                 if( !Interlace )
715                         ++cury;
716                 else {
717                      switch( Pass ) {
718 
719                        case 0:
720                           cury += 8;
721                           if( cury >= Height ) {
722                                 ++Pass;
723                                 cury = 4;
724                           }
725                           break;
726 
727                        case 1:
728                           cury += 8;
729                           if( cury >= Height ) {
730                                 ++Pass;
731                                 cury = 2;
732                           }
733                           break;
734 
735                        case 2:
736                           cury += 4;
737                           if( cury >= Height ) {
738                              ++Pass;
739                              cury = 1;
740                           }
741                           break;
742 
743                        case 3:
744                           cury += 2;
745                           break;
746                         }
747                 }
748         }
749 }
750 
751 /*
752  * Return the next pixel from the image
753  */
754 static int
755 GIFNextPixel( getpixel )
756 ifunptr getpixel;
757 {
758         int r;
759 
760         if( CountDown == 0 )
761                 return EOF;
762 
763         --CountDown;
764 
765         r = ( * getpixel )( curx, cury );
766 
767         BumpPixel();
768 
769         return r;
770 }
771 
772 /* public */
773 
774 void
775 GIFEncode( FILE *fp, int GWidth, int GHeight, int GInterlace, int Background,
776            int BitsPerPixel, int Red[], int Green[], int Blue[], 
777                         ifunptr GetPixel )
778 
779 {
780         int B;
781         int RWidth, RHeight;
782         int LeftOfs, TopOfs;
783         int Resolution;
784         int ColorMapSize;
785         int InitCodeSize;
786         int i;
787 
788         Interlace = GInterlace;
789 
790         ColorMapSize = 1 << BitsPerPixel;
791 
792         RWidth = Width = GWidth;
793         RHeight = Height = GHeight;
794         LeftOfs = TopOfs = 0;
795 
796         Resolution = BitsPerPixel;
797 
798         /*
799          * Calculate number of bits we are expecting
800          */
801         CountDown = (long)Width * (long)Height;
802 
803         /*
804          * Indicate which pass we are on (if interlace)
805          */
806         Pass = 0;
807 
808         /*
809          * The initial code size
810          */
811         if( BitsPerPixel <= 1 )
812                 InitCodeSize = 2;
813         else
814                 InitCodeSize = BitsPerPixel;
815 
816         /*
817          * Set up the current x and y position
818          */
819         curx = cury = 0;
820 
821         /*
822          * Write the Magic header
823          */
824         fwrite( "GIF87a", 1, 6, fp );
825 
826         /*
827          * Write out the screen width and height
828          */
829         Putword( RWidth, fp );
830         Putword( RHeight, fp );
831 
832         /*
833          * Indicate that there is a global colour map
834          */
835         B = 0x80;       /* Yes, there is a color map */
836 
837         /*
838          * OR in the resolution
839          */
840         B |= (Resolution - 1) << 5;
841 
842         /*
843          * OR in the Bits per Pixel
844          */
845         B |= (BitsPerPixel - 1);
846 
847         /*
848          * Write it out
849          */
850         fputc( B, fp );
851 
852         /*
853          * Write out the Background colour
854          */
855         fputc( Background, fp );
856 
857         /*
858          * Byte of 0's (future expansion)
859          */
860         fputc( 0, fp );
861 
862         /*
863          * Write out the Global Colour Map
864          */
865         for( i=0; i<ColorMapSize; ++i ) {
866                 fputc( Red[i], fp );
867                 fputc( Green[i], fp );
868                 fputc( Blue[i], fp );
869         }
870 
871         /*
872          * Write an Image separator
873          */
874         fputc( ',', fp );
875 
876         /*
877          * Write the Image header
878          */
879 
880         Putword( LeftOfs, fp );
881         Putword( TopOfs, fp );
882         Putword( Width, fp );
883         Putword( Height, fp );
884 
885         /*
886          * Write out whether or not the image is interlaced
887          */
888         if( Interlace )
889                 fputc( 0x40, fp );
890         else
891                 fputc( 0x00, fp );
892 
893         /*
894          * Write out the initial code size
895          */
896         fputc( InitCodeSize, fp );
897 
898         /*
899          * Go and actually compress the data
900          */
901         compress( InitCodeSize+1, fp, GetPixel );
902 
903         /*
904          * Write out a Zero-length packet (to end the series)
905          */
906         fputc( 0, fp );
907 
908         /*
909          * Write the GIF file terminator
910          */
911         fputc( ';', fp );
912 
913         /*
914          * And close the file
915          */
916         fclose( fp );
917 }
918 
919 /*
920  * Write out a word to the GIF file
921  */
922 void Putword( int w, FILE *fp )
923 {
924         fputc( w & 0xff, fp );
925         fputc( (w / 256) & 0xff, fp );
926 }
927 
928 
929 /***************************************************************************
930  *
931  *  GIFCOMPR.C       - GIF Image compression routines
932  *
933  *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
934  *  David Rowley (mgardi@watdcsu.waterloo.edu)
935  *
936  ***************************************************************************/
937 
938 /*
939  * General DEFINEs
940  */
941 
942 #define BTS    12
943 
944 #define HSIZE  5003            /* 80% occupancy */
945 
946 #ifdef NO_UCHAR
947  typedef char   char_type;
948 #else /*NO_UCHAR*/
949  typedef        unsigned char   char_type;
950 #endif /*NO_UCHAR*/
951 
952 /*
953  *
954  * GIF Image compression - modified 'compress'
955  *
956  * Based on: compress.c - File compression ala IEEE Computer, June 1984.
957  *
958  * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
959  *              Jim McKie               (decvax!mcvax!jim)
960  *              Steve Davies            (decvax!vax135!petsd!peora!srd)
961  *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
962  *              James A. Woods          (decvax!ihnp4!ames!jaw)
963  *              Joe Orost               (decvax!vax135!petsd!joe)
964  *
965  */
966 #include <ctype.h>
967 
968 #define ARGVAL() (*++(*argv) || (--argc && *++argv))
969 
970 static int n_bits;                        /* number of bits/code */
971 static int maxbits = BTS;                /* user settable max # bits/code */
972 static code_int maxcode;                  /* maximum code, given n_bits */
973 static code_int maxmaxcode = (code_int)1 << BTS; /* should NEVER generate this code */
974 #ifdef COMPATIBLE               /* But wrong! */
975 # define MAXCODE(n_bits)        ((code_int) 1 << (n_bits) - 1)
976 #else /*COMPATIBLE*/
977 # define MAXCODE(n_bits)        (((code_int) 1 << (n_bits)) - 1)
978 #endif /*COMPATIBLE*/
979 
980 static count_int htab [HSIZE];
981 static unsigned short codetab [HSIZE];
982 #define HashTabOf(i)       htab[i]
983 #define CodeTabOf(i)    codetab[i]
984 
985 static code_int hsize = HSIZE;                 /* for dynamic table sizing */
986 
987 /*
988  * To save much memory, we overlay the table used by compress() with those
989  * used by decompress().  The tab_prefix table is the same size and type
990  * as the codetab.  The tab_suffix table needs 2**BTS characters.  We
991  * get this from the beginning of htab.  The output stack uses the rest
992  * of htab, and contains characters.  There is plenty of room for any
993  * possible stack (stack used to be 8000 characters).
994  */
995 
996 #define tab_prefixof(i) CodeTabOf(i)
997 #define tab_suffixof(i)        ((char_type*)(htab))[i]
998 #define de_stack               ((char_type*)&tab_suffixof((code_int)1<<BTS))
999 
1000 static code_int free_ent = 0;                  /* first unused entry */
1001 
1002 /*
1003  * block compression parameters -- after all codes are used up,
1004  * and compression rate changes, start over.
1005  */
1006 static int clear_flg = 0;
1007 
1008 static int offset;
1009 static long int in_count = 1;            /* length of input */
1010 static long int out_count = 0;           /* # of codes output (for debugging) */
1011 
1012 /*
1013  * compress stdin to stdout
1014  *
1015  * Algorithm:  use open addressing double hashing (no chaining) on the
1016  * prefix code / next character combination.  We do a variant of Knuth's
1017  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
1018  * secondary probe.  Here, the modular division first probe is gives way
1019  * to a faster exclusive-or manipulation.  Also do block compression with
1020  * an adaptive reset, whereby the code table is cleared when the compression
1021  * ratio decreases, but after the table fills.  The variable-length output
1022  * codes are re-sized at this point, and a special CLEAR code is generated
1023  * for the decompressor.  Late addition:  construct the table according to
1024  * file size for noticeable speed improvement on small files.  Please direct
1025  * questions about this implementation to ames!jaw.
1026  */
1027 
1028 static int g_init_bits;
1029 static FILE* g_outfile;
1030 
1031 static int ClearCode;
1032 static int EOFCode;
1033 
1034 void compress( int init_bits, FILE *outfile, ifunptr ReadValue )
1035 {
1036     register long fcode;
1037     register code_int i /* = 0 */;
1038     register int c;
1039     register code_int ent;
1040     register code_int disp;
1041     register code_int hsize_reg;
1042     register int hshift;
1043 
1044     /*
1045      * Set up the globals:  g_init_bits - initial number of bits
1046      *                      g_outfile   - pointer to output file
1047      */
1048     g_init_bits = init_bits;
1049     g_outfile = outfile;
1050 
1051     /*
1052      * Set up the necessary values
1053      */
1054     offset = 0;
1055     out_count = 0;
1056     clear_flg = 0;
1057     in_count = 1;
1058     maxcode = MAXCODE(n_bits = g_init_bits);
1059 
1060     ClearCode = (1 << (init_bits - 1));
1061     EOFCode = ClearCode + 1;
1062     free_ent = ClearCode + 2;
1063 
1064     char_init();
1065 
1066     ent = GIFNextPixel( ReadValue );
1067 
1068     hshift = 0;
1069     for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
1070         ++hshift;
1071     hshift = 8 - hshift;                /* set hash code range bound */
1072 
1073     hsize_reg = hsize;
1074     cl_hash( (count_int) hsize_reg);            /* clear hash table */
1075 
1076     output( (code_int)ClearCode );
1077 
1078 #ifdef SIGNED_COMPARE_SLOW
1079     while ( (c = GIFNextPixel( ReadValue )) != (unsigned) EOF ) {
1080 #else /*SIGNED_COMPARE_SLOW*/
1081     while ( (c = GIFNextPixel( ReadValue )) != EOF ) {  /* } */
1082 #endif /*SIGNED_COMPARE_SLOW*/
1083 
1084         ++in_count;
1085 
1086         fcode = (long) (((long) c << maxbits) + ent);
1087         i = (((code_int)c << hshift) ^ ent);    /* xor hashing */
1088 
1089         if ( HashTabOf (i) == fcode ) {
1090             ent = CodeTabOf (i);
1091             continue;
1092         } else if ( (long)HashTabOf (i) < 0 )      /* empty slot */
1093             goto nomatch;
1094         disp = hsize_reg - i;           /* secondary hash (after G. Knott) */
1095         if ( i == 0 )
1096             disp = 1;
1097 probe:
1098         if ( (i -= disp) < 0 )
1099             i += hsize_reg;
1100 
1101         if ( HashTabOf (i) == fcode ) {
1102             ent = CodeTabOf (i);
1103             continue;
1104         }
1105         if ( (long)HashTabOf (i) > 0 )
1106             goto probe;
1107 nomatch:
1108         output ( (code_int) ent );
1109         ++out_count;
1110         ent = c;
1111 #ifdef SIGNED_COMPARE_SLOW
1112         if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
1113 #else /*SIGNED_COMPARE_SLOW*/
1114         if ( free_ent < maxmaxcode ) {  /* } */
1115 #endif /*SIGNED_COMPARE_SLOW*/
1116             CodeTabOf (i) = free_ent++; /* code -> hashtable */
1117             HashTabOf (i) = fcode;
1118         } else
1119                 cl_block();
1120     }
1121     /*
1122      * Put out the final code.
1123      */
1124     output( (code_int)ent );
1125     ++out_count;
1126     output( (code_int) EOFCode );
1127 }
1128 
1129 /*****************************************************************
1130  * TAG( output )
1131  *
1132  * Output the given code.
1133  * Inputs:
1134  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
1135  *              that n_bits =< (long)wordsize - 1.
1136  * Outputs:
1137  *      Outputs code to the file.
1138  * Assumptions:
1139  *      Chars are 8 bits long.
1140  * Algorithm:
1141  *      Maintain a BTS character long buffer (so that 8 codes will
1142  * fit in it exactly).  Use the VAX insv instruction to insert each
1143  * code in turn.  When the buffer fills up empty it and start over.
1144  */
1145 
1146 static unsigned long cur_accum = 0;
1147 static int cur_bits = 0;
1148 
1149 static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
1150                                   0x001F, 0x003F, 0x007F, 0x00FF,
1151                                   0x01FF, 0x03FF, 0x07FF, 0x0FFF,
1152                                   0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
1153 
1154 void output( code_int code )
1155 {
1156     cur_accum &= masks[ cur_bits ];
1157 
1158     if( cur_bits > 0 )
1159         cur_accum |= ((long)code << cur_bits);
1160     else
1161         cur_accum = code;
1162 
1163     cur_bits += n_bits;
1164 
1165     while( cur_bits >= 8 ) {
1166         char_out( (unsigned int)(cur_accum & 0xff) );
1167         cur_accum >>= 8;
1168         cur_bits -= 8;
1169     }
1170 
1171     /*
1172      * If the next entry is going to be too big for the code size,
1173      * then increase it, if possible.
1174      */
1175    if ( free_ent > maxcode || clear_flg ) {
1176 
1177             if( clear_flg ) {
1178 
1179                 maxcode = MAXCODE (n_bits = g_init_bits);
1180                 clear_flg = 0;
1181 
1182             } else {
1183 
1184                 ++n_bits;
1185                 if ( n_bits == maxbits )
1186                     maxcode = maxmaxcode;
1187                 else
1188                     maxcode = MAXCODE(n_bits);
1189             }
1190         }
1191 
1192     if( code == EOFCode ) {
1193         /*
1194          * At EOF, write the rest of the buffer.
1195          */
1196         while( cur_bits > 0 ) {
1197                 char_out( (unsigned int)(cur_accum & 0xff) );
1198                 cur_accum >>= 8;
1199                 cur_bits -= 8;
1200         }
1201 
1202         flush_char();
1203 
1204         fflush( g_outfile );
1205 
1206         if( ferror( g_outfile ) )
1207                 writeerr();
1208     }
1209 }
1210 
1211 /*
1212  * Clear out the hash table
1213  */
1214 void cl_block (void)             /* table clear for block compress */
1215 {
1216 
1217         cl_hash ( (count_int) hsize );
1218         free_ent = ClearCode + 2;
1219         clear_flg = 1;
1220 
1221         output( (code_int)ClearCode );
1222 }
1223 
1224 void    cl_hash(register count_int hsize)          /* reset code table */
1225 {
1226 
1227         register count_int *htab_p = htab+hsize;
1228 
1229         register long i;
1230         register long m1 = -1;
1231 
1232         i = hsize - 16;
1233         do {                            /* might use Sys V memset(3) here */
1234                 *(htab_p-16) = m1;
1235                 *(htab_p-15) = m1;
1236                 *(htab_p-14) = m1;
1237                 *(htab_p-13) = m1;
1238                 *(htab_p-12) = m1;
1239                 *(htab_p-11) = m1;
1240                 *(htab_p-10) = m1;
1241                 *(htab_p-9) = m1;
1242                 *(htab_p-8) = m1;
1243                 *(htab_p-7) = m1;
1244                 *(htab_p-6) = m1;
1245                 *(htab_p-5) = m1;
1246                 *(htab_p-4) = m1;
1247                 *(htab_p-3) = m1;
1248                 *(htab_p-2) = m1;
1249                 *(htab_p-1) = m1;
1250                 htab_p -= 16;
1251         } while ((i -= 16) >= 0);
1252 
1253         for ( i += 16; i > 0; --i )
1254                 *--htab_p = m1;
1255 }
1256 
1257 
1258 void    writeerr(void)
1259 {
1260         format( "error writing output file" );
1261 }
1262 
1263 /******************************************************************************
1264  *
1265  * GIF Specific routines
1266  *
1267  ******************************************************************************/
1268 
1269 /*
1270  * Number of characters so far in this 'packet'
1271  */
1272 static int a_count;
1273 
1274 /*
1275  * Set up the 'byte output' routine
1276  */
1277 void char_init(void)
1278 {
1279         a_count = 0;
1280 }
1281 
1282 /*
1283  * Define the storage for the packet accumulator
1284  */
1285 static char accum[ 256 ];
1286 
1287 /*
1288  * Add a character to the end of the current packet, and if it is 254
1289  * characters, flush the packet to disk.
1290  */
1291 void char_out( int c )
1292 {
1293         accum[ a_count++ ] = c;
1294         if( a_count >= 254 )
1295                 flush_char();
1296 }
1297 
1298 /*
1299  * Flush the packet to disk, and reset the accumulator
1300  */
1301 void    flush_char(void)
1302 {
1303         if( a_count > 0 ) {
1304                 fputc( a_count, g_outfile );
1305                 fwrite( accum, 1, a_count, g_outfile );
1306                 a_count = 0;
1307         }
1308 }
1309 
1310 /* The End */
1311 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.