Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

gifsicle.h File Reference

#include "gif.h"
#include "clp.h"

Go to the source code of this file.


Data Structures

struct  Gt_ColorTransform
struct  Gt_Crop
struct  Gt_Frame
struct  Gt_Frameset
struct  Gt_OutputData

Defines

#define NORETURN
#define EXIT_OK   0
#define EXIT_ERR   1
#define EXIT_USER_ERR   1
#define COLORMAP_ENSURE_SLOT_255   1
#define COLORMAP_DIVERSITY   0
#define COLORMAP_BLEND_DIVERSITY   1
#define COLORMAP_MEDIAN_CUT   2
#define FRAME(fs, i)   ((fs)->f[i])

Typedefs

typedef Gt_Frameset Gt_Frameset
typedef Gt_Crop Gt_Crop
typedef Gt_ColorTransform Gt_ColorTransform
typedef Gt_Frame Gt_Frame
typedef void(* colormap_transform_func )(Gif_Colormap *, void *)
typedef void(* color_transform_func )(Gif_Colormap *, void *)
typedef color_hash_item color_hash_item
typedef void(* colormap_image_func )(Gif_Image *, byte *, Gif_Colormap *, Gif_Colormap *, color_hash_item **, u_int32_t *)

Functions

void fatal_error (char *message,...) NORETURN
void warning (char *message,...)
void warncontext (char *message,...)
void error (char *message,...)
void clp_error_handler (char *clp_message)
void usage (void)
void short_usage (void)
void verbose_open (char, const char *)
void verbose_close (char)
void verbose_endline (void)
void stream_info (FILE *, Gif_Stream *, const char *, int colormaps, int extensions)
void image_info (FILE *, Gif_Stream *, Gif_Image *, int colormaps)
char * explode_filename (char *filename, int number, char *name, int max_nimg)
void unmark_colors (Gif_Colormap *)
void unmark_colors_2 (Gif_Colormap *)
int find_color_index (Gif_Color *c, int nc, Gif_Color *)
int merge_colormap_if_possible (Gif_Colormap *, Gif_Colormap *)
void merge_stream (Gif_Stream *dest, Gif_Stream *src, int no_comments)
void merge_comments (Gif_Comment *destc, Gif_Comment *srcc)
Gif_Imagemerge_image (Gif_Stream *dest, Gif_Stream *src, Gif_Image *srci)
void optimize_fragments (Gif_Stream *, int optimizeness)
Gif_Colormapread_colormap_file (char *, FILE *)
void apply_color_transforms (Gt_ColorTransform *, Gif_Stream *)
Gt_ColorTransformappend_color_transform (Gt_ColorTransform *list, color_transform_func, void *)
Gt_ColorTransformdelete_color_transforms (Gt_ColorTransform *list, color_transform_func)
void color_change_transformer (Gif_Colormap *, void *)
Gt_ColorTransformappend_color_change (Gt_ColorTransform *list, Gif_Color, Gif_Color)
void pipe_color_transformer (Gif_Colormap *, void *)
int crop_image (Gif_Image *, Gt_Crop *)
void flip_image (Gif_Image *, int scr_width, int scr_height, int is_vert)
void rotate_image (Gif_Image *, int scr_width, int scr_height, int rotation)
void scale_image (Gif_Stream *, Gif_Image *, double xfactor, double yfactor)
void resize_stream (Gif_Stream *, int new_width, int new_height)
Gif_Colorhistogram (Gif_Stream *, int *)
Gif_Colormapcolormap_blend_diversity (Gif_Color *, int, int)
Gif_Colormapcolormap_flat_diversity (Gif_Color *, int, int)
Gif_Colormapcolormap_median_cut (Gif_Color *, int, int)
void colormap_image_posterize (Gif_Image *, byte *, Gif_Colormap *, Gif_Colormap *, color_hash_item **, u_int32_t *)
void colormap_image_floyd_steinberg (Gif_Image *, byte *, Gif_Colormap *, Gif_Colormap *, color_hash_item **, u_int32_t *)
void colormap_stream (Gif_Stream *, Gif_Colormap *, colormap_image_func)
int parse_frame_spec (Clp_Parser *, const char *, int, void *)
int parse_dimensions (Clp_Parser *, const char *, int, void *)
int parse_position (Clp_Parser *, const char *, int, void *)
int parse_scale_factor (Clp_Parser *, const char *, int, void *)
int parse_color (Clp_Parser *, const char *, int, void *)
int parse_rectangle (Clp_Parser *, const char *, int, void *)
int parse_two_colors (Clp_Parser *, const char *, int, void *)
void input_stream (char *)
void input_done (void)
void output_frames (void)
Gt_Framesetnew_frameset (int initial_cap)
Gt_Frameadd_frame (Gt_Frameset *, int num, Gif_Stream *, Gif_Image *)
void clear_def_frame_once_options (void)
Gif_Streammerge_frame_interval (Gt_Frameset *, int f1, int f2, Gt_OutputData *, int compress)
void clear_frameset (Gt_Frameset *, int from)
void blank_frameset (Gt_Frameset *, int from, int to, int delete_ob)

Variables

const char * program_name
int verbosing
int error_count
int no_warnings
int gif_read_flags
int gif_write_flags
int warn_local_colormaps
int frame_spec_1
int frame_spec_2
char * frame_spec_name
int dimensions_x
int dimensions_y
int position_x
int position_y
Gif_Color parsed_color
Gif_Color parsed_color2
double parsed_scale_factor_x
double parsed_scale_factor_y
Gif_Streaminput
char * input_name
Gt_Frame def_frame

Define Documentation

#define COLORMAP_BLEND_DIVERSITY   1
 

Definition at line 202 of file gifsicle.h.

Referenced by do_colormap_change(), and main().

#define COLORMAP_DIVERSITY   0
 

Definition at line 201 of file gifsicle.h.

Referenced by do_colormap_change(), initialize_def_frame(), and main().

#define COLORMAP_ENSURE_SLOT_255   1
 

Definition at line 158 of file gifsicle.h.

Referenced by find_background(), and merge_colormap_if_possible().

#define COLORMAP_MEDIAN_CUT   2
 

Definition at line 203 of file gifsicle.h.

Referenced by do_colormap_change(), and main().

#define EXIT_ERR   1
 

Definition at line 143 of file gifsicle.h.

Referenced by main().

#define EXIT_OK   0
 

Definition at line 142 of file gifsicle.h.

Referenced by main().

#define EXIT_USER_ERR   1
 

Definition at line 144 of file gifsicle.h.

Referenced by fatal_error(), and main().

#define FRAME fs,
i       ((fs)->f[i])
 

Definition at line 255 of file gifsicle.h.

Referenced by blank_frameset(), merger_flatten(), output_frames(), output_information(), set_frame_change(), and show_frame().

#define NORETURN
 

Definition at line 15 of file gifsicle.h.


Typedef Documentation

typedef struct color_hash_item color_hash_item
 

Definition at line 208 of file gifsicle.h.

typedef void(* color_transform_func)(Gif_Colormap *, void *)
 

Definition at line 177 of file gifsicle.h.

Referenced by append_color_transform(), and delete_color_transforms().

typedef void(* colormap_image_func)(Gif_Image *, byte *, Gif_Colormap *, Gif_Colormap *, color_hash_item **, u_int32_t *)
 

Definition at line 210 of file gifsicle.h.

Referenced by colormap_stream(), and do_set_colormap().

typedef void(* colormap_transform_func)(Gif_Colormap *, void *)
 

Definition at line 84 of file gifsicle.h.

typedef struct Gt_ColorTransform Gt_ColorTransform
 

Definition at line 20 of file gifsicle.h.

typedef struct Gt_Crop Gt_Crop
 

Definition at line 19 of file gifsicle.h.

typedef struct Gt_Frame Gt_Frame
 

typedef struct Gt_Frameset Gt_Frameset
 

Definition at line 18 of file gifsicle.h.


Function Documentation

Gt_Frame* add_frame Gt_Frameset  ,
int    num,
Gif_Stream  ,
Gif_Image  
 

Definition at line 929 of file support.c.

References blank_frameset(), Gt_Frameset::cap, clear_def_frame_once_options(), Gt_Frameset::count, Gt_Frameset::f, Gif_ReArray, Gt_Frame::image, Gif_Stream::refcount, Gif_Image::refcount, and Gt_Frame::stream.

Referenced by input_stream(), and show_frame().

00930 {
00931   if (number < 0) {
00932     while (fset->count >= fset->cap) {
00933       fset->cap *= 2;
00934       Gif_ReArray(fset->f, Gt_Frame, fset->cap);
00935     }
00936     number = fset->count++;
00937   } else {
00938     assert(number < fset->count);
00939     blank_frameset(fset, number, number, 0);
00940   }
00941 
00942   /* Mark the stream and the image both */
00943   gfs->refcount++;
00944   gfi->refcount++;
00945   fset->f[number] = def_frame;
00946   fset->f[number].stream = gfs;
00947   fset->f[number].image = gfi;
00948   
00949   clear_def_frame_once_options();
00950   
00951   return &fset->f[number];
00952 }

Gt_ColorTransform* append_color_change Gt_ColorTransform   list,
Gif_Color   ,
Gif_Color   
 

Definition at line 104 of file xform.c.

References append_color_transform(), color_change_transformer(), Gt_ColorTransform::data, Gt_ColorTransform::func, Gif_New, Gt_ColorChange::new_color, Gt_ColorChange::next, Gt_ColorTransform::next, and Gt_ColorChange::old_color.

00106 {
00107   Gt_ColorTransform *xform;
00108   Gt_ColorChange *change = Gif_New(Gt_ColorChange);
00109   change->old_color = old_color;
00110   change->new_color = new_color;
00111   change->next = 0;
00112   
00113   for (xform = list; xform && xform->next; xform = xform->next)
00114     ;
00115   if (!xform || xform->func != &color_change_transformer)
00116     return append_color_transform(list, &color_change_transformer, change);
00117   else {
00118     Gt_ColorChange *prev = (Gt_ColorChange *)(xform->data);
00119     while (prev->next) prev = prev->next;
00120     prev->next = change;
00121     return list;
00122   }
00123 }

Gt_ColorTransform* append_color_transform Gt_ColorTransform   list,
color_transform_func   ,
void *   
 

Definition at line 25 of file xform.c.

References color_transform_func, Gt_ColorTransform::data, Gt_ColorTransform::func, Gif_New, and Gt_ColorTransform::next.

Referenced by append_color_change().

00027 {
00028   Gt_ColorTransform *trav;
00029   Gt_ColorTransform *xform = Gif_New(Gt_ColorTransform);
00030   xform->next = 0;
00031   xform->func = func;
00032   xform->data = data;
00033   
00034   for (trav = list; trav && trav->next; trav = trav->next)
00035     ;
00036   if (trav) {
00037     trav->next = xform;
00038     return list;
00039   } else
00040     return xform;
00041 }

void apply_color_transforms Gt_ColorTransform  ,
Gif_Stream  
 

Definition at line 61 of file xform.c.

References Gt_ColorTransform::data, Gt_ColorTransform::func, Gif_Stream::global, i, Gif_Stream::images, Gt_ColorTransform::next, and Gif_Stream::nimages.

Referenced by input_stream(), and merge_and_write_frames().

00062 {
00063   int i;
00064   Gt_ColorTransform *xform;
00065   for (xform = list; xform; xform = xform->next) {
00066     if (gfs->global)
00067       xform->func(gfs->global, xform->data);
00068     for (i = 0; i < gfs->nimages; i++)
00069       if (gfs->images[i]->local)
00070         xform->func(gfs->images[i]->local, xform->data);
00071   }
00072 }

void blank_frameset Gt_Frameset   fset,
int    f1,
int    f2,
int    delete_object
 

END MERGE LOOP *

Definition at line 1405 of file support.c.

References Gt_Frameset::count, Gt_Frameset::f, FRAME, Gif_Delete, Gif_DeleteArray, Gif_DeleteComment(), Gif_DeleteStream(), and i.

Referenced by add_frame(), clear_frameset(), and main().

01406 {
01407   int i;
01408   if (delete_object) f1 = 0, f2 = -1;
01409   if (f2 < 0) f2 = fset->count - 1;
01410   for (i = f1; i <= f2; i++) {
01411     /* We may have deleted stream and image earlier to save on memory; see
01412        above in merge_frame_interval(); but if we didn't, do it now. */
01413     if (FRAME(fset, i).image && FRAME(fset, i).image->refcount > 1)
01414       FRAME(fset, i).image->refcount--;
01415     Gif_DeleteStream(FRAME(fset, i).stream);
01416     Gif_DeleteComment(FRAME(fset, i).comment);
01417     if (FRAME(fset, i).nest)
01418       blank_frameset(FRAME(fset, i).nest, 0, 0, 1);
01419   }
01420   if (delete_object) {
01421     Gif_DeleteArray(fset->f);
01422     Gif_Delete(fset);
01423   }
01424 }

void clear_def_frame_once_options void   
 

Definition at line 906 of file support.c.

Referenced by add_frame().

00907 {
00908   /* Get rid of next-frame-only options.
00909      
00910      This causes problems with frame selection. In the command `gifsicle
00911      -nblah f.gif', the name should be applied to frame 0 of f.gif. This will
00912      happen automatically when f.gif is read, since all of its frames will be
00913      added when it is input. After frame 0, the name in def_frame will be
00914      cleared.
00915      
00916      Now, `gifsicle -nblah f.gif #1' should apply the name to frame 1 of
00917      f.gif. But once f.gif is input, its frames are added, and the name
00918      component of def_frame is cleared!! So when #1 comes around it's gone!
00919      
00920      We handle this in gifsicle.c using the _change fields. */
00921   
00922   def_frame.name = 0;
00923   def_frame.comment = 0;
00924   def_frame.extensions = 0;
00925 }

void clear_frameset Gt_Frameset  ,
int    from
 

Definition at line 1428 of file support.c.

References blank_frameset(), and Gt_Frameset::count.

Referenced by output_frames(), and show_frame().

01429 {
01430   blank_frameset(fset, f1, -1, 0);
01431   fset->count = f1;
01432 }

void clp_error_handler char *    clp_message
 

Definition at line 95 of file support.c.

