/* gifunopt.c - Unoptimization function for the GIF library. Copyright (C) 1997-9 Eddie Kohler, eddietwo@lcs.mit.edu This file is part of the GIF library. The GIF library is free software*. It is distributed under the GNU General Public License, version 2 or later; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. *The LZW compression method used by GIFs is patented. Unisys, the patent holder, allows the compression algorithm to be used without a license in software distributed at no cost to the user. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "gif.h" #include #include #ifdef __cplusplus extern "C" { #endif #define TRANSPARENT 256 static void put_image_in_screen(Gif_Stream *gfs, Gif_Image *gfi, u_int16_t *screen) { int transparent = gfi->transparent; int x, y; int w = gfi->width; int h = gfi->height; if (gfi->left + w > gfs->screen_width) w = gfs->screen_width - gfi->left; if (gfi->top + h > gfs->screen_height) h = gfs->screen_height - gfi->top; for (y = 0; y < h; y++) { u_int16_t *move = screen + gfs->screen_width * (y + gfi->top) + gfi->left; byte *line = gfi->img[y]; for (x = 0; x < w; x++, move++, line++) if (*line != transparent) *move = *line; } } static void put_background_in_screen(Gif_Stream *gfs, Gif_Image *gfi, u_int16_t *screen) { u_int16_t solid; int x, y; int w = gfi->width; int h = gfi->height; if (gfi->left + w > gfs->screen_width) w = gfs->screen_width - gfi->left; if (gfi->top + h > gfs->screen_height) h = gfs->screen_height - gfi->top; if (gfi->transparent >= 0) solid = TRANSPARENT; else if (gfs->images[0]->transparent >= 0) solid = TRANSPARENT; else solid = gfs->background; for (y = 0; y < h; y++) { u_int16_t *move = screen + gfs->screen_width * (y + gfi->top) + gfi->left; for (x = 0; x < w; x++, move++) *move = solid; } } static int create_image_data(Gif_Stream *gfs, Gif_Image *gfi, u_int16_t *screen, byte *new_data) { int have[257]; int transparent = -1; int size = gfs->screen_width * gfs->screen_height; u_int16_t *move; int i; /* mark colors used opaquely in the image */ assert(TRANSPARENT == 256); for (i = 0; i < 257; i++) have[i] = 0; for (i = 0, move = screen; i < size; i++, move++) have[*move] = 1; /* the new transparent color is a color unused in either */ if (have[TRANSPARENT]) { for (i = 0; i < 256 && transparent < 0; i++) if (!have[i]) transparent = i; if (transparent < 0) goto error; if (transparent >= gfs->global->ncol) { Gif_ReArray(gfs->global->col, Gif_Color, 256); if (!gfs->global->col) goto error; gfs->global->ncol = transparent + 1; } } /* map the wide image onto the new data */ for (i = 0, move = screen; i < size; i++, move++, new_data++) if (*move == TRANSPARENT) *new_data = transparent; else *new_data = *move; gfi->transparent = transparent; return 1; error: return 0; } static int unoptimize_image(Gif_Stream *gfs, Gif_Image *gfi, u_int16_t *screen) { int size = gfs->screen_width * gfs->screen_height; byte *new_data = Gif_NewArray(byte, size); u_int16_t *new_screen = screen; if (!new_data) return 0; /* Oops! May need to uncompress it */ Gif_UncompressImage(gfi); Gif_ReleaseCompressedImage(gfi); if (gfi->disposal == GIF_DISPOSAL_PREVIOUS) { new_screen = Gif_NewArray(u_int16_t, size); if (!new_screen) return 0; memcpy(new_screen, screen, size * sizeof(u_int16_t)); } put_image_in_screen(gfs, gfi, new_screen); if (!create_image_data(gfs, gfi, new_screen, new_data)) { 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 = GIF_DISPOSAL_BACKGROUND; Gif_SetUncompressedImage(gfi, new_data, Gif_DeleteArrayFunc, 0); return 1; } int Gif_Unoptimize(Gif_Stream *gfs) { int ok = 1; int i, size; u_int16_t *screen; u_int16_t background; Gif_Image *gfi; if (gfs->nimages < 1) return 1; for (i = 0; i < gfs->nimages; i++) if (gfs->images[i]->local) return 0; if (!gfs->global) return 0; Gif_CalculateScreenSize(gfs, 0); size = gfs->screen_width * gfs->screen_height; screen = Gif_NewArray(u_int16_t, size); gfi = gfs->images[0]; background = gfi->transparent >= 0 ? TRANSPARENT : gfs->background; for (i = 0; i < size; i++) screen[i] = background; for (i = 0; i < gfs->nimages; i++) if (!unoptimize_image(gfs, gfs->images[i], screen)) ok = 0; Gif_DeleteArray(screen); return ok; } #ifdef __cplusplus } #endif