Example #1
0
File: flif.cpp Project: hxford/FLIF
bool encode_flif(int argc, char **argv, Images &images, int palette_size, int acb, flifEncodingOptional method, int lookback, int learn_repeats, int frame_delay, 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 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();
    }
    bool grayscale=true;
    for (Image &image : images) if (image.uses_color()) grayscale=false;
    if (grayscale && images[0].numPlanes() == 3) {
        v_printf(2,"Chroma not actually used, dropping it.\n");
        for (Image &image : images) image.drop_color();
    }
    uint64_t nb_pixels = (uint64_t)images[0].rows() * images[0].cols();
    std::vector<std::string> desc;
    if (nb_pixels > 2) {         // no point in doing anything for 1- or 2-pixel images
      if (plc)
        desc.push_back("PLC");  // compactify channels
      if (yiq)
        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) {
        palette_size = 1024;
        if (nb_pixels * images.size() / 2 < 1024) palette_size = nb_pixels * images.size() / 2;
    }
    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 * images.size() > 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.o == Optional::undefined) {
        // no method specified, pick one heuristically
        if (nb_pixels * images.size() < 10000) method.encoding=flifEncoding::nonInterlaced; // if the image is small, not much point in doing interlacing
        else method.encoding=flifEncoding::interlaced; // 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 * images.size() < 5000) learn_repeats--;        // avoid large trees for small images
        if (learn_repeats < 0) learn_repeats=0;
    }
    FILE *file = fopen(argv[0],"wb");
    if (!file)
        return false;
    FileIO fio(file, argv[0]);
    return flif_encode(fio, images, desc, method.encoding, learn_repeats, acb, frame_delay, palette_size, lookback, divisor, min_size, split_threshold);
}
Example #2
0
bool encode_flif(int argc, char **argv, Images &images, flif_options &options) {
    bool flat=true;
    unsigned int framenb=0;
    for (Image& i : images) { i.frame_delay = options.frame_delay[framenb]; if (framenb+1 < options.frame_delay.size()) framenb++; }
    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();
    }
    bool grayscale=true;
    for (Image &image : images) if (image.uses_color()) grayscale=false;
    if (grayscale && images[0].numPlanes() == 3) {
        v_printf(2,"Chroma not actually used, dropping it.\n");
        for (Image &image : images) image.drop_color();
    }
    uint64_t nb_pixels = (uint64_t)images[0].rows() * images[0].cols();
    std::vector<std::string> desc;
    if (nb_pixels > 2) {         // no point in doing anything for 1- or 2-pixel images
      if (options.plc && (images[0].getDepth() > 8 || !options.loss)) {
        desc.push_back("Channel_Compact");  // compactify channels (not if lossy, because then loss gets magnified!)
      }
      if (options.ycocg) {
        desc.push_back("YCoCg");  // convert RGB(A) to YCoCg(A)
      }
      desc.push_back("PermutePlanes");  // permute RGB to GRB
      desc.push_back("Bounds");  // get the bounds of the color spaces
    }
    // only use palette/CB if we're lossless, because lossy and palette don't go well together...
    if (options.palette_size == -1) {
        options.palette_size = DEFAULT_MAX_PALETTE_SIZE;
        if (nb_pixels * images.size() / 3 < DEFAULT_MAX_PALETTE_SIZE) {
          options.palette_size = nb_pixels * images.size() / 3;
        }
    }
    if (!options.loss && options.palette_size != 0) {
        desc.push_back("Palette_Alpha");  // try palette (including alpha)
        desc.push_back("Palette");  // try palette (without alpha)
    }
    if (!options.loss) {
    if (options.acb == -1) {
      // not specified if ACB should be used
      if (nb_pixels * images.size() > 10000) {
        desc.push_back("Color_Buckets");  // try auto color buckets on large images
      }
    } else if (options.acb) {
      desc.push_back("Color_Buckets");  // try auto color buckets if forced
    }
    }
    if (options.method.o == Optional::undefined) {
        // no method specified, pick one heuristically
        if (nb_pixels * images.size() < 10000) options.method.encoding=flifEncoding::nonInterlaced; // if the image is small, not much point in doing interlacing
        else options.method.encoding=flifEncoding::interlaced; // default method: interlacing
    }
    if (images.size() > 1) {
        desc.push_back("Duplicate_Frame");  // find duplicate frames
        if (!options.loss) { // only if lossless
          if (options.frs) desc.push_back("Frame_Shape");  // get the shapes of the frames
          if (options.lookback) desc.push_back("Frame_Lookback");  // make a "deep" alpha channel (negative values are transparent to some previous frame)
        }
    }
    if (options.learn_repeats < 0) {
        // no number of repeats specified, pick a number heuristically
        options.learn_repeats = TREE_LEARN_REPEATS;
        //if (nb_pixels * images.size() < 5000) learn_repeats--;        // avoid large trees for small images
        if (options.learn_repeats < 0) options.learn_repeats=0;
    }
    bool result = true;
    if (!options.just_add_loss) {
      FILE *file = NULL;
      if (!strcmp(argv[0],"-")) file = stdout;
      else file = fopen(argv[0],"wb");
      if (!file) return false;
      FileIO fio(file, (file == stdout? "to standard output" : argv[0]));
      if (!flif_encode(fio, images, desc, options)) result = false;
    } else {
      BlobIO bio; // will just contain some unneeded FLIF header stuff
      if (!flif_encode(bio, images, desc, options)) result = false;
      else if (!images[0].save(argv[0])) result = false;
    }
    // get rid of palette
    images[0].clear();
    return result;
}
Example #3
0
bool encode_flif(int argc, char **argv, Images &images, int palette_size, int acb, flifEncodingOptional method, int lookback,
                 int learn_repeats, std::vector<int> &frame_delay, 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, int cutoff=2, int alpha=19, int crc_check=-1, int loss=0) {
    bool flat=true;
    unsigned int framenb=0;
    for (Image& i : images) { i.frame_delay = frame_delay[framenb]; if (framenb+1 < frame_delay.size()) framenb++; }
    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();
    }
    bool grayscale=true;
    for (Image &image : images) if (image.uses_color()) grayscale=false;
    if (grayscale && images[0].numPlanes() == 3) {
        v_printf(2,"Chroma not actually used, dropping it.\n");
        for (Image &image : images) image.drop_color();
    }
    uint64_t nb_pixels = (uint64_t)images[0].rows() * images[0].cols();
    std::vector<std::string> desc;
    if (nb_pixels > 2) {         // no point in doing anything for 1- or 2-pixel images
      if (plc && !loss) {
        desc.push_back("Channel_Compact");  // compactify channels (not if lossy, because then loss gets magnified!)
      }
      if (yiq) {
        desc.push_back("YCoCg");  // convert RGB(A) to YCoCg(A)
      }
      desc.push_back("Bounds");  // get the bounds of the color spaces
    }
    if (!loss) {
    // only use palette/CB if we're lossless, because lossy and palette don't go well together...
    if (palette_size == -1) {
        palette_size = 1024;
        if (nb_pixels * images.size() / 2 < 1024) {
          palette_size = nb_pixels * images.size() / 2;
        }
    }
    if (palette_size != 0) {
        desc.push_back("Palette_Alpha");  // try palette (including alpha)
    }
    if (palette_size != 0) {
        desc.push_back("Palette");  // try palette (without alpha)
    }
    if (acb == -1) {
      // not specified if ACB should be used
      if (nb_pixels * images.size() > 10000) {
        desc.push_back("Color_Buckets");  // try auto color buckets on large images
      }
    } else if (acb) {
      desc.push_back("Color_Buckets");  // try auto color buckets if forced
    }
    }
    if (method.o == Optional::undefined) {
        // no method specified, pick one heuristically
        if (nb_pixels * images.size() < 10000) method.encoding=flifEncoding::nonInterlaced; // if the image is small, not much point in doing interlacing
        else method.encoding=flifEncoding::interlaced; // default method: interlacing
    }
    if (images.size() > 1) {
        desc.push_back("Duplicate_Frame");  // find duplicate frames
        if (!loss) { // only if lossless
          if (frs) desc.push_back("Frame_Shape");  // get the shapes of the frames
          if (lookback) desc.push_back("Frame_Lookback");  // 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 * images.size() < 5000) learn_repeats--;        // avoid large trees for small images
        if (learn_repeats < 0) learn_repeats=0;
    }
    FILE *file = fopen(argv[0],"wb");
    if (!file)
        return false;
    FileIO fio(file, argv[0]);
    return flif_encode(fio, images, desc, method.encoding, learn_repeats, acb, palette_size, lookback, divisor, min_size, split_threshold, cutoff, alpha, crc_check, loss);
}
Example #4
0
bool handle_encode_arguments(int argc, char **argv, Images &images, int palette_size, int acb, flifEncodingOptional method, int lookback, int learn_repeats, int frame_delay) {
    int nb_input_images = argc-1;
    while(argc>1) {
        Image image;
        v_printf(2,"\r");
        if (!image.load(argv[0])) {
            e_printf("Could not read input file: %s\n", argv[0]);
            return 2;
        };
        images.push_back(std::move(image));
        const Image& last_image = images.back();
		if (last_image.rows() != images[0].rows() || last_image.cols() != images[0].cols() || last_image.numPlanes() != images[0].numPlanes()) {
            e_printf("Dimensions of all input images should be the same!\n");
            e_printf("  First image is %ux%u, %i channels.\n",images[0].cols(),images[0].rows(),images[0].numPlanes());
            e_printf("  This image is %ux%u, %i channels: %s\n",last_image.cols(),last_image.rows(),last_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.o == Optional::undefined) {
        // no method specified, pick one heuristically
        if (nb_pixels < 10000) method.encoding=flifEncoding::nonInterlaced; // if the image is small, not much point in doing interlacing
        else method.encoding=flifEncoding::interlaced; // 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;
    }
    FILE *file = fopen(argv[0],"wb");
    if (!file)
        return false;
    FileIO fio(file, argv[0]);
    return flif_encode(fio, images, desc, method.encoding, learn_repeats, acb, frame_delay, palette_size, lookback);
}