Exemple #1
0
static int
unoptimize_image(Gif_Stream *gfs, Gif_Image *gfi, uint16_t *screen)
{
    unsigned size = gfs->screen_width * gfs->screen_height;
    int used_transparent;
    uint8_t *new_data = Gif_NewArray(uint8_t, size);
    uint16_t *new_screen = screen;
    if (!new_data) return 0;

    /* Oops! May need to uncompress it */
    Gif_UncompressImage(gfs, gfi);
    Gif_ReleaseCompressedImage(gfi);

    if (gfi->disposal == GIF_DISPOSAL_PREVIOUS) {
        new_screen = Gif_NewArray(uint16_t, size);
        if (!new_screen) return 0;
        memcpy(new_screen, screen, size * sizeof(uint16_t));
    }

    put_image_in_screen(gfs, gfi, new_screen);
    if (!create_image_data(gfs, gfi, new_screen, new_data, &used_transparent)) {
        Gif_DeleteArray(new_data);
        return 0;
    }

    if (gfi->disposal == GIF_DISPOSAL_PREVIOUS)
        Gif_DeleteArray(new_screen);
    else if (gfi->disposal == GIF_DISPOSAL_BACKGROUND)
        put_background_in_screen(gfs, gfi, screen);

    gfi->left = 0;
    gfi->top = 0;
    gfi->width = gfs->screen_width;
    gfi->height = gfs->screen_height;
    gfi->disposal = used_transparent;
    Gif_SetUncompressedImage(gfi, new_data, Gif_Free, 0);

    return 1;
}
Exemple #2
0
static int
apply_image(int is_second, Gif_Stream *gfs, int imageno, uint16_t background)
{
  int i, x, y, any_change;
  Gif_Image *gfi = gfs->images[imageno];
  Gif_Image *pgfi = imageno ? gfs->images[imageno - 1] : 0;
  int width = gfi->width;
  uint16_t map[256];
  uint16_t *data = gdata[is_second];
  uint16_t *last = glast[is_second];
  Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global;

  /* set up colormap */
  for (i = 0; i < 256; i++)
    map[i] = 1;
  if (gfs)
    for (i = 0; i < gfcm->ncol; i++)
      map[i] = gfcm->col[i].pixel;
  if (gfi->transparent >= 0 && gfi->transparent < 256)
    map[gfi->transparent] = TRANSP;

  /* if this image's disposal is 'previous', save the post-disposal version in
     'scratch' */
  if (gfi->disposal == GIF_DISPOSAL_PREVIOUS) {
    copy_area(scratch, data, gfi->left, gfi->top, gfi->width, gfi->height);
    if (pgfi && pgfi->disposal == GIF_DISPOSAL_PREVIOUS)
      copy_area(scratch, last, pgfi->left, pgfi->top, pgfi->width, pgfi->height);
    else if (pgfi && pgfi->disposal == GIF_DISPOSAL_BACKGROUND)
      fill_area(scratch, pgfi->left, pgfi->top, pgfi->width, pgfi->height, background);
  }

  /* uncompress and clip */
  Gif_UncompressImage(gfs, gfi);
  Gif_ClipImage(gfi, 0, 0, screen_width, screen_height);

  any_change = imageno == 0;
  {
    int lf = 0, tp = 0, rt = 0, bt = 0;
    expand_bounds(&lf, &tp, &rt, &bt, gfi);
    if (pgfi && pgfi->disposal == GIF_DISPOSAL_PREVIOUS)
      expand_bounds(&lf, &tp, &rt, &bt, pgfi);
    else if (pgfi && pgfi->disposal == GIF_DISPOSAL_BACKGROUND) {
      expand_bounds(&lf, &tp, &rt, &bt, pgfi);
      fill_area(last, pgfi->left, pgfi->top, pgfi->width, pgfi->height, background);
    } else
      pgfi = 0;
    for (y = tp; y < bt; ++y) {
      uint16_t *outd = data + screen_width * y + lf;
      if (!any_change)
	memcpy(line, outd, (rt - lf) * sizeof(uint16_t));
      if (pgfi && y >= pgfi->top && y < pgfi->top + pgfi->height)
	memcpy(outd + pgfi->left - lf,
	       last + screen_width * y + pgfi->left,
	       pgfi->width * sizeof(uint16_t));
      if (y >= gfi->top && y < gfi->top + gfi->height) {
	uint16_t *xoutd = outd + gfi->left - lf;
	const uint8_t *ind = gfi->img[y - gfi->top];
	for (x = 0; x < width; ++x, ++ind, ++xoutd)
	  if (map[*ind] != TRANSP)
	    *xoutd = map[*ind];
      }
      if (!any_change && memcmp(line, outd, (rt - lf) * sizeof(uint16_t)) != 0)
	any_change = 1;
    }
  }

  Gif_ReleaseUncompressedImage(gfi);
  Gif_ReleaseCompressedImage(gfi);

  /* switch 'glast' with 'scratch' if necessary */
  if (gfi->disposal == GIF_DISPOSAL_PREVIOUS) {
    uint16_t *x = scratch;
    scratch = glast[is_second];
    glast[is_second] = x;
  }

  return any_change;
}
static void
create_new_image_data(Gif_Stream *gfs, int optimize_flags)
{
  Gif_Image cur_unopt_gfi;	/* placehoder; maintains pre-optimization
				   image size so we can apply background
				   disposal */
  unsigned screen_size = (unsigned) screen_width * (unsigned) screen_height;
  uint16_t *previous_data = 0;
  Gif_CompressInfo gcinfo = gif_write_info;
  if ((optimize_flags & GT_OPT_MASK) >= 3)
      gcinfo.flags |= GIF_WRITE_OPTIMIZE;

  gfs->global = out_global_map;

  /* do first image. Remember to uncompress it if necessary */
  erase_screen(last_data);
  erase_screen(this_data);

  for (image_index = 0; image_index < gfs->nimages; image_index++) {
    Gif_Image *cur_gfi = gfs->images[image_index];
    Gif_OptData *opt = (Gif_OptData *)cur_gfi->user_data;
    int was_compressed = (cur_gfi->img == 0);

    /* save previous data if necessary */
    if (cur_gfi->disposal == GIF_DISPOSAL_PREVIOUS) {
      if (!previous_data)
          previous_data = Gif_NewArray(uint16_t, screen_size);
      copy_data_area(previous_data, this_data, cur_gfi);
    }

    /* set up this_data to be equal to the current image */
    apply_frame(this_data, cur_gfi, 0, 0);

    /* save actual bounds and disposal from unoptimized version so we can
       apply the disposal correctly next time through */
    cur_unopt_gfi = *cur_gfi;

    /* set bounds and disposal from optdata */
    Gif_ReleaseUncompressedImage(cur_gfi);
    cur_gfi->left = opt->left;
    cur_gfi->top = opt->top;
    cur_gfi->width = opt->width;
    cur_gfi->height = opt->height;
    cur_gfi->disposal = opt->disposal;
    if (image_index > 0)
	cur_gfi->interlace = 0;

    /* find the new image's colormap and then make new data */
    {
      uint8_t *map = prepare_colormap(cur_gfi, opt->needed_colors);
      uint8_t *data = Gif_NewArray(uint8_t, (size_t) cur_gfi->width * (size_t) cur_gfi->height);
      Gif_SetUncompressedImage(cur_gfi, data, Gif_DeleteArrayFunc, 0);

      /* don't use transparency on first frame */
      if ((optimize_flags & GT_OPT_MASK) > 1 && image_index > 0
	  && cur_gfi->transparent >= 0)
	transp_frame_data(gfs, cur_gfi, map, optimize_flags, &gcinfo);
      else
	simple_frame_data(cur_gfi, map);

      if (cur_gfi->img) {
	if (was_compressed || (optimize_flags & GT_OPT_MASK) > 1) {
	  Gif_FullCompressImage(gfs, cur_gfi, &gcinfo);
	  Gif_ReleaseUncompressedImage(cur_gfi);
	} else			/* bug fix 22.May.2001 */
	  Gif_ReleaseCompressedImage(cur_gfi);
      }

      Gif_DeleteArray(map);
    }

    delete_opt_data(opt);
    cur_gfi->user_data = 0;

    /* Set up last_data and this_data. last_data must contain this_data + new
       disposal. this_data must contain this_data + old disposal. */
    if (cur_gfi->disposal == GIF_DISPOSAL_NONE
	|| cur_gfi->disposal == GIF_DISPOSAL_ASIS)
      copy_data_area(last_data, this_data, cur_gfi);
    else if (cur_gfi->disposal == GIF_DISPOSAL_BACKGROUND)
      fill_data_area(last_data, background, cur_gfi);
    else if (cur_gfi->disposal != GIF_DISPOSAL_PREVIOUS)
      assert(0 && "optimized frame has strange disposal");

    if (cur_unopt_gfi.disposal == GIF_DISPOSAL_BACKGROUND)
      fill_data_area(this_data, background, &cur_unopt_gfi);
    else if (cur_unopt_gfi.disposal == GIF_DISPOSAL_PREVIOUS)
      copy_data_area(this_data, previous_data, &cur_unopt_gfi);
  }

  if (previous_data)
      Gif_DeleteArray(previous_data);
}