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; }
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); }