Compress-Zopfli

 view release on metacpan or  search on metacpan

zopflib/README.zopflipng  view on Meta::CPAN

ZopfliPNG is a command line program to optimize the Portable Network Graphics
(PNG) images. This version has the following features:
- uses Zopfli compression for the Deflate compression,
- compares several strategies for choosing scanline filter codes,
- chooses a suitable color type to losslessly encode the image,
- removes all chunks that are unimportant for the typical web use (metadata,
  text, etc...),
- optionally alters the hidden colors of fully transparent pixels for more
  compression, and,
- optionally converts 16-bit color channels to 8-bit.

This is an alpha-release for testing while improvements, particularly to add
palette selection, are still being made. Feedback and bug reports are welcome.

Important:

This PNG optimizer removes ancillary chunks (pieces of metadata) from the
PNG image that normally do not affect rendering. However in special

zopflib/src/zopflipng/lodepng/lodepng.h  view on Meta::CPAN


  When decoding, by default you can ignore this palette, since LodePNG already
  fills the palette colors in the pixels of the raw RGBA output.

  The palette is only supported for color type 3.
  */
  unsigned char* palette; /*palette in RGBARGBA... order. When allocated, must be either 0, or have size 1024*/
  size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/

  /*
  transparent color key (tRNS)

  This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit.
  For greyscale PNGs, r, g and b will all 3 be set to the same.

  When decoding, by default you can ignore this information, since LodePNG sets
  pixels with this key to transparent already in the raw RGBA output.

  The color key is only supported for color types 0 and 2.
  */
  unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/
  unsigned key_r;       /*red/greyscale component of color key*/
  unsigned key_g;       /*green component of color key*/
  unsigned key_b;       /*blue component of color key*/
} LodePNGColorMode;

/*init, cleanup and copy functions to use with this struct*/
void lodepng_color_mode_init(LodePNGColorMode* info);
void lodepng_color_mode_cleanup(LodePNGColorMode* info);
/*return value is error code (0 means no error)*/
unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source);

zopflib/src/zopflipng/lodepng/lodepng.h  view on Meta::CPAN

#endif /*LODEPNG_COMPILE_CPP*/

/*
TODO:
[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often
[.] check compatibility with various compilers  - done but needs to be redone for every newer version
[X] converting color to 16-bit per channel types
[ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values)
[ ] make sure encoder generates no chunks with size > (2^31)-1
[ ] partial decoding (stream processing)
[X] let the "isFullyOpaque" function check color keys and transparent palettes too
[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl"
[ ] don't stop decoding on errors like 69, 57, 58 (make warnings)
[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes
[ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ...
[ ] allow user to give data (void*) to custom allocator
*/

#endif /*LODEPNG_H inclusion guard*/

