Exemple #1
0
static Gif_Colormap *
read_color_table(int size, Gif_Reader *grr)
{
  Gif_Colormap *gfcm = Gif_NewFullColormap(size, size);
  Gif_Color *c;
  if (!gfcm) return 0;

  GIF_DEBUG(("colormap(%d)", size));
  for (c = gfcm->col; size; size--, c++) {
    c->gfc_red = gifgetbyte(grr);
    c->gfc_green = gifgetbyte(grr);
    c->gfc_blue = gifgetbyte(grr);
    c->haspixel = 0;
  }

  return gfcm;
}
Exemple #2
0
static uint8_t *
prepare_colormap(Gif_Image *gfi, uint8_t *need)
{
  uint8_t *map;

  /* try to map pixel values into the global colormap */
  Gif_DeleteColormap(gfi->local);
  gfi->local = 0;
  map = prepare_colormap_map(gfi, out_global_map, need);

  if (!map) {
    /* that didn't work; add a local colormap. */
    gfi->local = Gif_NewFullColormap(0, 256);
    map = prepare_colormap_map(gfi, gfi->local, need);
  }

  return map;
}
Exemple #3
0
int
compare(Gif_Stream *s1, Gif_Stream *s2)
{
  Gif_Colormap *newcm;
  int imageno1, imageno2, background1, background2;
  char buf1[256], buf2[256], fbuf[256];

  was_different = 0;

  /* Compare image counts and screen sizes. If either of these differs, quit
     early. */
  Gif_CalculateScreenSize(s1, 0);
  Gif_CalculateScreenSize(s2, 0);

  if (s1->nimages != s2->nimages
      && (s1->nimages == 0 || s2->nimages == 0)) {
    different("frame counts differ: <#%d >#%d", s1->nimages, s2->nimages);
    return DIFFERENT;
  }

  if (s1->screen_width != s2->screen_width
      || s1->screen_height != s2->screen_height) {
    different("screen sizes differ: <%dx%d >%dx%d", s1->screen_width,
	      s1->screen_height, s2->screen_width, s2->screen_height);
    return DIFFERENT;
  }

  if (s1->screen_width == 0 || s1->screen_height == 0
      || s2->screen_width == 0 || s2->screen_height == 0) {
    /* paranoia -- don't think this can happen */
    different("zero screen sizes");
    return DIFFERENT;
  }

  /* Create arrays for the image data */
  screen_width = s1->screen_width;
  screen_height = s1->screen_height;

  gdata[0] = Gif_NewArray(uint16_t, screen_width * screen_height);
  gdata[1] = Gif_NewArray(uint16_t, screen_width * screen_height);
  glast[0] = Gif_NewArray(uint16_t, screen_width * screen_height);
  glast[1] = Gif_NewArray(uint16_t, screen_width * screen_height);
  scratch = Gif_NewArray(uint16_t, screen_width * screen_height);
  line = Gif_NewArray(uint16_t, screen_width);

  /* Merge all distinct colors from the two images into one colormap, setting
     the 'pixel' slots in the images' colormaps to the corresponding values
     in the merged colormap. Don't forget transparency */
  newcm = Gif_NewFullColormap(1, 256);
  combine_colormaps(s1->global, newcm);
  combine_colormaps(s2->global, newcm);
  for (imageno1 = 0; imageno1 < s1->nimages; ++imageno1)
    combine_colormaps(s1->images[imageno1]->local, newcm);
  for (imageno2 = 0; imageno2 < s2->nimages; ++imageno2)
    combine_colormaps(s2->images[imageno2]->local, newcm);

  /* Choose the background values and clear the image data arrays */
  if (s1->images[0]->transparent >= 0 || !s1->global)
    background1 = TRANSP;
  else
    background1 = s1->global->col[ s1->background ].pixel;

  if (s2->images[0]->transparent >= 0 || !s2->global)
    background2 = TRANSP;
  else
    background2 = s2->global->col[ s2->background ].pixel;

  fill_area(gdata[0], 0, 0, screen_width, screen_height, background1);
  fill_area(gdata[1], 0, 0, screen_width, screen_height, background2);

  /* Loopcounts differ? */
  if (s1->loopcount != s2->loopcount) {
    name_loopcount(s1->loopcount, buf1);
    name_loopcount(s2->loopcount, buf2);
    different("loop counts differ: <%s >%s", buf1, buf2);
  }

  /* Loop over frames, comparing image data and delays */
  apply_image(0, s1, 0, background1);
  apply_image(1, s2, 0, background2);
  imageno1 = imageno2 = 0;
  while (imageno1 != s1->nimages && imageno2 != s2->nimages) {
    int fi1 = imageno1, fi2 = imageno2,
      delay1 = s1->images[fi1]->delay, delay2 = s2->images[fi2]->delay;

    /* get message right */
    if (imageno1 == imageno2)
      sprintf(fbuf, "#%d", imageno1);
    else
      sprintf(fbuf, "<#%d >#%d", imageno1, imageno2);

    /* compare pixels */
    if (memcmp(gdata[0], gdata[1],
	       screen_width * screen_height * sizeof(uint16_t)) != 0) {
      unsigned d, c = screen_width * screen_height;
      uint16_t *d1 = gdata[0], *d2 = gdata[1];
      for (d = 0; d < c; d++, d1++, d2++)
	if (*d1 != *d2) {
	  name_color(*d1, newcm, buf1);
	  name_color(*d2, newcm, buf2);
	  different("frame %s pixels differ: %d,%d <%s >%s",
		    fbuf, d % screen_width, d / screen_width, buf1, buf2);
	  break;
	}
    }

    /* move to next images, skipping redundancy */
    for (++imageno1;
	 imageno1 < s1->nimages && !apply_image(0, s1, imageno1, background1);
	 ++imageno1)
      delay1 += s1->images[imageno1]->delay;
    for (++imageno2;
	 imageno2 < s2->nimages && !apply_image(1, s2, imageno2, background2);
	 ++imageno2)
      delay2 += s2->images[imageno2]->delay;

    if (!ignore_redundancy) {
      fi1 = (imageno1 - fi1) - (imageno2 - fi2);
      for (; fi1 > 0; --fi1)
	different("extra redundant frame: <#%d", imageno1 - fi1);
      for (; fi1 < 0; ++fi1)
	different("extra redundant frame: >#%d", imageno2 + fi1);
    }

    if (delay1 != delay2) {
      name_delay(delay1, buf1);
      name_delay(delay2, buf2);
      different("frame %s delays differ: <%s >%s", fbuf, buf1, buf2);
    }
  }

  if (imageno1 != s1->nimages || imageno2 != s2->nimages)
    different("frame counts differ: <#%d >#%d", s1->nimages, s2->nimages);

  /* That's it! */
  Gif_DeleteColormap(newcm);
  Gif_DeleteArray(gdata[0]);
  Gif_DeleteArray(gdata[1]);
  Gif_DeleteArray(glast[0]);
  Gif_DeleteArray(glast[1]);
  Gif_DeleteArray(scratch);
  Gif_DeleteArray(line);

  return was_different ? DIFFERENT : SAME;
}
Exemple #4
0
static int
initialize_optimizer(Gif_Stream *gfs)
{
  int i;

  if (gfs->nimages < 1)
    return 0;

  /* combine colormaps */
  all_colormap = Gif_NewFullColormap(1, 384);
  all_colormap->col[0].gfc_red = 255;
  all_colormap->col[0].gfc_green = 255;
  all_colormap->col[0].gfc_blue = 255;

  in_global_map = gfs->global;
  if (!in_global_map) {
    Gif_Color *col;
    in_global_map = Gif_NewFullColormap(256, 256);
    col = in_global_map->col;
    for (i = 0; i < 256; i++, col++)
      col->gfc_red = col->gfc_green = col->gfc_blue = i;
  }

  {
    int any_globals = 0;
    int first_transparent = -1;

    kchist_init(&all_colormap_hist);
    for (i = 0; i < gfs->nimages; i++) {
      Gif_Image *gfi = gfs->images[i];
      if (gfi->local)
        all_colormap_add(gfi->local);
      else
        any_globals = 1;
      if (gfi->transparent >= 0 && first_transparent < 0)
        first_transparent = i;
    }
    if (any_globals)
      all_colormap_add(in_global_map);
    kchist_cleanup(&all_colormap_hist);

    /* try and maintain transparency's pixel value */
    if (first_transparent >= 0) {
      Gif_Image *gfi = gfs->images[first_transparent];
      Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global;
      all_colormap->col[TRANSP] = gfcm->col[gfi->transparent];
    }
  }

  /* find screen_width and screen_height, and clip all images to screen */
  Gif_CalculateScreenSize(gfs, 0);
  screen_width = gfs->screen_width;
  screen_height = gfs->screen_height;
  for (i = 0; i < gfs->nimages; i++)
    Gif_ClipImage(gfs->images[i], 0, 0, screen_width, screen_height);

  /* choose background */
  if (gfs->images[0]->transparent < 0
      && gfs->global && gfs->background < in_global_map->ncol)
    background = in_global_map->col[gfs->background].pixel;
  else
    background = TRANSP;

  return 1;
}
static void
create_out_global_map(Gif_Stream *gfs)
{
  int all_ncol = all_colormap->ncol;
  int32_t *penalty = Gif_NewArray(int32_t, all_ncol);
  uint16_t *permute = Gif_NewArray(uint16_t, all_ncol);
  uint16_t *ordering = Gif_NewArray(uint16_t, all_ncol);
  int cur_ncol, i, imagei;
  int nglobal_all = (all_ncol <= 257 ? all_ncol - 1 : 256);
  int permutation_changed;

  /* initial permutation is null */
  for (i = 0; i < all_ncol - 1; i++)
    permute[i] = i + 1;

  /* choose appropriate penalties for each image */
  for (imagei = 0; imagei < gfs->nimages; imagei++) {
    Gif_OptData *opt = (Gif_OptData *)gfs->images[imagei]->user_data;
    opt->global_penalty = opt->colormap_penalty = 1;
    for (i = 2; i < opt->required_color_count; i *= 2)
      opt->colormap_penalty *= 3;
    opt->active_penalty =
      (all_ncol > 257 ? opt->colormap_penalty : opt->global_penalty);
  }

  /* set initial penalties for each color */
  for (i = 1; i < all_ncol; i++)
    penalty[i] = 0;
  for (imagei = 0; imagei < gfs->nimages; imagei++) {
    Gif_OptData *opt = (Gif_OptData *)gfs->images[imagei]->user_data;
    increment_penalties(opt, penalty, opt->active_penalty);
  }
  permutation_changed = 1;

  /* Loop, removing one color at a time. */
  for (cur_ncol = all_ncol - 1; cur_ncol; cur_ncol--) {
    uint16_t removed;

    /* sort permutation based on penalty */
    if (permutation_changed)
      sort_permutation(permute, cur_ncol, penalty, 1);
    permutation_changed = 0;

    /* update reverse permutation */
    removed = permute[cur_ncol - 1];
    ordering[removed] = cur_ncol - 1;

    /* decrement penalties for colors that are out of the running */
    for (imagei = 0; imagei < gfs->nimages; imagei++) {
      Gif_OptData *opt = (Gif_OptData *)gfs->images[imagei]->user_data;
      uint8_t *need = opt->needed_colors;
      if (opt->global_penalty > 0 && need[removed] == REQUIRED) {
	increment_penalties(opt, penalty, -opt->active_penalty);
	opt->global_penalty = 0;
	opt->colormap_penalty = (cur_ncol > 256 ? -1 : 0);
	permutation_changed = 1;
      }
    }

    /* change colormap penalties if we're no longer working w/globalmap */
    if (cur_ncol == 257) {
      for (i = 0; i < all_ncol; i++)
	penalty[i] = 0;
      for (imagei = 0; imagei < gfs->nimages; imagei++) {
	Gif_OptData *opt = (Gif_OptData *)gfs->images[imagei]->user_data;
	opt->active_penalty = opt->global_penalty;
	increment_penalties(opt, penalty, opt->global_penalty);
      }
      permutation_changed = 1;
    }
  }

  /* make sure background is in the global colormap */
  if (background != TRANSP && ordering[background] >= 256) {
    uint16_t other = permute[255];
    ordering[other] = ordering[background];
    ordering[background] = 255;
  }

  /* assign out_global_map based on permutation */
  out_global_map = Gif_NewFullColormap(nglobal_all, 256);

  for (i = 1; i < all_ncol; i++)
    if (ordering[i] < 256) {
      out_global_map->col[ordering[i]] = all_colormap->col[i];
      all_colormap->col[i].pixel = ordering[i];
    } else
      all_colormap->col[i].pixel = NOT_IN_OUT_GLOBAL;

  /* set the stream's background color */
  if (background != TRANSP)
    gfs->background = ordering[background];

  /* cleanup */
  Gif_DeleteArray(penalty);
  Gif_DeleteArray(permute);
  Gif_DeleteArray(ordering);
}
static int
initialize_optimizer(Gif_Stream *gfs)
{
  int i;
  unsigned screen_size;

  if (gfs->nimages < 1)
    return 0;

  /* combine colormaps */
  all_colormap = Gif_NewFullColormap(1, 384);
  all_colormap->col[0].gfc_red = 255;
  all_colormap->col[0].gfc_green = 255;
  all_colormap->col[0].gfc_blue = 255;

  in_global_map = gfs->global;
  if (!in_global_map) {
    Gif_Color *col;
    in_global_map = Gif_NewFullColormap(256, 256);
    col = in_global_map->col;
    for (i = 0; i < 256; i++, col++)
      col->gfc_red = col->gfc_green = col->gfc_blue = i;
  }

  {
    int any_globals = 0;
    int first_transparent = -1;
    for (i = 0; i < gfs->nimages; i++) {
      Gif_Image *gfi = gfs->images[i];
      if (gfi->local)
	colormap_combine(all_colormap, gfi->local);
      else
	any_globals = 1;
      if (gfi->transparent >= 0 && first_transparent < 0)
	first_transparent = i;
    }
    if (any_globals)
      colormap_combine(all_colormap, in_global_map);

    /* try and maintain transparency's pixel value */
    if (first_transparent >= 0) {
      Gif_Image *gfi = gfs->images[first_transparent];
      Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global;
      all_colormap->col[TRANSP] = gfcm->col[gfi->transparent];
    }
  }

  /* find screen_width and screen_height, and clip all images to screen */
  Gif_CalculateScreenSize(gfs, 0);
  screen_width = gfs->screen_width;
  screen_height = gfs->screen_height;
  for (i = 0; i < gfs->nimages; i++)
    Gif_ClipImage(gfs->images[i], 0, 0, screen_width, screen_height);

  /* create data arrays */
  screen_size = (unsigned) screen_width * (unsigned) screen_height;
  last_data = Gif_NewArray(uint16_t, screen_size);
  this_data = Gif_NewArray(uint16_t, screen_size);

  /* set up colormaps */
  gif_color_count = 2;
  while (gif_color_count < gfs->global->ncol && gif_color_count < 256)
    gif_color_count *= 2;

  /* choose background */
  if (gfs->images[0]->transparent < 0
      && gfs->background < in_global_map->ncol)
    background = in_global_map->col[gfs->background].pixel;
  else
    background = TRANSP;

  return 1;
}
Exemple #7
0
Gif_Image *
merge_image(Gif_Stream *dest, Gif_Stream *src, Gif_Image *srci,
            Gt_Frame* srcfr, int same_compressed_ok)
{
  Gif_Colormap *imagecm;
  int i;
  Gif_Colormap *localcm = 0;
  Gif_Colormap *destcm = dest->global;

  uint8_t map[256];             /* map[input pixel value] == output pixval */
  int trivial_map;              /* does the map take input pixval --> the same
                                   pixel value for all colors in the image? */
  uint8_t inused[256];          /* inused[input pival] == 1 iff used */
  uint8_t used[256];            /* used[output pixval K] == 1 iff K was used
                                   in the image */

  Gif_Image *desti;

  /* mark colors that were actually used in this image */
  imagecm = srci->local ? srci->local : src->global;
  merge_image_input_colors(inused, srci);
  for (i = imagecm ? imagecm->ncol : 0; i != 256; ++i)
      if (inused[i]) {
          lwarning(srcfr->input_filename, "some colors undefined by colormap");
          break;
      }

  /* map[old_pixel_value] == new_pixel_value */
  for (i = 0; i < 256; i++)
      map[i] = used[i] = 0;

  /* Merge the colormap */
  if (merge_colormap_if_possible(dest->global, imagecm)) {
      /* Create 'map' and 'used' for global colormap. */
      for (i = 0; i != 256; ++i)
          if (inused[i]) {
              if (imagecm && i < imagecm->ncol)
                  map[i] = imagecm->col[i].pixel;
              else
                  map[i] = 0;
          }

  } else {
      /* Need a local colormap. */
      destcm = localcm = Gif_NewFullColormap(0, 256);
      for (i = 0; i != 256; ++i)
          if (inused[i]) {
              map[i] = localcm->ncol;
              localcm->col[localcm->ncol] = imagecm->col[i];
              ++localcm->ncol;
          }
  }

  trivial_map = 1;
  for (i = 0; i != 256; ++i)
      if (inused[i]) {
          used[map[i]] = 1;
          trivial_map = trivial_map && map[i] == i;
      }

  /* Decide on a transparent index */
  if (srci->transparent >= 0) {
    int found_transparent = -1;

    /* try to keep the map trivial -- prefer same transparent index */
    if (trivial_map && !used[srci->transparent])
      found_transparent = srci->transparent;
    else
      for (i = destcm->ncol - 1; i >= 0; i--)
        if (!used[i])
          found_transparent = i;

    /* 1.Aug.1999 - Allow for the case that the transparent index is bigger
       than the number of colors we've created thus far. */
    if (found_transparent < 0 || found_transparent >= destcm->ncol) {
      Gif_Color *c;
      found_transparent = destcm->ncol;
      /* 1.Aug.1999 - Don't update destcm->ncol -- we want the output colormap
         to be as small as possible. */
      c = &destcm->col[found_transparent];
      if (imagecm && srci->transparent < imagecm->ncol)
        *c = imagecm->col[srci->transparent];
      c->haspixel = 2;
      assert(c->haspixel == 2 && found_transparent < 256);
    }

    map[srci->transparent] = found_transparent;
    if (srci->transparent != found_transparent) trivial_map = 0;
  }

  assert(destcm->ncol <= 256);
  /* Make the new image. */
  desti = Gif_NewImage();

  desti->identifier = Gif_CopyString(srci->identifier);
  if (srci->transparent > -1)
    desti->transparent = map[srci->transparent];
  desti->delay = srci->delay;
  desti->disposal = srci->disposal;
  desti->left = srci->left;
  desti->top = srci->top;
  desti->interlace = srci->interlace;

  desti->width = srci->width;
  desti->height = srci->height;
  desti->local = localcm;

  if (trivial_map && same_compressed_ok && srci->compressed) {
    desti->compressed_len = srci->compressed_len;
    desti->compressed = Gif_NewArray(uint8_t, srci->compressed_len);
    desti->free_compressed = Gif_Free;
    memcpy(desti->compressed, srci->compressed, srci->compressed_len);
  } else {
    int i, j;
    Gif_CreateUncompressedImage(desti, desti->interlace);

    if (trivial_map)
      for (j = 0; j < desti->height; j++)
        memcpy(desti->img[j], srci->img[j], desti->width);

    else
      for (j = 0; j < desti->height; j++) {
        uint8_t *srcdata = srci->img[j];
        uint8_t *destdata = desti->img[j];
        for (i = 0; i < desti->width; i++, srcdata++, destdata++)
          *destdata = map[*srcdata];
      }
  }

  /* comments and extensions */
  if (srci->comment) {
    desti->comment = Gif_NewComment();
    merge_comments(desti->comment, srci->comment);
  }
  if (srci->extension_list && !srcfr->no_extensions) {
      Gif_Extension* gfex;
      for (gfex = srci->extension_list; gfex; gfex = gfex->next)
          if (gfex->kind != 255 || !srcfr->no_app_extensions)
              Gif_AddExtension(dest, desti, Gif_CopyExtension(gfex));
  }
  while (srcfr->extensions) {
      Gif_Extension* next = srcfr->extensions->next;
      Gif_AddExtension(dest, desti, srcfr->extensions);
      srcfr->extensions = next;
  }

  Gif_AddImage(dest, desti);
  return desti;
}