References verbose_endline().

00096 {
00097   verbose_endline();
00098   fputs(message, stderr);
00099 }

void color_change_transformer Gif_Colormap  ,
void *   
 

Definition at line 82 of file xform.c.

References Gif_Colormap::col, GIF_COLOREQ, Gif_Color::haspixel, i, Gif_Colormap::ncol, Gt_ColorChange::new_color, Gt_ColorChange::next, Gt_ColorChange::old_color, and Gif_Color::pixel.

Referenced by append_color_change().

00083 {
00084   int i, have;
00085   Gt_ColorChange *first_change = (Gt_ColorChange *)thunk;
00086   Gt_ColorChange *change;
00087   
00088   /* change colors named by color */
00089   for (i = 0; i < gfcm->ncol; i++)
00090     for (change = first_change; change; change = change->next) {
00091       if (!change->old_color.haspixel)
00092         have = GIF_COLOREQ(&gfcm->col[i], &change->old_color);
00093       else
00094         have = change->old_color.pixel == i;
00095       
00096       if (have) {
00097         gfcm->col[i] = change->new_color;
00098         break;                  /* ignore remaining color changes */
00099       }
00100     }
00101 }

Gif_Colormap* colormap_blend_diversity Gif_Color  ,
int   ,
int   
 

Definition at line 517 of file quantize.c.

References colormap_diversity().

00518 {
00519   return colormap_diversity(hist, nhist, adapt_size, 1);
00520 }

Gif_Colormap* colormap_flat_diversity Gif_Color  ,
int   ,
int   
 

Definition at line 523 of file quantize.c.

References colormap_diversity().

00524 {
00525   return colormap_diversity(hist, nhist, adapt_size, 0);
00526 }

void colormap_image_floyd_steinberg Gif_Image  ,
byte  ,
Gif_Colormap  ,
Gif_Colormap  ,
color_hash_item **   ,
u_int32_t  
 

Definition at line 712 of file quantize.c.

References Gif_Color::blue, Gif_Colormap::col, DITHER_SCALE, DITHER_SCALE_M1, Gif_DeleteArray, Gif_NewArray, Gif_Color::green, hash_color(), Gif_Image::height, i, Gif_Image::img, Gif_Image::left, max, min, N_RANDOM_VALUES, RANDOM, Gif_Color::red, Gif_Image::transparent, u_int32_t, and Gif_Image::width.

00715 {
00716   static int32_t *random_values = 0;
00717   
00718   int width = gfi->width;
00719   int dither_direction = 0;
00720   int transparent = gfi->transparent;
00721   int i, j;
00722   int32_t *r_err, *g_err, *b_err, *r_err1, *g_err1, *b_err1;
00723   Gif_Color *col = old_cm->col;
00724   Gif_Color *new_col = new_cm->col;
00725   
00726   /* This code was written with reference to ppmquant by Jef Poskanzer, part
00727      of the pbmplus package. */
00728   
00729   /* Initialize Floyd-Steinberg error vectors to small random values, so we
00730      don't get artifacts on the top row */
00731   r_err = Gif_NewArray(int32_t, width + 2);
00732   g_err = Gif_NewArray(int32_t, width + 2);
00733   b_err = Gif_NewArray(int32_t, width + 2);
00734   r_err1 = Gif_NewArray(int32_t, width + 2);
00735   g_err1 = Gif_NewArray(int32_t, width + 2);
00736   b_err1 = Gif_NewArray(int32_t, width + 2);
00737   /* Use the same random values on each call in an attempt to minimize
00738      "jumping dithering" effects on animations */
00739   if (!random_values) {
00740     random_values = Gif_NewArray(int32_t, N_RANDOM_VALUES);
00741     for (i = 0; i < N_RANDOM_VALUES; i++)
00742       random_values[i] = RANDOM() % (DITHER_SCALE_M1 * 2) - DITHER_SCALE_M1;
00743   }
00744   for (i = 0; i < gfi->width + 2; i++) {
00745     int j = (i + gfi->left) * 3;
00746     r_err[i] = random_values[ (j + 0) % N_RANDOM_VALUES ];
00747     g_err[i] = random_values[ (j + 1) % N_RANDOM_VALUES ];
00748     b_err[i] = random_values[ (j + 2) % N_RANDOM_VALUES ];
00749   }
00750   /* *_err1 initialized below */
00751   
00752   /* Do the image! */
00753   for (j = 0; j < gfi->height; j++) {
00754     int d0, d1, d2, d3;         /* used for error diffusion */
00755     byte *data, *new_data;
00756     int x;
00757     
00758     if (dither_direction) {
00759       x = width - 1;
00760       d0 = 0, d1 = 2, d2 = 1, d3 = 0;
00761     } else {
00762       x = 0;
00763       d0 = 2, d1 = 0, d2 = 1, d3 = 2;
00764     }
00765     data = &gfi->img[j][x];
00766     new_data = all_new_data + j * width + x;
00767     
00768     for (i = 0; i < width + 2; i++)
00769       r_err1[i] = g_err1[i] = b_err1[i] = 0;
00770     
00771     /* Do a single row */
00772     while (x >= 0 && x < width) {
00773       int e, use_r, use_g, use_b;
00774       
00775       /* the transparent color never gets adjusted */
00776       if (*data == transparent)
00777         goto next;
00778       
00779       /* use Floyd-Steinberg errors to adjust actual color */
00780       use_r = col[*data].red + r_err[x+1] / DITHER_SCALE;
00781       use_g = col[*data].green + g_err[x+1] / DITHER_SCALE;
00782       use_b = col[*data].blue + b_err[x+1] / DITHER_SCALE;
00783       use_r = max(use_r, 0);  use_r = min(use_r, 255);
00784       use_g = max(use_g, 0);  use_g = min(use_g, 255);
00785       use_b = max(use_b, 0);  use_b = min(use_b, 255);
00786       
00787       *new_data = hash_color(use_r, use_g, use_b, hash, new_cm);
00788       histogram[*new_data]++;
00789       
00790       /* calculate and propagate the error between desired and selected color.
00791          Assume that, with a large scale (1024), we don't need to worry about
00792          image artifacts caused by error accumulation (the fact that the
00793          error terms might not sum to the error). */
00794       e = (use_r - new_col[*new_data].red) * DITHER_SCALE;
00795       if (e) {
00796         r_err [x+d0] += (e * 7) / 16;
00797         r_err1[x+d1] += (e * 3) / 16;
00798         r_err1[x+d2] += (e * 5) / 16;
00799         r_err1[x+d3] += e / 16;
00800       }
00801       
00802       e = (use_g - new_col[*new_data].green) * DITHER_SCALE;
00803       if (e) {
00804         g_err [x+d0] += (e * 7) / 16;
00805         g_err1[x+d1] += (e * 3) / 16;
00806         g_err1[x+d2] += (e * 5) / 16;
00807         g_err1[x+d3] += e / 16;
00808       }
00809       
00810       e = (use_b - new_col[*new_data].blue) * DITHER_SCALE;
00811       if (e) {
00812         b_err [x+d0] += (e * 7) / 16;
00813         b_err1[x+d1] += (e * 3) / 16;
00814         b_err1[x+d2] += (e * 5) / 16;
00815         b_err1[x+d3] += e / 16;
00816       }
00817       
00818      next:
00819       if (dither_direction)
00820         x--, data--, new_data--;
00821       else
00822         x++, data++, new_data++;
00823     }
00824     /* Did a single row */
00825     
00826     /* change dithering directions */
00827     {
00828       int32_t *temp;
00829       temp = r_err; r_err = r_err1; r_err1 = temp;
00830       temp = g_err; g_err = g_err1; g_err1 = temp;
00831       temp = b_err; b_err = b_err1; b_err1 = temp;
00832       dither_direction = !dither_direction;
00833     }
00834   }
00835   
00836   /* delete temporary storage */
00837   Gif_DeleteArray(r_err);
00838   Gif_DeleteArray(g_err);
00839   Gif_DeleteArray(b_err);
00840   Gif_DeleteArray(r_err1);
00841   Gif_DeleteArray(g_err1);
00842   Gif_DeleteArray(b_err1);
00843 }

void colormap_image_posterize Gif_Image  ,
byte  ,
Gif_Colormap  ,
Gif_Colormap  ,
color_hash_item **   ,
u_int32_t  
 

Definition at line 675 of file quantize.c.

References Gif_Colormap::col, hash_color(), Gif_Image::height, i, Gif_Image::img, ncol, Gif_Colormap::ncol, Gif_Image::transparent, u_int32_t, and Gif_Image::width.

00678 {
00679   int ncol = old_cm->ncol;
00680   Gif_Color *col = old_cm->col;
00681   int map[256];
00682   int i, j;
00683   int transparent = gfi->transparent;
00684   
00685   /* find closest colors in new colormap */
00686   for (i = 0; i < ncol; i++)
00687     if (col[i].haspixel)
00688       map[i] = col[i].pixel;
00689     else {
00690       map[i] = col[i].pixel =
00691         hash_color(col[i].red, col[i].green, col[i].blue, hash, new_cm);
00692       col[i].haspixel = 1;
00693     }
00694   
00695   /* map image */
00696   for (j = 0; j < gfi->height; j++) {
00697     byte *data = gfi->img[j];
00698     for (i = 0; i < gfi->width; i++, data++, new_data++)
00699       if (*data != transparent) {
00700         *new_data = map[*data];
00701         histogram[*new_data]++;
00702       }
00703   }
00704 }

Gif_Colormap* colormap_median_cut Gif_Color  ,
int   ,
int   
 

Definition at line 236 of file quantize.c.

References assert_hist_transparency(), Gif_Color::blue, blue_sort_compare(), Gif_Colormap::col, adaptive_slot::count, fatal_error(), adaptive_slot::first, Gif_DeleteArray, Gif_NewArray, Gif_NewFullColormap(), Gif_Color::green, green_sort_compare(), Gif_Color::haspixel, i, max, min, Gif_Colormap::ncol, adaptive_slot::pixel, Gif_Color::pixel, pixel_sort_compare(), Gif_Color::red, red_sort_compare(), u_int32_t, and warning().

00237 {
00238   adaptive_slot *slots = Gif_NewArray(adaptive_slot, adapt_size);
00239   Gif_Colormap *gfcm = Gif_NewFullColormap(adapt_size, 256);
00240   Gif_Color *adapt = gfcm->col;
00241   int nadapt;
00242   int i, j;
00243   
00244   /* This code was written with reference to ppmquant by Jef Poskanzer, part
00245      of the pbmplus package. */
00246   
00247   if (adapt_size < 2 || adapt_size > 256)
00248     fatal_error("adaptive palette size must be between 2 and 256");
00249   if (adapt_size >= nhist) {
00250     warning("trivial adaptive palette (only %d colors in source)", nhist);
00251     adapt_size = nhist;
00252   }
00253   
00254   /* 0. remove any transparent color from consideration; reduce adaptive
00255      palette size to accommodate transparency if it looks like that'll be
00256      necessary */
00257   assert_hist_transparency(hist, nhist);
00258   if (adapt_size > 2 && adapt_size < nhist && hist[0].haspixel == 255
00259       && nhist <= 265)
00260     adapt_size--;
00261   if (hist[0].haspixel == 255) {
00262     hist[0] = hist[nhist - 1];
00263     nhist--;
00264   }
00265   
00266   /* 1. set up the first slot, containing all pixels. */
00267   {
00268     u_int32_t total = 0;
00269     for (i = 0; i < nhist; i++)
00270       total += hist[i].pixel;
00271     slots[0].first = 0;
00272     slots[0].count = nhist;
00273     slots[0].pixel = total;
00274     qsort(hist, nhist, sizeof(Gif_Color), pixel_sort_compare);
00275   }
00276   
00277   /* 2. split slots until we have enough. */
00278   for (nadapt = 1; nadapt < adapt_size; nadapt++) {
00279     adaptive_slot *split = 0;
00280     Gif_Color minc, maxc, *slice;
00281     
00282     /* 2.1. pick the slot to split. */
00283     {
00284       u_int32_t split_pixel = 0;
00285       for (i = 0; i < nadapt; i++)
00286         if (slots[i].count >= 2 && slots[i].pixel > split_pixel) {
00287           split = &slots[i];
00288           split_pixel = slots[i].pixel;
00289         }
00290       if (!split)
00291         break;
00292     }
00293     slice = &hist[split->first];
00294     
00295     /* 2.2. find its extent. */
00296     {
00297       Gif_Color *trav = slice;
00298       minc = maxc = *trav;
00299       for (i = 1, trav++; i < split->count; i++, trav++) {
00300         minc.red = min(minc.red, trav->red);
00301         maxc.red = max(maxc.red, trav->red);
00302         minc.green = min(minc.green, trav->green);
00303         maxc.green = max(maxc.green, trav->green);
00304         minc.blue = min(minc.blue, trav->blue);
00305         maxc.blue = max(maxc.blue, trav->blue);
00306       }
00307     }
00308     
00309     /* 2.3. decide how to split it. use the luminance method. also sort the
00310        colors. */
00311     {
00312       double red_diff = 0.299 * (maxc.red - minc.red);
00313       double green_diff = 0.587 * (maxc.green - minc.green);
00314       double blue_diff = 0.114 * (maxc.blue - minc.blue);
00315       if (red_diff >= green_diff && red_diff >= blue_diff)
00316         qsort(slice, split->count, sizeof(Gif_Color), red_sort_compare);
00317       else if (green_diff >= blue_diff)
00318         qsort(slice, split->count, sizeof(Gif_Color), green_sort_compare);
00319       else
00320         qsort(slice, split->count, sizeof(Gif_Color), blue_sort_compare);
00321     }
00322     
00323     /* 2.4. decide where to split the slot and split it there. */
00324     {
00325       u_int32_t half_pixels = split->pixel / 2;
00326       u_int32_t pixel_accum = slice[0].pixel;
00327       u_int32_t diff1, diff2;
00328       for (i = 1; i < split->count - 1 && pixel_accum < half_pixels; i++)
00329         pixel_accum += slice[i].pixel;
00330 
00331       /* We know the area before the split has more pixels than the area
00332          after, possibly by a large margin (bad news). If it would shrink the
00333          margin, change the split. */
00334       diff1 = 2*pixel_accum - split->pixel;
00335       diff2 = split->pixel - 2*(pixel_accum - slice[i-1].pixel);
00336       if (diff2 < diff1 && i > 1) {
00337         i--;
00338         pixel_accum -= slice[i].pixel;
00339       }
00340       
00341       slots[nadapt].first = split->first + i;
00342       slots[nadapt].count = split->count - i;
00343       slots[nadapt].pixel = split->pixel - pixel_accum;
00344       split->count = i;
00345       split->pixel = pixel_accum;
00346     }
00347   }
00348   
00349   /* 3. make the new palette by choosing one color from each slot. */
00350   for (i = 0; i < nadapt; i++) {
00351     double red_total = 0, green_total = 0, blue_total = 0;
00352     Gif_Color *slice = &hist[ slots[i].first ];
00353     for (j = 0; j < slots[i].count; j++) {
00354       red_total += slice[j].red * slice[j].pixel;
00355       green_total += slice[j].green * slice[j].pixel;
00356       blue_total += slice[j].blue * slice[j].pixel;
00357     }
00358     adapt[i].red = (byte)(red_total / slots[i].pixel);
00359     adapt[i].green = (byte)(green_total / slots[i].pixel);
00360     adapt[i].blue = (byte)(blue_total / slots[i].pixel);
00361     adapt[i].haspixel = 0;
00362   }
00363   
00364   Gif_DeleteArray(slots);
00365   gfcm->ncol = nadapt;
00366   return gfcm;
00367 }

