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.c

Go to the documentation of this file.
00001 /* gifsicle.c - gifsicle's main loop.
00002    Copyright (C) 1997-2001 Eddie Kohler, eddietwo@lcs.mit.edu
00003    This file is part of gifsicle.
00004 
00005    Gifsicle is free software. It is distributed under the GNU Public License,
00006    version 2 or later; you can copy, distribute, or alter it at will, as long
00007    as this notice is kept intact and this source code is made available. There
00008    is no warranty, express or implied. */
00009 
00010 #include "config.h"
00011 #include "gifsicle.h"
00012 #include <string.h>
00013 #include <stdio.h>
00014 #include <stdlib.h>
00015 #include <ctype.h>
00016 #include <assert.h>
00017 #include <errno.h>
00018 
00019 /* Need _setmode under MS-DOS, to set stdin/stdout to binary mode */
00020 /* Need _fsetmode under OS/2 for the same reason */
00021 #if defined(_MSDOS) || defined(_WIN32) || defined(__EMX__)
00022 # include <fcntl.h>
00023 # include <io.h>
00024 #endif
00025 
00026 
00027 Gt_Frame def_frame;
00028 
00029 Gt_Frameset *frames = 0;
00030 int first_input_frame = 0;
00031 Gt_Frameset *nested_frames = 0;
00032 
00033 Gif_Stream *input = 0;
00034 char *input_name = 0;
00035 static int unoptimizing = 0;
00036 
00037 int gif_read_flags = 0;
00038 int gif_write_flags = 0;
00039 
00040 static int frames_done = 0;
00041 static int files_given = 0;
00042 
00043 int warn_local_colormaps = 1;
00044 
00045 static Gt_ColorTransform *input_transforms;
00046 static Gt_ColorTransform *output_transforms;
00047 
00048 #define BLANK_MODE      0
00049 #define MERGING         1
00050 #define BATCHING        2
00051 #define EXPLODING       3
00052 #define DELETING        4
00053 #define INSERTING       5
00054 static int mode = BLANK_MODE;
00055 static int nested_mode = 0;
00056 
00057 static int infoing = 0;
00058 int verbosing = 0;
00059 
00060 
00061 #define CHANGED(next, flag)     (((next) & 1<<(flag)) != 0)
00062 #define UNCHECKED_MARK_CH(where, what)                  \
00063   next_##where |= 1<<what;
00064 #define MARK_CH(where, what)                            \
00065   if (CHANGED(next_##where, what))                      \
00066     redundant_option_warning(where##_option_types[what]); \
00067   UNCHECKED_MARK_CH(where, what)
00068 
00069 /* frame option types */
00070 static int next_frame = 0;
00071 #define CH_INTERLACE            0
00072 #define CH_DISPOSAL             1
00073 #define CH_DELAY                2
00074 #define CH_TRANSPARENT          3
00075 #define CH_COMMENT              4
00076 #define CH_NAME                 5
00077 #define CH_POSITION             6
00078 #define CH_CROP                 7
00079 #define CH_EXTENSION            8
00080 #define CH_FLIP                 9
00081 #define CH_ROTATE               10
00082 static const char *frame_option_types[] = {
00083   "interlace", "disposal", "delay", "transparency",
00084   "comment", "name", "position", "crop",
00085   "extension", "flip", "rotation"
00086 };
00087 
00088 /* input option types */
00089 static int next_input = 0;
00090 #define CH_UNOPTIMIZE           0
00091 #define CH_CHANGE_COLOR         1
00092 static const char *input_option_types[] = {
00093   "unoptimization", "color change"
00094 };
00095 
00096 /* output option types */
00097 static Gt_OutputData def_output_data;
00098 static Gt_OutputData active_output_data;
00099 static int next_output = 0;
00100 static int active_next_output = 0;
00101 static int any_output_successful = 0;
00102 #define CH_LOOPCOUNT            0
00103 #define CH_LOGICAL_SCREEN       1
00104 #define CH_OPTIMIZE             2
00105 #define CH_OUTPUT               3
00106 #define CH_COLORMAP             4
00107 #define CH_DITHER               5
00108 #define CH_USE_COLORMAP         6
00109 #define CH_COLORMAP_METHOD      7
00110 #define CH_BACKGROUND           8
00111 #define CH_COLOR_TRANSFORM      9
00112 #define CH_RESIZE               10
00113 static const char *output_option_types[] = {
00114   "loopcount", "logical screen", "optimization", "output file",
00115   "colormap size", "dither", "colormap", "colormap method",
00116   "background", "color transformation", "resize"
00117 };
00118 
00119 
00120 #define SAME_INTERLACE_OPT      300
00121 #define INFO_OPT                301
00122 #define DISPOSAL_OPT            302
00123 #define SAME_LOOPCOUNT_OPT      303
00124 #define SAME_DISPOSAL_OPT       304
00125 #define SAME_DELAY_OPT          305
00126 #define SAME_TRANSPARENT_OPT    308
00127 #define LOGICAL_SCREEN_OPT      309
00128 #define COMMENT_OPT             310
00129 #define UNOPTIMIZE_OPT          311
00130 #define CAREFUL_OPT             312
00131 #define OPTIMIZE_OPT            313
00132 #define SAME_LOGICAL_SCREEN_OPT 314
00133 #define DELETE_OPT              315
00134 #define REPLACE_OPT             316
00135 #define INSERT_OPT              317
00136 #define ALTER_DONE_OPT          318
00137 #define APPEND_OPT              319
00138 #define COLOR_INFO_OPT          320
00139 #define VERBOSE_OPT             321
00140 #define NO_COMMENTS_OPT         322
00141 #define SAME_COMMENTS_OPT       323
00142 #define NAME_OPT                324
00143 #define SAME_NAME_OPT           325
00144 #define NO_NAME_OPT             326
00145 #define POSITION_OPT            327
00146 #define SAME_POSITION_OPT       328
00147 #define VERSION_OPT             329
00148 #define HELP_OPT                330
00149 #define OUTPUT_OPT              331
00150 #define CROP_OPT                332
00151 #define SAME_CROP_OPT           333
00152 #define CHANGE_COLOR_OPT        334
00153 #define COLORMAP_OPT            335
00154 #define COLORMAP_ALGORITHM_OPT  336
00155 #define DITHER_OPT              337
00156 #define USE_COLORMAP_OPT        338
00157 #define NO_EXTENSIONS_OPT       339
00158 #define SAME_EXTENSIONS_OPT     340
00159 #define EXTENSION_INFO_OPT      341
00160 #define BACKGROUND_OPT          342
00161 #define SAME_BACKGROUND_OPT     343
00162 #define FLIP_HORIZ_OPT          344
00163 #define FLIP_VERT_OPT           345
00164 #define NO_FLIP_OPT             346
00165 #define ROTATE_90_OPT           347
00166 #define ROTATE_180_OPT          348
00167 #define ROTATE_270_OPT          349
00168 #define NO_ROTATE_OPT           350
00169 #define APP_EXTENSION_OPT       351
00170 #define EXTENSION_OPT           352
00171 #define COLOR_TRANSFORM_OPT     353
00172 #define RESIZE_OPT              354
00173 #define SCALE_OPT               355
00174 #define NO_WARNINGS_OPT         356
00175 #define WARNINGS_OPT            357
00176 #define RESIZE_WIDTH_OPT        358
00177 #define RESIZE_HEIGHT_OPT       359
00178 
00179 #define LOOP_TYPE               (Clp_MaxDefaultType + 1)
00180 #define DISPOSAL_TYPE           (Clp_MaxDefaultType + 2)
00181 #define DIMENSIONS_TYPE         (Clp_MaxDefaultType + 3)
00182 #define FRAME_SPEC_TYPE         (Clp_MaxDefaultType + 4)
00183 #define COLOR_TYPE              (Clp_MaxDefaultType + 5)
00184 #define POSITION_TYPE           (Clp_MaxDefaultType + 6)
00185 #define RECTANGLE_TYPE          (Clp_MaxDefaultType + 7)
00186 #define TWO_COLORS_TYPE         (Clp_MaxDefaultType + 8)
00187 #define COLORMAP_ALG_TYPE       (Clp_MaxDefaultType + 9)
00188 #define SCALE_FACTOR_TYPE       (Clp_MaxDefaultType + 10)
00189 
00190 Clp_Option options[] = {
00191   
00192   { "append", 0, APPEND_OPT, 0, 0 },
00193   { "app-extension", 'x', APP_EXTENSION_OPT, Clp_ArgString, 0 },
00194   
00195   { "background", 'B', BACKGROUND_OPT, COLOR_TYPE, Clp_Negate },
00196   { "batch", 'b', 'b', 0, 0 },
00197   { "bg", 0, BACKGROUND_OPT, COLOR_TYPE, Clp_Negate },
00198 
00199   { "careful", 0, CAREFUL_OPT, 0, Clp_Negate },
00200   { "change-color", 0, CHANGE_COLOR_OPT, TWO_COLORS_TYPE, Clp_Negate },
00201   { "cinfo", 0, COLOR_INFO_OPT, 0, Clp_Negate },
00202   { "clip", 0, CROP_OPT, RECTANGLE_TYPE, Clp_Negate },
00203   { "colors", 'k', COLORMAP_OPT, Clp_ArgInt, Clp_Negate },
00204   { "color-method", 0, COLORMAP_ALGORITHM_OPT, COLORMAP_ALG_TYPE, 0 },
00205   { "color-info", 0, COLOR_INFO_OPT, 0, Clp_Negate },
00206   { "comment", 'c', COMMENT_OPT, Clp_ArgString, 0 },
00207   { "no-comments", 'c', NO_COMMENTS_OPT, 0, Clp_OnlyNegated },
00208   { "crop", 0, CROP_OPT, RECTANGLE_TYPE, Clp_Negate },
00209   
00210   { "delay", 'd', 'd', Clp_ArgInt, Clp_Negate },
00211   { "delete", 0, DELETE_OPT, 0, 0 },
00212   { "disposal", 'D', DISPOSAL_OPT, DISPOSAL_TYPE, Clp_Negate },
00213   { "dither", 'f', DITHER_OPT, 0, Clp_Negate },
00214   { "done", 0, ALTER_DONE_OPT, 0, 0 },
00215   
00216   { "explode", 'e', 'e', 0, 0 },
00217   { "explode-by-name", 'E', 'E', 0, 0 },
00218   { "extension", 0, EXTENSION_OPT, Clp_ArgString, 0 },
00219   { "no-extensions", 'x', NO_EXTENSIONS_OPT, 0, 0 },
00220   { "extension-info", 0, EXTENSION_INFO_OPT, 0, Clp_Negate },
00221   
00222   { "flip-horizontal", 0, FLIP_HORIZ_OPT, 0, Clp_Negate },
00223   { "flip-vertical", 0, FLIP_VERT_OPT, 0, Clp_Negate },
00224   { "no-flip", 0, NO_FLIP_OPT, 0, 0 },
00225   
00226   { "help", 'h', HELP_OPT, 0, 0 },
00227   
00228   { "info", 'I', INFO_OPT, 0, Clp_Negate },  
00229   { "insert-before", 0, INSERT_OPT, FRAME_SPEC_TYPE, 0 },
00230   { "interlace", 'i', 'i', 0, Clp_Negate },
00231   
00232   { "logical-screen", 'S', LOGICAL_SCREEN_OPT, DIMENSIONS_TYPE, Clp_Negate },
00233   { "loopcount", 'l', 'l', LOOP_TYPE, Clp_Optional | Clp_Negate },
00234   
00235   { "merge", 'm', 'm', 0, 0 },
00236   { "method", 0, COLORMAP_ALGORITHM_OPT, COLORMAP_ALG_TYPE, 0 },
00237   
00238   { "name", 'n', NAME_OPT, Clp_ArgString, 0 },
00239   { "no-names", 'n', NO_NAME_OPT, 0, Clp_OnlyNegated },
00240   
00241   { "optimize", 'O', OPTIMIZE_OPT, Clp_ArgInt, Clp_Negate | Clp_Optional },
00242   { "output", 'o', OUTPUT_OPT, Clp_ArgStringNotOption, 0 },
00243   
00244   { "position", 'p', POSITION_OPT, POSITION_TYPE, Clp_Negate },
00245   
00246   { "replace", 0, REPLACE_OPT, FRAME_SPEC_TYPE, 0 },
00247   { "resize", 0, RESIZE_OPT, DIMENSIONS_TYPE, Clp_Negate },
00248   { "resize-width", 0, RESIZE_WIDTH_OPT, Clp_ArgUnsigned, Clp_Negate },
00249   { "resize-height", 0, RESIZE_HEIGHT_OPT, Clp_ArgUnsigned, Clp_Negate },
00250   { "resiz", 0, RESIZE_OPT, DIMENSIONS_TYPE, Clp_Negate },
00251   { "resi", 0, RESIZE_OPT, DIMENSIONS_TYPE, Clp_Negate },
00252   { "res", 0, RESIZE_OPT, DIMENSIONS_TYPE, Clp_Negate },
00253   { "rotate-90", 0, ROTATE_90_OPT, 0, 0 },
00254   { "rotate-180", 0, ROTATE_180_OPT, 0, 0 },
00255   { "rotate-270", 0, ROTATE_270_OPT, 0, 0 },
00256   { "no-rotate", 0, NO_ROTATE_OPT, 0, 0 },
00257 
00258   { "scale", 0, SCALE_OPT, SCALE_FACTOR_TYPE, Clp_Negate },
00259   { "screen", 0, LOGICAL_SCREEN_OPT, DIMENSIONS_TYPE, Clp_Negate },
00260   { "same-background", 0, SAME_BACKGROUND_OPT, 0, 0 },
00261   { "same-bg", 0, SAME_BACKGROUND_OPT, 0, 0 },
00262   { "same-clip", 0, SAME_CROP_OPT, 0, 0 },
00263   { "same-comments", 0, SAME_COMMENTS_OPT, 0, 0 },
00264   { "same-crop", 0, SAME_CROP_OPT, 0, 0 },
00265   { "same-extensions", 0, SAME_EXTENSIONS_OPT, 0, 0 },
00266   { "same-interlace", 0, SAME_INTERLACE_OPT, 0, 0 },
00267   { "same-logical-screen", 0, SAME_LOGICAL_SCREEN_OPT, 0, 0 },
00268   { "same-loopcount", 0, SAME_LOOPCOUNT_OPT, 0, 0 },
00269   { "same-disposal", 0, SAME_DISPOSAL_OPT, 0, 0 },
00270   { "same-delay", 0, SAME_DELAY_OPT, 0, 0 },
00271   { "same-names", 0, SAME_NAME_OPT, 0, 0 },
00272   { "same-position", 0, SAME_POSITION_OPT, 0, 0 },
00273   { "same-screen", 0, SAME_LOGICAL_SCREEN_OPT, 0, 0 },
00274   { "same-transparent", 0, SAME_TRANSPARENT_OPT, 0, 0 },
00275   
00276   { "transform-colormap", 0, COLOR_TRANSFORM_OPT, Clp_ArgStringNotOption,
00277     Clp_Negate },
00278   { "transparent", 't', 't', COLOR_TYPE, Clp_Negate },
00279   
00280   { "unoptimize", 'U', UNOPTIMIZE_OPT, 0, Clp_Negate },
00281   { "use-colormap", 0, USE_COLORMAP_OPT, Clp_ArgString, Clp_Negate },
00282   
00283   { "verbose", 'v', VERBOSE_OPT, 0, Clp_Negate },
00284   { "version", 0, VERSION_OPT, 0, 0 },
00285   
00286   { 0, 'w', NO_WARNINGS_OPT, 0, Clp_Negate },
00287   { "warnings", 0, WARNINGS_OPT, 0, Clp_Negate },
00288   
00289   { "xinfo", 0, EXTENSION_INFO_OPT, 0, Clp_Negate },
00290   
00291 };
00292 
00293 
00294 static void combine_output_options(void);
00295 static void initialize_def_frame(void);
00296 static void redundant_option_warning(const char *);
00297 
00298 
00299 static void
00300 set_mode(int newmode)
00301 {
00302   if (mode == BLANK_MODE)
00303     mode = newmode;
00304   else if (mode == newmode)
00305     ;
00306   else
00307     fatal_error("too late to change modes");
00308 }
00309 
00310 
00311 void
00312 set_frame_change(int kind)
00313 {
00314   int i;
00315   Gt_Frameset *fset;
00316   
00317   if (mode == BLANK_MODE)
00318     set_mode(MERGING);
00319   if (mode < DELETING && frames_done) {
00320     fatal_error("frame selection and frame changes don't mix");
00321     return;
00322   }
00323   assert(!nested_mode);
00324   nested_mode = mode;
00325   
00326   switch (kind) {
00327     
00328    case DELETE_OPT:
00329     mode = DELETING;
00330     break;
00331     
00332    case REPLACE_OPT:
00333     for (i = frame_spec_1; i < frame_spec_2; i++)
00334       FRAME(frames, i).use = 0;
00335     /* We want to use the last frame's delay, but nothing else about it. */
00336     FRAME(frames, i).use = -1;
00337     /* FALLTHRU */
00338     
00339    case INSERT_OPT:
00340     /* Define a nested frameset (or use an existing one). */
00341     fset = FRAME(frames, frame_spec_2).nest;
00342     if (!fset) fset = new_frameset(8);
00343     FRAME(frames, frame_spec_2).nest = fset;
00344     
00345     /* Later: Merge frames at the end of the nested frameset. */
00346     mode = INSERTING;
00347     nested_frames = frames;
00348     frames = fset;
00349     break;
00350     
00351    case APPEND_OPT:
00352     /* Just merge frames at the end of this frameset. */
00353     mode = INSERTING;
00354     break;
00355     
00356   }
00357 }
00358 
00359 void
00360 frame_change_done(void)
00361 {
00362   if (nested_mode)
00363     mode = nested_mode;
00364   if (nested_frames)
00365     frames = nested_frames;
00366   nested_mode = 0;
00367   nested_frames = 0;
00368 }
00369 
00370 
00371 void
00372 show_frame(int imagenumber, int usename)
00373 {
00374   Gif_Image *gfi;
00375   Gt_Frame *frame;
00376   
00377   if (!input) return;
00378   gfi = Gif_GetImage(input, imagenumber);
00379   if (!gfi) return;
00380   
00381   switch (mode) {
00382     
00383    case MERGING:
00384    case INSERTING:
00385    case EXPLODING:
00386     if (!frames_done) clear_frameset(frames, first_input_frame);
00387     frame = add_frame(frames, -1, input, gfi);
00388     if (usename) frame->explode_by_name = 1;
00389     break;
00390     
00391    case BATCHING:
00392     add_frame(frames, first_input_frame + imagenumber, input, gfi);
00393     break;
00394     
00395    case DELETING:
00396     frame = &FRAME(frames, first_input_frame + imagenumber);
00397     frame->use = 0;
00398     break;
00399     
00400   }
00401   
00402   next_frame = 0;
00403   frames_done = 1;
00404 }
00405 
00406 
00407 /*****
00408  * input a stream
00409  **/
00410 
00411 static int gifread_error_count;
00412 
00413 static void
00414 gifread_error(const char *message, int which_image, void *thunk)
00415 {
00416   static int last_which_image = 0;
00417   static char last_message[256];
00418   static int different_error_count = 0;
00419   static int same_error_count = 0;
00420   const char *filename = (const char *)thunk;
00421   
00422   if (gifread_error_count == 0) {
00423     last_which_image = -1;
00424     last_message[0] = 0;
00425     different_error_count = 0;
00426   }
00427   
00428   gifread_error_count++;
00429   if (last_message[0] && different_error_count <= 10
00430       && (last_which_image != which_image || message == 0
00431           || strcmp(message, last_message) != 0)) {
00432     if (same_error_count == 1)
00433       error("  %s", last_message);
00434     else if (same_error_count > 0)
00435       error("  %s (%d times)", last_message, same_error_count);
00436     same_error_count = 0;
00437     last_message[0] = 0;
00438   }
00439 
00440   if (last_message[0] == 0)
00441     different_error_count++;
00442   
00443   same_error_count++;
00444   if (message)
00445     strcpy(last_message, message);
00446   else
00447     last_message[0] = 0;
00448   if (last_which_image != which_image && different_error_count <= 10
00449       && message) {
00450     error("Error while reading `%s' frame #%d:", filename, which_image);
00451     last_which_image = which_image;
00452   }
00453   
00454   if (different_error_count == 11 && message) {
00455     error("(more errors while reading `%s')", filename);
00456     different_error_count++;
00457   }
00458 }
00459 
00460 void
00461 input_stream(char *name)
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 }
00586 
00587 void
00588 input_done(void)
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 }
00611 
00612 
00613 /*****
00614  * colormap stuff
00615  **/
00616 
00617 static void
00618 set_new_fixed_colormap(char *name)
00619 {
00620   int i;
00621   if (name && strcmp(name, "web") == 0) {
00622     Gif_Colormap *cm = Gif_NewFullColormap(216, 256);
00623     Gif_Color *col = cm->col;
00624     for (i = 0; i < 216; i++) {
00625       col[i].red = (i / 36) * 0x33;
00626       col[i].green = ((i / 6) % 6) * 0x33;
00627       col[i].blue = (i % 6) * 0x33;
00628     }
00629     def_output_data.colormap_fixed = cm;
00630     
00631   } else if (name && (strcmp(name, "gray") == 0
00632                       || strcmp(name, "grey") == 0)) {
00633     Gif_Colormap *cm = Gif_NewFullColormap(256, 256);
00634     Gif_Color *col = cm->col;
00635     for (i = 0; i < 256; i++)
00636       col[i].red = col[i].green = col[i].blue = i;
00637     def_output_data.colormap_fixed = cm;
00638     
00639   } else if (name && strcmp(name, "bw") == 0) {
00640     Gif_Colormap *cm = Gif_NewFullColormap(2, 256);
00641     cm->col[0].red = cm->col[0].green = cm->col[0].blue = 0;
00642     cm->col[1].red = cm->col[1].green = cm->col[1].blue = 255;
00643     def_output_data.colormap_fixed = cm;
00644     
00645   } else
00646     def_output_data.colormap_fixed = read_colormap_file(name, 0);
00647 }
00648 
00649 static void
00650 do_set_colormap(Gif_Stream *gfs, Gif_Colormap *gfcm)
00651 {
00652   colormap_image_func image_func;
00653   if (active_output_data.colormap_dither)
00654     image_func = colormap_image_floyd_steinberg;
00655   else
00656     image_func = colormap_image_posterize;
00657   colormap_stream(gfs, gfcm, image_func);
00658 }
00659 
00660 static void
00661 do_colormap_change(Gif_Stream *gfs)
00662 {
00663   if (active_output_data.colormap_fixed)
00664     do_set_colormap(gfs, active_output_data.colormap_fixed);
00665   
00666   if (active_output_data.colormap_size > 0) {
00667     int nhist;
00668     Gif_Color *hist;
00669     Gif_Colormap *(*adapt_func)(Gif_Color *, int, int);
00670     Gif_Colormap *new_cm;
00671     
00672     /* set up the histogram */
00673     {
00674       int i, any_locals = 0;
00675       for (i = 0; i < gfs->nimages; i++)
00676         if (gfs->images[i]->local)
00677           any_locals = 1;
00678       hist = histogram(gfs, &nhist);
00679       if (nhist <= active_output_data.colormap_size && !any_locals) {
00680         warncontext("trivial adaptive palette (only %d colors in source)", nhist);
00681         return;
00682       }
00683     }
00684     
00685     switch (active_output_data.colormap_algorithm) {
00686       
00687      case COLORMAP_DIVERSITY:
00688       adapt_func = &colormap_flat_diversity;
00689       break;
00690       
00691      case COLORMAP_BLEND_DIVERSITY:
00692       adapt_func = &colormap_blend_diversity;
00693       break;
00694       
00695      case COLORMAP_MEDIAN_CUT:
00696       adapt_func = &colormap_median_cut;
00697       break;
00698       
00699      default:
00700       fatal_error("can't happen");
00701       
00702     }
00703     
00704     new_cm = (*adapt_func)(hist, nhist, active_output_data.colormap_size);
00705     do_set_colormap(gfs, new_cm);
00706     
00707     Gif_DeleteArray(hist);
00708     Gif_DeleteColormap(new_cm);
00709   }
00710 }
00711 
00712 
00713 /*****
00714  * output GIF images
00715  **/
00716 
00717 static void
00718 write_stream(char *output_name, Gif_Stream *gfs)
00719 {
00720   FILE *f;
00721   
00722   if (output_name)
00723     f = fopen(output_name, "wb");
00724   else {
00725 #ifndef OUTPUT_GIF_TO_TERMINAL
00726     extern int isatty(int);
00727     if (isatty(fileno(stdout))) {
00728       error("not writing to <stdout>: it's a terminal");
00729       return;
00730     }
00731 #endif
00732 #if defined(_MSDOS) || defined(_WIN32)
00733     _setmode(_fileno(stdout), _O_BINARY);
00734 #elif defined(__EMX__)
00735     _fsetmode(stdout, "b");
00736 #endif
00737     f = stdout;
00738     output_name = "<stdout>";
00739   }
00740   
00741   if (f) {
00742     Gif_FullWriteFile(gfs, gif_write_flags, f);
00743     fclose(f);
00744     any_output_successful = 1;
00745   } else
00746     error("%s: %s", output_name, strerror(errno));
00747 }
00748 
00749 static void
00750 merge_and_write_frames(char *outfile, int f1, int f2)
00751 {
00752   Gif_Stream *out;
00753   int compress_immediately;
00754   int colormap_change;
00755   assert(!nested_mode);
00756   if (verbosing) verbose_open('[', outfile ? outfile : "#stdout#");
00757   
00758   colormap_change = active_output_data.colormap_size > 0
00759     || active_output_data.colormap_fixed;
00760   compress_immediately = !colormap_change
00761     && active_output_data.scaling == 0
00762     && active_output_data.optimizing <= 0;
00763   warn_local_colormaps = !colormap_change;
00764   
00765   out = merge_frame_interval(frames, f1, f2, &active_output_data,
00766                              compress_immediately);
00767   
00768   if (out) {
00769     if (active_output_data.scaling == 1)
00770       resize_stream(out, active_output_data.resize_width,
00771                     active_output_data.resize_height);
00772     else if (active_output_data.scaling == 2)
00773       resize_stream(out, active_output_data.scale_x * out->screen_width,
00774                     active_output_data.scale_y * out->screen_height);
00775     if (colormap_change)
00776       do_colormap_change(out);
00777     if (output_transforms)
00778       apply_color_transforms(output_transforms, out);
00779     if (active_output_data.optimizing > 0)
00780       optimize_fragments(out, active_output_data.optimizing);
00781     write_stream(outfile, out);
00782     Gif_DeleteStream(out);
00783   }
00784   
00785   if (verbosing) verbose_close(']');
00786 }
00787 
00788 static void
00789 output_information(const char *outfile)
00790 {
00791   FILE *f;
00792   int i, j;
00793   Gt_Frame *fr;
00794   Gif_Stream *gfs;
00795   
00796   if (infoing == 2)
00797     f = stderr;
00798   else if (outfile == 0)
00799     f = stdout;
00800   else {
00801     f = fopen(outfile, "w");
00802     if (!f) {
00803       error("%s: %s", outfile, strerror(errno));
00804       return;
00805     }
00806   }
00807   
00808   for (i = 0; i < frames->count; i++)
00809     FRAME(frames, i).stream->userflags = 97;
00810 
00811   for (i = 0; i < frames->count; i++)
00812     if (FRAME(frames, i).stream->userflags == 97) {
00813       fr = &FRAME(frames, i);
00814       gfs = fr->stream;
00815       gfs->userflags = 0;
00816       stream_info(f, gfs, fr->input_filename, fr->colormap_info,
00817                   fr->extensions_info);
00818       for (j = i; j < frames->count; j++)
00819         if (FRAME(frames, j).stream == gfs) {
00820           fr = &FRAME(frames, j);
00821           image_info(f, gfs, fr->image, fr->colormap_info);
00822         }
00823     }
00824   
00825   if (f != stderr && f != stdout)
00826     fclose(f);
00827 }
00828 
00829 void
00830 output_frames(void)
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 }
00896 
00897 
00898 /*****
00899  * parsing arguments
00900  **/
00901 
00902 int
00903 frame_argument(Clp_Parser *clp, char *arg)
00904 {
00905   /* Returns 0 iff you should try a file named `arg'. */
00906   int val = parse_frame_spec(clp, arg, -1, 0);
00907   if (val == -97)
00908     return 0;
00909   else if (val > 0) {
00910     int i;
00911     for (i = frame_spec_1; i <= frame_spec_2; i++)
00912       show_frame(i, frame_spec_name != 0);
00913     if (next_output) combine_output_options();
00914     return 1;
00915   } else
00916     return 1;
00917 }
00918 
00919 static int
00920 handle_extension(Clp_Parser *clp, int is_app)
00921 {
00922   Gif_Extension *gfex;
00923   char *extension_type = clp->arg;
00924   char *extension_body = Clp_Shift(clp, 1);
00925   if (!extension_body) {
00926     Clp_OptionError(clp, "%O requires two arguments");
00927     return 0;
00928   }
00929 
00930   UNCHECKED_MARK_CH(frame, CH_EXTENSION);
00931   if (is_app)
00932     gfex = Gif_NewExtension(255, extension_type);
00933   else if (!isdigit(extension_type[0]) && extension_type[1] == 0)
00934     gfex = Gif_NewExtension(extension_type[0], 0);
00935   else {
00936     long l = strtol(extension_type, &extension_type, 0);
00937     if (*extension_type != 0 || l < 0 || l >= 256)
00938       fatal_error("bad extension type: must be a number between 0 and 255");
00939     gfex = Gif_NewExtension(l, 0);
00940   }
00941   
00942   gfex->data = (byte *)extension_body;
00943   gfex->length = strlen(extension_body);
00944   gfex->next = def_frame.extensions;
00945   def_frame.extensions = gfex;
00946   
00947   return 1;
00948 }
00949 
00950 
00951 /*****
00952  * option processing
00953  **/
00954 
00955 static void
00956 initialize_def_frame(void)
00957 {
00958   /* frame defaults */
00959   def_frame.stream = 0;
00960   def_frame.image = 0;
00961   def_frame.use = 1;
00962   
00963   def_frame.name = 0;
00964   def_frame.no_name = 0;
00965   def_frame.comment = 0;
00966   def_frame.no_comments = 0;
00967   
00968   def_frame.interlacing = -1;
00969   def_frame.transparent.haspixel = 0;
00970   def_frame.left = -1;
00971   def_frame.top = -1;
00972   def_frame.position_is_offset = 0;
00973   
00974   def_frame.crop = 0;
00975   
00976   def_frame.delay = -1;
00977   def_frame.disposal = -1;
00978   
00979   def_frame.nest = 0;
00980   def_frame.explode_by_name = 0;
00981   
00982   def_frame.no_extensions = 0;
00983   def_frame.extensions = 0;
00984   
00985   def_frame.flip_horizontal = 0;
00986   def_frame.flip_vertical = 0;
00987   
00988   /* output defaults */
00989   def_output_data.output_name = 0;
00990   
00991   def_output_data.screen_width = -1;
00992   def_output_data.screen_height = -1;
00993   def_output_data.background.haspixel = 0;
00994   def_output_data.loopcount = -2;
00995   
00996   def_output_data.colormap_size = 0;
00997   def_output_data.colormap_fixed = 0;
00998   def_output_data.colormap_algorithm = COLORMAP_DIVERSITY;
00999   def_output_data.colormap_dither = 0;
01000   
01001   def_output_data.optimizing = 0;
01002   def_output_data.scaling = 0;
01003   
01004   active_output_data = def_output_data;
01005 }
01006 
01007 static void
01008 combine_output_options(void)
01009 {
01010   int recent = next_output;
01011   next_output = active_next_output;
01012 #define COMBINE_ONE_OUTPUT_OPTION(value, field)         \
01013   if (CHANGED(recent, value)) {                         \
01014     MARK_CH(output, value);                             \
01015     active_output_data.field = def_output_data.field;   \
01016   }
01017   
01018   COMBINE_ONE_OUTPUT_OPTION(CH_OUTPUT, output_name);
01019   
01020   if (CHANGED(recent, CH_LOGICAL_SCREEN)) {
01021     MARK_CH(output, CH_LOGICAL_SCREEN);
01022     active_output_data.screen_width = def_output_data.screen_width;
01023     active_output_data.screen_height = def_output_data.screen_height;
01024   }
01025   COMBINE_ONE_OUTPUT_OPTION(CH_BACKGROUND, background);
01026   COMBINE_ONE_OUTPUT_OPTION(CH_LOOPCOUNT, loopcount);
01027   
01028   COMBINE_ONE_OUTPUT_OPTION(CH_OPTIMIZE, optimizing);
01029   COMBINE_ONE_OUTPUT_OPTION(CH_COLORMAP, colormap_size);
01030   COMBINE_ONE_OUTPUT_OPTION(CH_COLORMAP_METHOD, colormap_algorithm);
01031   if (CHANGED(recent, CH_USE_COLORMAP)) {
01032     MARK_CH(output, CH_USE_COLORMAP);
01033     if (def_output_data.colormap_fixed)
01034       def_output_data.colormap_fixed->refcount++;
01035     Gif_DeleteColormap(active_output_data.colormap_fixed);
01036     active_output_data.colormap_fixed = def_output_data.colormap_fixed;
01037   }
01038   COMBINE_ONE_OUTPUT_OPTION(CH_DITHER, colormap_dither);
01039   
01040   if (CHANGED(recent, CH_RESIZE)) {
01041     MARK_CH(output, CH_RESIZE);
01042     active_output_data.scaling = def_output_data.scaling;
01043     active_output_data.resize_width = def_output_data.resize_width;
01044     active_output_data.resize_height = def_output_data.resize_height;
01045     active_output_data.scale_x = def_output_data.scale_x;
01046     active_output_data.scale_y = def_output_data.scale_y;
01047   }
01048   
01049   def_output_data.colormap_fixed = 0;
01050   def_output_data.output_name = 0;
01051   
01052   active_next_output |= next_output;
01053   next_output = 0;
01054 }
01055 
01056 static void
01057 redundant_option_warning(const char *option_type)
01058 {
01059   static int context = 0;
01060   warning("redundant %s option", option_type);
01061   if (!context) {
01062     warncontext("(The %s option was overridden by another %s option",
01063                 option_type, option_type);
01064     warncontext("before it had any effect.)");
01065   }
01066   context = 1;
01067 }
01068 
01069 static void
01070 print_useless_options(const char *type_name, int value, const char *names[])
01071 {
01072   int explanation_printed = 0;
01073   int i;
01074   if (!value) return;
01075   for (i = 0; i < 32; i++)
01076     if (CHANGED(value, i)) {
01077       warning("useless %s-related %s option", names[i], type_name);
01078       if (!explanation_printed)
01079         warncontext("(It didn't affect any %s.)", type_name);
01080       explanation_printed = 1;
01081     }
01082 }
01083 
01084 
01085 /*****
01086  * main
01087  **/
01088 
01089 int
01090 main(int argc, char **argv)
01091 {
01092   Clp_Parser *clp =
01093     Clp_NewParser(argc, argv, sizeof(options) / sizeof(options[0]), options);
01094   
01095   Clp_AddStringListType
01096     (clp, LOOP_TYPE, Clp_AllowNumbers,
01097      "infinite", 0, "forever", 0,
01098      0);
01099   Clp_AddStringListType
01100     (clp, DISPOSAL_TYPE, Clp_AllowNumbers,
01101      "none", GIF_DISPOSAL_NONE,
01102      "asis", GIF_DISPOSAL_ASIS,
01103      "background", GIF_DISPOSAL_BACKGROUND,
01104      "bg", GIF_DISPOSAL_BACKGROUND,
01105      "previous", GIF_DISPOSAL_ASIS,
01106      0);
01107   Clp_AddStringListType
01108     (clp, COLORMAP_ALG_TYPE, 0,
01109      "diversity", COLORMAP_DIVERSITY,
01110      "blend-diversity", COLORMAP_BLEND_DIVERSITY,
01111      "median-cut", COLORMAP_MEDIAN_CUT,
01112      0);
01113   Clp_AddType(clp, DIMENSIONS_TYPE, 0, parse_dimensions, 0);
01114   Clp_AddType(clp, POSITION_TYPE, 0, parse_position, 0);
01115   Clp_AddType(clp, SCALE_FACTOR_TYPE, 0, parse_scale_factor, 0);
01116   Clp_AddType(clp, FRAME_SPEC_TYPE, 0, parse_frame_spec, 0);
01117   Clp_AddType(clp, COLOR_TYPE, Clp_DisallowOptions, parse_color, 0);
01118   Clp_AddType(clp, RECTANGLE_TYPE, 0, parse_rectangle, 0);
01119   Clp_AddType(clp, TWO_COLORS_TYPE, Clp_DisallowOptions, parse_two_colors, 0);
01120   Clp_SetOptionChar(clp, '+', Clp_ShortNegated);
01121   Clp_SetErrorHandler(clp, clp_error_handler);
01122   
01123   program_name = Clp_ProgramName(clp);
01124   
01125   frames = new_frameset(16);
01126   initialize_def_frame();
01127   
01128 #ifdef DMALLOC
01129   dmalloc_verbose("fudge");
01130 #endif
01131   
01132   /* Yep, I'm an idiot.
01133      GIF dimensions are unsigned 16-bit integers. I assume that these
01134      numbers will fit in an `int'. This assertion tests that assumption.
01135      Really I should go through & change everything over, but it doesn't
01136      seem worth my time. */
01137   {
01138     u_int16_t m = 0xFFFFU;
01139     int i = m;
01140     assert(i > 0 && "configuration/lameness failure! bug the author!");
01141   }
01142   
01143   while (1) {
01144     int opt = Clp_Next(clp);
01145     switch (opt) {
01146       
01147       /* MODE OPTIONS */
01148       
01149      case 'b':
01150       set_mode(BATCHING);
01151       break;
01152       
01153      case 'm':
01154       set_mode(MERGING);
01155       break;
01156       
01157      case 'e':
01158       set_mode(EXPLODING);
01159       def_frame.explode_by_name = 0;
01160       break;
01161       
01162      case 'E':
01163       set_mode(EXPLODING);
01164       def_frame.explode_by_name = 1;
01165       break;
01166       
01167       /* INFORMATION OPTIONS */
01168       
01169      case INFO_OPT:
01170       if (clp->negated)
01171         infoing = 0;
01172       else
01173         /* switch between infoing == 1 (suppress regular output) and 2 (don't
01174            suppress) */
01175         infoing = (infoing == 1 ? 2 : 1);
01176       break;
01177       
01178      case COLOR_INFO_OPT:
01179       if (clp->negated)
01180         def_frame.colormap_info = 0;
01181       else {
01182         def_frame.colormap_info = 1;
01183         if (!infoing) infoing = 1;
01184       }
01185       break;
01186       
01187      case EXTENSION_INFO_OPT:
01188       if (clp->negated)
01189         def_frame.extensions_info = 0;
01190       else {
01191         def_frame.extensions_info = 1;
01192         if (!infoing) infoing = 1;
01193       }
01194       break;
01195       
01196      case VERBOSE_OPT:
01197       verbosing = clp->negated ? 0 : 1;
01198       break;
01199       
01200       /* FRAME CHANGE OPTIONS */
01201       
01202      case DELETE_OPT:
01203      case REPLACE_OPT:
01204      case INSERT_OPT:
01205      case APPEND_OPT:
01206       frame_change_done();
01207       set_frame_change(opt);
01208       break;
01209       
01210      case ALTER_DONE_OPT:
01211       frame_change_done();
01212       break;
01213       
01214       /* IMAGE OPTIONS */
01215       
01216      case NAME_OPT:
01217       if (clp->negated) goto no_names;
01218       MARK_CH(frame, CH_NAME);
01219       def_frame.name = clp->arg;
01220       break;
01221       
01222      no_names:
01223      case NO_NAME_OPT:
01224       MARK_CH(frame, CH_NAME);
01225       def_frame.no_name = 1;
01226       def_frame.name = 0;
01227       break;
01228       
01229      case SAME_NAME_OPT:
01230       def_frame.no_name = 0;
01231       def_frame.name = 0;
01232       break;
01233       
01234      case COMMENT_OPT:
01235       if (clp->negated) goto no_comments;
01236       MARK_CH(frame, CH_COMMENT);
01237       if (!def_frame.comment) def_frame.comment = Gif_NewComment();
01238       Gif_AddComment(def_frame.comment, clp->arg, -1);
01239       break;
01240       
01241      no_comments:
01242      case NO_COMMENTS_OPT:
01243       Gif_DeleteComment(def_frame.comment);
01244       def_frame.comment = 0;
01245       def_frame.no_comments = 1;
01246       break;
01247       
01248      case SAME_COMMENTS_OPT:
01249       def_frame.no_comments = 0;
01250       break;
01251       
01252      case 'i':
01253       MARK_CH(frame, CH_INTERLACE);
01254       def_frame.interlacing = clp->negated ? 0 : 1;
01255       break;
01256       
01257      case SAME_INTERLACE_OPT:
01258       def_frame.interlacing = -1;
01259       break;
01260       
01261      case POSITION_OPT:
01262       MARK_CH(frame, CH_POSITION);
01263       def_frame.left = clp->negated ? 0 : position_x;
01264       def_frame.top = clp->negated ? 0 : position_y;
01265       break;
01266       
01267      case SAME_POSITION_OPT:
01268       def_frame.left = -1;
01269       def_frame.top = -1;
01270       break;
01271       
01272      case 't':
01273       MARK_CH(frame, CH_TRANSPARENT);
01274       if (clp->negated)
01275         def_frame.transparent.haspixel = 255;
01276       else {
01277         def_frame.transparent = parsed_color;
01278         def_frame.transparent.haspixel = parsed_color.haspixel ? 2 : 1;
01279       }
01280       break;
01281       
01282      case SAME_TRANSPARENT_OPT:
01283       def_frame.transparent.haspixel = 0;
01284       break;
01285       
01286      case BACKGROUND_OPT:
01287       MARK_CH(output, CH_BACKGROUND);
01288       if (clp->negated) {
01289         def_output_data.background.haspixel = 2;
01290         def_output_data.background.pixel = 0;
01291       } else {
01292         def_output_data.background = parsed_color;
01293         def_output_data.background.haspixel = parsed_color.haspixel ? 2 : 1;
01294       }
01295       break;
01296       
01297      case SAME_BACKGROUND_OPT:
01298       MARK_CH(output, CH_BACKGROUND);
01299       def_output_data.background.haspixel = 0;
01300       break;
01301       
01302      case LOGICAL_SCREEN_OPT:
01303       MARK_CH(output, CH_LOGICAL_SCREEN);
01304       if (clp->negated)
01305         def_output_data.screen_width = def_output_data.screen_height = 0;
01306       else {
01307         def_output_data.screen_width = dimensions_x;
01308         def_output_data.screen_height = dimensions_y;
01309       }
01310       break;
01311       
01312      case SAME_LOGICAL_SCREEN_OPT:
01313       MARK_CH(output, CH_LOGICAL_SCREEN);
01314       def_output_data.screen_width = def_output_data.screen_height = -1;
01315       break;
01316       
01317      case CROP_OPT:
01318       if (clp->negated) goto no_crop;
01319       MARK_CH(frame, CH_CROP);
01320       {
01321         Gt_Crop *crop = Gif_New(Gt_Crop);
01322         /* Memory leak on crops, but this just is NOT a problem. */
01323         crop->ready = 0;
01324         crop->whole_stream = 0;
01325         crop->spec_x = position_x;
01326         crop->spec_y = position_y;
01327         crop->spec_w = dimensions_x;
01328         crop->spec_h = dimensions_y;
01329         def_frame.crop = crop;
01330       }
01331       break;
01332       
01333      no_crop:
01334      case SAME_CROP_OPT:
01335       def_frame.crop = 0;
01336       break;
01337       
01338       /* extensions options */
01339       
01340      case NO_EXTENSIONS_OPT:
01341       def_frame.no_extensions = 1;
01342       break;
01343       
01344      case SAME_EXTENSIONS_OPT:
01345       def_frame.no_extensions = 0;
01346       break;
01347       
01348      case EXTENSION_OPT:
01349       if (!handle_extension(clp, 0))
01350         goto bad_option;
01351       break;
01352       
01353      case APP_EXTENSION_OPT:
01354       if (!handle_extension(clp, 1))
01355         goto bad_option;
01356       break;
01357       
01358       /* IMAGE DATA OPTIONS */
01359       
01360      case FLIP_HORIZ_OPT:
01361       MARK_CH(frame, CH_FLIP);
01362       def_frame.flip_horizontal = !clp->negated;
01363       break;
01364       
01365      case FLIP_VERT_OPT:
01366       MARK_CH(frame, CH_FLIP);
01367       def_frame.flip_vertical = !clp->negated;
01368       break;
01369        
01370      case NO_FLIP_OPT:
01371       def_frame.flip_horizontal = def_frame.flip_vertical = 0;
01372       break;
01373       
01374      case NO_ROTATE_OPT:
01375       def_frame.rotation = 0;
01376       break;
01377        
01378      case ROTATE_90_OPT:
01379       MARK_CH(frame, CH_ROTATE);
01380       def_frame.rotation = 1;
01381       break;
01382        
01383      case ROTATE_180_OPT:
01384       MARK_CH(frame, CH_ROTATE);
01385       def_frame.rotation = 2;
01386       break;
01387       
01388      case ROTATE_270_OPT:
01389       MARK_CH(frame, CH_ROTATE);
01390       def_frame.rotation = 3;
01391       break;
01392        
01393       /* ANIMATION OPTIONS */
01394       
01395      case 'd':
01396       MARK_CH(frame, CH_DELAY);
01397       def_frame.delay = clp->negated ? 0 : clp->val.i;
01398       break;
01399       
01400      case SAME_DELAY_OPT:
01401       def_frame.delay = -1;
01402       break;
01403       
01404      case DISPOSAL_OPT:
01405       MARK_CH(frame, CH_DISPOSAL);
01406       if (clp->negated)
01407         def_frame.disposal = GIF_DISPOSAL_NONE;
01408       else if (clp->val.i < 0 || clp->val.i > 7)
01409         error("disposal must be between 0 and 7");
01410       else
01411         def_frame.disposal = clp->val.i;
01412       break;
01413       
01414      case SAME_DISPOSAL_OPT:
01415       def_frame.disposal = -1;
01416       break;
01417       
01418      case 'l':
01419       MARK_CH(output, CH_LOOPCOUNT);
01420       if (clp->negated)
01421         def_output_data.loopcount = -1;
01422       else
01423         def_output_data.loopcount = (clp->have_arg ? clp->val.i : 0);
01424       break;
01425       
01426      case SAME_LOOPCOUNT_OPT:
01427       MARK_CH(output, CH_LOOPCOUNT);
01428       def_output_data.loopcount = -2;
01429       break;
01430       
01431      case OPTIMIZE_OPT:
01432       MARK_CH(output, CH_OPTIMIZE);
01433       if (clp->negated)
01434         def_output_data.optimizing = 0;
01435       else
01436         def_output_data.optimizing = (clp->have_arg ? clp->val.i : 1);
01437       break;
01438       
01439      case UNOPTIMIZE_OPT:
01440       UNCHECKED_MARK_CH(input, CH_UNOPTIMIZE);
01441       unoptimizing = clp->negated ? 0 : 1;
01442       break;
01443       
01444       /* WHOLE-GIF OPTIONS */
01445 
01446      case CAREFUL_OPT: {
01447        if (clp->negated)
01448          gif_read_flags = gif_write_flags = 0;
01449        else {
01450          gif_read_flags = 0;
01451          gif_write_flags = GIF_WRITE_CAREFUL_MIN_CODE_SIZE;
01452        }
01453        break;
01454      }
01455       
01456      case CHANGE_COLOR_OPT: {
01457        next_input |= CH_CHANGE_COLOR;
01458        if (clp->negated)
01459          input_transforms = delete_color_transforms
01460            (input_transforms, &color_change_transformer);
01461        else if (parsed_color2.haspixel)
01462          error("COLOR2 must be in RGB format in `--change-color COLOR1 COLOR2'");
01463        else
01464          input_transforms = append_color_change
01465            (input_transforms, parsed_color, parsed_color2);
01466        break;
01467      }
01468      
01469      case COLOR_TRANSFORM_OPT:
01470       next_output |= CH_COLOR_TRANSFORM;
01471       if (clp->negated)
01472         output_transforms = delete_color_transforms
01473           (output_transforms, &pipe_color_transformer);
01474       else
01475         output_transforms = append_color_transform
01476           (output_transforms, &pipe_color_transformer, clp->arg);
01477       break;
01478       
01479      case COLORMAP_OPT:
01480       MARK_CH(output, CH_COLORMAP);
01481       if (clp->negated)
01482         def_output_data.colormap_size = 0;
01483       else {
01484         def_output_data.colormap_size = clp->val.i;
01485         if (def_output_data.colormap_size < 2
01486             || def_output_data.colormap_size > 256) {
01487           Clp_OptionError(clp, "argument to `%O' must be between 2 and 256");
01488           def_output_data.colormap_size = 0;
01489         }
01490       }
01491       break;
01492       
01493      case USE_COLORMAP_OPT:
01494       MARK_CH(output, CH_USE_COLORMAP);
01495       Gif_DeleteColormap(def_output_data.colormap_fixed);
01496       if (clp->negated)
01497         def_output_data.colormap_fixed = 0;
01498       else
01499         set_new_fixed_colormap(clp->arg);
01500       break;
01501       
01502      case COLORMAP_ALGORITHM_OPT:
01503       MARK_CH(output, CH_COLORMAP_METHOD);
01504       def_output_data.colormap_algorithm = clp->val.i;
01505       break;
01506       
01507      case DITHER_OPT:
01508       MARK_CH(output, CH_DITHER);
01509       def_output_data.colormap_dither = !clp->negated;
01510       break;
01511       
01512      case RESIZE_OPT:
01513       MARK_CH(output, CH_RESIZE);
01514       if (clp->negated)
01515         def_output_data.scaling = 0;
01516       else if (dimensions_x <= 0 && dimensions_y <= 0) {
01517         error("one of W and H must be positive in `--resize WxH'");
01518         def_output_data.scaling = 0;
01519       } else {
01520         def_output_data.scaling = 1; /* use resize dimensions */
01521         def_output_data.resize_width = dimensions_x;
01522         def_output_data.resize_height = dimensions_y;
01523       }
01524       break;
01525       
01526      case RESIZE_WIDTH_OPT:
01527       MARK_CH(output, CH_RESIZE);
01528       if (clp->negated)
01529         def_output_data.scaling = 0;
01530       else if (clp->val.u == 0) {
01531         error("`--resize-width' argument must be positive");
01532         def_output_data.scaling = 0;
01533       } else {
01534         def_output_data.scaling = 1; /* use resize dimensions */
01535         def_output_data.resize_width = clp->val.u;
01536         def_output_data.resize_height = 0;
01537       }
01538       break;
01539       
01540      case RESIZE_HEIGHT_OPT:
01541       MARK_CH(output, CH_RESIZE);
01542       if (clp->negated)
01543         def_output_data.scaling = 0;
01544       else if (clp->val.u == 0) {
01545         error("`--resize-height' argument must be positive");
01546         def_output_data.scaling = 0;
01547       } else {
01548         def_output_data.scaling = 1; /* use resize dimensions */
01549         def_output_data.resize_width = 0;
01550         def_output_data.resize_height = clp->val.u;
01551       }
01552       break;
01553       
01554      case SCALE_OPT:
01555       MARK_CH(output, CH_RESIZE);
01556       if (clp->negated)
01557         def_output_data.scaling = 0;
01558       else if (parsed_scale_factor_x <= 0 || parsed_scale_factor_y <= 0) {
01559         error("`--scale' X and Y factors must be positive");
01560         def_output_data.scaling = 0;
01561       } else {
01562         def_output_data.scaling = 2; /* use scale factor */
01563         def_output_data.scale_x = parsed_scale_factor_x;
01564         def_output_data.scale_y = parsed_scale_factor_y;
01565       }
01566       break;
01567       
01568       /* RANDOM OPTIONS */
01569       
01570      case NO_WARNINGS_OPT:
01571       no_warnings = !clp->negated;
01572       break;
01573       
01574      case WARNINGS_OPT:
01575       no_warnings = clp->negated;
01576       break;
01577       
01578      case VERSION_OPT:
01579 #ifdef GIF_UNGIF
01580       printf("LCDF Gifsicle %s (ungif)\n", VERSION);
01581 #else
01582       printf("LCDF Gifsicle %s\n", VERSION);
01583 #endif
01584       printf("Copyright (C) 1997-2001 Eddie Kohler\n\
01585 This is free software; see the source for copying conditions.\n\
01586 There is NO warranty, not even for merchantability or fitness for a\n\
01587 particular purpose.\n");
01588       exit(EXIT_OK);
01589       break;
01590       
01591      case HELP_OPT:
01592       usage();
01593       exit(EXIT_OK);
01594       break;
01595       
01596      case OUTPUT_OPT:
01597       MARK_CH(output, CH_OUTPUT);
01598       if (strcmp(clp->arg, "-") == 0)
01599         def_output_data.output_name = 0;
01600       else
01601         def_output_data.output_name = clp->arg;
01602       break;
01603       
01604       /* NONOPTIONS */
01605       
01606      case Clp_NotOption:
01607       if (clp->arg[0] != '#' || !frame_argument(clp, clp->arg)) {
01608         input_done();
01609         input_stream(clp->arg);
01610       }
01611       break;
01612       
01613      case Clp_Done:
01614       goto done;
01615       
01616      bad_option:
01617      case Clp_BadOption:
01618       short_usage();
01619       exit(EXIT_USER_ERR);
01620       break;
01621       
01622      default:
01623       break;
01624       
01625     }
01626   }
01627   
01628  done:
01629   
01630   if (next_output)
01631     combine_output_options();
01632   if (!files_given)
01633     input_stream(0);
01634   
01635   frame_change_done();
01636   input_done();
01637   if (mode == MERGING)
01638     output_frames();
01639   
01640   verbose_endline();
01641   print_useless_options("frame", next_frame, frame_option_types);
01642   print_useless_options("input", next_input, input_option_types);
01643   if (any_output_successful)
01644     print_useless_options("output", active_next_output, output_option_types);
01645   blank_frameset(frames, 0, 0, 1);
01646 #ifdef DMALLOC
01647   dmalloc_report();
01648 #endif
01649   return (error_count ? EXIT_ERR : EXIT_OK);
01650 }
 

Powered by Plone

This site conforms to the following standards: