home *** CD-ROM | disk | FTP | other *** search
/ The Best of Mecomp Multimedia 2 / MECOMP-CD-II.iso / amiga / datatypes / gifanim_datatype / encoder.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-13  |  32.1 KB  |  1,047 lines

  1.  
  2. /*
  3. **
  4. **  $VER: encoder.c 2.2 (13.4.98)
  5. **  gifanim.datatype 2.2
  6. **
  7. **  GIF Encoder of gifanim.datatype
  8. **
  9. **  Written 1997/1998 by Roland 'Gizzy' Mainz
  10. **  Original example source from David N. Junod
  11. **
  12. */
  13.  
  14. /* main includes */
  15. #include "classbase.h"
  16. #include "classdata.h"
  17.  
  18. /* encoder header */
  19. #include "encoder.h"
  20.  
  21. /*****************************************************************************/
  22.  
  23. #define fputc( c, fh ) FPutC( (fh), (long)(c) )
  24. #define EOF            (-1)
  25.  
  26. static const int      maxbits    = MAX_LWZ_BITS;                  /* user settable max # bits/code */
  27. static const code_int maxmaxcode = (code_int)1UL << MAX_LWZ_BITS; /* should NEVER generate this code */
  28.  
  29. #define MAXCODE( nbits ) (((code_int) 1 << (nbits)) - 1)
  30.  
  31. #define HashTabOf( i )    (genc -> htab[ i ])
  32. #define CodeTabOf( i )    (genc -> codetab[ i ])
  33.  
  34. static const code_int hsize = HSIZE;                 /* for dynamic table sizing */
  35.  
  36. /* To save much memory, we overlay the table used by compress() with those
  37.  * used by decompress().  The tab_prefix table is the same size and type
  38.  * as the codetab.  The tab_suffix table needs 2**MAX_LWZ_BITS characters.  We
  39.  * get this from the beginning of htab.  The output stack uses the rest
  40.  * of htab, and contains characters.  There is plenty of room for any
  41.  * possible stack (stack used to be 8000 characters).
  42.  */
  43.  
  44. #define tab_prefixof(i) CodeTabOf(i)
  45. #define tab_suffixof(i) ((UBYTE *)(genc -> htab))[i]
  46. #define de_stack        ((UBYTE *)&tab_suffixof((code_int)1<<MAX_LWZ_BITS))
  47.  
  48. /*****************************************************************************/
  49.  
  50. /* local prototypes */
  51. static struct GIFEncoder *CreateGIFEncoder( struct ClassBase *, Object *, struct GIFAnimInstData *, struct BitMap *, ULONG, ULONG, ULONG, ULONG, ULONG, BPTR );
  52. static void               DeleteGIFEncoder( struct ClassBase *, struct GIFEncoder *  );
  53.  
  54. static int                GetPixel( struct GIFEncoder *, int x, int y );
  55. static void               BumpPixel( struct GIFEncoder * );
  56. static int                GIFNextPixel( struct GIFEncoder * );
  57. static BOOL               GIFEncode( struct GIFEncoder *, struct GIFAnimInstData *, BOOL, WORD, WORD, struct ColorRegister *, ULONG, ULONG, ULONG );
  58. static void               Putword( struct GIFEncoder *, int );
  59. static void               compress( struct GIFEncoder *, int init_bits );
  60. static void               output( struct GIFEncoder *, code_int );
  61. static void               cl_block( struct GIFEncoder * );
  62. static void               cl_hash( struct GIFEncoder *, count_int hsize );
  63. static void               char_init( struct GIFEncoder * );
  64.  
  65. static void               char_out( struct GIFEncoder *, int );
  66. static void               flush_char( struct GIFEncoder * );
  67.  
  68. /*****************************************************************************/
  69.  
  70.  
  71. ULONG SaveGIFAnim( struct ClassBase *cb, struct IClass *cl, Object *o, struct dtWrite *dtw )
  72. {
  73.     ULONG retval = 0UL;
  74.     LONG  error  = 0L;
  75.  
  76.     /* A NULL file handle is a nop (GMultiView uses this to test if a datatype supports RAW writing) */
  77.     if( dtw -> dtw_FileHandle )
  78.     {
  79.       struct GIFAnimInstData *gaid = (struct GIFAnimInstData *)INST_DATA( cl, o );
  80.  
  81.       ULONG                 modeid;
  82.       struct ColorRegister *cm;
  83.       ULONG                 numcolors;
  84.       ULONG                 startframe = 0UL,
  85.                             numframes  = 0UL,
  86.                             framestep  = 1UL;
  87.       ULONG                 tpf        = 0UL;
  88.       ULONG                 animwidth,
  89.                             animheight,
  90.                             animdepth;
  91.       struct BitMap        *keyframe;
  92.  
  93.       if( GetDTAttrs( o, ADTA_ModeID,           (&modeid),
  94.                          ADTA_ColorRegisters,   (&cm),
  95.                          ADTA_NumColors,        (&numcolors),
  96.                          ADTA_Width,            (&animwidth),
  97.                          ADTA_Height,           (&animheight),
  98.                          ADTA_Depth,            (&animdepth),
  99.                          ADTA_KeyFrame,         (&keyframe),
  100.                          ADTA_Frame,            (&startframe),
  101.                          ADTA_Frames,           (&numframes),
  102.                          ADTA_TicksPerFrame,    (&tpf),
  103.                          TAG_DONE ) == 10UL )
  104.       {
  105.         verbose_printf( cb, gaid, "anim %lu*%lu*%lu, %lu colors, %lu frames, tpf %lu\n",
  106.                                   animwidth, animheight, animdepth, numcolors, numframes, tpf );
  107.  
  108.         /* GIF only supports up to 256 colors (8 bit) */
  109.         if( animdepth <= 8UL )
  110.         {
  111.           /* HAM cannot be implemented (same problem as truecolor support); EHB would be possible (on request) */
  112.           if( !(modeid & (HAM | EXTRA_HALFBRITE)) )
  113.           {
  114.             struct GIFEncoder *genc;
  115.  
  116.             if( genc = CreateGIFEncoder( cb, o, gaid, keyframe, animwidth, animheight, animdepth, numcolors, tpf, (dtw -> dtw_FileHandle) ) )
  117.             {
  118.               struct TagItem *tstate,
  119.                              *ti;
  120.  
  121.               numframes -= startframe;
  122.  
  123.               tstate = dtw -> dtw_AttrList;
  124.  
  125.               while( ti = NextTagItem( (&tstate) ) )
  126.               {
  127.                 switch( ti -> ti_Tag )
  128.                 {
  129.                   case ADTA_Frame:            startframe = ti -> ti_Data; break;
  130.                   case ADTA_Frames:           numframes  = ti -> ti_Data; break;
  131.                   case ADTA_FrameIncrement:   framestep  = ti -> ti_Data; break;
  132.                 }
  133.               }
  134.  
  135.               if( framestep == 0UL ) framestep = 1UL;
  136.  
  137.               error_printf( cb, gaid, "saving gif anim %lu %lu %lu\n", startframe, numframes, framestep );
  138.  
  139.               if( numframes )
  140.               {
  141.                 retval = (LONG)GIFEncode( genc, gaid, (genc -> interlace), (genc -> backgroundpen), (genc -> transparentpen), cm, startframe, numframes, framestep );
  142.                 error = IoErr();
  143.               }
  144.  
  145.               DeleteGIFEncoder( cb, genc );
  146.             }
  147.             else
  148.             {
  149.               /* Can't alloc gif encoder context data */
  150.               error = ERROR_NO_FREE_STORE;
  151.               error_printf( cb, gaid, "no memory for encoder context data\n" );
  152.             }
  153.           }
  154.           else
  155.           {
  156.             error_printf( cb, gaid, "HAM/EHB not supported by the GIF format\n" );
  157.             error = (modeid & EXTRA_HALFBRITE)?(ERROR_NOT_IMPLEMENTED):(DTERROR_INVALID_DATA);
  158.           }
  159.         }
  160.         else
  161.         {
  162.           error_printf( cb, gaid, "Object is too deep (%lu planes), gif encoder works only with depth <= 8\n", animdepth );
  163.           error = DTERROR_INVALID_DATA;
  164.         }
  165.       }
  166.       else
  167.       {
  168.         /* can't get required attributes from object */
  169.         error_printf( cb, gaid, "not enougth attributes\n" );
  170.         error = ERROR_OBJECT_WRONG_TYPE;
  171.       }
  172.  
  173.       /* Some info... */
  174.       if( retval )
  175.       {
  176.         verbose_printf( cb, gaid, "GIF Animation successfully created\n" );
  177.       }
  178.       else
  179.       {
  180.         error_printf( cb, gaid, "GIF Animation creation failed, error %ld\n", error );
  181.       }
  182.     }
  183.  
  184.     SetIoErr( error );
  185.  
  186.     return( retval );
  187. }
  188.  
  189.  
  190. /*****************************************************************************/
  191.  
  192. static
  193. struct GIFEncoder *CreateGIFEncoder( struct ClassBase *cb, Object *o, struct GIFAnimInstData *gaid, struct BitMap *keybm, ULONG animwidth, ULONG animheight, ULONG animdepth, ULONG numcolors, ULONG tpf, BPTR out )
  194. {
  195.     /* Idiot testing... */
  196.     if( o && animwidth && animheight && animdepth && (numcolors > 0UL) && (numcolors <= MAXCOLORMAPSIZE) && tpf && keybm )
  197.     {
  198.       ULONG              chunkysize = (animwidth + 2UL) * (animheight + 2UL) + 256; /* size of one chunkymap with safety space */
  199.       struct GIFEncoder *genc;
  200.       ULONG              size1,
  201.                          size2,
  202.                          msize;
  203.  
  204.       /* Compute amount of memory needed for the gif encoder... */
  205.       size1 =         sizeof( struct GIFEncoder ) + 8UL;    /* Encoder context data */
  206.       size2 = size1 + chunkysize                  + 8UL;    /* Chunky map 1 */
  207.       msize = size2 + chunkysize                  + 8UL;    /* Chunky map 2 */
  208.  
  209.       if( genc = (struct GIFEncoder *)AllocVec( msize, (MEMF_PUBLIC | MEMF_CLEAR) ) )
  210.       {
  211.         /* get the chunkymap ptrs... */
  212.         genc -> srcchunkymap[ 0 ] = MEMORY_NAL_FOLLOWING( genc, size1 );
  213.         genc -> srcchunkymap[ 1 ] = MEMORY_NAL_FOLLOWING( genc, size2 );
  214.  
  215.         /* Init the temp. rastport required by ReadPixelArray8 */
  216.         InitRastPort( (&(genc -> rpa8tmprp)) );
  217.         genc -> rpa8tmprp . BitMap = AllocBitMap( ((animwidth + 15UL) & ~15UL), 1UL, animdepth, BMF_MINPLANES, keybm );
  218.  
  219.         /* Get a system bitmap (where RPA8 can read from...) */
  220.         genc -> srcbm = AllocBitMap( animwidth, animheight, animdepth, BMF_MINPLANES, keybm );
  221.  
  222.         if( (genc -> srcbm) && (genc -> rpa8tmprp . BitMap) )
  223.         {
  224.           /* Fill-in the remaining ptrs... */
  225.           genc -> classbase  = cb;
  226.           genc -> object     = o;
  227.           genc -> outfile    = out;
  228.           genc -> animwidth  = animwidth;
  229.           genc -> animheight = animheight;
  230.           genc -> animdepth  = animdepth;
  231.           genc -> numcolors  = numcolors;
  232.           genc -> tpf        = tpf;
  233.  
  234.           /* Prefs defaults... */
  235.           genc -> interlace      = FALSE;
  236.           genc -> backgroundpen  =  0; /* default bg pen */
  237.           genc -> transparentpen = -1; /* means: no transparent pen */
  238.  
  239.           /* Read encoder preferences */
  240.           ReadENVPrefs( cb, gaid, genc );
  241.  
  242.           /* Init source rastport */
  243.           InitRastPort( (&(genc -> rp)) );
  244.           genc -> rp . BitMap = genc -> srcbm;
  245.  
  246.           return( genc );
  247.         }
  248.         else
  249.         {
  250.           error_printf( cb, gaid, "no memory for temporary bitmap(s)\n" );
  251.         }
  252.  
  253.         FreeBitMap( (genc -> rpa8tmprp . BitMap) );
  254.         FreeBitMap( (genc -> srcbm) );
  255.       }
  256.       else
  257.       {
  258.         error_printf( cb, gaid, "no memory for encoder context data\n" );
  259.       }
  260.  
  261.       FreeVec( genc );
  262.     }
  263.     else
  264.     {
  265.       error_printf( cb, gaid, "invalid arguments\n" );
  266.     }
  267.  
  268.  
  269.     return( NULL );
  270. }
  271.  
  272.  
  273. static
  274. void DeleteGIFEncoder( struct ClassBase *cb, struct GIFEncoder *genc )
  275. {
  276.     if( genc )
  277.     {
  278.       /* Unload any loaded frame... */
  279.       if( genc -> loadmsg . alf_UserData )
  280.       {
  281.         genc -> loadmsg . MethodID = ADTM_UNLOADFRAME;
  282.         DoMethodA( (genc -> object), (Msg)(&(genc -> loadmsg)) );
  283.       }
  284.  
  285.       FreeBitMap( (genc -> rpa8tmprp . BitMap) );
  286.       FreeBitMap( (genc -> srcbm) );
  287.  
  288.       FreeVec( genc );
  289.     }
  290. }
  291.  
  292. /*****************************************************************************/
  293.  
  294. /* here begins the real encoder code... */
  295. #define cb (genc -> classbase)
  296.  
  297. static
  298. int GetPixel( struct GIFEncoder *genc, int x, int y )
  299. {
  300. #if 1
  301.     int pixel = (int)ReadPixel( (&(genc -> rp)), (long)x, (long)y );
  302. #else
  303.     int pixel = (int)genc -> currchunkymap[ ((genc -> animwidth) * y) + x ];
  304. #endif
  305.  
  306.     /* Should not occur, but... */
  307.     if( pixel >= (1UL << (genc -> animdepth)) )
  308.     {
  309.       pixel = 0;
  310.     }
  311.  
  312.     return( pixel );
  313. }
  314.  
  315.  
  316. /* Bump the 'curx' and 'cury' to point to the next pixel */
  317. static
  318. void BumpPixel( struct GIFEncoder *genc )
  319. {
  320.     /* Bump the current X position */
  321.     genc -> curx++;
  322.  
  323.     /* If we are at the end of a scan line, set curx back to the beginning
  324.      * If we are interlaced, bump the cury to the appropriate spot,
  325.      * otherwise, just increment it.
  326.      */
  327.     if( (genc -> curx) == (genc -> Width) )
  328.     {
  329.       genc -> curx = 0;
  330.  
  331.       if( genc -> Interlace )
  332.       {
  333.         switch( genc -> Pass )
  334.         {
  335.           case 0:
  336.           {
  337.               genc -> cury += 8;
  338.  
  339.               if( (genc -> cury) >= (genc -> Height) )
  340.               {
  341.                 genc -> Pass++;
  342.                 genc -> cury = 4;
  343.               }
  344.           }
  345.               break;
  346.  
  347.           case 1:
  348.           {
  349.               genc -> cury += 8;
  350.  
  351.               if( (genc -> cury) >= (genc -> Height) )
  352.               {
  353.                 genc -> Pass++;
  354.                 genc -> cury = 2;
  355.               }
  356.           }
  357.               break;
  358.  
  359.           case 2:
  360.           {
  361.               genc -> cury += 4;
  362.  
  363.               if( (genc -> cury) >= (genc -> Height) )
  364.               {
  365.                 genc -> Pass++;
  366.                 genc -> cury = 1;
  367.               }
  368.           }
  369.               break;
  370.  
  371.           case 3:
  372.           {
  373.               genc -> cury += 2;
  374.           }
  375.               break;
  376.         }
  377.       }
  378.       else
  379.       {
  380.         genc -> cury++;
  381.       }
  382.     }
  383. }
  384.  
  385.  
  386. /* Return the next pixel from the image */
  387. static
  388. int GIFNextPixel( struct GIFEncoder *genc )
  389. {
  390.     int r;
  391.  
  392.     if( (genc -> CountDown) == 0 )
  393.       return( EOF );
  394.  
  395.     genc -> CountDown--;
  396.  
  397.     r = GetPixel( genc, (genc -> curx), (genc -> cury) );
  398.  
  399.     BumpPixel( genc );
  400.  
  401.     return( r );
  402. }
  403.  
  404.  
  405. /* public */
  406. static
  407. BOOL GIFEncode( struct GIFEncoder *genc, struct GIFAnimInstData *gaid,
  408.                 BOOL GInterlace, WORD Background, WORD Transparent,
  409.                 struct ColorRegister *cm, ULONG startframe, ULONG numframes, ULONG framestep )
  410. {
  411.     ULONG                timestamp;
  412.     int                  B;
  413.     int                  RWidth,
  414.                          RHeight;
  415.     int                  Resolution;
  416.     int                  ColorMapSize;
  417.     int                  InitCodeSize;
  418.     int                  i;
  419.     BPTR                 fp               = genc -> outfile;
  420.     LONG                 gif_delay        = 0L;
  421.     BOOL                 save_frame;
  422.     struct ColorRegister localcolormap[ MAXCOLORMAPSIZE ];
  423.     BOOL                 save_localcolormap;
  424.     BOOL                 firstframe       = TRUE; /* the first frame has not been written yet */
  425.  
  426.     genc -> Interlace = GInterlace;
  427.  
  428.     ColorMapSize = 1UL << (genc -> animdepth);
  429.  
  430.     RWidth  = genc -> Width  = genc -> animwidth;
  431.     RHeight = genc -> Height = genc -> animheight;
  432.  
  433.     Resolution = genc -> animdepth;
  434.  
  435.     /* The initial code size */
  436.     if( (genc -> animdepth) <= 1 )
  437.       InitCodeSize = 2;
  438.     else
  439.       InitCodeSize = (genc -> animdepth);
  440.  
  441.     /* Write the GIF signature */
  442.     FWrite( fp, "GIF", 1, 3 );
  443.  
  444.     /* Write the GIF version number (only "89a" because of the "Graphics Control Extension" used for timing) */
  445.     FWrite( fp, "89a", 1, 3 );
  446.  
  447.     /* Write out the screen width and height */
  448.     Putword( genc, RWidth  );
  449.     Putword( genc, RHeight );
  450.  
  451.     /* Flag field */
  452.     {
  453.       /* Indicate that there is a global colour map */
  454.       B = LOCALCOLORMAP; /* Yes, there is a global color map */
  455.  
  456.       /* OR in the resolution */
  457.       B |= (Resolution - 1) << 5;
  458.  
  459.       /* OR in the Bits per Pixel (Size of global color map) */
  460.       B |= ((genc -> animdepth) - 1);
  461.  
  462.       /* Write it out */
  463.       fputc( B, fp );
  464.     }
  465.  
  466.     /* Write out the Background colour */
  467.     fputc( Background, fp );
  468.  
  469.     /* Write pixel aspect ratio (not implemented yet, therefore 0 here) */
  470.     fputc( 0, fp );
  471.  
  472.     /* Write out the Global Colour Map */
  473.     for( i = 0 ; i < ColorMapSize ; i++ )
  474.     {
  475.       fputc( (cm[ i ] . red),   fp );
  476.       fputc( (cm[ i ] . green), fp );
  477.       fputc( (cm[ i ] . blue),  fp );
  478.     }
  479.  
  480.     /* Write comment extensions for each DTA_Obj#? attribute we found... */
  481.     {
  482.       /* ti_Tag is the attribute to check; ti_Data is the label written in front of the data */
  483.       struct TagItem commentstags[] =
  484.       {
  485.         { DTA_ObjName,       (ULONG)"name: "       },
  486.         { DTA_ObjAuthor,     (ULONG)"author: "     },
  487.         { DTA_ObjAnnotation, (ULONG)"annotation: " },
  488.         { DTA_ObjCopyright,  (ULONG)"copyright: "  },
  489.         { DTA_ObjVersion,    (ULONG)"version: "    },
  490.         { TAG_DONE,          0UL                   }
  491.       };
  492.  
  493.       struct TagItem *tstate = commentstags,
  494.                      *ti;
  495.  
  496.       while( ti = NextTagItem( (&tstate) ) )
  497.       {
  498.         STRPTR string,
  499.                label = (STRPTR)(ti -> ti_Data);
  500.  
  501.         (void)GetDTAttrs( (genc -> object), (ti -> ti_Tag), (&string), TAG_DONE );
  502.  
  503.         if( string )
  504.         {
  505.           UBYTE *c;
  506.  
  507.           fputc( '!',   fp ); /* Extension */
  508.           fputc( 0xfe,  fp ); /* GIF89a Comment extension */
  509.  
  510.           c = label;  while( *c ) char_out( genc, *c++ ); /* write comment label            */
  511.           c = string; while( *c ) char_out( genc, *c++ ); /* write DTA_Obj#? attribute data */
  512.  
  513.           flush_char( genc );
  514.  
  515.           fputc( 0, fp ); /* Block terminator */
  516.         }
  517.       }
  518.     }
  519.  
  520.     for( timestamp = startframe ; numframes > 0UL ; timestamp += framestep, numframes-- )
  521.     {
  522.       /* reset some values */
  523.       save_frame         = FALSE;
  524.       save_localcolormap = FALSE;
  525.  
  526.       /* Check for abort... */
  527.       if( CheckSignal( SIGBREAKF_CTRL_D ) )
  528.       {
  529.         SetIoErr( ERROR_BREAK );
  530.         return( FALSE );
  531.       }
  532.  
  533.       genc -> loadmsg . MethodID      = ADTM_LOADFRAME;
  534.       genc -> loadmsg . alf_TimeStamp = timestamp;
  535.       genc -> loadmsg . alf_Frame     = timestamp; /* CBM anim.datatype compatibility ONLY */
  536.  
  537.       if( DoMethodA( (genc -> object), (Msg)(&(genc -> loadmsg)) ) )
  538.       {
  539.         /* print frame contents */
  540.         verbose_printf( cb, gaid, "frame: timestamp %lu frame %lu duration %lu bitmap %lx cmap %lx sample %lx len %lu period %lu\n",
  541.                         timestamp,
  542.                         (genc -> loadmsg . alf_Frame),
  543.                         (genc -> loadmsg . alf_Duration),
  544.                         (genc -> loadmsg . alf_BitMap),
  545.                         (genc -> loadmsg . alf_CMap),
  546.                         (genc -> loadmsg . alf_Sample),
  547.                         (genc -> loadmsg . alf_SampleLength),
  548.                         (genc -> loadmsg . alf_Period) );
  549.  
  550.         /* If we got a bitmap (should always be TRUE), compare it with the previous one
  551.          * If there was a change of the contents, write a matching gif image out...
  552.          */
  553.         if( genc -> loadmsg . alf_BitMap )
  554.         {
  555.           /* swap bitmaps */
  556.           genc -> whichbm = !(genc -> whichbm); /* 0 to 1 or 1 to 0 */
  557.  
  558.           genc -> currchunkymap = genc -> srcchunkymap[ (genc -> whichbm) ]; /* shortcut */
  559.  
  560.           /* Copy given bitmap (which may be a planar bitmap in fast-mem) to a system-allocated bitmap
  561.            * that ReadPixel(%|Array8) can reach it...
  562.            */
  563.           CopyBitMap( cb, (genc -> srcbm), (genc -> loadmsg . alf_BitMap), (genc -> animwidth), (genc -> animheight) );
  564.  
  565.           /* Convert data into a chunky pixel map */
  566.           (void)ReadPixelArray8( (&(genc -> rp)), 0UL, 0UL, ((genc -> animwidth) - 1UL), ((genc -> animheight) - 1UL), (genc -> currchunkymap), (&(genc -> rpa8tmprp)) );
  567.  
  568.           /* The first frame must be written because ther's no previous frame to compare... */
  569.           if( firstframe )
  570.           {
  571.             firstframe = FALSE;
  572.             save_frame = TRUE;
  573.           }
  574.           else
  575.           {
  576.             /* Compare old and new chunky map and check if they're equal
  577.              * If they're equal, there's no need to write them out...
  578.              */
  579.             save_frame = memcmp( (genc -> srcchunkymap[ (genc -> whichbm) ]),
  580.                                  (genc -> srcchunkymap[ !(genc -> whichbm) ]),
  581.                                  (size_t)((genc -> animwidth) * (genc -> animheight)) );
  582.           }
  583.         }
  584.         else
  585.         {
  586.           /* Should not occur */
  587.           error_printf( cb, gaid, "WARNING: no bitmap\n" );
  588.           SetIoErr( ERROR_OBJECT_WRONG_TYPE ); /* not very meaningfull */
  589.           return( FALSE );
  590.         }
  591.  
  592.         /* If we got a local colormap, check if it is different from the global one.
  593.          * If there is a difference, set "save_localcolormap" to TRUE that a local colormap is saved below
  594.          */
  595.         if( genc -> loadmsg . alf_CMap )
  596.         {
  597.           ULONG color;
  598.           ULONG rgb[ 3 ];
  599.  
  600.           for( color = 0UL ; color < ColorMapSize ; color++ )
  601.           {
  602.             GetRGB32( (genc -> loadmsg . alf_CMap), color, 1UL, rgb );
  603.  
  604.             localcolormap[ color ] . red   = (UBYTE)(rgb[ 0 ] >> 24UL);
  605.             localcolormap[ color ] . green = (UBYTE)(rgb[ 1 ] >> 24UL);
  606.             localcolormap[ color ] . blue  = (UBYTE)(rgb[ 2 ] >> 24UL);
  607.  
  608.             /* Any different between alf_CMap and global color map (e.g. ADTA_ColorRegisters) ? */
  609.             if( ((localcolormap[ color ] . red)   != (cm[ color ] . red))   ||
  610.                 ((localcolormap[ color ] . green) != (cm[ color ] . green)) ||
  611.                 ((localcolormap[ color ] . blue)  != (cm[ color ] . blue)) )
  612.             {
  613.               /* Save local colormap */
  614.               save_localcolormap = TRUE;
  615.             }
  616.           }
  617.         }
  618.  
  619.         /* Any change in the data ? */
  620.         if( save_frame || save_localcolormap )
  621.         {
  622.           verbose_printf( cb, gaid, "saving gif image%s, %ld/100 sec delay\n",
  623.                           ((save_localcolormap)?(" with local colormap"):("")),
  624.                           gif_delay );
  625.  
  626.           /* Calculate number of bits we are expecting */
  627.           genc -> CountDown = (long)(genc -> Width) * (long)(genc -> Height);
  628.  
  629.           /* Set up the current x and y position */
  630.           genc -> curx = genc -> cury = 0;
  631.  
  632.           /* Indicate which pass we are on (if interlace) */
  633.           genc -> Pass = 0;
  634.  
  635.           /* Reset */
  636.           genc -> cur_accum = 0;
  637.           genc -> cur_bits  = 0;
  638.  
  639.           genc -> a_count   = 0;
  640.  
  641.           /* Write out Graphic Control Extension for timing (and transparent colour index, if necessary.) */
  642.           {
  643.             UBYTE packed = 0U;
  644.  
  645.             fputc( '!',                                  fp );  /* Extension */
  646.             fputc( 0xf9,                                 fp );  /* GIF89a Graphic Control Extension */
  647.             fputc( 4,                                    fp );  /* Block size */
  648.  
  649.             if( Transparent >= 0 )
  650.             {
  651.               packed |= 0x01;                                   /* has transparent color ! */
  652.             }
  653.  
  654.             fputc( packed,                               fp );
  655.  
  656.             Putword( genc, (int)gif_delay );                    /* Delay in 1/100 sec */
  657.  
  658.             fputc( (Transparent >= 0)?(Transparent):(0), fp );
  659.             fputc( 0,                                    fp );  /* Block terminator */
  660.  
  661.             gif_delay = 0L; /* delay time written... */
  662.           }
  663.  
  664.           /* Write GIF Image Descriptor */
  665.           {
  666.             UBYTE packed = 0U;
  667.  
  668.             /* Write: "Start of raster data" */
  669.             fputc( ',', fp );
  670.  
  671.             /* Write the Image header (does currently not support deltas) */
  672.             Putword( genc, 0                 );
  673.             Putword( genc, 0                 );
  674.             Putword( genc, (genc -> Width)   );
  675.             Putword( genc, (genc -> Height)  );
  676.  
  677.             /* Write out whether or not the image is interlaced */
  678.             if( genc -> Interlace )
  679.             {
  680.               packed |= INTERLACE;
  681.             }
  682.  
  683.             /* Write out whether or not the image has an own colormap */
  684.             if( save_localcolormap )
  685.             {
  686.               packed |= LOCALCOLORMAP;
  687.  
  688.               /* OR in the Bits per Pixel (Size of local color map) */
  689.               packed |= ((genc -> animdepth) - 1);
  690.             }
  691.  
  692.             fputc( packed, fp );
  693.           }
  694.  
  695.           /* Write local color map ? */
  696.           if( save_localcolormap )
  697.           {
  698.             ULONG color;
  699.  
  700.             /* Write out the Local Colour Map */
  701.             for( color = 0UL ; color < ColorMapSize ; color++ )
  702.             {
  703.               fputc( (localcolormap[ color ] . red),    fp );
  704.               fputc( (localcolormap[ color ] . green),  fp );
  705.               fputc( (localcolormap[ color ] . blue),   fp );
  706.             }
  707.           }
  708.  
  709.           /* Write out the initial code size */
  710.           fputc( InitCodeSize, fp );
  711.  
  712.           /* Go and actually compress the data */
  713.           compress( genc, (InitCodeSize + 1) );
  714.  
  715.           /* Write out a Zero-length packet (to end the series) */
  716.           fputc( 0, fp );
  717.         }
  718.  
  719.         /* Sum here the time to wait for this frame...
  720.          * (and Scale from 1/1200 units (realtime.library && ADTA_TicksPerFrame) to GIF delay (1/100) units)
  721.          */
  722.         gif_delay += INTDIVR( (100UL * (genc -> tpf)),  TICK_FREQ );
  723.       }
  724.       else
  725.       {
  726.         /* ADTM_LOADFRAME failed: Result2 contains the error cause */
  727.         return( FALSE );
  728.       }
  729.     }
  730.  
  731.     /* Write the GIF file terminator */
  732.     fputc( ';', fp );
  733.  
  734.     return( TRUE );
  735. }
  736.  
  737.  
  738. /* Write out a LITTLE_ENDIAN word to the GIF file */
  739. static
  740. void Putword( struct GIFEncoder *genc, int w )
  741. {
  742.     fputc( (w & 0xff),         (genc -> outfile) );
  743.     fputc( ((w / 256) & 0xff), (genc -> outfile) );
  744. }
  745.  
  746.  
  747. /***************************************************************************
  748.  *
  749.  *  GIFCOMPR.C       - GIF Image compression routines
  750.  *
  751.  *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
  752.  *  David Rowley (mgardi@watdcsu.waterloo.edu)
  753.  *
  754.  ***************************************************************************/
  755.  
  756.  
  757. /*
  758.  *
  759.  * GIF Image compression - modified 'compress'
  760.  *
  761.  * Based on: compress.c - File compression ala IEEE Computer, June 1984.
  762.  *
  763.  * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
  764.  *              Jim McKie               (decvax!mcvax!jim)
  765.  *              Steve Davies            (decvax!vax135!petsd!peora!srd)
  766.  *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
  767.  *              James A. Woods          (decvax!ihnp4!ames!jaw)
  768.  *              Joe Orost               (decvax!vax135!petsd!joe)
  769.  *
  770.  */
  771.  
  772.  
  773. /*
  774.  * compress stdin to stdout
  775.  *
  776.  * Algorithm:  use open addressing double hashing (no chaining) on the
  777.  * prefix code / next character combination.  We do a variant of Knuth's
  778.  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
  779.  * secondary probe.  Here, the modular division first probe is gives way
  780.  * to a faster exclusive-or manipulation.  Also do block compression with
  781.  * an adaptive reset, whereby the code table is cleared when the compression
  782.  * ratio decreases, but after the table fills.  The variable-length output
  783.  * codes are re-sized at this point, and a special CLEAR code is generated
  784.  * for the decompressor.  Late addition:  construct the table according to
  785.  * file size for noticeable speed improvement on small files.  Please direct
  786.  * questions about this implementation to ames!jaw.
  787.  */
  788.  
  789. static
  790. void compress( struct GIFEncoder *genc, int init_bits )
  791. {
  792.     register long     fcode;
  793.     register code_int i /* = 0 */;
  794.     register int      c;
  795.     register code_int ent;
  796.     register code_int disp;
  797.     register code_int hsize_reg;
  798.     register int      hshift;
  799.  
  800.     /* Set up the globals:  g_init_bits - initial number of bits */
  801.     genc -> g_init_bits = init_bits;
  802.  
  803.     /* Set up the necessary values */
  804.     genc -> clear_flg = FALSE;
  805.     genc -> maxcode   = MAXCODE((genc -> n_bits) = (genc -> g_init_bits));
  806.  
  807.     genc -> ClearCode  = (1 << (init_bits - 1));
  808.     genc -> EOFCode    = genc -> ClearCode + 1;
  809.     genc -> free_ent   = genc -> ClearCode + 2;
  810.  
  811.     char_init( genc );
  812.  
  813.     ent = GIFNextPixel( genc );
  814.  
  815.     for( fcode = (long)hsize, hshift = 0 ;  fcode < 65536L ; fcode *= 2L )
  816.     {
  817.       hshift++;
  818.     }
  819.  
  820.     hshift = 8 - hshift;                /* set hash code range bound */
  821.  
  822.     hsize_reg = hsize;
  823.     cl_hash( genc, (count_int)hsize_reg );            /* clear hash table */
  824.  
  825.     output( genc, (code_int)(genc -> ClearCode) );
  826.  
  827.     while( (c = GIFNextPixel( genc )) != EOF )
  828.     {
  829.         fcode = (long) (((long) c << maxbits) + ent);
  830.         i = (((code_int)c << hshift) ^ ent);    /* xor hashing */
  831.  
  832.         if( HashTabOf (i) == fcode )
  833.         {
  834.             ent = CodeTabOf (i);
  835.             continue;
  836.         }
  837.         else
  838.           if ( (long)HashTabOf (i) < 0 )      /* empty slot */
  839.             goto nomatch;
  840.  
  841.         disp = hsize_reg - i;           /* secondary hash (after G. Knott) */
  842.         if ( i == 0 )
  843.           disp = 1;
  844. probe:
  845.         if ( (i -= disp) < 0 )
  846.           i += hsize_reg;
  847.  
  848.         if ( HashTabOf (i) == fcode )
  849.         {
  850.           ent = CodeTabOf (i);
  851.           continue;
  852.         }
  853.  
  854.         if( (long)HashTabOf (i) > 0 )
  855.           goto probe;
  856.  
  857. nomatch:
  858.         output( genc, (code_int) ent );
  859.         ent = c;
  860.         if( (genc -> free_ent) < maxmaxcode )
  861.         {
  862.           CodeTabOf( i ) = genc -> free_ent++; /* code -> hashtable */
  863.           HashTabOf( i ) = fcode;
  864.         }
  865.         else
  866.         {
  867.           cl_block( genc );
  868.         }
  869.     }
  870.  
  871.     /* Put out the final code. */
  872.     output( genc, (code_int)ent );
  873.     output( genc, (code_int)(genc -> EOFCode) );
  874. }
  875.  
  876. /*****************************************************************
  877.  * TAG( output )
  878.  *
  879.  * Output the given code.
  880.  * Inputs:
  881.  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
  882.  *              that n_bits =< (long)wordsize - 1.
  883.  * Outputs:
  884.  *      Outputs code to the file.
  885.  * Assumptions:
  886.  *      Chars are 8 bits long.
  887.  * Algorithm:
  888.  *      Maintain a BITS character long buffer (so that 8 codes will
  889.  * fit in it exactly).  Use the VAX insv instruction to insert each
  890.  * code in turn.  When the buffer fills up empty it and start over.
  891.  */
  892.  
  893. static const
  894. unsigned long masks[] =
  895. {
  896.   0x0000, 0x0001, 0x0003, 0x0007,
  897.   0x000F, 0x001F, 0x003F, 0x007F,
  898.   0x00FF, 0x01FF, 0x03FF, 0x07FF,
  899.   0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF,
  900.   0xFFFF
  901. };
  902.  
  903.  
  904. static
  905. void output( struct GIFEncoder *genc, code_int code )
  906. {
  907.     genc -> cur_accum &= masks[ genc -> cur_bits ];
  908.  
  909.     if( genc -> cur_bits > 0 )
  910.       genc -> cur_accum |= ((long)code << genc -> cur_bits);
  911.     else
  912.       genc -> cur_accum = code;
  913.  
  914.     genc -> cur_bits += genc -> n_bits;
  915.  
  916.     while( genc -> cur_bits >= 8 )
  917.     {
  918.       char_out( genc, (unsigned int)(genc -> cur_accum & 0xff) );
  919.       genc -> cur_accum >>= 8;
  920.       genc -> cur_bits -= 8;
  921.     }
  922.  
  923.     /* If the next entry is going to be too big for the code size,
  924.      * then increase it, if possible.
  925.      */
  926.     if( ((genc -> free_ent) > (genc -> maxcode)) || (genc -> clear_flg) )
  927.     {
  928.       if( genc -> clear_flg )
  929.       {
  930.         genc -> maxcode = MAXCODE ((genc -> n_bits) = (genc -> g_init_bits));
  931.         genc -> clear_flg = FALSE;
  932.       }
  933.       else
  934.       {
  935.         ++genc -> n_bits;
  936.  
  937.         if( (genc -> n_bits) == maxbits )
  938.           genc -> maxcode = maxmaxcode;
  939.         else
  940.           genc -> maxcode = MAXCODE(genc -> n_bits);
  941.       }
  942.     }
  943.  
  944.     if( code == (genc -> EOFCode) )
  945.     {
  946.       /* At EOF, write the rest of the buffer. */
  947.       while( genc -> cur_bits > 0 )
  948.       {
  949.         char_out( genc, (unsigned int)(genc -> cur_accum & 0xff) );
  950.         genc -> cur_accum >>= 8;
  951.         genc -> cur_bits -= 8;
  952.       }
  953.  
  954.       flush_char( genc );
  955.     }
  956. }
  957.  
  958.  
  959. /* Clear out the hash table */
  960. static
  961. void cl_block( struct GIFEncoder *genc )             /* table clear for block compress */
  962. {
  963.     cl_hash ( genc, (count_int) hsize );
  964.     genc -> free_ent  = (genc -> ClearCode) + 2;
  965.     genc -> clear_flg = TRUE;
  966.  
  967.     output( genc, (code_int)(genc -> ClearCode) );
  968. }
  969.  
  970.  
  971. static
  972. void cl_hash( struct GIFEncoder *genc, register count_int hsize )          /* reset code table */
  973. {
  974.     register count_int *htab_p = (genc -> htab) + hsize;
  975.  
  976.     register long i;
  977.     register long m1 = -1;
  978.  
  979.     i = hsize - 16;
  980.     do /* might use Sys V memset(3) here */
  981.     {
  982.       *(htab_p-16) = m1;
  983.       *(htab_p-15) = m1;
  984.       *(htab_p-14) = m1;
  985.       *(htab_p-13) = m1;
  986.       *(htab_p-12) = m1;
  987.       *(htab_p-11) = m1;
  988.       *(htab_p-10) = m1;
  989.       *(htab_p- 9) = m1;
  990.       *(htab_p- 8) = m1;
  991.       *(htab_p- 7) = m1;
  992.       *(htab_p- 6) = m1;
  993.       *(htab_p- 5) = m1;
  994.       *(htab_p- 4) = m1;
  995.       *(htab_p- 3) = m1;
  996.       *(htab_p- 2) = m1;
  997.       *(htab_p- 1) = m1;
  998.       htab_p -= 16;
  999.     } while ((i -= 16) >= 0);
  1000.  
  1001.     for ( i += 16 ; i > 0 ; i-- )
  1002.       *--htab_p = m1;
  1003. }
  1004.  
  1005.  
  1006. /******************************************************************************
  1007.  *
  1008.  * GIF Specific routines
  1009.  *
  1010.  ******************************************************************************/
  1011.  
  1012.  
  1013. /* Set up the 'byte output' routine */
  1014. static
  1015. void char_init( struct GIFEncoder *genc )
  1016. {
  1017.     genc -> a_count = 0;
  1018. }
  1019.  
  1020.  
  1021. /* Add a character to the end of the current packet, and if it is 254
  1022.  * characters, flush the packet to disk.
  1023.  */
  1024. static
  1025. void char_out( struct GIFEncoder *genc, int c )
  1026. {
  1027.     genc -> accum[ (genc -> a_count)++ ] = c;
  1028.  
  1029.     if( (genc -> a_count) >= 254 )
  1030.       flush_char( genc );
  1031. }
  1032.  
  1033.  
  1034. /* Flush the packet to disk, and reset the accumulator */
  1035. static
  1036. void flush_char( struct GIFEncoder *genc )
  1037. {
  1038.     if( (genc -> a_count) > 0 )
  1039.     {
  1040.       fputc( (genc -> a_count), (genc -> outfile) );
  1041.       FWrite( (genc -> outfile), (genc -> accum), 1UL, (ULONG)(genc -> a_count) );
  1042.       genc -> a_count = 0;
  1043.     }
  1044. }
  1045.  
  1046.  
  1047.