/*

zopflib/src/zopflipng/lodepng/lodepng.h  view on Meta::CPAN

background color, the interlace method, unknown chunks, ...

When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk.
If the palette contains any colors for which the alpha channel is not 255 (so
there are translucent colors in the palette), it'll add a tRNS chunk.

LodePNGColorMode info_raw
-------------------------

You specify the color type of the raw image that you give to the input here,
including a possible transparent color key and palette you happen to be using in
your raw image data.

By default, 32-bit color is assumed, meaning your input has to be in RGBA
format with 4 bytes (unsigned chars) per pixel.

LodePNGEncoderSettings encoder
------------------------------

The following settings are supported (some are in sub-structs):
*) auto_convert: when this option is enabled, the encoder will

zopflib/src/zopflipng/zopflipng_bin.cc  view on Meta::CPAN

         "-m: compress more: use more iterations (depending on file size)\n"
         "--prefix=[fileprefix]: Adds a prefix to output filenames. May also"
         " contain a directory path. When using a prefix, multiple input files"
         " can be given and the output filenames are generated with the"
         " prefix\n"
         " If --prefix is specified without value, 'zopfli_' is used.\n"
         " If input file names contain the prefix, they are not processed but"
         " considered as output from previous runs. This is handy when using"
         " *.png wildcard expansion with multiple runs.\n"
         "-y: do not ask about overwriting files.\n"
         "--lossy_transparent: remove colors behind alpha channel 0. No visual"
         " difference, removes hidden information.\n"
         "--lossy_8bit: convert 16-bit per channel image to 8-bit per"
         " channel.\n"
         "-d: dry run: don't save any files, just see the console output"
         " (e.g. for benchmarking)\n"
         "--always_zopflify: always output the image encoded by Zopfli, even if"
         " it's bigger than the original, for benchmarking the algorithm. Not"
         " good for real optimization.\n"
         "-q: use quick, but not very good, compression"
         " (e.g. for only trying the PNG filter and color types)\n"

zopflib/src/zopflipng/zopflipng_bin.cc  view on Meta::CPAN

         " ZopfliPNG only keeps (and losslessly modifies) the following chunks"
         " because they are essential: IHDR, PLTE, tRNS, IDAT and IEND.\n"
         "\n"
         "Usage examples:\n"
         "Optimize a file and overwrite if smaller: zopflipng infile.png"
         " outfile.png\n"
         "Compress more: zopflipng -m infile.png outfile.png\n"
         "Optimize multiple files: zopflipng --prefix a.png b.png c.png\n"
         "Compress really good and trying all filter strategies: zopflipng"
         " --iterations=500 --filters=01234mepb --lossy_8bit"
         " --lossy_transparent infile.png outfile.png\n");
}

void PrintSize(const char* label, size_t size) {
  printf("%s: %d (%dK)\n", label, (int) size, (int) size / 1024);
}

void PrintResultSize(const char* label, size_t oldsize, size_t newsize) {
  printf("%s: %d (%dK). Percentage of original: %.3f%%\n",
         label, (int) newsize, (int) newsize / 1024, newsize * 100.0 / oldsize);
}

zopflib/src/zopflipng/zopflipng_bin.cc  view on Meta::CPAN

      }
    } else if (arg[0] == '-' && arg.size() > 1 && arg[1] == '-') {
      size_t eq = arg.find('=');
      std::string name = arg.substr(0, eq);
      std::string value = eq >= arg.size() - 1 ? "" : arg.substr(eq + 1);
      int num = atoi(value.c_str());
      if (name == "--always_zopflify") {
        always_zopflify = true;
      } else if (name == "--verbose") {
        png_options.verbose = true;
      } else if (name == "--lossy_transparent") {
        png_options.lossy_transparent = true;
      } else if (name == "--lossy_8bit") {
        png_options.lossy_8bit = true;
      } else if (name == "--iterations") {
        if (num < 1) num = 1;
        png_options.num_iterations = num;
        png_options.num_iterations_large = num;
      } else if (name == "--splitting") {
        // ignored
      } else if (name == "--filters") {
        for (size_t j = 0; j < value.size(); j++) {

zopflib/src/zopflipng/zopflipng_bin.cc  view on Meta::CPAN

      if (!error) {
        std::vector<unsigned char> origimage;
        unsigned origw, origh;
        lodepng::decode(origimage, origw, origh, origpng);
        if (origw != w || origh != h || origimage.size() != image.size()) {
          error = 1;
        } else {
          for (size_t i = 0; i < image.size(); i += 4) {
            bool same_alpha = image[i + 3] == origimage[i + 3];
            bool same_rgb =
                (png_options.lossy_transparent && image[i + 3] == 0) ||
                (image[i + 0] == origimage[i + 0] &&
                 image[i + 1] == origimage[i + 1] &&
                 image[i + 2] == origimage[i + 2]);
            if (!same_alpha || !same_rgb) {
              error = 1;
              break;
            }
          }
        }
      }

zopflib/src/zopflipng/zopflipng_lib.cc  view on Meta::CPAN

#include <string.h>
#include <set>
#include <vector>

#include "lodepng/lodepng.h"
#include "lodepng/lodepng_util.h"
#include "../zopfli/deflate.h"

ZopfliPNGOptions::ZopfliPNGOptions()
  : verbose(false)
  , lossy_transparent(false)
  , lossy_8bit(false)
  , auto_filter_strategy(true)
  , use_zopfli(true)
  , num_iterations(15)
  , num_iterations_large(5)
  , block_split_strategy(1) {
}

// Deflate compressor passed as fuction pointer to LodePNG to have it use Zopfli
// as its compression backend.

zopflib/src/zopflipng/zopflipng_lib.cc  view on Meta::CPAN

  ZopfliDeflate(&options, 2 /* Dynamic */, 1, in, insize, &bp, out, outsize);

  return 0;  // OK
}

// Returns 32-bit integer value for RGBA color.
static unsigned ColorIndex(const unsigned char* color) {
  return color[0] + 256u * color[1] + 65536u * color[2] + 16777216u * color[3];
}

// Counts amount of colors in the image, up to 257. If transparent_counts_as_one
// is enabled, any color with alpha channel 0 is treated as a single color with
// index 0.
void CountColors(std::set<unsigned>* unique,
                 const unsigned char* image, unsigned w, unsigned h,
                 bool transparent_counts_as_one) {
  unique->clear();
  for (size_t i = 0; i < w * h; i++) {
    unsigned index = ColorIndex(&image[i * 4]);
    if (transparent_counts_as_one && image[i * 4 + 3] == 0) index = 0;
    unique->insert(index);
    if (unique->size() > 256) break;
  }
}