void colormap_stream Gif_Stream  ,
Gif_Colormap  ,
colormap_image_func   
 

Definition at line 911 of file quantize.c.

References Gif_Stream::background, Gif_Color::blue, c, Gif_Colormap::capacity, Gif_Colormap::col, colormap_image_func, free_all_color_hash_items(), Gif_CopyColormap(), Gif_DeleteArray, Gif_DeleteArrayFunc, Gif_DeleteColormap(), Gif_NewArray, Gif_ReleaseUncompressedImage(), Gif_SetUncompressedImage(), Gif_Stream::global, Gif_Color::green, hash_color(), Gif_Color::haspixel, Gif_Image::height, Gif_Image::image_data, Gif_Stream::images, Gif_Image::local, Gif_Colormap::ncol, new_color_hash(), Gif_Stream::nimages, Gif_Color::pixel, popularity_sort_compare(), Gif_Color::red, Gif_Image::transparent, try_assign_transparency(), u_int32_t, unmark_colors(), and Gif_Image::width.

Referenced by do_set_colormap().

00913 { 
00914   color_hash_item **hash = new_color_hash();
00915   int background_transparent = gfs->images[0]->transparent >= 0;
00916   Gif_Color *new_col = new_cm->col;
00917   int new_ncol = new_cm->ncol;
00918   int imagei, j;
00919   int compress_new_cm = 1;
00920 
00921   /* make sure colormap has enough space */
00922   if (new_cm->capacity < 256) {
00923     Gif_Color *x = Gif_NewArray(Gif_Color, 256);
00924     memcpy(x, new_col, sizeof(Gif_Color) * new_ncol);
00925     Gif_DeleteArray(new_col);
00926     new_cm->col = new_col = x;
00927     new_cm->capacity = 256;
00928   }
00929   assert(new_cm->capacity >= 256);
00930   
00931   /* new_col[j].pixel == number of pixels with color j in the new image. */
00932   for (j = 0; j < 256; j++)
00933     new_col[j].pixel = 0;
00934   
00935   for (imagei = 0; imagei < gfs->nimages; imagei++) {
00936     Gif_Image *gfi = gfs->images[imagei];
00937     Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global;
00938 
00939     if (gfcm) {
00940       /* If there was an old colormap, change the image data */
00941       byte *new_data = Gif_NewArray(byte, gfi->width * gfi->height);
00942       u_int32_t histogram[256];
00943       unmark_colors(new_cm);
00944       unmark_colors(gfcm);
00945       
00946       do {
00947         for (j = 0; j < 256; j++) histogram[j] = 0;
00948         image_changer(gfi, new_data, gfcm, new_cm, hash, histogram);
00949       } while (try_assign_transparency(gfi, gfcm, new_data, new_cm, &new_ncol,
00950                                        histogram));
00951       
00952       Gif_ReleaseUncompressedImage(gfi);
00953       Gif_SetUncompressedImage(gfi, new_data, Gif_DeleteArrayFunc, 0);
00954       
00955       /* update count of used colors */
00956       for (j = 0; j < 256; j++)
00957         new_col[j].pixel += histogram[j];
00958       if (gfi->transparent >= 0)
00959         /* we don't have data on the number of used colors for transparency
00960            so fudge it. */
00961         new_col[gfi->transparent].pixel += gfi->width * gfi->height / 8;
00962       
00963     } else {
00964       /* Can't compress new_cm afterwards if we didn't actively change colors
00965          over */
00966       compress_new_cm = 0;
00967     }
00968     
00969     if (gfi->local) {
00970       Gif_DeleteColormap(gfi->local);
00971       gfi->local = 0;
00972     }
00973   }
00974 
00975   /* Set new_cm->ncol from new_ncol. We didn't update new_cm->ncol before so
00976      the closest-color algorithms wouldn't see any new transparent colors.
00977      That way added transparent colors were only used for transparency. */
00978   new_cm->ncol = new_ncol;
00979   
00980   /* change the background. I hate the background by now */
00981   if (background_transparent)
00982     gfs->background = gfs->images[0]->transparent;
00983   else if (gfs->global && gfs->background < gfs->global->ncol) {
00984     Gif_Color *c = &gfs->global->col[ gfs->background ];
00985     gfs->background = hash_color(c->red, c->green, c->blue, hash, new_cm);
00986     new_col[gfs->background].pixel++;
00987   }
00988   
00989   Gif_DeleteColormap(gfs->global);
00990   
00991   /* We may have used only a subset of the colors in new_cm. We try to store
00992      only that subset, just as if we'd piped the output of `gifsicle
00993      --use-colormap=X' through `gifsicle' another time. */
00994   gfs->global = Gif_CopyColormap(new_cm);
00995   if (compress_new_cm) {
00996     /* only bother to recompress if we'll get anything out of it */
00997     compress_new_cm = 0;
00998     for (j = 0; j < new_cm->ncol - 1; j++)
00999       if (new_col[j].pixel == 0 || new_col[j].pixel < new_col[j+1].pixel) {
01000         compress_new_cm = 1;
01001         break;
01002       }
01003   }
01004   
01005   if (compress_new_cm) {
01006     int map[256];
01007     
01008     /* Gif_CopyColormap copies the `pixel' values as well */
01009     new_col = gfs->global->col;
01010     for (j = 0; j < new_cm->ncol; j++)
01011       new_col[j].haspixel = j;
01012     
01013     /* sort based on popularity */
01014     qsort(new_col, new_cm->ncol, sizeof(Gif_Color), popularity_sort_compare);
01015     
01016     /* set up the map and reduce the number of colors */
01017     for (j = 0; j < new_cm->ncol; j++)
01018       map[ new_col[j].haspixel ] = j;
01019     for (j = 0; j < new_cm->ncol; j++)
01020       if (!new_col[j].pixel) {
01021         gfs->global->ncol = j;
01022         break;
01023       }
01024     
01025     /* map the image data, transparencies, and background */
01026     gfs->background = map[gfs->background];
01027     for (imagei = 0; imagei < gfs->nimages; imagei++) {
01028       Gif_Image *gfi = gfs->images[imagei];
01029       u_int32_t size;
01030       byte *data = gfi->image_data;
01031       for (size = gfi->width * gfi->height; size > 0; size--, data++)
01032         *data = map[*data];
01033       if (gfi->transparent >= 0)
01034         gfi->transparent = map[gfi->transparent];
01035     }
01036   }
01037   
01038   /* free storage */
01039   free_all_color_hash_items();
01040   Gif_DeleteArray(hash);
01041 }

int crop_image Gif_Image  ,
Gt_Crop  
 

Definition at line 192 of file xform.c.

References error(), Gif_DeleteArray, Gif_NewArray, Gt_Crop::h, Gif_Image::height, Gif_Image::img, Gif_Image::left, Gt_Crop::left_off, Gt_Crop::ready, Gt_Crop::right_off, Gt_Crop::spec_h, Gt_Crop::spec_w, Gt_Crop::spec_x, Gt_Crop::spec_y, Gif_Image::top, Gt_Crop::w, Gt_Crop::whole_stream, Gif_Image::width, Gt_Crop::x, and Gt_Crop::y.

Referenced by merge_frame_interval().

00193 {
00194   int x, y, w, h, j;
00195   byte **img;
00196   
00197   if (!crop->ready) {
00198     crop->x = crop->spec_x + gfi->left;
00199     crop->y = crop->spec_y + gfi->top;
00200     crop->w = crop->spec_w <= 0 ? gfi->width + crop->spec_w : crop->spec_w;
00201     crop->h = crop->spec_h <= 0 ? gfi->height + crop->spec_h : crop->spec_h;
00202     if (crop->x < 0 || crop->y < 0 || crop->w <= 0 || crop->h <= 0
00203         || crop->x + crop->w > gfi->width
00204         || crop->y + crop->h > gfi->height) {
00205       error("cropping dimensions don't fit image");
00206       crop->ready = 2;
00207     } else
00208       crop->ready = 1;
00209   }
00210   if (crop->ready == 2)
00211     return 1;
00212   
00213   x = crop->x - gfi->left;
00214   y = crop->y - gfi->top;
00215   w = crop->w;
00216   h = crop->h;
00217   
00218   /* Check that the rectangle actually intersects with the image. */
00219   if (x < 0) w += x, x = 0;
00220   if (y < 0) h += y, y = 0;
00221   if (x + w > gfi->width) w = gfi->width - x;
00222   if (y + h > gfi->height) h = gfi->height - y;
00223   
00224   if (w > 0 && h > 0) {
00225     img = Gif_NewArray(byte *, h + 1);
00226     for (j = 0; j < h; j++)
00227       img[j] = gfi->img[y + j] + x;
00228     img[h] = 0;
00229     
00230     /* Change position of image appropriately */
00231     if (crop->whole_stream) {
00232       /* If cropping the whole stream, then this is the first frame. Position
00233          it at (0,0). */
00234       crop->left_off = x + gfi->left;
00235       crop->right_off = y + gfi->top;
00236       gfi->left = 0;
00237       gfi->top = 0;
00238       crop->whole_stream = 0;
00239     } else {
00240       gfi->left += x - crop->left_off;
00241       gfi->top += y - crop->right_off;
00242     }
00243     
00244   } else {
00245     /* Empty image */
00246     w = h = 0;
00247     img = 0;
00248   }
00249   
00250   Gif_DeleteArray(gfi->img);
00251   gfi->img = img;
00252   gfi->width = w;
00253   gfi->height = h;
00254   return gfi->img != 0;
00255 }

Gt_ColorTransform* delete_color_transforms Gt_ColorTransform   list,
color_transform_func   
 

Definition at line 44 of file xform.c.

References color_transform_func, Gt_ColorTransform::func, Gif_Delete, and Gt_ColorTransform::next.

00045 {
00046   Gt_ColorTransform *prev = 0, *trav = list;
00047   while (trav) {
00048     Gt_ColorTransform *next = trav->next;
00049     if (trav->func == func) {
00050       if (prev) prev->next = next;
00051       else list = next;
00052       Gif_Delete(trav);
00053     } else
00054       prev = trav;
00055     trav = next;
00056   }
00057   return list;
00058 }

void error char *    message,
...   
 

Definition at line 205 of file gifview.c.

Referenced by parse_geometry().

00206 {
00207   va_list val;
00208   va_start(val, message);
00209   fprintf(stderr, "%s: ", program_name);
00210   vfprintf(stderr, message, val);
00211   fputc('\n', stderr);
00212 }

char* explode_filename char *    filename,
int    number,
char *    name,
int    max_nimg
 

Definition at line 446 of file support.c.

References Gif_Delete, Gif_NewArray, l, and name.

Referenced by output_frames().

00447 {
00448   static char *s;
00449   int l = strlen(filename);
00450   l += name ? strlen(name) : 10;
00451   
00452   Gif_Delete(s);
00453   s = Gif_NewArray(char, l + 3);
00454   if (name)
00455     sprintf(s, "%s.%s", filename, name);
00456   else if (max_nimages <= 1000)
00457     sprintf(s, "%s.%03d", filename, number);
00458   else {
00459     int digits;
00460     unsigned j;
00461     unsigned max = (max_nimages < 0 ? 0 : max_nimages);
00462     for (digits = 4, j = 10000; max > j; digits++)
00463       j *= 10;
00464     sprintf(s, "%s.%0*d", filename, digits, number);
00465   }
00466   
00467   return s;
00468 }

void fatal_error char *    message,
...   
 

Definition at line 194 of file gifview.c.

References EXIT_USER_ERR, and verror().

Referenced by colormap_diversity(), colormap_median_cut(), do_colormap_change(), get_used_colors(), handle_extension(), main(), merge_image(), pipe_color_transformer(), scale_image(), set_frame_change(), and set_mode().

00195 {
00196   va_list val;
00197   va_start(val, message);
00198   fprintf(stderr, "%s: ", program_name);
00199   vfprintf(stderr, message, val);
00200   fputc('\n', stderr);
00201   exit(1);
00202 }

int find_color_index Gif_Color   c,
int    nc,
Gif_Color  
 

Definition at line 81 of file gifsicledir/merge.c.

References c, color, GIF_COLOREQ, and nc.

Referenced by merge_colormap_if_possible().

00082 {
00083   int index;
00084   for (index = 0; index < nc; index++)
00085     if (GIF_COLOREQ(&c[index], color))
00086       return index;
00087   return -1;
00088 }

void flip_image Gif_Image  ,
int    scr_width,
int    scr_height,
int    is_vert
 

Definition at line 263 of file xform.c.

References Gif_DeleteArray, Gif_NewArray, Gif_Image::height, Gif_Image::img, Gif_Image::left, Gif_Image::top, and Gif_Image::width.

Referenced by handle_flip_and_screen().

