/* 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 <assert.h>
#include <string.h>
#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
syntax highlighted by Code2HTML, v. 0.9.1