// Remove RGB information from pixels with alpha=0
void LossyOptimizeTransparent(lodepng::State* inputstate, unsigned char* image,
    unsigned w, unsigned h) {
  // First check if we want to preserve potential color-key background color,
  // or instead use the last encountered RGB value all the time to save bytes.
  bool key = true;
  for (size_t i = 0; i < w * h; i++) {
    if (image[i * 4 + 3] > 0 && image[i * 4 + 3] < 255) {
      key = false;
      break;
    }
  }
  std::set<unsigned> count;  // Color count, up to 257.
  CountColors(&count, image, w, h, true);
  // If true, means palette is possible so avoid using different RGB values for
  // the transparent color.
  bool palette = count.size() <= 256;

  // Choose the color key or first initial background color.
  int r = 0, g = 0, b = 0;
  if (key || palette) {
    for (size_t i = 0; i < w * h; i++) {
      if (image[i * 4 + 3] == 0) {
        // Use RGB value of first encountered transparent pixel. This can be
        // used as a valid color key, or in case of palette ensures a color
        // existing in the input image palette is used.
        r = image[i * 4 + 0];
        g = image[i * 4 + 1];
        b = image[i * 4 + 2];
        break;
      }
    }
  }

zopflib/src/zopflipng/zopflipng_lib.cc  view on Meta::CPAN

  bool bit16 = false;  // Using 16-bit per channel raw image
  if (inputstate.info_png.color.bitdepth == 16 &&
      (keep_colortype || !png_options.lossy_8bit)) {
    // Decode as 16-bit
    image.clear();
    error = lodepng::decode(image, w, h, origpng, LCT_RGBA, 16);
    bit16 = true;
  }

  if (!error) {
    // If lossy_transparent, remove RGB information from pixels with alpha=0
    if (png_options.lossy_transparent && !bit16) {
      LossyOptimizeTransparent(&inputstate, &image[0], w, h);
    }

    if (png_options.auto_filter_strategy) {
      error = AutoChooseFilterStrategy(image, w, h, inputstate, bit16,
                                       keep_colortype, origpng,
                                       /* Don't try brute force */
                                       kNumFilterStrategies - 1,
                                       filterstrategies, strategy_enable);
    }

zopflib/src/zopflipng/zopflipng_lib.cc  view on Meta::CPAN


  return error;
}

extern "C" void CZopfliPNGSetDefaults(CZopfliPNGOptions* png_options) {

  memset(png_options, 0, sizeof(*png_options));
  // Constructor sets the defaults
  ZopfliPNGOptions opts;

  png_options->lossy_transparent    = opts.lossy_transparent;
  png_options->lossy_8bit           = opts.lossy_8bit;
  png_options->auto_filter_strategy = opts.auto_filter_strategy;
  png_options->use_zopfli           = opts.use_zopfli;
  png_options->num_iterations       = opts.num_iterations;
  png_options->num_iterations_large = opts.num_iterations_large;
  png_options->block_split_strategy = opts.block_split_strategy;
}

extern "C" int CZopfliPNGOptimize(const unsigned char* origpng,
                                  const size_t origpng_size,
                                  const CZopfliPNGOptions* png_options,
                                  int verbose,
                                  unsigned char** resultpng,
                                  size_t* resultpng_size) {
  ZopfliPNGOptions opts;

  // Copy over to the C++-style struct
  opts.lossy_transparent    = !!png_options->lossy_transparent;
  opts.lossy_8bit           = !!png_options->lossy_8bit;
  opts.auto_filter_strategy = !!png_options->auto_filter_strategy;
  opts.use_zopfli           = !!png_options->use_zopfli;
  opts.num_iterations       = png_options->num_iterations;
  opts.num_iterations_large = png_options->num_iterations_large;
  opts.block_split_strategy = png_options->block_split_strategy;

  for (int i = 0; i < png_options->num_filter_strategies; i++) {
    opts.filter_strategies.push_back(png_options->filter_strategies[i]);
  }

zopflib/src/zopflipng/zopflipng_lib.h  view on Meta::CPAN

  kStrategyThree = 3,
  kStrategyFour = 4,
  kStrategyMinSum,
  kStrategyEntropy,
  kStrategyPredefined,
  kStrategyBruteForce,
  kNumFilterStrategies /* Not a strategy but used for the size of this enum */
};

typedef struct CZopfliPNGOptions {
  int lossy_transparent;
  int lossy_8bit;

  enum ZopfliPNGFilterStrategy* filter_strategies;
  // How many strategies to try.
  int num_filter_strategies;

  int auto_filter_strategy;

  char** keepchunks;
  // How many entries in keepchunks.

zopflib/src/zopflipng/zopflipng_lib.h  view on Meta::CPAN

#endif

// C++ API
#ifdef __cplusplus

struct ZopfliPNGOptions {
  ZopfliPNGOptions();

  bool verbose;

  // Allow altering hidden colors of fully transparent pixels
  bool lossy_transparent;
  // Convert 16-bit per channel images to 8-bit per channel
  bool lossy_8bit;

  // Filter strategies to try
  std::vector<ZopfliPNGFilterStrategy> filter_strategies;

  // Automatically choose filter strategy using less good compression
  bool auto_filter_strategy;

  // PNG chunks to keep



( run in 0.486 second using v1.01-cache-2.11-cpan-0a6323c29d9 )