Exemplo n.º 1
0
void create_mgif_delta()
  {
  void *d;
  long siz;

  //conv_2_rgb();
  init_palmap();
  if (BZTRATA) create_color_state();
  set_max_color_change(BZTRATA);
  create_low_quality();
  if (delta_data_size+frame_delta_size>FRAME_LEN)
     {
     create_mgif_lzw();
     return;
     }
  if (!frame_delta_size) return;
  reduce_palette();
  filter_colors(frame_delta,frame_delta_size,color_map);
  d=join_two_blocks(delta_data,frame_delta,delta_data_size,frame_delta_size,&siz);
  init_lzw_compressor(8);
  memset(lzw_buffer,0,sizeof(lzw_buffer));
  siz=lzw_encode(d,lzw_buffer,siz);
  done_lzw_compressor();
  free(d);
  if (siz>FRAME_LEN)
     {
     create_mgif_lzw();
     return;
     }
  write_chunk(MGIF_DELTA,siz,lzw_buffer);
  create_mgif_pal();
  }
Exemplo n.º 2
0
int main(void)
{
	unsigned char outbuf[DICTSIZE];
	unsigned char *outbuf_end = outbuf + DICTSIZE;
	struct lzw_state enc;
	struct lzw_state dec;

	for(unsigned n = 0; tests[n]; n++) {
		char *input = tests[n];
		unsigned compressed[1024];
		unsigned char output[1024];

		printf(" input: %s\n", input);
	
		lzw_state_init(&enc);
	
		unsigned *comp_curs = &compressed[0];
		unsigned complen = 0;
		for(unsigned i = 0; input[i]; i++)
			comp_curs += lzw_encode(&enc, input[i], comp_curs);
		comp_curs += lzw_encode_finish(&enc, comp_curs);
		complen = comp_curs - compressed;
		printf("compressed: ");
		for(unsigned i = 0; i < complen; i++) {
			printf("%u (", compressed[i]);
			print_dict_item(&enc, compressed[i]);
			printf(") ");
		}
		printf("\n");
	
		memset(output, 0, sizeof(output));
		lzw_state_init(&dec);
	
		unsigned char *dec_curs = &output[0];
		for(unsigned i = 0; i < complen; i++) {
			unsigned char *outbuf_curs = lzw_decode(&dec, compressed[i], outbuf);
			memcpy(dec_curs, outbuf_curs, (outbuf_end - outbuf_curs));
			dec_curs += (outbuf_end - outbuf_curs);
		}
		unsigned declen = dec_curs - output;
		printf("output: %*s (%u)\n\n", declen, output, declen);
	
		for(unsigned i = 0; input[i]; i++)
			assert(input[i] == output[i]);
		assert(declen == strlen(input));
	}

	return 0;
}
Exemplo n.º 3
0
int main(int argc, char* argv[]){
  int input_length = 100;
  uint8_t input[100] = {1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,2,2,2,2,2,1,1,1,0,0,0,0,2,2,2,1,1,1,0,0,0,0,2,2,2,2,2,2,0,0,0,0,1,1,1,2,2,2,0,0,0,0,1,1,1,2,2,2,2,2,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1};
  int color_list_size = 4;

  LZWEncoderData ld;
  lzw_encode_initialize(&ld, color_list_size);
  lzw_encode(&ld, input, input_length);
  lzw_encode_free(&ld);

  for(int m=0; m<ld.output_active_length; m++) printf("%02x ", ld.output[m]); printf("\n");

  free(ld.output);
  return 0;
}
Exemplo n.º 4
0
/* ======================================================================== */
int gif_wr_frame_s
(
    gif_t  *gif,
    uint_8 *vid
)
{
    uint_8 *enc_ptr = gif_enc_buf;
    int lzw_len;
    size_t wrote;

    assert(enc_ptr);

    /* -------------------------------------------------------------------- */
    /*  Output local header.                                                */
    /* -------------------------------------------------------------------- */
    *enc_ptr++ = 0x2C;                      /* Local header signature.      */
    *enc_ptr++ = 0;                         /* X position of image = 0 LSB  */
    *enc_ptr++ = 0;                         /* X position of image = 0 MSB  */
    *enc_ptr++ = 0;                         /* Y position of image = 0 LSB  */
    *enc_ptr++ = 0;                         /* Y position of image = 0 MSB  */
    *enc_ptr++ = (gif->x_dim >> 0) & 0xFF;  /* Width = X dimension LSB      */
    *enc_ptr++ = (gif->x_dim >> 8) & 0xFF;  /* Width = X dimension MSB      */
    *enc_ptr++ = (gif->y_dim >> 0) & 0xFF;  /* Height = Y dimension LSB     */
    *enc_ptr++ = (gif->y_dim >> 8) & 0xFF;  /* Height = Y dimension MSB     */
    *enc_ptr++ = 0;                         /* No local colors              */


    /* -------------------------------------------------------------------- */
    /*  Now compress the image.                                             */
    /* -------------------------------------------------------------------- */
    lzw_len = lzw_encode(vid, enc_ptr, gif->x_dim*gif->y_dim, 
                         gif_enc_buf_sz - (enc_ptr - gif_enc_buf));

    if (lzw_len < 0)
        return -1;

    enc_ptr += lzw_len;
    assert(enc_ptr < gif_enc_buf + gif_enc_buf_sz);

    /* -------------------------------------------------------------------- */
    /*  Write the compressed image out.                                     */
    /* -------------------------------------------------------------------- */
    wrote = fwrite(gif_enc_buf, 1, enc_ptr - gif_enc_buf, gif->f);
    if (wrote < (unsigned)(enc_ptr - gif_enc_buf))
        return -1;

    return wrote;
}
Exemplo n.º 5
0
int lzw_benchmark(char *code) 
{
    char *alphabet = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI";
    data *d = lzw_encode(alphabet, code);
    int result = data_size(d);
    /*char *dec = lzw_decode(alphabet, d);
    if (strncmp(dec, code, strlen(code)) != 0) {
        printf("[LZW ERROR]\n");
        printf("Original: %s\n", code);
        printf("Decoded : %s\n", dec);
    }
    free(dec);*/
    data_free(d);
    return result;

}
Exemplo n.º 6
0
void create_mgif_lzw()
  {
  int siz;

  //conv_2_rgb();
  init_palmap();
  create_mgif_pal();
  filter_colors(frame_buffer,FRAME_LEN,color_map);
  create_last_frame(frame_buffer,last_frame,hipal,FRAME_LEN);
  init_lzw_compressor(8);
  memset(lzw_buffer,0,sizeof(lzw_buffer));
  siz=lzw_encode(frame_buffer,lzw_buffer,FRAME_LEN);
  if (siz>FRAME_LEN) write_chunk(MGIF_COPY,FRAME_LEN,frame_buffer);
  else write_chunk(MGIF_LZW,siz,lzw_buffer);
  done_lzw_compressor(8);
  }
