Defining new codecs
This page provides some detail on how to add new image compressors (codecs) to your experiments.
In general, to add new custom codecs to your lossless (or lossy) compression experiments,
you just need to add new instances of enb.icompression.AbstractCodec
subclasses.
Notwithstanding, several helper classes have been added to enb.icompression
to speed up
the creation of new codecs
Lossless codecs
Lossless codecs are expected to be able to reconstruct a mathematically identical representation the original data.
You can define new Lossless codecs by subclassing the enb.icompression.LosslessCodec
class, like in the
following example:
class LZ77Huffman(icompression.LosslessCodec):
MIN_COMPRESSION_LEVEL = 1
MAX_COMPRESSION_LEVEL = 9
DEFAULT_COMPRESSION_LEVEL = 5
def __init__(self, compression_level=DEFAULT_COMPRESSION_LEVEL, param_dict=None):
assert self.MIN_COMPRESSION_LEVEL <= compression_level <= self.MAX_COMPRESSION_LEVEL
param_dict = dict() if param_dict is None else param_dict
param_dict["compression_level"] = compression_level
super().__init__(param_dict=param_dict)
def compress(self, original_path, compressed_path, original_file_info):
with open(original_path, "rb") as original_file, \
open(compressed_path, "wb") as compressed_file:
compressed_file.write(zlib.compress(original_file.read(),
level=self.param_dict["compression_level"]))
def decompress(self, compressed_path, reconstructed_path, original_file_info=None):
with open(compressed_path, "rb") as compressed_file, \
open(reconstructed_path, "wb") as reconstructed_file:
reconstructed_file.write(zlib.decompress(compressed_file.read()))
@property
def label(self):
return f"lz77huffman_lvl{self.param_dict['compression_level']}"
Further working examples are readily available in the plugin_zip plugin.
Lossy and near lossless codecs
Lossy and near-lossless codecs can be defined by subclassing enb.icompression.LossyCodec
and
enb.icompression.NearLosslessCodec
, respectively.
As in the previous example, the compress(self, original_path, compressed_path, original_file_info) and decompress(self, compressed_path, reconstructed_path, original_file_info=None) functions need to be specified.
Executable wrapper codecs
Very often, compressors are implemented as an external tools, and compression and decompression
consists in running those executables. To minimize the amount of lines of code (and bugs) that
you need to type, the enb.icompression.WrapperCodec
is provided.
This class is better explained with an example:
class TrivialCpWrapper(icompression.WrapperCodec, icompression.LosslessCodec):
"""Trivial codec wrapper for /bin/cp.
"""
def __init__(self):
super().__init__(compressor_path="cp", decompressor_path="cp")
def get_compression_params(self, original_path, compressed_path, original_file_info):
return f"'{original_path}' '{compressed_path}'"
def get_decompression_params(self, compressed_path, reconstructed_path, original_file_info):
return f"'{compressed_path}' '{reconstructed_path}'"
In this case, only get_compression_params and get_decompression_params need to be implemented
The return value of these is a string with the parameters one would type after the binary path, e.g., in a bash console.
Note
The return value of get_compression_params and get_decompression_params should not include the executable path itself, only the parameters.
Packing your codec as a plugin
Once you have tested your codec, you might want to release it as a plugin so that other enb users can benefit from your development.
To create your plugin and share it with the community,
Create a folder with your code
Add a __init__.py file to that folder, with imports such as
from . import my_moduleif my_module.py is one of the modules you want to make available .
Add a __plugin__.py file such as the one in plugin_zip’s __plugin__.py, updating all needed fields. This contains basic metainformation for
enb
to be able to dynamically find and install your plugin.Send a pull request to the dev branch or get in touch with the maintainers so that it can be reviewed an published.