00264 {
00265   int x, y;
00266   int width = gfi->width;
00267   int height = gfi->height;
00268   byte **img = gfi->img;
00269   
00270   /* horizontal flips */
00271   if (!is_vert) {
00272     byte *buffer = Gif_NewArray(byte, width);
00273     byte *trav;
00274     for (y = 0; y < height; y++) {
00275       memcpy(buffer, img[y], width);
00276       trav = img[y] + width - 1;
00277       for (x = 0; x < width; x++)
00278         *trav-- = buffer[x];
00279     }
00280     gfi->left = screen_width - (gfi->left + width);
00281     Gif_DeleteArray(buffer);
00282   }
00283   
00284   /* vertical flips */
00285   if (is_vert) {
00286     byte **buffer = Gif_NewArray(byte *, height);
00287     memcpy(buffer, img, height * sizeof(byte *));
00288     for (y = 0; y < height; y++)
00289       img[y] = buffer[height - y - 1];
00290     gfi->top = screen_height - (gfi->top + height);
00291     Gif_DeleteArray(buffer);
00292   }
00293 }

Gif_Color* histogram Gif_Stream  ,
int *   
 

Definition at line 100 of file quantize.c.

References add_histogram_color(), Gif_Stream::background, Gif_Histogram::c, Gif_Histogram::cap, Gif_Colormap::col, delete_histogram(), Gif_Image::disposal, GIF_DISPOSAL_BACKGROUND, Gif_NewArray, Gif_Stream::global, Gif_Color::haspixel, Gif_Image::height, i, Gif_Stream::images, Gif_Image::img, init_histogram(), Gif_Image::local, Gif_Histogram::n, ncol, Gif_Colormap::ncol, Gif_Stream::nimages, Gif_Color::pixel, Gif_Image::transparent, u_int32_t, unmark_colors(), and Gif_Image::width.

Referenced by do_colormap_change().

00101 {
00102   Gif_Histogram hist;
00103   Gif_Color *linear;
00104   Gif_Color transparent_color;
00105   unsigned long ntransparent = 0;
00106   unsigned long nbackground = 0;
00107   int x, y, i;
00108   
00109   unmark_colors(gfs->global);
00110   for (i = 0; i < gfs->nimages; i++)
00111     unmark_colors(gfs->images[i]->local);
00112 
00113   init_histogram(&hist, 0);
00114   
00115   /* Count pixels. Be careful about values which are outside the range of the
00116      colormap. */
00117   for (i = 0; i < gfs->nimages; i++) {
00118     Gif_Image *gfi = gfs->images[i];
00119     Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global;
00120     u_int32_t count[256];
00121     Gif_Color *col;
00122     int ncol;
00123     int transparent = gfi->transparent;
00124     if (!gfcm) continue;
00125     
00126     /* sweep over the image data, counting pixels */
00127     for (x = 0; x < 256; x++)
00128       count[x] = 0;
00129     for (y = 0; y < gfi->height; y++) {
00130       byte *data = gfi->img[y];
00131       for (x = 0; x < gfi->width; x++, data++)
00132         count[*data]++;
00133     }
00134     
00135     /* add counted colors to global histogram */
00136     col = gfcm->col;
00137     ncol = gfcm->ncol;
00138     for (x = 0; x < ncol; x++)
00139       if (count[x] && x != transparent) {
00140         if (col[x].haspixel)
00141           hist.c[ col[x].pixel ].pixel += count[x];
00142         else
00143           add_histogram_color(&col[x], &hist, count[x]);
00144       }
00145     if (transparent >= 0) {
00146       if (ntransparent == 0) transparent_color = col[transparent];
00147       ntransparent += count[transparent];
00148     }
00149     
00150     /* if this image has background disposal, count its size towards the
00151        background's pixel count */
00152     if (gfi->disposal == GIF_DISPOSAL_BACKGROUND)
00153       nbackground += gfi->width * gfi->height;
00154   }
00155   
00156   /* account for background by adding it to `ntransparent' or the histogram */
00157   if (gfs->images[0]->transparent < 0 && gfs->global
00158       && gfs->background < gfs->global->ncol)
00159     add_histogram_color(&gfs->global->col[gfs->background], &hist, nbackground);
00160   else
00161     ntransparent += nbackground;
00162   
00163   /* now, make the linear histogram from the hashed histogram */
00164   linear = Gif_NewArray(Gif_Color, hist.n + 1);
00165   i = 0;
00166   
00167   /* Put all transparent pixels in histogram slot 0. Transparent pixels are
00168      marked by haspixel == 255. */
00169   if (ntransparent) {
00170     linear[0] = transparent_color;
00171     linear[0].haspixel = 255;
00172     linear[0].pixel = ntransparent;
00173     i++;
00174   }
00175   
00176   /* put hash histogram colors into linear histogram */
00177   for (x = 0; x < hist.cap; x++)
00178     if (hist.c[x].haspixel)
00179       linear[i++] = hist.c[x];
00180 
00181   delete_histogram(&hist);
00182   *nhist_store = i;
00183   return linear;
00184 }

void image_info FILE *   ,
Gif_Stream  ,
Gif_Image  ,
int    colormaps
 

Definition at line 397 of file support.c.

References colormap_info(), Gif_Image::comment, comment_info(), Gif_Image::compressed, Gif_Image::compressed_len, Gif_Image::delay, Gif_Image::disposal, disposal_names, Gif_ImageNumber(), Gif_Image::height, Gif_Image::identifier, Gif_Image::interlace, Gif_Image::left, Gif_Image::local, Gif_Colormap::ncol, Gif_Image::top, Gif_Image::transparent, verbose_endline(), and Gif_Image::width.

Referenced by output_information().

00398 {
00399   int num;
00400   if (!gfs || !gfi) return;
00401   num = Gif_ImageNumber(gfs, gfi);
00402   
00403   verbose_endline();
00404   fprintf(where, "  + image #%d ", num);
00405   if (gfi->identifier)
00406     fprintf(where, "#%s ", gfi->identifier);
00407   
00408   fprintf(where, "%dx%d", gfi->width, gfi->height);
00409   if (gfi->left || gfi->top)
00410     fprintf(where, " at %d,%d", gfi->left, gfi->top);
00411   
00412   if (gfi->interlace)
00413     fprintf(where, " interlaced");
00414   
00415   if (gfi->transparent >= 0)
00416     fprintf(where, " transparent %d", gfi->transparent);
00417   
00418 #if defined(PRINT_SIZE)
00419   if (gfi->compressed)
00420     fprintf(where, " compressed size %u min_code_size %d", gfi->compressed_len, *gfi->compressed);
00421 #endif
00422   
00423   fprintf(where, "\n");
00424   
00425   if (gfi->comment)
00426     comment_info(where, gfi->comment, "    comment ");
00427   
00428   if (gfi->local) {
00429     fprintf(where, "    local color table [%d]\n", gfi->local->ncol);
00430     if (colormaps) colormap_info(where, gfi->local, "    |");
00431   }
00432   
00433   if (gfi->disposal || gfi->delay) {
00434     fprintf(where, "   ");
00435     if (gfi->disposal)
00436       fprintf(where, " disposal %s", disposal_names[gfi->disposal]);
00437     if (gfi->delay)
00438       fprintf(where, " delay %d.%02ds",
00439               gfi->delay / 100, gfi->delay % 100);
00440     fprintf(where, "\n");
00441   }
00442 }

void input_done void   
 

Definition at line 588 of file gifsicle.c.

References BATCHING, DELETING, EXPLODING, frame_change_done(), Gif_DeleteStream(), mode, output_frames(), and verbose_close().

Referenced by main().

00589 {
00590   if (!input) return;
00591   
00592   if (verbosing) verbose_close('>');
00593   /*if (infoing) {
00594     int i;
00595     if (input->userflags == 97)
00596       stream_info(infoing, input, input_name,
00597                   colormap_infoing, extension_infoing);
00598     for (i = first_input_frame; i < frames->count; i++)
00599       if (FRAME(frames, i).stream == input && FRAME(frames, i).use)
00600         image_info(infoing, input, FRAME(frames, i).image, colormap_infoing);
00601   }*/
00602   
00603   Gif_DeleteStream(input);
00604   input = 0;
00605   
00606   if (mode == DELETING)
00607     frame_change_done();
00608   if (mode == BATCHING || mode == EXPLODING)
00609     output_frames();
00610 }

void input_stream char *   
 

Definition at line 461 of file gifsicle.c.

References add_frame(), apply_color_transforms(), BATCHING, BLANK_MODE, CH_COMMENT, CH_EXTENSION, CH_NAME, CHANGED, combine_output_options(), Gt_Frame::comment, Gt_Frameset::count, error(), Gif_Stream::errors, EXPLODING, Gt_Frame::extensions, files_given, first_input_frame, frames_done, Gif_DeleteStream(), Gif_FullReadFile(), Gif_ImageCount, GIF_READ_COMPRESSED, gif_read_flags, Gif_Unoptimize(), gifread_error(), gifread_error_count, i, Gif_Stream::images, Gt_Frame::input_filename, input_name, MERGING, mode, Gt_Frame::name, name, next_frame, next_input, Gif_Stream::nimages, Gt_OutputData::output_name, Gt_Frame::position_is_offset, Gif_Stream::refcount, set_mode(), strerror(), ungetc(), verbose_close(), verbose_open(), warncontext(), and warning().

Referenced by main(), and parse_frame_spec().

00462 {
00463   FILE *f;
00464   Gif_Stream *gfs;
00465   int i;
00466   int saved_next_frame = next_frame;
00467   Gt_Frame old_def_frame;
00468   
00469   input = 0;
00470   input_name = name;
00471   frames_done = 0;
00472   next_frame = 0;
00473   next_input = 0;
00474   if (next_output) combine_output_options();
00475   files_given++;
00476   
00477   if (name == 0 || strcmp(name, "-") == 0) {
00478 #if defined(_MSDOS) || defined(_WIN32)
00479     _setmode(_fileno(stdin), _O_BINARY);
00480 #elif defined(__EMX__)
00481     _fsetmode(stdin, "b");
00482 #endif
00483     f = stdin;
00484     name = "<stdin>";
00485   } else
00486     f = fopen(name, "rb");
00487   if (!f) {
00488     error("%s: %s", name, strerror(errno));
00489     return;
00490   }
00491   
00492   /* special error message for empty files */
00493   i = getc(f);
00494   if (i == EOF) {
00495     error("%s: empty file", name);
00496     return;
00497   }
00498   ungetc(i, f);
00499   
00500   if (verbosing) verbose_open('<', name);
00501   gifread_error_count = 0;
00502   gfs = Gif_FullReadFile(f, gif_read_flags | GIF_READ_COMPRESSED,
00503                          gifread_error, (void *)name);
00504   fclose(f);
00505   gifread_error(0, -1, (void *)name); /* print out last error message */
00506   
00507   if (!gfs || (Gif_ImageCount(gfs) == 0 && gfs->errors > 0)) {
00508     error("%s: not a GIF", name);
00509     Gif_DeleteStream(gfs);
00510     if (verbosing) verbose_close('>');
00511     return;
00512   }
00513   
00514   input = gfs;
00515   
00516   /* Processing when we've got a new input frame */
00517   if (mode == BLANK_MODE)
00518     set_mode(MERGING);
00519   
00520   if (active_output_data.output_name == 0) {
00521     /* Don't override explicit output names.
00522        This code works 'cause output_name is reset to 0 after each output. */
00523     if (mode == BATCHING)
00524       active_output_data.output_name = input_name;
00525     else if (mode == EXPLODING) {
00526       /* Explode into current directory. */
00527       char *explode_name = (input_name ? input_name : "#stdin#");
00528       char *slash = strrchr(explode_name, PATHNAME_SEPARATOR);
00529       if (slash)
00530         active_output_data.output_name = slash + 1;
00531       else
00532         active_output_data.output_name = explode_name;
00533     }
00534   }
00535   
00536   /* This code rather sucks. Here's the problem: Since we consider options
00537      strictly sequentially, one at a time, we can't tell the difference
00538      between these:
00539      
00540      --name=X g.gif             h.gif   // name on g.gif #0
00541      --name=X g.gif          #2 h.gif   // name on g.gif #2
00542               g.gif --name=X #2 h.gif   // name on g.gif #2
00543               g.gif --name=X    h.gif   // name on h.gif #0 !!!
00544       
00545      Here's the solution. Mark when we CHANGE an option. After processing
00546      an input GIF, mark all the options as `unchanged' -- but leave the
00547      VALUES as is. Then when we read the next frame, CLEAR the unchanged
00548      options. So it's like so: (* means changed, . means not.)
00549      
00550      [-.] --name=X [X*] g.gif [X.] #2 [-.] h.gif   == name on g.gif #2
00551      [-.] g.gif [-.] --name=X [X*] #2 [-.] h.gif  == name on g.gif #2
00552      [-.] --name=X [X*] g.gif [X.|-.] h.gif  == name on g.gif #0
00553      [-.] g.gif [-.] --name=X [X*] h.gif  == name on h.gif #0 */
00554   
00555   /* Clear old options from the last input stream */
00556   if (!CHANGED(saved_next_frame, CH_NAME))
00557     def_frame.name = 0;
00558   if (!CHANGED(saved_next_frame, CH_COMMENT))
00559     def_frame.comment = 0;
00560   if (!CHANGED(saved_next_frame, CH_EXTENSION))
00561     def_frame.extensions = 0;
00562   def_frame.input_filename = input_name;
00563   
00564   old_def_frame = def_frame;
00565   first_input_frame = frames->count;
00566   if (gfs->nimages > 1)
00567     def_frame.position_is_offset = 1;
00568   for (i = 0; i < gfs->nimages; i++)
00569     add_frame(frames, -1, gfs, gfs->images[i]);
00570   def_frame = old_def_frame;
00571   
00572   if (unoptimizing)
00573     if (!Gif_Unoptimize(gfs)) {
00574       static int context = 0;
00575       warning("`%s' is too complex to unoptimize", name);
00576       if (!context) {
00577         warncontext("(The reason was local color tables or complex transparency.");
00578         warncontext("Try running the GIF through `gifsicle --colors=255' first.)");
00579       }
00580       context = 1;
00581     }
00582   
00583   apply_color_transforms(input_transforms, gfs);
00584   gfs->refcount++;
00585 }