Exemplo n.º 7
0
void assert_lzw(char *plain) {
	memset(enc_buf, 0, sizeof(enc_buf));
	memset(res_buf, 0, sizeof(res_buf));
	size_t esz = lzw_encode(plain, strlen(plain), enc_buf);
	lzw_decode(enc_buf, esz, res_buf);

	char *input = plain;
	char *output = res_buf;
	while (*input) {
		if (*input++ != *output++) {
			res_buf[4095] = 0;
			fprintf(stderr, "\x1b[41mTEST FAILED: %s == %s\x1b[0m\n", plain, res_buf);
			failed = true;
			return;
		}
	}
	fprintf(stderr, "\x1b[42mTEST PASSED: \"%s\" == \"%s\"\x1b[0m\n", plain, res_buf);
}
Exemplo n.º 8
0
int main(int argc, char **argv) {
#if 1
	bitstream_t bs = {};
	bs.data = malloc(1000000);
	memset(bs.data, 0, 1000000);

	{
		write_bits(&bs, 1, 0b1);
		ASSERT_EQ(bs.data[0], 0b00000001);
		ASSERT_EQ(bs.bit, 1);
		ASSERT_EQ(bs.index, 0);
		fprintf(stderr, "\n");

		write_bits(&bs, 4, 0b1010);
		ASSERT_EQ(bs.data[0], 0b00010101);
		ASSERT_EQ(bs.bit, 5);
		ASSERT_EQ(bs.index, 0);
		fprintf(stderr, "\n");

		write_bits(&bs, 3, 0b101);
		ASSERT_EQ(bs.data[0], 0b10110101);
		ASSERT_EQ(bs.bit, 0);
		ASSERT_EQ(bs.index, 1);
		fprintf(stderr, "\n");

		write_bits(&bs, 5, 0b11011);
		ASSERT_EQ(bs.data[0], 0b10110101);
		ASSERT_EQ(bs.data[1], 0b00011011);
		ASSERT_EQ(bs.bit, 5);
		ASSERT_EQ(bs.index, 1);
		fprintf(stderr, "\n");

		write_bits(&bs, 5, 0b10110);
		ASSERT_EQ(bs.data[0], 0b10110101);
		ASSERT_EQ(bs.data[1], 0b11011011);
		ASSERT_EQ(bs.data[2], 0b00000010);
		ASSERT_EQ(bs.bit, 2);
		ASSERT_EQ(bs.index, 2);
		fprintf(stderr, "\n");

		write_bits(&bs, 20, 0xABCDE);
		ASSERT_EQ(bs.data[0], 0b10110101);
		ASSERT_EQ(bs.data[1], 0b11011011);
		ASSERT_EQ(bs.data[2], 0b01111010);
		ASSERT_EQ(bs.data[3], 0b11110011);
		ASSERT_EQ(bs.data[4], 0b00101010);
		ASSERT_EQ(bs.bit, 6);
		ASSERT_EQ(bs.index, 4);
		fprintf(stderr, "\n");

		write_bits(&bs, 1, 0);
		ASSERT_EQ(bs.data[0], 0b10110101);
		ASSERT_EQ(bs.data[1], 0b11011011);
		ASSERT_EQ(bs.data[2], 0b01111010);
		ASSERT_EQ(bs.data[3], 0b11110011);
		ASSERT_EQ(bs.data[4], 0b00101010);
		ASSERT_EQ(bs.bit, 7);
		ASSERT_EQ(bs.index, 4);
		fprintf(stderr, "\n");
	}

	{
		ASSERT_EQ(extract_bits(0b11011011, 0, 8), 0b11011011);
		ASSERT_EQ(extract_bits(0b00000001, 0, 1), 0b1);
		ASSERT_EQ(extract_bits(0b11111110, 0, 1), 0b0);
		ASSERT_EQ(extract_bits(0b01111111, 7, 8), 0b0);
		ASSERT_EQ(extract_bits(0b10000000, 7, 8), 0b1);
		ASSERT_EQ(extract_bits(0b11011011, 2, 6), 0b0110);
		fprintf(stderr, "\n");
	}

	bs.index = 0;
	bs.bit = 0;

	{
		ASSERT_EQ(read_bits(&bs, 1), 0b1);
		ASSERT_EQ(read_bits(&bs, 4), 0b1010);
		ASSERT_EQ(read_bits(&bs, 3), 0b101);
		ASSERT_EQ(read_bits(&bs, 5), 0b11011);
		ASSERT_EQ(read_bits(&bs, 5), 0b10110);
		ASSERT_EQ(read_bits(&bs, 20), 0xABCDE);
		ASSERT_EQ(read_bits(&bs, 1), 0);
		fprintf(stderr, "\n");
	}

	assert_lzw("ababcbababaaaaaaa");
	assert_lzw("A circular buffer, or ring buffer, is a FIFO container consisting of a fixed-size buffer and head & tail indices. The head index is incremented as items are added and the tail index when items are removed.");
	if (failed) {
		return 1;
	}
#endif
#if 1
	// void *ibuff = malloc(10000000);
	// memset(ibuff, 0, 10000000);
	// void *obuff = malloc(10000000);
	// memset(obuff, 0, 10000000);
	// int *ebuff = malloc(10000000);
	// memset(ebuff, 0, 10000000);
	size_t rsz = read(STDIN_FILENO, ibuff, 10000000);
	size_t esz = lzw_encode(ibuff, rsz, ebuff);
	lzw_decode(ebuff, esz, obuff);
	write(STDOUT_FILENO, obuff, rsz);
	fprintf(stderr, "input size: %lu; compressed size: %lu; rate: %f\n", rsz, esz, (float)esz/(float)rsz);
#endif
}
Exemplo n.º 9
0
/* ======================================================================== */
int gif_wr_frame_m
(
    gif_t  *gif,
    uint_8 *vid,
    int     delay,
    int     mode
)
{
    int trans = gif->trans >= 0;
    uint_8 *enc_ptr = gif_enc_buf;
    uint_8 *vid_ptr, *prv_ptr, *trn_ptr;
    uint_8 *best_img1, *best_img2, *best_lct;
    int x, y, xx, yy, min_x, min_y, max_x, max_y, width, height;
    int n_col_d, n_col_e = 0, n_col_f = 0, lct_sz_d, lct_sz_e, lct_sz_f;
    int enc_sz_a, enc_sz_b, enc_sz_c, enc_sz_d, enc_sz_e, enc_sz_f;
    int best_sz, best_lct_sz, trans_idx, do_trans = 0;
    int lzw_len; 
    int cnt, num_trans = 0;
    char best = '*';
    size_t wrote;

    assert(enc_ptr);

    /* -------------------------------------------------------------------- */
    /*  Allocate our image optimization scratch buffers, if necessary.      */
    /* -------------------------------------------------------------------- */
    if (gif_img_sz < gif->x_dim * gif->y_dim)
    {
        if (gif_img_tr) free(gif_img_tr);
        gif_img_sz = gif->x_dim * gif->y_dim;
        gif_img_tr = CALLOC(uint_8, 7 * gif->x_dim * gif->y_dim + 3*256);

        if (!gif_img_tr)
        {
            fprintf(stderr, "gif_wr_frame_m: out of memory\n");
            return -1;
        }

        gif_img_a = gif_img_tr + gif_img_sz * 2;
        gif_img_b = gif_img_a  + gif_img_sz;
        gif_img_d = gif_img_b  + gif_img_sz;
        gif_img_e = gif_img_d  + gif_img_sz;
        gif_img_f = gif_img_e  + gif_img_sz;
        gif_pal_d = gif_img_f  + gif_img_sz;
        gif_pal_e = gif_pal_d  + 256;
        gif_pal_f = gif_pal_e  + 256;
    }

    /* -------------------------------------------------------------------- */
    /*  Optimize image:                                                     */
    /*                                                                      */
    /*   1. Generate "transparency" image with trans pixels wherever this   */
    /*      image is the same as the previous one.                          */
    /*                                                                      */
    /*   2. Compute tighter bounding box on image--that is, smallest box    */
    /*      that contains all the non-trans pixels.                         */
    /*                                                                      */
    /*   3. Crop the incoming image based on the tighter bounding box.      */
    /*                                                                      */
    /*   4. Generate "minimal palette" images that renumber all the         */
    /*      pixels into the smallest possible numbering space.              */
    /*                                                                      */
    /*   5. Compress the image multiple ways, and take the best:            */
    /*                                                                      */
    /*       a. Cropped image, orig palette, no trans pixels                */
    /*       b. Cropped image, orig palette, trans pixels                   */
    /*       c. Cropped image, orig palette, "wildcard" trans/no-trans      */
    /*       d. Cropped image, new palette, no trans pixels                 */
    /*       e. Cropped image, new palette, trans pixels                    */
    /*       f. Cropped image, new palette, "wildcard" trans/no-trans       */
    /*                                                                      */
    /*      When comparing new palette to orig palette, include cost        */
    /*      of sending local palette.  If the global palette has too        */
    /*      many colors, we may not be able to try b or c.  If the local    */
    /*      palette has too many colors, we may not be able to try e or     */
    /*      f.                                                              */
    /*                                                                      */
    /* -------------------------------------------------------------------- */

    /* -------------------------------------------------------------------- */
    /*   1. Generate "transparency" image...                                */
    /*   2. Compute tighter bounding box on image...                        */
    /* -------------------------------------------------------------------- */
    min_x = gif->x_dim;
    min_y = gif->y_dim;
    max_x = 0;
    max_y = 0;

    vid_ptr = vid;
    prv_ptr = gif->vid;
    trn_ptr = gif_img_tr;

    for (y = 0; y < gif->y_dim; y++)
        for (x = 0; x < gif->x_dim; x++)
        {
            uint_8 curr = *vid_ptr++;
            uint_8 prev = *prv_ptr++;
            uint_8 tran = gif->trans;

            if (curr != prev)
            {
                tran = curr;
                if (x < min_x) min_x = x;
                if (y < min_y) min_y = y;
                if (x > max_x) max_x = x;
                if (y > max_y) max_y = y;
            }

            *trn_ptr++ = tran;
        }


    /* -------------------------------------------------------------------- */
    /*  Stop now if current image matches previous image.                   */
    /* -------------------------------------------------------------------- */
    if (min_x > max_x || min_y > max_y)
        return 0;

    if (mode != 0)
    {
        min_x = 0;
        min_y = 0;
        max_x = gif->x_dim - 1;
        max_y = gif->y_dim - 1;
    }

    width  = max_x - min_x + 1;
    height = max_y - min_y + 1;
    cnt    = width*height;

    /* -------------------------------------------------------------------- */
    /*   3. Crop the incoming image based on the tighter bounding box.      */
    /* -------------------------------------------------------------------- */
    for (y = min_y, yy = 0; y <= max_y; y++, yy++)
        for (x = min_x, xx = 0; x <= max_x; x++, xx++)
        {
            /*  a. Cropped image, orig palette, no trans pixels             */
            /*  b. Cropped image, orig palette, trans pixels                */
            gif_img_a[xx + yy*width] = vid       [x + y*gif->x_dim];
            gif_img_b[xx + yy*width] = gif_img_tr[x + y*gif->x_dim];

            if (gif_img_tr[x + y*gif->x_dim] == gif->trans)
                num_trans++;
        }

    if (num_trans == 0) trans = 0;
    if (mode != 0)      trans = 0;
#if 0
    {
        FILE *ff;
        ff = fopen("debug", "wb");
        if (ff)
        {
            fwrite(gif_img_a, 1, cnt, ff);
            fclose(ff);
        }
    }
#endif

    /* -------------------------------------------------------------------- */
    /*   4. Generate "minimal palette" images...                            */
    /*       d. Cropped image, new palette, no trans pixels                 */
    /*       e. Cropped image, new palette, trans pixels                    */
    /*       f. Cropped image, new palette, "wildcard" trans/no-trans       */
    /* -------------------------------------------------------------------- */
              n_col_d = gen_mpi(gif_img_a, NULL,    gif_img_d, cnt, gif_pal_d);
    if(trans) n_col_e = gen_mpi(gif_img_b, NULL,    gif_img_e, cnt, gif_pal_e);
    if(trans) n_col_f = gen_mpi(gif_img_b,gif_img_a,gif_img_f, cnt, gif_pal_f);

    for (lct_sz_d = 1; (2 << lct_sz_d) < n_col_d; lct_sz_d++);
    for (lct_sz_e = 1; (2 << lct_sz_e) < n_col_e; lct_sz_e++);
    for (lct_sz_f = 1; (2 << lct_sz_f) < n_col_f; lct_sz_f++);

    if (trans)
    {
        int i;
        for (i = 0; i < n_col_d; i++)
            assert(gif_pal_d[i] == gif_pal_f[i]);
/*printf("n_col_d=%d, n_col_f=%d gif_pal_f[n_col_f-1]=%d gif->trans=%d\n", n_col_d, n_col_f, gif_pal_f[n_col_f-1], gif->trans);*/
        assert(n_col_d < n_col_f);
        assert(gif_pal_f[n_col_f - 1] == gif->trans);
    }


    /* -------------------------------------------------------------------- */
    /*   5. Compress the image multiple ways, and take the best...          */
    /*                                                                      */
    /*  We reuse gif_img_tr as a compression buffer here, since we don't    */
    /*  need that image any longer, but we do need a temp buffer for LZW.   */
    /* -------------------------------------------------------------------- */
    enc_sz_a  = lzw_encode(gif_img_a, gif_img_tr, cnt, gif_img_sz*2);
    enc_sz_b  = -1;
    enc_sz_c  = -1;
    enc_sz_d  = lzw_encode(gif_img_d, gif_img_tr, cnt, gif_img_sz*2);
    enc_sz_e  = -1;
    enc_sz_f  = -1;
    if (trans)
    {
        enc_sz_b = lzw_encode(gif_img_b, gif_img_tr, cnt, gif_img_sz*2);
        enc_sz_e = lzw_encode(gif_img_e, gif_img_tr, cnt, gif_img_sz*2);
#if 1
        enc_sz_c = lzw_encode2(gif_img_b,  gif_img_a, 
                               gif_img_tr, cnt, gif_img_sz);
        enc_sz_f = lzw_encode2(gif_img_f,  gif_img_d, 
                               gif_img_tr, cnt, gif_img_sz);
#endif
    }

    if (enc_sz_d > 0) enc_sz_d += 3 << (lct_sz_d + 1);
    if (enc_sz_e > 0) enc_sz_e += 3 << (lct_sz_e + 1);
    if (enc_sz_f > 0) enc_sz_f += 3 << (lct_sz_f + 1);

    if (enc_sz_a < 0) enc_sz_a = INT_MAX;
    if (enc_sz_b < 0) enc_sz_b = INT_MAX;
    if (enc_sz_c < 0) enc_sz_c = INT_MAX;
    if (enc_sz_d < 0) enc_sz_d = INT_MAX;
    if (enc_sz_e < 0) enc_sz_e = INT_MAX;
    if (enc_sz_f < 0) enc_sz_f = INT_MAX;

    /* Initially assume A's the best. */
    best_img1   = gif_img_a;
    best_img2   = NULL;
    best_lct    = NULL;
    best_lct_sz = 0;
    best_sz     = enc_sz_a;
    trans_idx   = 0;
    do_trans    = 0;
    best        = 'a';

#if 1
    if (enc_sz_b < best_sz) 
    { 
        best_img1   = gif_img_b; 
        best_img2   = NULL;
        best_lct    = NULL;
        best_lct_sz = 0;
        best_sz     = enc_sz_b;
        trans_idx   = gif->trans;
        do_trans    = 1;
        best        = 'b';
    }              
                   
    if (enc_sz_d < best_sz) 
    {              
        best_img1   = gif_img_d; 
        best_img2   = NULL;
        best_lct    = gif_pal_d;
        best_lct_sz = lct_sz_d;
        best_sz     = enc_sz_d;
        trans_idx   = 0;
        do_trans    = 0;
        best        = 'd';
    }              
                   
    if (enc_sz_e < best_sz) 
    {              
        best_img1   = gif_img_e; 
        best_img2   = NULL;
        best_lct    = gif_pal_e;
        best_lct_sz = lct_sz_e;
        best_sz     = enc_sz_e;
        trans_idx   = n_col_e - 1;
        do_trans    = 1;
        best        = 'e';
    }              

    if (enc_sz_c < best_sz) 
    {              
        best_img1   = gif_img_b; 
        best_img2   = gif_img_a; 
        best_lct    = NULL;
        best_lct_sz = 0;
        best_sz     = enc_sz_c;
        trans_idx   = gif->trans;
        do_trans    = 1;
        best        = 'c';
    }              
                   
    if (enc_sz_f < best_sz) 
    {              
        best_img1   = gif_img_f; 
        best_img2   = gif_img_d; 
        best_lct    = gif_pal_f;
        best_lct_sz = lct_sz_f;
        best_sz     = enc_sz_f;
        trans_idx   = n_col_f - 1;
        do_trans    = 1;
        best        = 'f';
    }              

    if (best_sz < 0 || best_sz == INT_MAX)
    {
        fprintf(stderr, "gif_wr_frame_m: Image overflowed compression "
                        "buffer.\n");
        return -1;
    }
#endif
    gif_best_stat[best - 'a']++;

    /* -------------------------------------------------------------------- */
    /*  Output a Graphic Control Ext.                                       */
    /* -------------------------------------------------------------------- */
    *enc_ptr++ = 0x21;                  /* Extension signature              */
    *enc_ptr++ = 0xF9;                  /* Graphic control extension        */
    *enc_ptr++ = 0x04;                  /* Length of block:  Fixed at 4.    */
    *enc_ptr++ = 0x04 | do_trans;       /* Disposal 01, No input, Trans     */
    *enc_ptr++ = (delay >> 0) & 0xFF;   /* delay in 100ths of a second LSB  */
    *enc_ptr++ = (delay >> 8) & 0xFF;   /* delay in 100ths of a second MSB  */
    *enc_ptr++ = trans_idx;             /* Transparency index, if any.      */
    *enc_ptr++ = 0x00;                  /* GCE block terminator.            */

    /* -------------------------------------------------------------------- */
    /*  Output an Image Descriptor.                                         */
    /* -------------------------------------------------------------------- */
    *enc_ptr++ = 0x2C;                  /* Image Separator                  */
    *enc_ptr++ = (min_x >> 0) & 0xFF;   /* Left edge, LSB                   */
    *enc_ptr++ = (min_x >> 8) & 0xFF;   /* Left edge, MSB                   */
    *enc_ptr++ = (min_y >> 0) & 0xFF;   /* Top edge, LSB                    */
    *enc_ptr++ = (min_y >> 8) & 0xFF;   /* Top edge, MSB                    */
    *enc_ptr++ = (width >> 0) & 0xFF;   /* Image width, LSB                 */
    *enc_ptr++ = (width >> 8) & 0xFF;   /* Image width, MSB                 */
    *enc_ptr++ = (height >> 0) & 0xFF;  /* Image height, LSB                */
    *enc_ptr++ = (height >> 8) & 0xFF;  /* Image height, MSB                */
    *enc_ptr++ = best_lct_sz == 0 ? 0   /* no local color table?            */
               : best_lct_sz | 0x80;    /* or yes local color table?        */

/*printf("[%3d,%3d] [%3d,%3d] [%3d,%3d] delay=%-3d trans=%-3d%c lct=%d\n", min_x, min_y, width, height, min_x + width, min_y + height, delay, trans_idx, do_trans ? '*' : ' ', best_lct_sz);*/

    /* -------------------------------------------------------------------- */
    /*  If we're sending a local color table, put it here.                  */
    /* -------------------------------------------------------------------- */
    if (best_lct_sz)
    {
        int i;

        for (i = 0; i < (2 << best_lct_sz); i++)
        {
            if (best_lct[i] < gif->n_cols)
            {
                *enc_ptr++ = gif->pal[3*best_lct[i] + 0];
                *enc_ptr++ = gif->pal[3*best_lct[i] + 1];
                *enc_ptr++ = gif->pal[3*best_lct[i] + 2];
            } else
            {
                *enc_ptr++ = 0;
                *enc_ptr++ = 0;
                *enc_ptr++ = 0;
            }
        }
    }

    /* -------------------------------------------------------------------- */
    /*  Now, re-encode the winning image.                                   */
    /* -------------------------------------------------------------------- */
    if (best_img2)
    {
        lzw_len = lzw_encode2(best_img1, best_img2, enc_ptr, cnt, 
                              gif_enc_buf_sz - (enc_ptr - gif_enc_buf) - 1);

    } else
    {
        lzw_len = lzw_encode(best_img1, enc_ptr, cnt,
                             gif_enc_buf_sz - (enc_ptr - gif_enc_buf) - 1);
    }
    if (lzw_len < 0)
    {
        fprintf(stderr, "gif_wr_frame_m: Final encode failed?\n");
        return -1;
    }

    enc_ptr += lzw_len;
    assert(enc_ptr < gif_enc_buf + gif_enc_buf_sz);

    /* -------------------------------------------------------------------- */
    /*  Write the compressed image out.                                     */
    /* -------------------------------------------------------------------- */
    wrote = fwrite(gif_enc_buf, 1, enc_ptr - gif_enc_buf, gif->f);
    if (wrote < (unsigned)(enc_ptr - gif_enc_buf))
    {
        fprintf(stderr, "gif_wr_frame_m: Short write? %ld vs %ld\n", 
                (long)wrote, (long)(enc_ptr - gif_enc_buf));
        return -1;
    }

    /* -------------------------------------------------------------------- */
    /*  Make the current image the new previous image.                      */
    /* -------------------------------------------------------------------- */
    memcpy(gif->vid, vid, gif->x_dim * gif->y_dim);

    return wrote;
}