Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
int main(int argc, char **argv)
{
    Images images;
    int mode = 0; // 0 = encode, 1 = decode
    int method = 0; // 1=non-interlacing, 2=interlacing
    int quality = 100; // 100 = everything, positive value: partial decode, negative value: only rough data
    int learn_repeats = -1;
    int acb = -1; // try auto color buckets
    int scale = 1;
    int frame_delay = 100;
    int palette_size = 512;
    int lookback = 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'},
        {"encode", 0, NULL, 'e'},
        {"decode", 0, NULL, 'd'},
        {"first", 1, NULL, 'f'},
        {"verbose", 0, NULL, 'v'},
        {"interlace", 0, NULL, 'i'},
        {"no-interlace", 0, NULL, 'n'},
        {"acb", 0, NULL, 'a'},
        {"no-acb", 0, NULL, 'b'},
        {"quality", 1, NULL, 'q'},
        {"scale", 1, NULL, 's'},
        {"palette", 1, NULL, 'p'},
        {"repeats", 1, NULL, 'r'},
        {"frame-delay", 1, NULL, 'f'},
        {"lookback", 1, NULL, 'l'},
        {0, 0, 0, 0}
    };
    int i,c;
    while ((c = getopt_long (argc, argv, "hedvinabq:s:p:r:f:l:", optlist, &i)) != -1) {
        switch (c) {
        case 'e': mode=0; break;
        case 'd': mode=1; break;
        case 'v': verbosity++; break;
        case 'i': if (method==0) method=2; break;
        case 'n': method=1; break;
        case 'a': acb=1; break;
        case 'b': acb=0; break;
        case 'p': palette_size=atoi(optarg);
                  if (palette_size < -1 || palette_size > 30000) {fprintf(stderr,"Not a sensible number for option -p\n"); return 1; }
                  if (palette_size == 0) {v_printf(2,"Palette disabled\n"); }
                  break;
        case 'q': quality=atoi(optarg);
                  if (quality < -1 || quality > 100) {fprintf(stderr,"Not a sensible number for option -q\n"); return 1; }
                  break;
        case 's': scale=atoi(optarg);
                  if (scale < 1 || scale > 128) {fprintf(stderr,"Not a sensible number for option -s\n"); return 1; }
                  break;
        case 'r': learn_repeats=atoi(optarg);
                  if (learn_repeats < 0 || learn_repeats > 1000) {fprintf(stderr,"Not a sensible number for option -r\n"); return 1; }
                  break;
        case 'f': frame_delay=atoi(optarg);
                  if (frame_delay < 0 || frame_delay > 60000) {fprintf(stderr,"Not a sensible number for option -f\n"); return 1; }
                  break;
        case 'l': lookback=atoi(optarg);
                  if (lookback < -1 || lookback > 256) {fprintf(stderr,"Not a sensible number for option -l\n"); return 1; }
                  break;
        case 'h':
        default: show_help(); return 0;
        }
    }
    argc -= optind;
    argv += optind;

  v_printf(3,"  _____  __  (__) _____");
  v_printf(3,"\n (___  ||  | |  ||  ___)   ");v_printf(2,"FLIF 0.1 [2 October 2015]");
  v_printf(3,"\n  (__  ||  |_|__||  __)    Free Lossless Image Format");
  v_printf(3,"\n    (__||______) |__)      (c) 2010-2015 J.Sneyers & P.Wuille, GNU GPL v3+\n");
  v_printf(3,"\n");
  if (argc == 0) {
        //fprintf(stderr,"Input file missing.\n");
        if (verbosity == 1) show_help();
        return 1;
  }
  if (argc == 1) {
        fprintf(stderr,"Output file missing.\n");
        show_help();
        return 1;
  }

    if (file_exists(argv[0])) {
            if (mode == 0 && file_is_flif(argv[0])) {
              v_printf(2,"Input file is a FLIF file, adding implicit -d\n");
              mode = 1;
            }
            char *f = strrchr(argv[0],'/');
            char *ext = f ? strrchr(f,'.') : strrchr(argv[0],'.');
            if (mode == 0) {
                    if (ext && ( !strcasecmp(ext,".png") ||  !strcasecmp(ext,".pnm") ||  !strcasecmp(ext,".ppm")  ||  !strcasecmp(ext,".pgm") ||  !strcasecmp(ext,".pbm") ||  !strcasecmp(ext,".pam"))) {
                          // ok
                    } else {
                          fprintf(stderr,"Warning: expected \".png\" or \".pnm\" file name extension for input file, trying anyway...\n");
                    }
            } else {
                    if (ext && ( !strcasecmp(ext,".flif")  || ( !strcasecmp(ext,".flf") ))) {
                          // ok
                    } else {
                          fprintf(stderr,"Warning: expected file name extension \".flif\" for input file, trying anyway...\n");
                    }
            }
    } else if (argc>0) {
          fprintf(stderr,"Input file does not exist: %s\n",argv[0]);
          return 1;
    }


  if (mode == 0) {
        int nb_input_images = argc-1;
        while(argc>1) {
          Image image;
          v_printf(2,"\r");
          if (!image.load(argv[0])) {
            fprintf(stderr,"Could not read input file: %s\n", argv[0]);
            return 2;
          };
          images.push_back(image);
          if (image.rows() != images[0].rows() || image.cols() != images[0].cols() || image.numPlanes() != images[0].numPlanes()) {
            fprintf(stderr,"Dimensions of all input images should be the same!\n");
            fprintf(stderr,"  First image is %ux%u, %i channels.\n",images[0].cols(),images[0].rows(),images[0].numPlanes());
            fprintf(stderr,"  This image is %ux%u, %i channels: %s\n",image.cols(),image.rows(),image.numPlanes(),argv[0]);
            return 2;
          }
          argc--; argv++;
          if (nb_input_images>1) {v_printf(2,"    (%i/%i)         ",(int)images.size(),nb_input_images); v_printf(4,"\n");}
        }
        v_printf(2,"\n");
        bool flat=true;
        for (Image &image : images) if (image.uses_alpha()) flat=false;
        if (flat && images[0].numPlanes() == 4) {
              v_printf(2,"Alpha channel not actually used, dropping it.\n");
              for (Image &image : images) image.drop_alpha();
        }
        uint64_t nb_pixels = (uint64_t)images[0].rows() * images[0].cols();
        std::vector<std::string> desc;
        desc.push_back("YIQ");  // convert RGB(A) to YIQ(A)
        desc.push_back("BND");  // get the bounds of the color spaces
        if (palette_size > 0)
          desc.push_back("PLA");  // try palette (including alpha)
        if (palette_size > 0)
          desc.push_back("PLT");  // try palette (without alpha)
        if (acb == -1) {
          // not specified if ACB should be used
          if (nb_pixels > 10000) desc.push_back("ACB");  // try auto color buckets on large images
        } else if (acb) desc.push_back("ACB");  // try auto color buckets if forced
        if (method == 0) {
          // no method specified, pick one heuristically
          if (nb_pixels < 10000) method=1; // if the image is small, not much point in doing interlacing
          else method=2; // default method: interlacing
        }
        if (images.size() > 1) {
          desc.push_back("DUP");  // find duplicate frames
          desc.push_back("FRS");  // get the shapes of the frames
          if (lookback != 0) desc.push_back("FRA");  // make a "deep" alpha channel (negative values are transparent to some previous frame)
        }
        if (learn_repeats < 0) {
          // no number of repeats specified, pick a number heuristically
          learn_repeats = TREE_LEARN_REPEATS;
          if (nb_pixels < 5000) learn_repeats--;        // avoid large trees for small images
          if (learn_repeats < 0) learn_repeats=0;
        }
        encode(argv[0], images, desc, method, learn_repeats, acb, frame_delay, palette_size, lookback);
  } else {
        char *ext = strrchr(argv[1],'.');
        if (ext && ( !strcasecmp(ext,".png") ||  !strcasecmp(ext,".pnm") ||  !strcasecmp(ext,".ppm")  ||  !strcasecmp(ext,".pgm") ||  !strcasecmp(ext,".pbm") ||  !strcasecmp(ext,".pam"))) {
                 // ok
        } else {
           fprintf(stderr,"Error: expected \".png\", \".pnm\" or \".pam\" file name extension for output file\n");
           return 1;
        }
        if (!decode(argv[0], 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");
  }
  for (Image &image : images) image.clear();
  return 0;
}
Beispiel #4
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;
}
Beispiel #5
0
bool encode_load_input_images(int argc, char **argv, Images &images, flif_options &options) {
    int nb_input_images = argc-1;
    int nb_actual_images = 0;
    metadata_options md;
    md.icc = options.color_profile;
    md.xmp = options.metadata;
    md.exif = options.metadata;
    while(argc>1) {
      int maxlength = strlen(argv[0])+100;
      std::vector<char> vfilename(maxlength);
      char *filename = argv[0];
      int framecounter = 0;
      int stop_searching = 0;
      bool multiple=false;
      if (!file_exists(argv[0]) && strchr(argv[0],'%')) {
        multiple=true;
        filename = &vfilename[0];
      }
      for ( ; framecounter < 0xFFFFFFF && stop_searching < 1000; framecounter++ ) {
        if (multiple) {
             snprintf(filename,maxlength,argv[0],framecounter);
             if (!file_exists(filename)) {
                stop_searching++;
                continue;
             }
             stop_searching = 0;
        }
        Image image;
        if (options.keep_palette) image.palette = true; // tells the PNG loader to keep palette intact
        v_printf_tty(2,"\r");
        if (!image.load(filename,md)) {
            e_printf("Could not read input file: %s\n", argv[0]);
            return false;
        };
        if (image.numPlanes() > 0) {
          nb_actual_images++;
          images.push_back(std::move(image));
          Image& last_image = images.back();
          if (last_image.rows() != images[0].rows() || last_image.cols() != images[0].cols()) {
            e_printf("Dimensions of all input images should be the same!\n");
            e_printf("  First image is %ux%u\n",images[0].cols(),images[0].rows());
            e_printf("  This image is %ux%u: %s\n",last_image.cols(),last_image.rows(),filename);
            return false;
          }
          if (last_image.numPlanes() < images[0].numPlanes()) {
            if (images[0].numPlanes() == 3) last_image.ensure_chroma();
            else if (images[0].numPlanes() == 4) last_image.ensure_alpha();
            else { e_printf("Problem while loading input images, please report this.\n"); return false; }
          } else if (last_image.numPlanes() > images[0].numPlanes()) {
            if (last_image.numPlanes() == 3) { for (Image& i : images) i.ensure_chroma(); }
            else if (last_image.numPlanes() == 4) { for (Image& i : images) i.ensure_alpha(); }
            else { e_printf("Problem while loading input images, please report this.\n"); return false; }
          }
        } else {
          if (images.size() == 0) {
            e_printf("First specify the actual image(s), then the metadata.\n");
            return false;
          }
          for (size_t i=0; i<image.metadata.size(); i++)
              images[0].metadata.push_back(image.metadata[i]);
        }
        if (nb_input_images>1) {v_printf(2,"    (%i/%i)         ",(int)images.size(),nb_input_images); v_printf(4,"\n");}
        if (!multiple) break;
      }
      argc--; argv++;
    }
    if (nb_actual_images > 0) return true;
    e_printf("Error: no actual input images to be encoded!\n");
    return false;
}