int merge_colormap_if_possible Gif_Colormap  ,
Gif_Colormap  
 

Definition at line 103 of file gifsicledir/merge.c.

References Gif_Colormap::col, COLORMAP_ENSURE_SLOT_255, ensure_slot_255(), find_color_index(), GIF_COLOREQ, Gif_Color::haspixel, i, Gif_Colormap::ncol, Gif_Color::pixel, Gif_Colormap::userflags, warncontext(), and warning().

Referenced by merge_image().

00104 {
00105   Gif_Color *srccol = src->col;
00106   Gif_Color *destcol = dest->col;
00107   int ndestcol = dest->ncol;
00108   int dest_userflags = dest->userflags;
00109   int i, x;
00110   int trivial_map = 1;
00111   
00112   for (i = 0; i < src->ncol; i++) {
00113     if (srccol[i].haspixel == 1) {
00114       /* Store an image color cell's mapping to the global colormap in its
00115          `pixel' slot. This is useful caching: oftentimes many input frames
00116          will share a colormap */
00117       int mapto = srccol[i].pixel < 256 ? srccol[i].pixel : -1;
00118       
00119       if (mapto == -1)
00120         mapto = find_color_index(destcol, ndestcol, &srccol[i]);
00121       
00122       if (mapto == -1 && ndestcol == 255
00123           && (dest_userflags & COLORMAP_ENSURE_SLOT_255) != 0) {
00124         ndestcol = ensure_slot_255(dest, ndestcol);
00125         dest_userflags &= ~COLORMAP_ENSURE_SLOT_255;
00126         /* slot 255 might have been equal to `srccol[i]'! */
00127         if (ndestcol == 256 && GIF_COLOREQ(&destcol[255], &srccol[i]))
00128           mapto = 255;
00129       }
00130       
00131       if (mapto == -1 && ndestcol < 256) {
00132         /* add the color */
00133         mapto = ndestcol;
00134         destcol[mapto] = srccol[i];
00135         ndestcol++;
00136       }
00137       
00138       if (mapto == -1)
00139         /* check for a pure-transparent color */
00140         for (x = 0; x < ndestcol; x++)
00141           if (destcol[x].haspixel == 2) {
00142             mapto = x;
00143             destcol[mapto] = srccol[i];
00144             break;
00145           }
00146       
00147       if (mapto == -1)
00148         /* give up and require a local colormap */
00149         goto local_colormap_required;
00150       
00151       assert(mapto >= 0 && mapto < ndestcol);
00152       assert(GIF_COLOREQ(&destcol[mapto], &srccol[i]));
00153       
00154       srccol[i].pixel = mapto;
00155       destcol[mapto].haspixel = 1;
00156       if (mapto != i)
00157         trivial_map = 0;
00158       
00159     } else if (srccol[i].haspixel == 2)
00160       /* a dedicated transparent color; if trivial_map & at end of colormap
00161          insert it with haspixel == 2. (strictly not necessary; we do it to
00162          try to keep the map trivial.) */
00163       if (trivial_map && i == ndestcol) {
00164         destcol[ndestcol] = srccol[i];
00165         ndestcol++;
00166       }
00167   }
00168 
00169   /* success! save new number of colors */
00170   dest->ncol = ndestcol;
00171   dest->userflags = dest_userflags;
00172   return 1;
00173   
00174   /* failure: a local colormap is required */
00175  local_colormap_required:
00176   if (warn_local_colormaps == 1) {
00177     static int context = 0;
00178     warning("so many colors that local colormaps were required");
00179     if (!context)
00180       warncontext("(You may want to try `--colors 256'.)");
00181     warn_local_colormaps = 2;
00182     context = 1;
00183   }
00184   
00185   /* 9.Dec.1998 - This must have been a longstanding bug! We MUST clear
00186      the cached mappings of any pixels in the source colormap we
00187      assigned this time through, since we are throwing those colors
00188      away. We assigned it this time through if the cached mapping is >=
00189      dest->ncol. */
00190   for (x = 0; x < i; x++)
00191     if (srccol[x].haspixel == 1 && srccol[x].pixel >= dest->ncol)
00192       srccol[x].pixel = 256;
00193   
00194   return 0;
00195 }

void merge_comments Gif_Comment   destc,
Gif_Comment   srcc
 

Definition at line 222 of file gifsicledir/merge.c.

References Gif_Comment::count, Gif_AddComment(), i, Gif_Comment::len, and Gif_Comment::str.

Referenced by fix_total_crop(), merge_frame_interval(), merge_image(), and merge_stream().

00223 {
00224   int i;
00225   for (i = 0; i < srcc->count; i++)
00226     Gif_AddComment(destc, srcc->str[i], srcc->len[i]);
00227 }

Gif_Stream* merge_frame_interval Gt_Frameset  ,
int    f1,
int    f2,
Gt_OutputData  ,
int    compress
 

Definition at line 1203 of file support.c.

References Gt_OutputData::background, Gif_Stream::background, Gif_Colormap::col, Gif_Image::comment, Gt_Frame::comment, copy_extension(), Gt_Frameset::count, Gt_Frame::crop, crop_image(), Gt_Frame::delay, Gif_Image::delay, Gt_Frame::disposal, Gif_Image::disposal, error(), Gif_Stream::extensions, Gt_Frame::extensions, find_background(), find_color_or_error(), fix_total_crop(), Gt_Frame::flip_horizontal, Gt_Frame::flip_vertical, Gif_AddExtension(), Gif_CalculateScreenSize(), Gif_CopyImage(), Gif_CopyString(), Gif_DeleteArray, Gif_DeleteComment(), Gif_DeleteImage(), Gif_DeleteStream(), Gif_FullCompressImage(), Gif_NewComment(), Gif_NewFullColormap(), Gif_NewStream(), Gif_ReleaseCompressedImage(), Gif_ReleaseUncompressedImage(), Gif_UncompressImage, global, Gif_Stream::global, handle_flip_and_screen(), handle_screen(), Gif_Color::haspixel, i, Gif_Image::identifier, Gt_Frame::image, Gif_Stream::images, Gif_Image::interlace, Gt_Frame::interlacing, Gt_Frame::left, Gif_Image::left, Gt_OutputData::loopcount, Gif_Stream::loopcount, merge_comments(), merge_image(), merge_stream(), merger_flatten(), Gt_Frame::name, Gif_Colormap::ncol, Gif_Extension::next, nmerger, Gt_Frame::no_comments, Gt_Frame::no_extensions, Gt_Frame::no_name, Gif_Extension::position, Gt_Frame::position_is_offset, Gif_Image::refcount, Gt_Frame::rotation, Gif_Stream::screen_height, Gt_OutputData::screen_height, Gif_Stream::screen_width, Gt_OutputData::screen_width, Gt_Frame::stream, Gt_Frame::top, Gif_Image::top, Gif_Image::transparent, Gt_Frame::transparent, unmark_colors_2(), Gif_Stream::userflags, and Gt_Crop::whole_stream.

Referenced by merge_and_write_frames().

01205 {
01206   Gif_Stream *dest = Gif_NewStream();
01207   Gif_Colormap *global = Gif_NewFullColormap(256, 256);
01208   Gif_Color dest_background;
01209   int i;
01210   
01211   global->ncol = 0;
01212   dest->global = global;
01213   /* 11/23/98 A new stream's screen size is 0x0; we'll use the max of the
01214      merged-together streams' screen sizes by default (in merge_stream()) */
01215   
01216   if (f2 < 0) f2 = fset->count - 1;
01217   nmerger = 0;
01218   merger_flatten(fset, f1, f2);
01219   if (nmerger == 0) {
01220     error("empty output GIF not written");
01221     return 0;
01222   }
01223   
01224   /* merge stream-specific info and clear colormaps */
01225   for (i = 0; i < nmerger; i++)
01226     merger[i]->stream->userflags = 1;
01227   for (i = 0; i < nmerger; i++) {
01228     if (merger[i]->stream->userflags) {
01229       Gif_Stream *src = merger[i]->stream;
01230       Gif_CalculateScreenSize(src, 0);
01231       /* merge_stream() unmarks the global colormap */
01232       merge_stream(dest, src, merger[i]->no_comments);
01233       src->userflags = 0;
01234     }
01235     if (merger[i]->image->local)
01236       unmark_colors_2(merger[i]->image->local);
01237   }
01238   
01239   /* decide on the background. use the one from output_data */
01240   dest_background = output_data->background;
01241   find_background(global, &dest_background);
01242   
01243   /* check for cropping the whole stream */
01244   for (i = 0; i < nmerger; i++)
01245     if (merger[i]->crop)
01246       merger[i]->crop->whole_stream = 0;
01247   if (merger[0]->crop) {
01248     merger[0]->crop->whole_stream = 1;
01249     for (i = 1; i < nmerger; i++)
01250       if (merger[i]->crop != merger[0]->crop)
01251         merger[0]->crop->whole_stream = 0;
01252   }
01253   
01254   /* copy stream-wide information from output_data */
01255   if (output_data->loopcount > -2)
01256     dest->loopcount = output_data->loopcount;
01257   dest->screen_width = dest->screen_height = 0;
01258   
01259   /** ACTUALLY MERGE FRAMES INTO THE NEW STREAM **/
01260   for (i = 0; i < nmerger; i++) {
01261     Gt_Frame *fr = merger[i];
01262     Gif_Image *srci;
01263     Gif_Image *desti;
01264     int old_transparent;
01265     
01266     /* First, check for extensions */
01267     {
01268       int j;
01269       Gif_Extension *gfex = fr->stream->extensions;
01270       for (j = 0; fr->stream->images[j] != fr->image; j++) ;
01271       while (gfex && gfex->position < j)
01272         gfex = gfex->next;
01273       while (!fr->no_extensions && gfex && gfex->position == j) {
01274         Gif_AddExtension(dest, copy_extension(gfex), i);
01275         gfex = gfex->next;
01276       }
01277       gfex = fr->extensions;
01278       while (gfex) {
01279         Gif_Extension *next = gfex->next;
01280         Gif_AddExtension(dest, gfex, i);
01281         gfex = next;
01282       }
01283     }
01284     
01285     /* Make a copy of the image and crop it if we're cropping */
01286     if (fr->crop) {
01287       srci = Gif_CopyImage(fr->image);
01288       Gif_UncompressImage(srci);
01289       if (!crop_image(srci, fr->crop)) {
01290         /* We cropped the image out of existence! Be careful not to make 0x0
01291            frames. */
01292         fix_total_crop(dest, srci, i);
01293         goto merge_frame_done;
01294       }
01295     } else {
01296       srci = fr->image;
01297       Gif_UncompressImage(srci);
01298     }
01299     
01300     /* It was pretty stupid to remove this code, which I did between 1.2b6 and
01301        1.2 */
01302     old_transparent = srci->transparent;
01303     if (fr->transparent.haspixel == 255)
01304       srci->transparent = -1;
01305     else if (fr->transparent.haspixel)
01306       srci->transparent =
01307         find_color_or_error(&fr->transparent, fr->stream, srci, "transparent");
01308     
01309     desti = merge_image(dest, fr->stream, srci);
01310     
01311     srci->transparent = old_transparent; /* restore real transparent value */
01312     
01313     /* Flipping and rotating, and also setting the screen size */
01314     if (fr->flip_horizontal || fr->flip_vertical || fr->rotation)
01315       handle_flip_and_screen(dest, desti, fr, i == 0);
01316     else
01317       handle_screen(dest, fr->stream->screen_width, fr->stream->screen_height);
01318     
01319     /* Names and comments */
01320     if (fr->name || fr->no_name) {
01321       Gif_DeleteArray(desti->identifier);
01322       desti->identifier = Gif_CopyString(fr->name);
01323     }
01324     if (fr->no_comments && desti->comment) {
01325       Gif_DeleteComment(desti->comment);
01326       desti->comment = 0;
01327     }
01328     if (fr->comment) {
01329       if (!desti->comment) desti->comment = Gif_NewComment();
01330       merge_comments(desti->comment, fr->comment);
01331       /* delete the comment early to help with memory; set field to 0 so we
01332          don't re-free it later */
01333       Gif_DeleteComment(fr->comment);
01334       fr->comment = 0;
01335     }
01336     
01337     if (fr->interlacing >= 0)
01338       desti->interlace = fr->interlacing;
01339     if (fr->left >= 0)
01340       desti->left = fr->left + (fr->position_is_offset ? desti->left : 0);
01341     if (fr->top >= 0)
01342       desti->top = fr->top + (fr->position_is_offset ? desti->top : 0);
01343     
01344     if (fr->delay >= 0)
01345       desti->delay = fr->delay;
01346     if (fr->disposal >= 0)
01347       desti->disposal = fr->disposal;
01348     
01349     /* compress immediately if possible to save on memory */
01350     if (compress_immediately) {
01351       Gif_FullCompressImage(dest, desti, gif_write_flags);
01352       Gif_ReleaseUncompressedImage(desti);
01353     }
01354     
01355    merge_frame_done:
01356     /* Destroy the copied, cropped image if necessary */
01357     if (fr->crop)
01358       Gif_DeleteImage(srci);
01359     
01360     /* if we can, delete the image's data right now to save memory */
01361     srci = fr->image;
01362     assert(srci->refcount > 1);
01363     if (--srci->refcount == 1) {
01364       /* only 1 reference ==> the reference is from the input stream itself */
01365       Gif_ReleaseUncompressedImage(srci);
01366       Gif_ReleaseCompressedImage(srci);
01367       fr->image = 0;
01368     }
01369     
01370     /* 5/26/98 Destroy the stream now to help with memory. Assumes that
01371        all frames are added with add_frame() which properly increments the
01372        stream's refcount. Set field to 0 so we don't redelete */
01373     Gif_DeleteStream(fr->stream);
01374     fr->stream = 0;
01375   }
01376   /** END MERGE LOOP **/
01377 
01378   /* Cropping the whole output? Clear the logical screen */
01379   if (merger[0]->crop && merger[0]->crop == merger[nmerger-1]->crop)
01380     dest->screen_width = dest->screen_height = 0;
01381   /* Set the logical screen from the user's preferences */
01382   if (output_data->screen_width >= 0)
01383     dest->screen_width = output_data->screen_width;
01384   if (output_data->screen_height >= 0)
01385     dest->screen_height = output_data->screen_height;
01386   
01387   /* Find the background color in the colormap, or add it if we can */
01388   {
01389     int bg = find_color_or_error(&dest_background, dest, 0, 0);
01390     if (bg < 0 && dest->images[0]->transparent >= 0)
01391       dest->background = dest->images[0]->transparent;
01392     else if (bg < 0 && global->ncol < 256) {
01393       dest->background = global->ncol;
01394       global->col[ global->ncol ] = dest_background;
01395       global->ncol++;
01396     } else
01397       dest->background = bg;
01398   }
01399 
01400   return dest;
01401 }

