Doxygen Source Code Documentation
Main Page Alphabetical List Data Structures File List Data Fields Globals Search
gifunopt.c
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifdef HAVE_CONFIG_H
00015 # include "config.h"
00016 #endif
00017 #include "gif.h"
00018 #include <assert.h>
00019 #include <string.h>
00020 #ifdef __cplusplus
00021 extern "C" {
00022 #endif
00023
00024 #define TRANSPARENT 256
00025
00026 static void
00027 put_image_in_screen(Gif_Stream *gfs, Gif_Image *gfi, u_int16_t *screen)
00028 {
00029 int transparent = gfi->transparent;
00030 int x, y;
00031 int w = gfi->width;
00032 int h = gfi->height;
00033 if (gfi->left + w > gfs->screen_width) w = gfs->screen_width - gfi->left;
00034 if (gfi->top + h > gfs->screen_height) h = gfs->screen_height - gfi->top;
00035
00036 for (y = 0; y < h; y++) {
00037 u_int16_t *move = screen + gfs->screen_width * (y + gfi->top) + gfi->left;
00038 byte *line = gfi->img[y];
00039 for (x = 0; x < w; x++, move++, line++)
00040 if (*line != transparent)
00041 *move = *line;
00042 }
00043 }
00044
00045
00046 static void
00047 put_background_in_screen(Gif_Stream *gfs, Gif_Image *gfi, u_int16_t *screen)
00048 {
00049 u_int16_t solid;
00050 int x, y;
00051 int w = gfi->width;
00052 int h = gfi->height;
00053 if (gfi->left + w > gfs->screen_width) w = gfs->screen_width - gfi->left;
00054 if (gfi->top + h > gfs->screen_height) h = gfs->screen_height - gfi->top;
00055
00056 if (gfi->transparent >= 0)
00057 solid = TRANSPARENT;
00058 else if (gfs->images[0]->transparent >= 0)
00059 solid = TRANSPARENT;
00060 else
00061 solid = gfs->background;
00062
00063 for (y = 0; y < h; y++) {
00064 u_int16_t *move = screen + gfs->screen_width * (y + gfi->top) + gfi->left;
00065 for (x = 0; x < w; x++, move++)
00066 *move = solid;
00067 }
00068 }
00069
00070
00071 static int
00072 create_image_data(Gif_Stream *gfs, Gif_Image *gfi, u_int16_t *screen,
00073 byte *new_data)
00074 {
00075 int have[257];
00076 int transparent = -1;
00077 int size = gfs->screen_width * gfs->screen_height;
00078 u_int16_t *move;
00079 int i;
00080
00081
00082 assert(TRANSPARENT == 256);
00083 for (i = 0; i < 257; i++)
00084 have[i] = 0;
00085 for (i = 0, move = screen; i < size; i++, move++)
00086 have[*move] = 1;
00087
00088
00089 if (have[TRANSPARENT]) {
00090 for (i = 0; i < 256 && transparent < 0; i++)
00091 if (!have[i])
00092 transparent = i;
00093 if (transparent < 0)
00094 goto error;
00095 if (transparent >= gfs->global->ncol) {
00096 Gif_ReArray(gfs->global->col, Gif_Color, 256);
00097 if (!gfs->global->col) goto error;
00098 gfs->global->ncol = transparent + 1;
00099 }
00100 }
00101
00102
00103 for (i = 0, move = screen; i < size; i++, move++, new_data++)
00104 if (*move == TRANSPARENT)
00105 *new_data = transparent;
00106 else
00107 *new_data = *move;
00108
00109 gfi->transparent = transparent;
00110 return 1;
00111
00112 error:
00113 return 0;
00114 }
00115
00116
00117 static int
00118 unoptimize_image(Gif_Stream *gfs, Gif_Image *gfi, u_int16_t *screen)
00119 {
00120 int size = gfs->screen_width * gfs->screen_height;
00121 byte *new_data = Gif_NewArray(byte, size);
00122 u_int16_t *new_screen = screen;
00123 if (!new_data) return 0;
00124
00125
00126 Gif_UncompressImage(gfi);
00127 Gif_ReleaseCompressedImage(gfi);
00128
00129 if (gfi->disposal == GIF_DISPOSAL_PREVIOUS) {
00130 new_screen = Gif_NewArray(u_int16_t, size);
00131 if (!new_screen) return 0;
00132 memcpy(new_screen, screen, size * sizeof(u_int16_t));
00133 }
00134
00135 put_image_in_screen(gfs, gfi, new_screen);
00136 if (!create_image_data(gfs, gfi, new_screen, new_data)) {
00137 Gif_DeleteArray(new_data);
00138 return 0;
00139 }
00140
00141 if (gfi->disposal == GIF_DISPOSAL_PREVIOUS)
00142 Gif_DeleteArray(new_screen);
00143 else if (gfi->disposal == GIF_DISPOSAL_BACKGROUND)
00144 put_background_in_screen(gfs, gfi, screen);
00145
00146 gfi->left = 0;
00147 gfi->top = 0;
00148 gfi->width = gfs->screen_width;
00149 gfi->height = gfs->screen_height;
00150 gfi->disposal = GIF_DISPOSAL_BACKGROUND;
00151 Gif_SetUncompressedImage(gfi, new_data, Gif_DeleteArrayFunc, 0);
00152
00153 return 1;
00154 }
00155
00156
00157 int
00158 Gif_Unoptimize(Gif_Stream *gfs)
00159 {
00160 int ok = 1;
00161 int i, size;
00162 u_int16_t *screen;
00163 u_int16_t background;
00164 Gif_Image *gfi;
00165
00166 if (gfs->nimages < 1) return 1;
00167 for (i = 0; i < gfs->nimages; i++)
00168 if (gfs->images[i]->local)
00169 return 0;
00170 if (!gfs->global)
00171 return 0;
00172
00173 Gif_CalculateScreenSize(gfs, 0);
00174 size = gfs->screen_width * gfs->screen_height;
00175
00176 screen = Gif_NewArray(u_int16_t, size);
00177 gfi = gfs->images[0];
00178 background = gfi->transparent >= 0 ? TRANSPARENT : gfs->background;
00179 for (i = 0; i < size; i++)
00180 screen[i] = background;
00181
00182 for (i = 0; i < gfs->nimages; i++)
00183 if (!unoptimize_image(gfs, gfs->images[i], screen))
00184 ok = 0;
00185
00186 Gif_DeleteArray(screen);
00187 return ok;
00188 }
00189
00190
00191 #ifdef __cplusplus
00192 }
00193 #endif