00001
00002
00003
00004
00005
00006
00007
00008
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
00020
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
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
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
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
00336 FRAME(frames, i).use = -1;
00337
00338
00339 case INSERT_OPT:
00340
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
00346 mode = INSERTING;
00347 nested_frames = frames;
00348 frames = fset;
00349 break;
00350
00351 case APPEND_OPT:
00352
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
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
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);
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
00517 if (mode == BLANK_MODE)
00518 set_mode(MERGING);
00519
00520 if (active_output_data.output_name == 0) {
00521
00522
00523 if (mode == BATCHING)
00524 active_output_data.output_name = input_name;
00525 else if (mode == EXPLODING) {
00526
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
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
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
00594
00595
00596
00597
00598
00599
00600
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
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
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
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
00833
00834
00835
00836 int i;
00837 char *outfile = active_output_data.output_name;
00838 active_output_data.output_name = 0;
00839
00840
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
00854
00855
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)
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
00884 break;
00885
00886 }
00887
00888 active_next_output = 0;
00889 clear_frameset(frames, 0);
00890
00891
00892
00893 if (def_frame.crop)
00894 def_frame.crop->ready = 0;
00895 }
00896
00897
00898
00899
00900
00901
00902 int
00903 frame_argument(Clp_Parser *clp, char *arg)
00904 {
00905
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
00953
00954
00955 static void
00956 initialize_def_frame(void)
00957 {
00958
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
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
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
01133
01134
01135
01136
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
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
01168
01169 case INFO_OPT:
01170 if (clp->negated)
01171 infoing = 0;
01172 else
01173
01174
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
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
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
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
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
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
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
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;
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;
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;
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;
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
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
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 }