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