Gif_Image* merge_image Gif_Stream   dest,
Gif_Stream   src,
Gif_Image   srci
 

Definition at line 231 of file gifsicledir/merge.c.

References c, Gif_Colormap::col, Gif_Image::comment, Gif_Image::delay, Gif_Image::disposal, fatal_error(), Gif_AddImage(), Gif_CopyString(), Gif_CreateUncompressedImage(), Gif_NewComment(), Gif_NewFullColormap(), Gif_NewImage(), Gif_Stream::global, Gif_Color::haspixel, Gif_Image::height, i, Gif_Image::identifier, Gif_Image::img, Gif_Image::interlace, Gif_Image::left, Gif_Image::local, mark_used_colors(), merge_colormap_if_possible(), merge_comments(), Gif_Colormap::ncol, ncol, Gif_Image::top, Gif_Image::transparent, and Gif_Image::width.

Referenced by merge_frame_interval().

00232 {
00233   Gif_Colormap *imagecm;
00234   Gif_Color *imagecol;
00235   int islocal;
00236   int i;
00237   Gif_Colormap *localcm = 0;
00238   Gif_Colormap *destcm = dest->global;
00239   
00240   byte map[256];                /* map[input pixel value] == output pixval */
00241   int trivial_map = 1;          /* does the map take input pixval --> the same
00242                                    pixel value for all colors in the image? */
00243   byte used[256];               /* used[output pixval K] == 1 iff K was used
00244                                    in the image */
00245   
00246   Gif_Image *desti;
00247   
00248   /* mark colors that were actually used in this image */
00249   islocal = srci->local != 0;
00250   imagecm = islocal ? srci->local : src->global;
00251   if (!imagecm)
00252     fatal_error("no global or local colormap for source image");
00253   
00254   mark_used_colors(srci, imagecm);
00255   imagecol = imagecm->col;      /* may be changed by mark_used_colors */
00256   
00257   /* map[old_pixel_value] == new_pixel_value */
00258   for (i = 0; i < 256; i++)
00259     map[i] = used[i] = 0;
00260   
00261   /* Merge the colormap */
00262   if (merge_colormap_if_possible(dest->global, imagecm)) {
00263     /* Create `map' and `used' for global colormap. */
00264     for (i = 0; i < imagecm->ncol; i++)
00265       if (imagecol[i].haspixel == 1) {
00266         map[i] = imagecol[i].pixel;
00267         if (map[i] != i) trivial_map = 0;
00268         used[map[i]] = 1;
00269       }
00270     
00271   } else {
00272     /* Need a local colormap. */
00273     int ncol = 0;
00274     destcm = localcm = Gif_NewFullColormap(0, 256);
00275     for (i = 0; i < imagecm->ncol; i++)
00276       if (imagecol[i].haspixel) {
00277         map[i] = ncol;
00278         if (ncol != i) trivial_map = 0;
00279         /* 19.Aug.1999- BUGFIX! color is only used if it was opaque */
00280         if (imagecol[i].haspixel == 1)
00281           used[ncol] = 1;
00282         localcm->col[ ncol++ ] = imagecol[i];
00283       }
00284     localcm->ncol = ncol;
00285   }
00286   
00287   /* Decide on a transparent index */
00288   if (srci->transparent >= 0) {
00289     int found_transparent = -1;
00290     
00291     /* try to keep the map trivial -- prefer same transparent index */
00292     if (trivial_map && !used[srci->transparent])
00293       found_transparent = srci->transparent;
00294     else
00295       for (i = destcm->ncol - 1; i >= 0; i--)
00296         if (!used[i])
00297           found_transparent = i;
00298     
00299     /* 1.Aug.1999 - Allow for the case that the transparent index is bigger
00300        than the number of colors we've created thus far. */
00301     if (found_transparent < 0 || found_transparent >= destcm->ncol) {
00302       Gif_Color *c;
00303       found_transparent = destcm->ncol;
00304       /* 1.Aug.1999 - Don't update destcm->ncol -- we want the output colormap
00305          to be as small as possible. */
00306       c = &destcm->col[found_transparent];
00307       if (srci->transparent < imagecm->ncol)
00308         *c = imagecol[srci->transparent];
00309       else
00310         c->haspixel = 2;
00311       assert(c->haspixel == 2 && found_transparent < 256);
00312     }
00313     
00314     map[srci->transparent] = found_transparent;
00315     if (srci->transparent != found_transparent) trivial_map = 0;
00316   }
00317   
00318   assert(destcm->ncol <= 256);
00319   /* Make the new image. */
00320   desti = Gif_NewImage();
00321   
00322   desti->identifier = Gif_CopyString(srci->identifier);
00323   if (srci->transparent > -1)
00324     desti->transparent = map[srci->transparent];
00325   desti->delay = srci->delay;
00326   desti->disposal = srci->disposal;
00327   desti->left = srci->left;
00328   desti->top = srci->top;
00329   desti->interlace = srci->interlace;
00330   
00331   desti->width = srci->width;
00332   desti->height = srci->height;
00333   desti->local = localcm;
00334   
00335   if (srci->comment) {
00336     desti->comment = Gif_NewComment();
00337     merge_comments(desti->comment, srci->comment);
00338   }
00339   
00340   Gif_CreateUncompressedImage(desti);
00341   
00342   {
00343     int i, j;
00344     
00345     if (trivial_map)
00346       for (j = 0; j < desti->height; j++)
00347         memcpy(desti->img[j], srci->img[j], desti->width);
00348     
00349     else
00350       for (j = 0; j < desti->height; j++) {
00351         byte *srcdata = srci->img[j];
00352         byte *destdata = desti->img[j];
00353         for (i = 0; i < desti->width; i++, srcdata++, destdata++)
00354           *destdata = map[*srcdata];
00355       }
00356   }
00357   
00358   Gif_AddImage(dest, desti);
00359   return desti;  
00360 }

void merge_stream Gif_Stream   dest,
Gif_Stream   src,
int    no_comments
 

Definition at line 199 of file gifsicledir/merge.c.

References Gif_Stream::comment, Gif_NewComment(), Gif_Stream::global, i, Gif_Stream::images, Gif_Stream::loopcount, merge_comments(), Gif_Stream::nimages, and unmark_colors_2().

Referenced by merge_frame_interval().

00200 {
00201   int i;
00202   assert(dest->global);
00203   
00204   /* unmark colors in global and local colormaps -- 12/9 */
00205   if (src->global)
00206     unmark_colors_2(src->global);
00207   for (i = 0; i < src->nimages; i++)
00208     if (src->images[i]->local)
00209       unmark_colors_2(src->images[i]->local);
00210   
00211   if (dest->loopcount < 0)
00212     dest->loopcount = src->loopcount;
00213   
00214   if (src->comment && !no_comments) {
00215     if (!dest->comment) dest->comment = Gif_NewComment();
00216     merge_comments(dest->comment, src->comment);
00217   }
00218 }

Gt_Frameset* new_frameset int    initial_cap
 

Definition at line 894 of file support.c.

References Gt_Frameset::cap, Gt_Frameset::count, Gt_Frameset::f, Gif_New, and Gif_NewArray.

Referenced by main(), and set_frame_change().

00895 {
00896   Gt_Frameset *fs = Gif_New(Gt_Frameset);
00897   if (initial_cap < 0) initial_cap = 0;
00898   fs->cap = initial_cap;
00899   fs->count = 0;
00900   fs->f = Gif_NewArray(Gt_Frame, initial_cap);
00901   return fs;
00902 }

void optimize_fragments Gif_Stream  ,
int    optimizeness
 

Definition at line 1264 of file optimize.c.

References create_new_image_data(), create_out_global_map(), create_subimages(), finalize_optimizer(), and initialize_optimizer().

Referenced by merge_and_write_frames().

01265 {
01266   if (!initialize_optimizer(gfs, optimize_level))
01267     return;
01268 
01269   create_subimages(gfs, optimize_level);
01270   create_out_global_map(gfs);
01271   create_new_image_data(gfs, optimize_level);
01272   
01273   finalize_optimizer(gfs);
01274 }

void output_frames void   
 

Definition at line 830 of file gifsicle.c.

References active_next_output, BATCHING, clear_frameset(), Gt_Frameset::count, Gt_Frame::crop, Gt_Frame::explode_by_name, explode_filename(), EXPLODING, FRAME, Gif_ImageNumber(), i, Gif_Image::identifier, Gt_Frame::image, infoing, INSERTING, merge_and_write_frames(), MERGING, Gt_Frame::name, Gif_Stream::nimages, output_information(), Gt_OutputData::output_name, Gt_Crop::ready, and Gt_Frame::stream.

Referenced by input_done(), and main().

00831 {
00832   /* Use the current output name, not the stored output name.
00833      This supports `gifsicle a.gif -o xxx'.
00834      It's not like any other option, but seems right: it fits the natural
00835      order -- input, then output. */
00836   int i;
00837   char *outfile = active_output_data.output_name;
00838   active_output_data.output_name = 0;
00839   
00840   /* Output information only now. */
00841   if (infoing)
00842     output_information(outfile);
00843   
00844   if (infoing != 1 && frames->count > 0)
00845     switch (mode) {
00846       
00847      case MERGING:
00848      case BATCHING:
00849       merge_and_write_frames(outfile, 0, -1);
00850       break;
00851       
00852      case EXPLODING: {
00853        /* Use the current output name for consistency, even though that means
00854           we can't explode different frames to different names. Not a big deal
00855           anyway; they can always repeat the gif on the cmd line. */
00856        int max_nimages = 0;
00857        for (i = 0; i < frames->count; i++) {
00858          Gt_Frame *fr = &FRAME(frames, i);
00859          if (fr->stream->nimages > max_nimages)
00860            max_nimages = fr->stream->nimages;
00861        }
00862        
00863        if (!outfile) /* Watch out! */
00864          outfile = "-";
00865        
00866        for (i = 0; i < frames->count; i++) {
00867          Gt_Frame *fr = &FRAME(frames, i);
00868          int imagenumber = Gif_ImageNumber(fr->stream, fr->image);
00869          char *explodename;
00870          
00871          char *imagename = 0;
00872          if (fr->explode_by_name)
00873            imagename = fr->name ? fr->name : fr->image->identifier;
00874          
00875          explodename = explode_filename(outfile, imagenumber, imagename,
00876                                         max_nimages);
00877          merge_and_write_frames(explodename, i, i);
00878        }
00879        break;
00880      }
00881      
00882      case INSERTING:
00883       /* do nothing */
00884       break;
00885       
00886     }
00887   
00888   active_next_output = 0;
00889   clear_frameset(frames, 0);
00890   
00891   /* cropping: clear the `crop->ready' information, which depended on the last
00892      input image. */
00893   if (def_frame.crop)
00894     def_frame.crop->ready = 0;
00895 }

int parse_color Clp_Parser  ,
const char *   ,
int   ,
void *   
 

Definition at line 698 of file support.c.

References arg, Gif_Color::blue, Clp_OptionError(), error(), Gif_Color::green, Gif_Color::haspixel, parse_hex_color_channel(), Gif_Color::pixel, and Gif_Color::red.

Referenced by parse_two_colors().

00699 {
00700   const char *input_arg = arg;
00701   char *str;
00702   int red, green, blue;
00703   
00704   if (*arg == '#') {
00705     int len = strlen(++arg);
00706     if (!len || len % 3 != 0 || strspn(arg, "0123456789ABCDEFabcdef") != len) {
00707       if (complain)
00708         Clp_OptionError(clp, "invalid color `%s' (want `#RGB' or `#RRGGBB')",
00709                         input_arg);
00710       return 0;
00711     }
00712     
00713     len /= 3;
00714     red   = parse_hex_color_channel(&arg[ 0 * len ], len);
00715     green = parse_hex_color_channel(&arg[ 1 * len ], len);
00716     blue  = parse_hex_color_channel(&arg[ 2 * len ], len);
00717     goto gotrgb;
00718     
00719   } else if (!isdigit(*arg))
00720     goto error;
00721   
00722   red = strtol(arg, &str, 10);
00723   if (*str == 0) {
00724     if (red < 0 || red > 255)
00725       goto error;
00726     parsed_color.haspixel = 1;
00727     parsed_color.pixel = red;
00728     return 1;
00729     
00730   } else if (*str != ',' && *str != '/')
00731     goto error;
00732   
00733   if (*++str == 0) goto error;
00734   green = strtol(str, &str, 10);
00735   if (*str != ',' && *str != '/') goto error;
00736   
00737   if (*++str == 0) goto error;
00738   blue = strtol(str, &str, 10);
00739   if (*str != 0) goto error;
00740   
00741  gotrgb:
00742   if (red < 0 || green < 0 || blue < 0
00743       || red > 255 || green > 255 || blue > 255)
00744     goto error;
00745   parsed_color.red = red;
00746   parsed_color.green = green;
00747   parsed_color.blue = blue;
00748   parsed_color.haspixel = 0;
00749   return 1;
00750   
00751  error:
00752   if (complain)
00753     return Clp_OptionError(clp, "invalid color `%s'", input_arg);
00754   else
00755     return 0;
00756 }

int parse_dimensions Clp_Parser  ,
const char *   ,
int   ,
void *   
 

Definition at line 569 of file support.c.

References arg, Clp_OptionError(), dimensions_x, and dimensions_y.

Referenced by parse_rectangle().

