int handle_decode(char **argv, Images &images, int quality, int scale) { char *ext = strrchr(argv[1],'.'); if (!check_compatible_extension(ext)) { e_printf("Error: expected \".png\", \".pnm\" or \".pam\" file name extension for output file\n"); return 1; } if (!decode_flif(argv, images, quality, scale)) return 3; if (scale>1) v_printf(3,"Downscaling output: %ux%u -> %ux%u\n",images[0].cols(),images[0].rows(),images[0].cols()/scale,images[0].rows()/scale); if (images.size() == 1) { if (!images[0].save(argv[1],scale)) return 2; } else { int counter=0; std::vector<char> vfilename(strlen(argv[1])+6); char *filename = &vfilename[0]; strcpy(filename,argv[1]); char *a_ext = strrchr(filename,'.'); for (Image& image : images) { sprintf(a_ext,"-%03d%s",counter++,ext); if (!image.save(filename,scale)) return 2; v_printf(2," (%i/%i) \r",counter,(int)images.size()); v_printf(4,"\n"); } } v_printf(2,"\n"); return -1; }
int handle_decode(int argc, char **argv, Images &images, int quality, int scale, int resize_width, int resize_height) { if (scale < 0) { // just identify the file(s), don't actually decode while (argc>0) { decode_flif(argv, images, quality, scale, resize_width, resize_height); argv++; argc--; } return 0; } char *ext = strrchr(argv[1],'.'); if (!check_compatible_extension(ext) && strcmp(argv[1],"null:")) { e_printf("Error: expected \".png\", \".pnm\" or \".pam\" file name extension for output file\n"); return 1; } if (!decode_flif(argv, images, quality, scale, resize_width, resize_height)) { e_printf("Error: could not decode FLIF file\n"); return 3; } if (!strcmp(argv[1],"null:")) return 0; // if (scale>1) // v_printf(3,"Downscaling output: %ux%u -> %ux%u\n",images[0].cols(),images[0].rows(),images[0].cols()/scale,images[0].rows()/scale); if (images.size() == 1) { if (!images[0].save(argv[1])) return 2; } else { int counter=0; std::vector<char> vfilename(strlen(argv[1])+6); char *filename = &vfilename[0]; strcpy(filename,argv[1]); char *a_ext = strrchr(filename,'.'); for (Image& image : images) { sprintf(a_ext,"-%03d%s",counter++,ext); if (!image.save(filename)) return 2; v_printf(2," (%i/%i) \r",counter,(int)images.size()); v_printf(4,"\n"); } } v_printf(2,"\n"); return 0; }
int main(int argc, char **argv) { Images images; #ifdef HAS_ENCODER int mode = 0; // 0 = encode, 1 = decode, 2 = transcode flifEncodingOptional method; int learn_repeats = -1; int acb = -1; // try auto color buckets std::vector<int> frame_delay; frame_delay.push_back(100); int palette_size = -1; int lookback = 1; int divisor=CONTEXT_TREE_COUNT_DIV; int min_size=CONTEXT_TREE_MIN_SUBTREE_SIZE; int split_threshold=CONTEXT_TREE_SPLIT_THRESHOLD; int yiq = 1; int plc = 1; int frs = 1; bool alpha_zero_special = true; int alpha=19; int cutoff=2; #else int mode = 1; #endif int quality = 100; // 100 = everything, positive value: partial decode, negative value: only rough data int scale = 1; int resize_width = 0, resize_height = 0; bool showhelp = false; if (strcmp(argv[0],"flif") == 0) mode = 0; if (strcmp(argv[0],"dflif") == 0) mode = 1; if (strcmp(argv[0],"deflif") == 0) mode = 1; if (strcmp(argv[0],"decflif") == 0) mode = 1; static struct option optlist[] = { {"help", 0, NULL, 'h'}, {"decode", 0, NULL, 'd'}, {"verbose", 0, NULL, 'v'}, {"quality", 1, NULL, 'q'}, {"scale", 1, NULL, 's'}, {"resize", 1, NULL, 'r'}, {"identify", 0, NULL, 'i'}, {"version", 0, NULL, 'V'}, #ifdef HAS_ENCODER {"encode", 0, NULL, 'e'}, {"transcode", 0, NULL, 't'}, {"interlace", 0, NULL, 'I'}, {"no-interlace", 0, NULL, 'N'}, {"frame-delay", 1, NULL, 'F'}, {"keep-invisible-rgb", 0, NULL, 'K'}, {"max-palette-size", 1, NULL, 'P'}, {"force-color-buckets", 0, NULL, 'A'}, {"no-color-buckets", 0, NULL, 'B'}, {"no-ycocg", 0, NULL, 'Y'}, {"no-channel-compact", 0, NULL, 'C'}, {"max-frame-lookback", 1, NULL, 'L'}, {"no-frame-shape", 0, NULL, 'S'}, {"maniac-repeats", 1, NULL, 'R'}, {"maniac-divisor", 1, NULL, 'D'}, {"maniac-min-size", 1, NULL, 'M'}, {"maniac-threshold", 1, NULL, 'T'}, {"chance-cutoff", 1, NULL, 'X'}, {"chance-alpha", 1, NULL, 'Z'}, #endif {0, 0, 0, 0} }; int i,c; #ifdef HAS_ENCODER while ((c = getopt_long (argc, argv, "hdviVq:s:r:etINnF:KP:ABYCL:SR:D:M:T:X:Z:", optlist, &i)) != -1) { #else while ((c = getopt_long (argc, argv, "hdviVq:s:r:", optlist, &i)) != -1) { #endif switch (c) { case 'd': mode=1; break; case 'v': increase_verbosity(); break; case 'V': increase_verbosity(3); break; case 'q': quality=atoi(optarg); if (quality < 0 || quality > 100) {e_printf("Not a sensible number for option -q\n"); return 1; } break; case 's': scale=atoi(optarg); if (scale < 1 || scale > 128) {e_printf("Not a sensible number for option -s\n"); return 1; } break; case 'r': if (sscanf(optarg,"%ix%i", &resize_width, &resize_height) < 1) {e_printf("Not a sensible value for option -r (expected WxH)\n"); return 1; } if (!resize_height) resize_height = resize_width; break; case 'i': scale = -1; break; #ifdef HAS_ENCODER case 'e': mode=0; break; case 't': mode=2; break; case 'I': method.encoding=flifEncoding::interlaced; break; case 'n': // undocumented: lower case -n still works case 'N': method.encoding=flifEncoding::nonInterlaced; break; case 'A': acb=1; break; case 'B': acb=0; break; case 'P': palette_size=atoi(optarg); if (palette_size < -32000 || palette_size > 32000) {e_printf("Not a sensible number for option -P\n"); return 1; } if (palette_size == 0) {v_printf(5,"Palette disabled\n"); } break; case 'R': learn_repeats=atoi(optarg); if (learn_repeats < 0 || learn_repeats > 20) {e_printf("Not a sensible number for option -R\n"); return 1; } break; case 'F': frame_delay.clear(); while(optarg != 0) { int d=strtol(optarg,&optarg,10); if (d==0) break; if (*optarg == ',' || *optarg == '+') optarg++; frame_delay.push_back(d); if (d < 0 || d > 60000) {e_printf("Not a sensible number for option -F: %i\n",d); return 1; } } if (frame_delay.size() < 1) frame_delay.push_back(100); break; case 'L': lookback=atoi(optarg); if (lookback < -1 || lookback > 256) {e_printf("Not a sensible number for option -L\n"); return 1; } break; case 'D': divisor=atoi(optarg); if (divisor <= 0 || divisor > 0xFFFFFFF) {e_printf("Not a sensible number for option -D\n"); return 1; } break; case 'M': min_size=atoi(optarg); if (min_size < 0) {e_printf("Not a sensible number for option -M\n"); return 1; } break; case 'T': split_threshold=atoi(optarg); if (split_threshold <= 3 || split_threshold > 100000) {e_printf("Not a sensible number for option -T\n"); return 1; } split_threshold *= 5461; break; case 'Y': yiq=0; break; case 'C': plc=0; break; case 'S': frs=0; break; case 'K': alpha_zero_special=false; break; case 'X': cutoff=atoi(optarg); if (cutoff < 1 || cutoff > 128) {e_printf("Not a sensible number for option -X (try something between 1 and 128)\n"); return 1; } break; case 'Z': alpha=atoi(optarg); if (alpha < 2 || alpha > 128) {e_printf("Not a sensible number for option -Z (try something between 2 and 128)\n"); return 1; } break; #endif case 'h': showhelp=true; break; default: show_help(); return 0; } } argc -= optind; argv += optind; show_banner(); if (argc == 0 || showhelp) { if (get_verbosity() == 1 || showhelp) show_help(); return 0; } if (argc == 1 && scale != -1) { show_help(); e_printf("\nOutput file missing.\n"); return 1; } if (scale == -1) mode = 1; if (file_exists(argv[0])) { char *f = strrchr(argv[0],'/'); char *ext = f ? strrchr(f,'.') : strrchr(argv[0],'.'); #ifdef HAS_ENCODER if (mode == 0 && file_is_flif(argv[0])) { char *f = strrchr(argv[1],'/'); char *ext = f ? strrchr(f,'.') : strrchr(argv[1],'.'); if ((ext && ( !strcasecmp(ext,".flif") || ( !strcasecmp(ext,".flf") )))) { v_printf(3,"Input and output file are both FLIF file, adding implicit -t\n"); mode = 2; } else { v_printf(3,"Input file is a FLIF file, adding implicit -d\n"); mode = 1; } } if (mode != 0) { #endif if (!(ext && ( !strcasecmp(ext,".flif") || ( !strcasecmp(ext,".flf") )))) { e_printf("Warning: expected file name extension \".flif\" for input file, trying anyway...\n"); } #ifdef HAS_ENCODER } else { if (!check_compatible_extension(ext)) { e_printf("Warning: expected \".png\", \".pnm\" or \".pam\" file name extension for input file, trying anyway...\n"); } } #endif } else if (argc>0) { e_printf("Input file does not exist: %s\n",argv[0]); return 1; } if (mode > 0 && argc > 2 && scale != -1) { e_printf("Too many arguments.\n"); return 1; } #ifdef HAS_ENCODER if (mode == 0) { if (!handle_encode(argc, argv, images, palette_size, acb, method, lookback, learn_repeats, frame_delay, divisor, min_size, split_threshold, yiq, plc, alpha_zero_special, frs, cutoff, alpha)) return 2; } else if (mode == 1) { #endif return handle_decode(argc, argv, images, quality, scale, resize_width, resize_height); #ifdef HAS_ENCODER } else if (mode == 2) { // if (scale > 1) {e_printf("Not yet supported: transcoding downscaled image; use decode + encode!\n");} if (!decode_flif(argv, images, quality, scale, resize_width, resize_height)) return 2; argc--; argv++; if (!encode_flif(argc, argv, images, palette_size, acb, method, lookback, learn_repeats, frame_delay, divisor, min_size, split_threshold, yiq, plc, frs, cutoff, alpha)) return 2; } #endif return 0; }
int main(int argc, char **argv) { Images images; flif_options options = FLIF_DEFAULT_OPTIONS; #ifdef HAS_ENCODER int mode = -1; // 0 = encode, 1 = decode, 2 = transcode #else int mode = 1; #endif bool showhelp = false; if (strcmp(argv[0],"cflif") == 0) mode = 0; if (strcmp(argv[0],"dflif") == 0) mode = 1; if (strcmp(argv[0],"deflif") == 0) mode = 1; if (strcmp(argv[0],"decflif") == 0) mode = 1; static struct option optlist[] = { {"help", 0, NULL, 'h'}, {"decode", 0, NULL, 'd'}, {"verbose", 0, NULL, 'v'}, {"no-crc", 0, NULL, 'c'}, {"no-metadata", 0, NULL, 'm'}, {"no-color-profile", 0, NULL, 'p'}, {"quality", 1, NULL, 'q'}, {"scale", 1, NULL, 's'}, {"resize", 1, NULL, 'r'}, {"fit", 1, NULL, 'f'}, {"identify", 0, NULL, 'i'}, {"version", 0, NULL, 'V'}, {"overwrite", 0, NULL, 'o'}, {"breakpoints", 0, NULL, 'b'}, {"keep-palette", 0, NULL, 'k'}, #ifdef HAS_ENCODER {"encode", 0, NULL, 'e'}, {"transcode", 0, NULL, 't'}, {"interlace", 0, NULL, 'I'}, {"no-interlace", 0, NULL, 'N'}, {"frame-delay", 1, NULL, 'F'}, {"keep-invisible-rgb", 0, NULL, 'K'}, {"max-palette-size", 1, NULL, 'P'}, {"force-color-buckets", 0, NULL, 'A'}, {"no-color-buckets", 0, NULL, 'B'}, {"no-ycocg", 0, NULL, 'Y'}, {"no-channel-compact", 0, NULL, 'C'}, {"max-frame-lookback", 1, NULL, 'L'}, {"no-frame-shape", 0, NULL, 'S'}, {"maniac-repeats", 1, NULL, 'R'}, {"maniac-divisor", 1, NULL, 'D'}, {"maniac-min-size", 1, NULL, 'M'}, {"maniac-threshold", 1, NULL, 'T'}, {"chance-cutoff", 1, NULL, 'X'}, {"chance-alpha", 1, NULL, 'Z'}, {"lossy", 1, NULL, 'Q'}, {"adaptive", 0, NULL, 'U'}, {"guess", 1, NULL, 'G'}, {"invisible-guess", 1, NULL, 'H'}, {"effort", 1, NULL, 'E'}, {"chroma-subsample", 0, NULL, 'J'}, {"no-subtract-green", 0, NULL, 'W'}, #endif {0, 0, 0, 0} }; int i,c; #ifdef HAS_ENCODER while ((c = getopt_long (argc, argv, "hdvcmiVq:s:r:f:obketINnF:KP:ABYWCL:SR:D:M:T:X:Z:Q:UG:H:E:J", optlist, &i)) != -1) { #else while ((c = getopt_long (argc, argv, "hdvcmiVq:s:r:f:obk", optlist, &i)) != -1) { #endif switch (c) { case 'd': mode=1; break; case 'v': increase_verbosity(); break; case 'V': increase_verbosity(3); break; case 'c': options.crc_check = 0; break; case 'm': options.metadata = 0; break; case 'p': options.color_profile = 0; break; case 'o': options.overwrite = 1; break; case 'q': options.quality=atoi(optarg); if (options.quality < 0 || options.quality > 100) {e_printf("Not a sensible number for option -q\n"); return 1; } break; case 's': options.scale=atoi(optarg); if (options.scale < 1 || options.scale > 128) {e_printf("Not a sensible number for option -s\n"); return 1; } break; case 'r': if (sscanf(optarg,"%ix%i", &options.resize_width, &options.resize_height) < 1) { if (sscanf(optarg,"x%i", &options.resize_height) < 1) {e_printf("Not a sensible value for option -r (expected WxH)\n"); return 1; } } if (!options.resize_height) options.resize_height = options.resize_width; break; case 'f': if (sscanf(optarg,"%ix%i", &options.resize_width, &options.resize_height) < 1) { if (sscanf(optarg,"x%i", &options.resize_height) < 1) {e_printf("Not a sensible value for option -f (expected WxH)\n"); return 1; } } options.fit=1; break; case 'i': options.scale = -1; break; case 'b': options.show_breakpoints = 8; mode=1; break; case 'k': options.keep_palette = true; break; #ifdef HAS_ENCODER case 'e': mode=0; break; case 't': mode=2; break; case 'I': options.method.encoding=flifEncoding::interlaced; break; case 'n': // undocumented: lower case -n still works case 'N': options.method.encoding=flifEncoding::nonInterlaced; break; case 'A': options.acb=1; break; case 'B': options.acb=0; break; case 'P': options.palette_size=atoi(optarg); if (options.palette_size < -32000 || options.palette_size > 32000) {e_printf("Not a sensible number for option -P\n"); return 1; } if (options.palette_size > 512) {v_printf(1,"Warning: palette size above 512 implies that simple FLIF decoders (8-bit only) cannot decode this file.\n"); } if (options.palette_size == 0) {v_printf(5,"Palette disabled\n"); } break; case 'R': options.learn_repeats=atoi(optarg); if (options.learn_repeats < 0 || options.learn_repeats > 20) {e_printf("Not a sensible number for option -R\n"); return 1; } break; case 'F': options.frame_delay.clear(); while(optarg != 0) { int d=strtol(optarg,&optarg,10); if (d==0) break; if (*optarg == ',' || *optarg == '+' || *optarg == ' ') optarg++; options.frame_delay.push_back(d); if (d < 0 || d > 60000) {e_printf("Not a sensible number for option -F: %i\n",d); return 1; } } if (options.frame_delay.size() < 1) options.frame_delay.push_back(100); break; case 'L': options.lookback=atoi(optarg); if (options.lookback < -1 || options.lookback > 256) {e_printf("Not a sensible number for option -L\n"); return 1; } break; case 'D': options.divisor=atoi(optarg); if (options.divisor <= 0 || options.divisor > 0xFFFFFFF) {e_printf("Not a sensible number for option -D\n"); return 1; } break; case 'M': options.min_size=atoi(optarg); if (options.min_size < 0) {e_printf("Not a sensible number for option -M\n"); return 1; } break; case 'T': options.split_threshold=atoi(optarg); if (options.split_threshold <= 3 || options.split_threshold > 100000) {e_printf("Not a sensible number for option -T\n"); return 1; } options.split_threshold *= 5461; break; case 'Y': options.ycocg=0; break; case 'W': options.ycocg=0; options.subtract_green=0; break; case 'C': options.plc=0; break; case 'S': options.frs=0; break; case 'K': options.alpha_zero_special=0; break; case 'X': options.cutoff=atoi(optarg); if (options.cutoff < 1 || options.cutoff > 128) {e_printf("Not a sensible number for option -X (try something between 1 and 128)\n"); return 1; } break; case 'Z': options.alpha=atoi(optarg); if (options.alpha < 2 || options.alpha > 128) {e_printf("Not a sensible number for option -Z (try something between 2 and 128)\n"); return 1; } break; case 'Q': options.loss=100-atoi(optarg); // can't go above quality 100 = lossless // can go way below 0 if you want if (options.loss < 0) {e_printf("Not a sensible number for option -Q (try something between 0 and 100)\n"); return 1; } break; case 'U': options.adaptive=1; break; case 'G': { int p=0; while(*optarg != 0) { int d=0; switch (*optarg) { case '?': case 'G': case 'g': case 'H': case 'h': // guess/heuristically choose d = -2; break; case '0': case 'A': case 'a': // average d = 0; break; case '1': case 'M': case 'm': // median of 3 values (avg, grad1, grad2) d = 1; break; case '2': case 'N': case 'n': // median of 3 neighbors d = 2; break; case '3': case 'X': case 'x': // auto/mixed, usually a bad idea d = -1; break; case ' ': case ',': case '+': optarg++; continue; default: e_printf("Not a sensible value for option -G\nValid values are: 0 (avg), 1 (median avg/gradients), 2 (median neighbors), X (auto/mixed), ? (heuristically pick 0-2)\n"); return 1; } if (p>4) {e_printf("Error while parsing option -G: too many planes specified\n"); return 1; } options.predictor[p] = d; p++; optarg++; } for (; p<5; p++) options.predictor[p]=options.predictor[0]; } break; case 'H': options.invisible_predictor=atoi(optarg); if (options.invisible_predictor < 0 || options.invisible_predictor > 2) {e_printf("Not a sensible value for option -H\nValid values are: 0 (avg), 1 (median avg/gradients), 2 (median neighbors)\n"); return 1; } break; case 'J': options.chroma_subsampling = 1; break; case 'E': { int effort=atoi(optarg); if (effort < 0 || effort > 100) {e_printf("Not a sensible number for option -E (try something between 0 and 100)\n"); return 1; } // set some parameters automatically if (effort < 10) options.learn_repeats=0; else if (effort <= 50) {options.learn_repeats=1; options.split_threshold=5461*8*5;} else if (effort <= 70) {options.learn_repeats=2; options.split_threshold=5461*8*8;} else if (effort <= 90) {options.learn_repeats=3; options.split_threshold=5461*8*10;} else if (effort <= 100) {options.learn_repeats=4; options.split_threshold=5461*8*12;} if (effort < 15) { for (int i=0; i<5; i++) options.predictor[i]=0; } else if (effort < 30) { options.predictor[1]=0; options.predictor[2]=0; } if (effort < 5) options.acb=0; if (effort < 8) options.palette_size=0; if (effort < 25) options.plc=0; if (effort < 30) options.lookback=0; if (effort < 5) options.frs=0; v_printf(3,"Encode effort: %i, corresponds to parameters -R%i -T%i%s%s%s%s\n", effort, options.learn_repeats, options.split_threshold/5461, (effort<15?" -G0":(effort<30?" -G?00":"")), (effort<5?" -B":""), (effort<8?" -P0":""), (effort<25?" -C":"")); // not mentioning animation options since they're usually irrelevant } break; #endif case 'h': showhelp=true; break; default: show_help(mode); return 0; } } argc -= optind; argv += optind; bool last_is_output = (options.scale != -1); if (options.show_breakpoints && argc == 1) { last_is_output = false; options.no_full_decode = 1; options.scale = 2; } if (!strcmp(argv[argc-1],"-")) { // writing output to stdout, so redirecting verbose output to stderr to avoid contaminating the output stream redirect_stdout_to_stderr(); } show_banner(); if (argc == 0 || showhelp) { if (get_verbosity() == 1 || showhelp) show_help(mode); return 0; } if (argc == 1 && last_is_output) { show_help(mode); e_printf("\nOutput file missing.\n"); return 1; } if (options.scale == -1) mode = 1; if (mode < 0) mode = 0; if (file_exists(argv[0])) { char *f = strrchr(argv[0],'/'); char *ext = f ? strrchr(f,'.') : strrchr(argv[0],'.'); #ifdef HAS_ENCODER if (mode == 0 && file_is_flif(argv[0])) { char *f = strrchr(argv[1],'/'); char *ext = f ? strrchr(f,'.') : strrchr(argv[1],'.'); if ((ext && ( !strcasecmp(ext,".flif") || ( !strcasecmp(ext,".flf") )))) { v_printf(3,"Input and output file are both FLIF file, adding implicit -t\n"); mode = 2; } else { v_printf(3,"Input file is a FLIF file, adding implicit -d\n"); mode = 1; } } if (mode == 0) { char *f = strrchr(argv[argc-1],'/'); char *ext = f ? strrchr(f,'.') : strrchr(argv[argc-1],'.'); if (ext && !options.loss && strcasecmp(ext,".flif") && strcasecmp(ext,".flf") ) { e_printf("Warning: expected file name extension \".flif\" for output file.\n"); } else if (options.loss && check_compatible_extension(ext)) { v_printf(2,"Not doing actual lossy encoding to FLIF, just applying loss.\n"); options.just_add_loss = 1; } } if (mode != 0) { #endif if (!(ext && ( !strcasecmp(ext,".flif") || ( !strcasecmp(ext,".flf") )))) { e_printf("Warning: expected file name extension \".flif\" for input file, trying anyway...\n"); } #ifdef HAS_ENCODER } else { if (!check_compatible_extension(ext)) { e_printf("Warning: expected \".png\", \".pnm\" or \".pam\" file name extension for input file, trying anyway...\n"); } } #endif } else if (argc>0) { if (!strcmp(argv[0],"-")) { v_printf(4,"Taking input from standard input. Mode: %s\n", (mode==0?"encode": (mode==1?"decode":"transcode"))); } else if (!strchr(argv[0],'%')) { e_printf("Error: input file does not exist: %s\n",argv[0]); return 1; } } if (last_is_output && file_exists(argv[argc-1]) && !options.overwrite) { e_printf("Error: output file already exists: %s\nUse --overwrite to force overwrite.\n",argv[argc-1]); return 1; } if (mode > 0 && argc > 2 && options.scale != -1) { e_printf("Too many arguments.\n"); return 1; } #ifdef HAS_ENCODER if (options.chroma_subsampling) v_printf(1,"Warning: chroma subsampling produces a truncated FLIF file. Image will not be lossless!\n"); if (options.loss > 0) options.keep_palette = false; // not going to add loss to indexed colors if (options.adaptive) options.loss = -options.loss; // use negative loss to indicate we want to do adaptive lossy encoding if (mode == 0) { if (!handle_encode(argc, argv, images, options)) return 2; } else if (mode == 1) { #endif return handle_decode(argc, argv, images, options); #ifdef HAS_ENCODER } else if (mode == 2) { // if (scale > 1) {e_printf("Not yet supported: transcoding downscaled image; use decode + encode!\n");} if (!decode_flif(argv, images, options)) return 2; argc--; argv++; if (!encode_flif(argc, argv, images, options)) return 2; } #endif return 0; }
int handle_decode(int argc, char **argv, Images &images, flif_options &options) { if (options.scale < 0) { // just identify the file(s), don't actually decode while (argc>0) { decode_flif(argv, images, options); argv++; argc--; } return 0; } if (argc == 1 && options.show_breakpoints) { decode_flif(argv, images, options); return 0; } char *ext = strrchr(argv[1],'.'); if (check_metadata_extension(ext)) { // only requesting metadata, no need to actually decode the file options.scale = -2; decode_flif(argv, images, options); if (!images[0].save(argv[1])) return 2; v_printf(2,"\n"); return 0; } if (!check_compatible_extension(ext) && strcmp(argv[1],"null:") && strcmp(argv[1],"-")) { e_printf("Error: expected \".png\", \".pnm\" or \".pam\" file name extension for output file\n"); return 1; } if (!(ext && ( !strcasecmp(ext,".png")))) options.keep_palette = false; // don't try to make a palette PNM try { if (!decode_flif(argv, images, options)) { e_printf("Error: could not decode FLIF file\n"); return 3; } } catch (std::bad_alloc& ba) { e_printf("Error: memory allocation problem (unexpected)\n"); return 3; } if (!strcmp(argv[1],"null:")) return 0; // if (scale>1) // v_printf(3,"Downscaling output: %ux%u -> %ux%u\n",images[0].cols(),images[0].rows(),images[0].cols()/scale,images[0].rows()/scale); if (images.size() == 1) { if (!images[0].save(argv[1])) return 2; } else { bool to_stdout=false; if (!strcmp(argv[1],"-")) { to_stdout=true; v_printf(1,"Warning: writing animation to standard output as a concatenation of PAM files.\n"); } int counter=0; int maxlength = strlen(argv[1])+100; std::vector<char> vfilename(maxlength); char *filename = &vfilename[0]; bool use_custom_format = false; if (strchr(argv[1],'%')) use_custom_format = true; strcpy(filename,argv[1]); char *a_ext = strrchr(filename,'.'); if (!a_ext && !to_stdout) { e_printf("Problem saving animation to %s\n",filename); return 2; } for (Image& image : images) { if (!to_stdout) { if (use_custom_format) snprintf(filename,maxlength,argv[1],counter); else if (images.size() < 1000) sprintf(a_ext,"-%03d%s",counter,ext); else if (images.size() < 10000) sprintf(a_ext,"-%04d%s",counter,ext); else if (images.size() < 100000) sprintf(a_ext,"-%05d%s",counter,ext); else sprintf(a_ext,"-%08d%s",counter,ext); if (file_exists(filename) && !options.overwrite) { e_printf("Error: output file already exists: %s\nUse --overwrite to force overwrite.\n",filename); return 4; } if (!image.save(filename)) return 2; } else { if (!image.save(argv[1])) return 2; } counter++; v_printf(2," (%i/%i) \r",counter,(int)images.size()); v_printf(4,"\n"); } } // get rid of palette (should also do this in the non-standard/error paths, but being lazy here since the tool will exit anyway) images[0].clear(); v_printf(2,"\n"); return 0; }
int main(int argc, char **argv) { Images images; #ifdef HAS_ENCODER int mode = 0; // 0 = encode, 1 = decode, 2 = transcode flifEncodingOptional method; int learn_repeats = -1; int acb = -1; // try auto color buckets int frame_delay = 100; int palette_size = 512; int lookback = 1; #else int mode = 1; #endif int quality = 100; // 100 = everything, positive value: partial decode, negative value: only rough data int scale = 1; if (strcmp(argv[0],"flif") == 0) mode = 0; if (strcmp(argv[0],"dflif") == 0) mode = 1; if (strcmp(argv[0],"deflif") == 0) mode = 1; if (strcmp(argv[0],"decflif") == 0) mode = 1; static struct option optlist[] = { {"help", 0, NULL, 'h'}, {"decode", 0, NULL, 'd'}, {"verbose", 0, NULL, 'v'}, {"quality", 1, NULL, 'q'}, {"scale", 1, NULL, 's'}, #ifdef HAS_ENCODER {"encode", 0, NULL, 'e'}, {"transcode", 0, NULL, 't'}, {"interlace", 0, NULL, 'i'}, {"no-interlace", 0, NULL, 'n'}, {"acb", 0, NULL, 'a'}, {"no-acb", 0, NULL, 'b'}, {"palette", 1, NULL, 'p'}, {"repeats", 1, NULL, 'r'}, {"frame-delay", 1, NULL, 'f'}, {"lookback", 1, NULL, 'l'}, #endif {0, 0, 0, 0} }; int i,c; #ifdef HAS_ENCODER while ((c = getopt_long (argc, argv, "hedtvinabq:s:p:r:f:l:", optlist, &i)) != -1) { #else while ((c = getopt_long (argc, argv, "hdvq:s:", optlist, &i)) != -1) { #endif switch (c) { case 'd': mode=1; break; case 'v': increase_verbosity(); break; case 'q': quality=atoi(optarg); if (quality < 0 || quality > 100) {e_printf("Not a sensible number for option -q\n"); return 1; } break; case 's': scale=atoi(optarg); if (scale < 1 || scale > 128) {e_printf("Not a sensible number for option -s\n"); return 1; } break; #ifdef HAS_ENCODER case 'e': mode=0; break; case 't': mode=2; break; case 'i': method.encoding=flifEncoding::interlaced; break; case 'n': method.encoding=flifEncoding::nonInterlaced; break; case 'a': acb=1; break; case 'b': acb=0; break; case 'p': palette_size=atoi(optarg); if (palette_size < -1 || palette_size > 30000) {e_printf("Not a sensible number for option -p\n"); return 1; } if (palette_size == 0) {v_printf(2,"Palette disabled\n"); } break; case 'r': learn_repeats=atoi(optarg); if (learn_repeats < 0 || learn_repeats > 1000) {e_printf("Not a sensible number for option -r\n"); return 1; } break; case 'f': frame_delay=atoi(optarg); if (frame_delay < 0 || frame_delay > 60000) {e_printf("Not a sensible number for option -f\n"); return 1; } break; case 'l': lookback=atoi(optarg); if (lookback < -1 || lookback > 256) {e_printf("Not a sensible number for option -l\n"); return 1; } break; #endif case 'h': default: show_help(); return 0; } } argc -= optind; argv += optind; show_banner(); if (argc == 0) { //e_printf("Input file missing.\n"); if (get_verbosity() == 1) show_help(); return 1; } if (argc == 1) { show_help(); e_printf("\nOutput file missing.\n"); return 1; } if (file_exists(argv[0])) { #ifdef HAS_ENCODER if (mode == 0 && file_is_flif(argv[0])) { char *f = strrchr(argv[1],'/'); char *ext = f ? strrchr(f,'.') : strrchr(argv[1],'.'); if (check_compatible_extension(ext)) { v_printf(2,"Input file is a FLIF file, adding implicit -d\n"); mode = 1; } else if ((ext && ( !strcasecmp(ext,".flif") || ( !strcasecmp(ext,".flf") )))) { v_printf(2,"Input and output file are both FLIF file, adding implicit -t\n"); mode = 2; } } #endif char *f = strrchr(argv[0],'/'); char *ext = f ? strrchr(f,'.') : strrchr(argv[0],'.'); if (mode == 0) { if (!check_compatible_extension(ext)) { e_printf("Warning: expected \".png\" or \".pnm\" file name extension for input file, trying anyway...\n"); } } else { if (!(ext && ( !strcasecmp(ext,".flif") || ( !strcasecmp(ext,".flf") )))) { e_printf("Warning: expected file name extension \".flif\" for input file, trying anyway...\n"); } } } else if (argc>0) { e_printf("Input file does not exist: %s\n",argv[0]); return 1; } if (mode > 0 && argc > 2) { e_printf("Too many arguments.\n"); return 1; } #ifdef HAS_ENCODER if (mode == 0) { if (!handle_encode(argc, argv, images, palette_size, acb, method, lookback, learn_repeats, frame_delay)) return 2; } else if (mode == 1) { #endif if (!handle_decode(argv, images, quality, scale)) return 2; #ifdef HAS_ENCODER } else if (mode == 2) { if (scale > 1) {e_printf("Not yet supported: transcoding downscaled image; use decode + encode!\n");} if (!decode_flif(argv, images, quality, scale)) return 2; argc--; argv++; if (!encode_flif(argc, argv, images, palette_size, acb, method, lookback, learn_repeats, frame_delay)) return 2; } #endif return 0; }
int main(int argc, char **argv) { Images images; #ifdef HAS_ENCODER int mode = 0; // 0 = encode, 1 = decode, 2 = transcode flifEncodingOptional method; int learn_repeats = -1; int acb = -1; // try auto color buckets int frame_delay = 100; int palette_size = -1; int lookback = 1; int divisor=CONTEXT_TREE_COUNT_DIV; int min_size=CONTEXT_TREE_MIN_SUBTREE_SIZE; int split_threshold=CONTEXT_TREE_SPLIT_THRESHOLD; int yiq = 1; int plc = 1; bool alpha_zero_special = true; #else int mode = 1; #endif int quality = 100; // 100 = everything, positive value: partial decode, negative value: only rough data int scale = 1; bool showhelp = false; if (strcmp(argv[0],"flif") == 0) mode = 0; if (strcmp(argv[0],"dflif") == 0) mode = 1; if (strcmp(argv[0],"deflif") == 0) mode = 1; if (strcmp(argv[0],"decflif") == 0) mode = 1; static struct option optlist[] = { {"help", 0, NULL, 'h'}, {"decode", 0, NULL, 'd'}, {"verbose", 0, NULL, 'v'}, {"quality", 1, NULL, 'q'}, {"scale", 1, NULL, 's'}, {"identify", 1, NULL, 'I'}, #ifdef HAS_ENCODER {"encode", 0, NULL, 'e'}, {"transcode", 0, NULL, 't'}, {"interlace", 0, NULL, 'i'}, {"no-interlace", 0, NULL, 'n'}, {"acb", 0, NULL, 'a'}, {"no-acb", 0, NULL, 'b'}, {"palette", 1, NULL, 'p'}, {"repeats", 1, NULL, 'r'}, {"frame-delay", 1, NULL, 'f'}, {"lookback", 1, NULL, 'l'}, {"divisor", 1, NULL, 'D'}, {"min-size", 1, NULL, 'M'}, {"split-threshold", 1, NULL, 'S'}, {"rgb", 0, NULL, 'R'}, {"no-plc", 0, NULL, 'C'}, {"keep-alpha-zero", 0, NULL, 'A'}, #endif {0, 0, 0, 0} }; int i,c; #ifdef HAS_ENCODER while ((c = getopt_long (argc, argv, "hedtvIinabq:s:p:r:f:l:D:M:S:RCA", optlist, &i)) != -1) { #else while ((c = getopt_long (argc, argv, "hdvIq:s:", optlist, &i)) != -1) { #endif switch (c) { case 'd': mode=1; break; case 'v': increase_verbosity(); break; case 'q': quality=atoi(optarg); if (quality < 0 || quality > 100) {e_printf("Not a sensible number for option -q\n"); return 1; } break; case 's': scale=atoi(optarg); if (scale < 1 || scale > 128) {e_printf("Not a sensible number for option -s\n"); return 1; } break; case 'I': scale = -1; break; #ifdef HAS_ENCODER case 'e': mode=0; break; case 't': mode=2; break; case 'i': method.encoding=flifEncoding::interlaced; break; case 'n': method.encoding=flifEncoding::nonInterlaced; break; case 'a': acb=1; break; case 'b': acb=0; break; case 'p': palette_size=atoi(optarg); if (palette_size < 0 || palette_size > 30000) {e_printf("Not a sensible number for option -p\n"); return 1; } if (palette_size == 0) {v_printf(2,"Palette disabled\n"); } break; case 'r': learn_repeats=atoi(optarg); if (learn_repeats < 0 || learn_repeats > 20) {e_printf("Not a sensible number for option -r\n"); return 1; } break; case 'f': frame_delay=atoi(optarg); if (frame_delay < 0 || frame_delay > 60000) {e_printf("Not a sensible number for option -f\n"); return 1; } break; case 'l': lookback=atoi(optarg); if (lookback < -1 || lookback > 256) {e_printf("Not a sensible number for option -l\n"); return 1; } break; case 'D': divisor=atoi(optarg); if (divisor <= 0 || divisor > 0xFFFFFFF) {e_printf("Not a sensible number for option -D\n"); return 1; } break; case 'M': min_size=atoi(optarg); if (min_size < 0 || min_size > CONTEXT_TREE_MAX_COUNT) {e_printf("Not a sensible number for option -M\n"); return 1; } break; case 'S': split_threshold=atoi(optarg); if (split_threshold <= 0 || split_threshold > 100000) {e_printf("Not a sensible number for option -S\n"); return 1; } split_threshold *= 5461; break; case 'R': yiq=0; break; case 'C': plc=0; break; case 'A': alpha_zero_special=false; break; #endif case 'h': showhelp=true; break; default: show_help(); return 0; } } argc -= optind; argv += optind; show_banner(); if (argc == 0 || showhelp) { //e_printf("Input file missing.\n"); if (get_verbosity() == 1 || showhelp) show_help(); return 1; } if (argc == 1 && scale != -1) { show_help(); e_printf("\nOutput file missing.\n"); return 1; } if (scale == -1) mode = 1; if (file_exists(argv[0])) { char *f = strrchr(argv[0],'/'); char *ext = f ? strrchr(f,'.') : strrchr(argv[0],'.'); #ifdef HAS_ENCODER if (mode == 0 && file_is_flif(argv[0])) { char *f = strrchr(argv[1],'/'); char *ext = f ? strrchr(f,'.') : strrchr(argv[1],'.'); if (check_compatible_extension(ext)) { v_printf(3,"Input file is a FLIF file, adding implicit -d\n"); mode = 1; } else if ((ext && ( !strcasecmp(ext,".flif") || ( !strcasecmp(ext,".flf") )))) { v_printf(3,"Input and output file are both FLIF file, adding implicit -t\n"); mode = 2; } } if (mode != 0) { #endif if (!(ext && ( !strcasecmp(ext,".flif") || ( !strcasecmp(ext,".flf") )))) { e_printf("Warning: expected file name extension \".flif\" for input file, trying anyway...\n"); } #ifdef HAS_ENCODER } else { if (!check_compatible_extension(ext)) { e_printf("Warning: expected \".png\", \".pnm\" or \".pam\" file name extension for input file, trying anyway...\n"); } } #endif } else if (argc>0) { e_printf("Input file does not exist: %s\n",argv[0]); return 1; } if (mode > 0 && argc > 2 && scale != -1) { e_printf("Too many arguments.\n"); return 1; } #ifdef HAS_ENCODER if (mode == 0) { if (!handle_encode(argc, argv, images, palette_size, acb, method, lookback, learn_repeats, frame_delay, divisor, min_size, split_threshold, yiq, plc, alpha_zero_special)) return 2; } else if (mode == 1) { #endif return handle_decode(argc, argv, images, quality, scale); #ifdef HAS_ENCODER } else if (mode == 2) { if (scale > 1) {e_printf("Not yet supported: transcoding downscaled image; use decode + encode!\n");} if (!decode_flif(argv, images, quality, scale)) return 2; argc--; argv++; if (!encode_flif(argc, argv, images, palette_size, acb, method, lookback, learn_repeats, frame_delay, divisor, min_size, split_threshold, yiq, plc)) return 2; } #endif return 0; }