00570 {
00571   char *val;
00572 
00573   if (*arg == '_' && arg[1] == 'x') {
00574     dimensions_x = 0;
00575     val = (char *)(arg + 1);
00576   } else
00577     dimensions_x = strtol(arg, &val, 10);
00578   if (*val == 'x') {
00579     if (val[1] == '_' && val[2] == 0) {
00580       dimensions_y = 0;
00581       val = val + 2;
00582     } else
00583       dimensions_y = strtol(val + 1, &val, 10);
00584     if (*val == 0)
00585       return 1;
00586   }
00587   
00588   if (complain)
00589     return Clp_OptionError(clp, "invalid dimensions `%s' (want WxH)", arg);
00590   else
00591     return 0;
00592 }

int parse_frame_spec Clp_Parser  ,
const char *   ,
int   ,
void *   
 

Definition at line 488 of file support.c.

References arg, c, Clp_OptionError(), frame_spec_1, frame_spec_2, frame_spec_name, Gif_GetNamedImage(), Gif_ImageCount, Gif_ImageNumber(), and input_stream().

Referenced by frame_argument().

00489 {
00490   char *c;
00491   
00492   frame_spec_1 = 0;
00493   frame_spec_2 = -1;
00494   frame_spec_name = 0;
00495   
00496   if (!input && !input_name)
00497     input_stream(0);
00498   if (!input)
00499     return 0;
00500   
00501   if (arg[0] != '#') {
00502     if (complain)
00503       return Clp_OptionError(clp, "frame specifications must start with #");
00504     else
00505       return 0;
00506   }
00507   arg++;
00508   c = (char *)arg;
00509   
00510   /* Get a number range (#x, #x-y, or #x-). First, read x. */
00511   if (isdigit(c[0]))
00512     frame_spec_1 = frame_spec_2 = strtol(c, &c, 10);
00513   else if (c[0] == '-' && isdigit(c[1])) {
00514     frame_spec_1 = frame_spec_2 = Gif_ImageCount(input) + strtol(c, &c, 10);
00515     if (frame_spec_1 < 0)
00516       return complain ? Clp_OptionError(clp, "there are only %d frames",
00517                                         Gif_ImageCount(input)) : 0;
00518   }
00519   
00520   /* Then, if the next character is a dash, read y. Be careful to prevent
00521      #- from being interpreted as a frame range. */
00522   if (c[0] == '-' && (frame_spec_2 > 0 || c[1] != 0)) {
00523     c++;
00524     if (isdigit(c[0]))
00525       frame_spec_2 = strtol(c, &c, 10);
00526     else if (c[0] == '-' && isdigit(c[1]))
00527       frame_spec_2 = Gif_ImageCount(input) + strtol(c, &c, 10);
00528     else
00529       frame_spec_2 = Gif_ImageCount(input) - 1;
00530   }
00531   
00532   /* It really was a number range (and not a frame name)
00533      only if c is now at the end of the argument. */
00534   if (c[0] != 0) {
00535     Gif_Image *gfi = Gif_GetNamedImage(input, arg);
00536     if (gfi) {
00537       frame_spec_name = (char *)arg;
00538       frame_spec_1 = frame_spec_2 = Gif_ImageNumber(input, gfi);
00539       return 1;
00540     } else if (complain < 0)    /* -1 is special value meaning `don't complain
00541                                    about frame NAMES, but do complain about
00542                                    frame numbers.' */
00543       return -97;               /* Return -97 on bad frame name. */
00544     else if (complain)
00545       return Clp_OptionError(clp, "no frame named `#%s'", arg);
00546     else
00547       return 0;
00548     
00549   } else {
00550     if (frame_spec_1 >= 0 && frame_spec_1 <= frame_spec_2
00551         && frame_spec_2 < Gif_ImageCount(input))
00552       return 1;
00553     else if (!complain)
00554       return 0;
00555     
00556     if (frame_spec_1 == frame_spec_2)
00557       return Clp_OptionError(clp, "no frame number #%d", frame_spec_1);
00558     else if (frame_spec_1 < 0)
00559       return Clp_OptionError(clp, "frame numbers can't be negative");
00560     else if (frame_spec_1 > frame_spec_2)
00561       return Clp_OptionError(clp, "empty frame range");
00562     else
00563       return Clp_OptionError(clp, "there are only %d frames",
00564                              Gif_ImageCount(input));
00565   }
00566 }

int parse_position Clp_Parser  ,
const char *   ,
int   ,
void *   
 

Definition at line 595 of file support.c.

References arg, Clp_OptionError(), position_x, and position_y.

Referenced by parse_rectangle().

00596 {
00597   char *val;
00598   
00599   position_x = strtol(arg, &val, 10);
00600   if (*val == ',') {
00601     position_y = strtol(val + 1, &val, 10);
00602     if (*val == 0)
00603       return 1;
00604   }
00605   
00606   if (complain)
00607     return Clp_OptionError(clp, "invalid position `%s' (want `X,Y')", arg);
00608   else
00609     return 0;
00610 }

int parse_rectangle Clp_Parser  ,
const char *   ,
int   ,
void *   
 

Definition at line 634 of file support.c.

References arg, Clp_OptionError(), dimensions_x, dimensions_y, parse_dimensions(), parse_position(), position_x, and position_y.

00635 {
00636   const char *input_arg = arg;
00637   char *val;
00638   
00639   int x = position_x = strtol(arg, &val, 10);
00640   if (*val == ',') {
00641     int y = position_y = strtol(val + 1, &val, 10);
00642     if (*val == '-' && parse_position(clp, val + 1, 0, 0)) {
00643       if (x >= 0 && y >= 0 && x < position_x && y < position_y) {
00644         dimensions_x = position_x - x;
00645         dimensions_y = position_y - y;
00646         position_x = x;
00647         position_y = y;
00648         return 1;
00649       }
00650     } else if (*val == '+' && parse_dimensions(clp, val + 1, 0, 0))
00651       return 1;
00652   } else if (*val == 'x') {
00653     dimensions_x = position_x;
00654     dimensions_y = strtol(val + 1, &val, 10);
00655     if (*val == 0) {
00656       position_x = position_y = 0;
00657       return 1;
00658     }
00659   }
00660   
00661   if (complain)
00662     return Clp_OptionError(clp, "invalid rectangle `%s' (want `X1,Y1-X2,Y2' or `X1,Y1+WxH'", input_arg);
00663   else
00664     return 0;
00665 }

int parse_scale_factor Clp_Parser  ,
const char *   ,
int   ,
void *   
 

Definition at line 613 of file support.c.

References arg, Clp_OptionError(), parsed_scale_factor_x, parsed_scale_factor_y, and strtod().

00614 {
00615   char *val;
00616   
00617   parsed_scale_factor_x = strtod(arg, &val);
00618   if (*val == 'x') {
00619     parsed_scale_factor_y = strtod(val + 1, &val);
00620     if (*val == 0)
00621       return 1;
00622   } else if (*val == 0) {
00623     parsed_scale_factor_y = parsed_scale_factor_x;
00624     return 1;
00625   }
00626   
00627   if (complain)
00628     return Clp_OptionError(clp, "invalid scale factor `%s' (want XxY)", arg);
00629   else
00630     return 0;
00631 }

int parse_two_colors Clp_Parser  ,
const char *   ,
int   ,
void *   
 

Definition at line 759 of file support.c.

References arg, Clp_OptionError(), Clp_Shift(), and parse_color().

00760 {
00761   Gif_Color old_color;
00762   if (parse_color(clp, arg, complain, thunk) <= 0)
00763     return 0;
00764   old_color = parsed_color;
00765   
00766   arg = Clp_Shift(clp, 0);
00767   if (!arg && complain)
00768     return Clp_OptionError(clp, "`%O' takes two color arguments");
00769   else if (!arg)
00770     return 0;
00771   
00772   if (parse_color(clp, arg, complain, thunk) <= 0)
00773     return 0;
00774   
00775   parsed_color2 = parsed_color;
00776   parsed_color = old_color;
00777   return 1;
00778 }

void pipe_color_transformer Gif_Colormap  ,
void *   
 

Definition at line 127 of file xform.c.

References Gif_Colormap::col, error(), fatal_error(), Gif_DeleteArray, Gif_DeleteColormap(), Gif_NewArray, i, nc, Gif_Colormap::ncol, pclose, popen, read_colormap_file(), strerror(), and warning().

00128 {
00129   int i, status;
00130   FILE *f;
00131   Gif_Color *col = gfcm->col;
00132   Gif_Colormap *new_cm = 0;
00133   char *command = (char *)thunk;
00134   char *tmp_file = tmpnam(0);
00135   char *new_command;
00136   
00137   if (!tmp_file)
00138     fatal_error("can't create temporary file!");
00139   
00140   new_command = Gif_NewArray(char, strlen(command) + strlen(tmp_file) + 4);
00141   sprintf(new_command, "%s  >%s", command, tmp_file);
00142   f = popen(new_command, "w");
00143   if (!f)
00144     fatal_error("can't run color transformation command: %s", strerror(errno));
00145   Gif_DeleteArray(new_command);
00146   
00147   for (i = 0; i < gfcm->ncol; i++)
00148     fprintf(f, "%d %d %d\n", col[i].red, col[i].green, col[i].blue);
00149   
00150   errno = 0;
00151   status = pclose(f);
00152   if (status < 0) {
00153     error("color transformation error: %s", strerror(errno));
00154     goto done;
00155   } else if (status > 0) {
00156     error("color transformation command failed");
00157     goto done;
00158   }
00159   
00160   f = fopen(tmp_file, "r");
00161   if (!f || feof(f)) {
00162     error("color transformation command generated no output", command);
00163     if (f) fclose(f);
00164     goto done;
00165   }
00166   new_cm = read_colormap_file("<color transformation>", f);
00167   fclose(f);
00168   
00169   if (new_cm) {
00170     int nc = new_cm->ncol;
00171     if (nc < gfcm->ncol) {
00172       nc = gfcm->ncol;
00173       warning("too few colors in color transformation results");
00174     } else if (nc > gfcm->ncol)
00175       warning("too many colors in color transformation results");
00176     for (i = 0; i < nc; i++)
00177       col[i] = new_cm->col[i];
00178   }
00179   
00180  done:
00181   remove(tmp_file);
00182   Gif_DeleteColormap(new_cm);
00183 }

Gif_Colormap* read_colormap_file char *   ,
FILE *   
 

Definition at line 841 of file support.c.

References c, error(), Gif_Stream::errors, Gif_CopyColormap(), Gif_DeleteStream(), Gif_ReadFile, Gif_Stream::global, name, read_text_colormap(), strerror(), ungetc(), verbose_close(), verbose_open(), and warning().

Referenced by pipe_color_transformer(), and set_new_fixed_colormap().

00842 {
00843   Gif_Colormap *cm = 0;
00844   int c;
00845   int my_file = 0;
00846   
00847   if (name && strcmp(name, "-") == 0)
00848     name = 0;
00849   if (!f) {
00850     my_file = 1;
00851     if (!name)
00852       f = stdin;
00853     else
00854       f = fopen(name, "rb");
00855     if (!f) {
00856       error("%s: %s", name, strerror(errno));
00857       return 0;
00858     }
00859   }
00860   
00861   name = name ? name : "<stdin>";
00862   if (verbosing) verbose_open('<', name);
00863   
00864   c = getc(f);
00865   ungetc(c, f);
00866   if (c == 'G') {
00867     Gif_Stream *gfs = Gif_ReadFile(f);
00868     if (!gfs)
00869       error("`%s' doesn't seem to contain a GIF", name);
00870     else if (!gfs->global)
00871       error("can't use `%s' as a palette (no global color table)", name);
00872     else {
00873       if (gfs->errors)
00874         warning("there were errors reading `%s'", name);
00875       cm = Gif_CopyColormap(gfs->global);
00876     }
00877     
00878     Gif_DeleteStream(gfs);
00879   } else
00880     cm = read_text_colormap(f, name);
00881   
00882   if (my_file) fclose(f);
00883   if (verbosing) verbose_close('>');
00884   return cm;
00885 }

void resize_stream Gif_Stream  ,
int    new_width,
int    new_height
 

Definition at line 423 of file xform.c.

References Gif_CalculateScreenSize(), i, Gif_Stream::images, Gif_Stream::nimages, scale_image(), Gif_Stream::screen_height, and Gif_Stream::screen_width.

Referenced by merge_and_write_frames().

00424 {
00425   double xfactor, yfactor;
00426   int i;
00427 
00428   if (new_width <= 0)
00429     new_width = (int)(((double)gfs->screen_width / gfs->screen_height) * new_height);
00430   if (new_height <= 0)
00431     new_height = (int)(((double)gfs->screen_height / gfs->screen_width) * new_width);
00432   
00433   Gif_CalculateScreenSize(gfs, 0);
00434   xfactor = (double)new_width / gfs->screen_width;
00435   yfactor = (double)new_height / gfs->screen_height;
00436   for (i = 0; i < gfs->nimages; i++)
00437     scale_image(gfs, gfs->images[i], xfactor, yfactor);
00438   
00439   gfs->screen_width = new_width;
00440   gfs->screen_height = new_height;
00441 }

void rotate_image Gif_Image  ,
int    scr_width,
int    scr_height,
int    rotation
 

Definition at line 296 of file xform.c.

References Gif_DeleteArrayFunc, Gif_NewArray, Gif_ReleaseUncompressedImage(), Gif_SetUncompressedImage(), Gif_Image::height, Gif_Image::img, Gif_Image::left, Gif_Image::top, and Gif_Image::width.

Referenced by handle_flip_and_screen().

00297 {
00298   int x, y;
00299   int width = gfi->width;
00300   int height = gfi->height;
00301   byte **img = gfi->img;
00302   byte *new_data = Gif_NewArray(byte, width * height);
00303   byte *trav = new_data;
00304   
00305   /* this function can only rotate by 90 or 270 degrees */
00306   assert(rotation == 1 || rotation == 3);
00307   
00308   if (rotation == 1) {
00309     for (x = 0; x < width; x++)
00310       for (y = height - 1; y >= 0; y--)
00311         *trav++ = img[y][x];
00312     x = gfi->left;
00313     gfi->left = screen_height - (gfi->top + height);
00314     gfi->top = x;
00315     
00316   } else {
00317     for (x = width - 1; x >= 0; x--)
00318       for (y = 0; y < height; y++)
00319         *trav++ = img[y][x];
00320     y = gfi->top;
00321     gfi->top = screen_width - (gfi->left + width);
00322     gfi->left = y;
00323   }
00324   
00325   Gif_ReleaseUncompressedImage(gfi);
00326   gfi->width = height;
00327   gfi->height = width;
00328   Gif_SetUncompressedImage(gfi, new_data, Gif_DeleteArrayFunc, 0);
00329 }

void scale_image Gif_Stream  ,
Gif_Image  ,
double    xfactor,
double    yfactor
 

Definition at line 341 of file xform.c.

References fatal_error(), Gif_DeleteArrayFunc, Gif_NewArray, Gif_ReleaseCompressedImage(), Gif_ReleaseUncompressedImage(), Gif_SetUncompressedImage(), Gif_Image::height, i, Gif_Image::img, Gif_Image::left, SCALE, SCALE_FACTOR, Gif_Image::top, UNSCALE, and Gif_Image::width.

Referenced by resize_stream().

00342 {
00343   byte *new_data;
00344   int new_left, new_top, new_right, new_bottom, new_width, new_height;
00345   
00346   int i, j, new_x, new_y;
00347   int scaled_xstep, scaled_ystep, scaled_new_x, scaled_new_y;
00348 
00349   /* Fri 9 Jan 1999: Fix problem with resizing animated GIFs: we scaled from
00350      left edge of the *subimage* to right edge of the subimage, causing
00351      consistency problems when several subimages overlap. Solution: always use
00352      scale factors relating to the *whole image* (the screen size). */
00353   
00354   /* use fixed-point arithmetic */
00355   scaled_xstep = (int)(SCALE_FACTOR * xfactor + 0.5);
00356   scaled_ystep = (int)(SCALE_FACTOR * yfactor + 0.5);
00357   
00358   /* calculate new width and height based on the four edges (left, right, top,
00359      bottom). This is better than simply multiplying the width and height by
00360      the scale factors because it avoids roundoff inconsistencies between
00361      frames on animated GIFs. Don't allow 0-width or 0-height images; GIF
00362      doesn't support them well. */
00363   new_left = UNSCALE(scaled_xstep * gfi->left);
00364   new_top = UNSCALE(scaled_ystep * gfi->top);
00365   new_right = UNSCALE(scaled_xstep * (gfi->left + gfi->width));
00366   new_bottom = UNSCALE(scaled_ystep * (gfi->top + gfi->height));
00367   
00368   new_width = new_right - new_left;
00369   new_height = new_bottom - new_top;
00370 
00371   if (new_width <= 0) new_width = 1, new_right = new_left + 1;
00372   if (new_height <= 0) new_height = 1, new_bottom = new_top + 1;
00373   if (new_width > UNSCALE(INT_MAX) || new_height > UNSCALE(INT_MAX))
00374     fatal_error("new image size is too big for me to handle");
00375   
00376   assert(gfi->img);
00377   new_data = Gif_NewArray(byte, new_width * new_height);
00378   
00379   new_y = new_top;
00380   scaled_new_y = scaled_ystep * gfi->top;
00381   
00382   for (j = 0; j < gfi->height; j++) {
00383     byte *in_line = gfi->img[j];
00384     byte *out_data;
00385     int x_delta, y_delta, yinc;
00386     
00387     scaled_new_y += scaled_ystep;
00388     /* account for images which should've had 0 height but don't */
00389     if (j == gfi->height - 1) scaled_new_y = SCALE(new_bottom);
00390     
00391     if (scaled_new_y < SCALE(new_y + 1)) continue;
00392     y_delta = UNSCALE(scaled_new_y - SCALE(new_y));
00393     
00394     new_x = new_left;
00395     scaled_new_x = scaled_xstep * gfi->left;
00396     out_data = &new_data[(new_y - new_top) * new_width + (new_x - new_left)];
00397     
00398     for (i = 0; i < gfi->width; i++) {
00399       scaled_new_x += scaled_xstep;
00400       /* account for images which should've had 0 width but don't */
00401       if (i == gfi->width - 1) scaled_new_x = SCALE(new_right);
00402       
00403       x_delta = UNSCALE(scaled_new_x - SCALE(new_x));
00404       
00405       for (; x_delta > 0; new_x++, x_delta--, out_data++)
00406         for (yinc = 0; yinc < y_delta; yinc++)
00407           out_data[yinc * new_width] = in_line[i];
00408     }
00409     
00410     new_y += y_delta;
00411   }
00412   
00413   Gif_ReleaseUncompressedImage(gfi);
00414   Gif_ReleaseCompressedImage(gfi);
00415   gfi->width = new_width;
00416   gfi->height = new_height;
00417   gfi->left = UNSCALE(scaled_xstep * gfi->left);
00418   gfi->top = UNSCALE(scaled_ystep * gfi->top);
00419   Gif_SetUncompressedImage(gfi, new_data, Gif_DeleteArrayFunc, 0);
00420 }

void short_usage void   
 

Definition at line 225 of file gifview.c.

References program_name.

00226 {
00227   fprintf(stderr, "Usage: %s [--display DISPLAY] [OPTION]... [FILE | FRAME]...\n\
00228 Try `%s --help' for more information.\n",
00229           program_name, program_name);
00230 }

void stream_info FILE *   ,
Gif_Stream  ,
const char *   ,
int    colormaps,
int    extensions
 

Definition at line 356 of file support.c.

References Gif_Stream::background, colormap_info(), Gif_Stream::comment, comment_info(), extension_info(), Gif_Stream::extensions, Gif_Stream::global, Gif_Stream::loopcount, Gif_Colormap::ncol, Gif_Extension::next, Gif_Stream::nimages, Gif_Stream::screen_height, Gif_Stream::screen_width, and verbose_endline().

Referenced by output_information().

00358 {
00359   Gif_Extension *gfex;
00360   int n;
00361   
00362   if (!gfs) return;
00363   
00364   verbose_endline();
00365   fprintf(where, "* %s %d image%s\n", (filename ? filename : "<stdin>"),
00366           gfs->nimages, gfs->nimages == 1 ? "" : "s");
00367   fprintf(where, "  logical screen %dx%d\n",
00368           gfs->screen_width, gfs->screen_height);
00369   
00370   if (gfs->global) {
00371     fprintf(where, "  global color table [%d]\n", gfs->global->ncol);
00372     if (colormaps) colormap_info(where, gfs->global, "  |");
00373     fprintf(where, "  background %d\n", gfs->background);
00374   }
00375   
00376   if (gfs->comment)
00377     comment_info(where, gfs->comment, "  end comment ");
00378   
00379   if (gfs->loopcount == 0)
00380     fprintf(where, "  loop forever\n");
00381   else if (gfs->loopcount > 0)
00382     fprintf(where, "  loop count %u\n", (unsigned)gfs->loopcount);
00383   
00384   for (n = 0, gfex = gfs->extensions; gfex; gfex = gfex->next, n++)
00385     if (extensions)
00386       extension_info(where, gfs, gfex, n);
00387   if (n && !extensions)
00388     fprintf(where, "  extensions %d\n", n);
00389 }

void unmark_colors Gif_Colormap  
 

Definition at line 22 of file gifsicledir/merge.c.

References Gif_Colormap::col, i, and Gif_Colormap::ncol.

Referenced by colormap_stream(), and histogram().

00023 {
00024   int i;
00025   if (gfcm)
00026     for (i = 0; i < gfcm->ncol; i++)
00027       gfcm->col[i].haspixel = 0;
00028 }

void unmark_colors_2 Gif_Colormap  
 

Definition at line 31 of file gifsicledir/merge.c.

References Gif_Colormap::col, i, and Gif_Colormap::ncol.

Referenced by merge_frame_interval(), and merge_stream().

00032 {
00033   int i;
00034   for (i = 0; i < gfcm->ncol; i++)
00035     gfcm->col[i].pixel = 256;
00036 }

void usage void   
 

Definition at line 233 of file gifview.c.

00234 {
00235   printf("\
00236 `Gifview' is a lightweight GIF viewer for X. It can display animated GIFs as\n\
00237 slideshows, one frame at a time, or as animations.\n\
00238 \n\
00239 Usage: %s [--display DISPLAY] [OPTION]... [FILE | FRAME]...\n\
00240 \n\
00241 Options are:\n\
00242   -a, --animate                 Animate multiframe GIFs.\n\
00243   -U, --unoptimize              Unoptimize displayed GIFs.\n\
00244   -d, --display DISPLAY         Set display to DISPLAY.\n\
00245       --name NAME               Set application resource name to NAME.\n\
00246   -g, --geometry GEOMETRY       Set window geometry.\n\
00247   -w, --window WINDOW           Show GIF in existing WINDOW.\n\
00248   -i, --install-colormap        Use a private colormap.\n\
00249   --bg, --background COLOR      Use COLOR for transparent pixels.\n\
00250   +e, --no-interactive          Ignore buttons and keystrokes.\n\
00251       --help                    Print this message and exit.\n\
00252       --version                 Print version number and exit.\n\
00253 \n\
00254 Frame selections:               #num, #num1-num2, #num1-, #name\n\
00255 \n\
00256 Keystrokes:\n\
00257   [Space] Go to next frame.             [B] Go to previous frame.\n\
00258   [R]/[<] Go to first frame.            [>] Go to last frame.\n\
00259   [ESC] Stop animation.                 [S]/[A] Toggle animation.\n\
00260   [U] Toggle unoptimization.            [Backspace]/[W] Delete window.\n\
00261   [Q] Quit.\n\
00262 \n\
00263 Left mouse button goes to next frame, right mouse button deletes window.\n\
00264 \n\
00265 Report bugs to <eddietwo@lcs.mit.edu>.\n", program_name);
00266 }

void verbose_close char   
 

Definition at line 222 of file support.c.

References close(), and verbose_pos.

Referenced by input_done(), input_stream(), merge_and_write_frames(), and read_colormap_file().

00223 {
00224   fputc(close, stderr);
00225   verbose_pos++;
00226 }

void verbose_endline void   
 

Definition at line 230 of file support.c.

References verbose_pos.

Referenced by clp_error_handler(), image_info(), main(), stream_info(), and verror().

00231 {
00232   if (verbose_pos) {
00233     fputc('\n', stderr);
00234     fflush(stderr);
00235     verbose_pos = 0;
00236   }
00237 }

void verbose_open char   ,
const char *   
 

Definition at line 204 of file support.c.

References l, name, and verbose_pos.

Referenced by input_stream(), merge_and_write_frames(), and read_colormap_file().

00205 {
00206   int l = strlen(name);
00207   if (verbose_pos && verbose_pos + 3 + l > 79) {
00208     fputc('\n', stderr);
00209     verbose_pos = 0;
00210   }
00211   if (verbose_pos) {
00212     fputc(' ', stderr);
00213     verbose_pos++;
00214   }
00215   fputc(open, stderr);
00216   fputs(name, stderr);
00217   verbose_pos += 1 + l;
00218 }

void warncontext char *    message,
...   
 

Definition at line 86 of file support.c.

References verror().

Referenced by do_colormap_change(), find_background(), input_stream(), merge_colormap_if_possible(), print_useless_options(), and redundant_option_warning().

00087 {
00088   va_list val;
00089   va_start(val, message);
00090   verror(0, message, val);
00091   va_end(val);
00092 }

void warning char *    message,
...   
 

Definition at line 215 of file gifview.c.

References verror().

Referenced by colormap_diversity(), colormap_median_cut(), find_background(), input_stream(), merge_colormap_if_possible(), new_viewer(), parse_geometry(), pipe_color_transformer(), print_useless_options(), read_colormap_file(), and redundant_option_warning().

00216 {
00217   va_list val;
00218   va_start(val, message);
00219   fprintf(stderr, "%s: warning: ", program_name);
00220   vfprintf(stderr, message, val);
00221   fputc('\n', stderr);
00222 }

Variable Documentation

Gt_Frame def_frame
 

Definition at line 254 of file gifsicle.h.

int dimensions_x
 

Definition at line 227 of file gifsicle.h.

Referenced by parse_dimensions(), and parse_rectangle().

int dimensions_y
 

Definition at line 228 of file gifsicle.h.

Referenced by parse_dimensions(), and parse_rectangle().

int error_count
 

Definition at line 125 of file gifsicle.h.

Referenced by verror().

int frame_spec_1
 

Definition at line 224 of file gifsicle.h.

Referenced by parse_frame_spec().

int frame_spec_2
 

Definition at line 225 of file gifsicle.h.

Referenced by parse_frame_spec().

char* frame_spec_name
 

Definition at line 226 of file gifsicle.h.

Referenced by parse_frame_spec().

int gif_read_flags
 

Definition at line 127 of file gifsicle.h.

Referenced by input_stream(), and main().

int gif_write_flags
 

Definition at line 128 of file gifsicle.h.

Referenced by main(), and write_stream().

Gif_Stream* input
 

Definition at line 244 of file gifsicle.h.

char* input_name
 

Definition at line 245 of file gifsicle.h.

Referenced by input_stream().

int no_warnings
 

Definition at line 126 of file gifsicle.h.

Gif_Color parsed_color
 

Definition at line 231 of file gifsicle.h.

Gif_Color parsed_color2
 

Definition at line 232 of file gifsicle.h.

double parsed_scale_factor_x
 

Definition at line 233 of file gifsicle.h.

Referenced by parse_scale_factor().

double parsed_scale_factor_y
 

Definition at line 234 of file gifsicle.h.

Referenced by parse_scale_factor().

int position_x
 

Definition at line 229 of file gifsicle.h.

Referenced by parse_position(), and parse_rectangle().

int position_y
 

Definition at line 230 of file gifsicle.h.

Referenced by parse_position(), and parse_rectangle().

const char* program_name
 

Definition at line 123 of file gifsicle.h.

Referenced by short_usage(), usage(), and verror().

int verbosing
 

Definition at line 124 of file gifsicle.h.

Referenced by main().

int warn_local_colormaps
 

Definition at line 164 of file gifsicle.h.

Referenced by merge_and_write_frames().

 

Powered by Plone

This site conforms to the following standards: