libimagequant Python Bindings Documentation¶
Welcome to the documentation for the unofficial Python bindings for libimagequant.
These bindings are designed to be Pythonic, yet still faithful to the C API. Almost every C function can be used through the bindings. The Python classes correspond directly to C structs, and each Python function represents one C function. However, some changes have been made:
- All functions have been made into class methods.
- Functions that are effectively getters and setters for struct members are represented as class properties.
- Values that are semantically boolean but are of the
inttype in C are given the Pythonbooltype. - Error-code return values are instead expressed by raising exceptions (see Exceptions).
- A few functions – mostly ones that don’t make much sense in Python – are not supported (see Functions with no direct Python equivalent).
This documentation is intentionally terse, so as to avoid duplicating the information in the official C API documentation. The recommended way to use this page is to first peruse the official libimagequant C API documentation to see how you could accomplish your goals in C, and to then search for the C function names here to find the equivalent Python APIs.
You may want to take a look at Examples, Installation, or the API reference.
Note
You might also be interested in the companion library libimagequant_integrations, which provides helper functions for using libimagequant with many other Python libraries used for imagery.
Indices and tables¶
Examples¶
Note: instead of copypasting these examples in order to use libimagequant with PyPNG or other imagery modules, consider using the libimagequant_integrations library, which provides robust conversion functions for you.
Here’s the simplest useful example, which uses PyPNG for loading/saving PNGs:
import libimagequant as liq
import png
# Load the image with PyPNG
img = png.Reader(filename='input.png')
width, height, data, info = img.read_flat()
# Create libimagequant Attr and Image objects from it
attr = liq.Attr()
input_image = attr.create_rgba(data, width, height, info.get('gamma', 0))
# Quantize
result = input_image.quantize(attr)
# Get the quantization result
out_pixels = result.remap_image(input_image)
out_palette = result.get_palette()
# Save it
writer = png.Writer(input_image.width, input_image.height, palette=out_palette)
with open('output.png', 'wb') as f:
writer.write_array(f, out_pixels)
And here’s a port of example.c from the libimagequant repository:
import sys
import libimagequant as liq
import png
def main(argv):
if len(argv) < 2:
print('Please specify a path to a PNG file', file=sys.stderr)
return 1
input_png_file_path = argv[1]
# Load PNG file and decode it as raw RGBA pixels
# This uses the PyPNG library for PNG reading (not part of libimagequant)
reader = png.Reader(filename=input_png_file_path)
width, height, input_rgba_pixels, info = reader.read_flat()
# Use libimagequant to make a palette for the RGBA pixels
attr = liq.Attr()
input_image = attr.create_rgba(input_rgba_pixels, width, height, info.get('gamma', 0))
result = input_image.quantize(attr)
# Use libimagequant to make new image pixels from the palette
result.dithering_level = 1.0
raw_8bit_pixels = result.remap_image(input_image)
palette = result.get_palette()
# Save converted pixels as a PNG file
# This uses the PyPNG library for PNG writing (not part of libimagequant)
writer = png.Writer(input_image.width, input_image.height, palette=palette)
output_png_file_path = 'quantized_example.png'
with open(output_png_file_path, 'wb') as f:
writer.write_array(f, raw_8bit_pixels)
print('Written ' + output_png_file_path)
# Done.
main(sys.argv)
Installation¶
Builds (fully unit-tested) are provided for supported versions of CPython 3 (3.6 through 3.10, at the time of this writing) on the following platforms:
- x86_64 Windows
- x86 (32-bit) Windows
- x86_64 macOS
- x86_64 Linux (for both the “manylinux2014” platform and a PEP-600-compatible manylinux platform)
A source distribution (“sdist”) is also available, which should be compatible with PyPy, as well as other platforms and architectures.
The recommended way to install is through pip. You can try running:
pip install libimagequant
If that doesn’t work, you might have better luck with either of:
python3 -m pip install libimagequant
py -3 -m pip install libimagequant
If for some reason you’d instead like to install from source manually (such as for debugging), read on.
Building from source¶
To build from source manually, begin by cloning or downloading the repository.
If desired, you can replace the libimagequant folder with the latest
libimagequant source code from its own repository.
Install cffi, setuptools and wheel on the Python interpreter you
want the bindings to be built against. For example,
python3 -m pip install --upgrade cffi setuptools wheel
Navigate (in a terminal) to the bindings directory, and run
setup.py bdist_wheel with the Python interpreter you want the bindings to
be built against. For example,
python3 setup.py bdist_wheel
This should create (among other things) a dist folder with a .whl
(wheel) file inside. You can now install that wheel file with pip, or
distribute it.
API reference¶
Exceptions¶
Many functions in libimagequant’s C API use liq_error enum return values to
indicate success or errors. Since it is more Pythonic to use exceptions for
this, the Python bindings for those functions convert those return values to
exceptions, which you can catch using try/except. The following table
outlines how they’re mapped:
liq_error value |
Python exception |
|---|---|
LIQ_OK |
(n/a) |
LIQ_QUALITY_TOO_LOW |
libimagequant.QualityTooLowError |
LIQ_VALUE_OUT_OF_RANGE |
ValueError |
LIQ_OUT_OF_MEMORY |
MemoryError |
LIQ_ABORTED |
libimagequant.AbortedError |
LIQ_BITMAP_NOT_AVAILABLE |
libimagequant.BitmapNotAvailableError |
LIQ_BUFFER_TOO_SMALL |
libimagequant.BufferTooSmallError |
LIQ_INVALID_POINTER |
RuntimeError |
LIQ_UNSUPPORTED |
libimagequant.UnsupportedError |
Constants¶
-
libimagequant.LIQ_VERSION and libimagequant.LIQ_VERSION_STRING Information about the version of libimagequant currently in use.
Depending on your use case, you may want to use
BINDINGS_VERSIONandBINDINGS_VERSION_STRINGinstead.Python equivalents of
LIQ_VERSIONandLIQ_VERSION_STRING.
-
libimagequant.BINDINGS_VERSION and libimagequant.BINDINGS_VERSION_STRING Information about the version of the Python bindings currently in use.
The bindings version is the version of libimagequant the bindings were designed for, with an additional version segment (usually
.0). For example, for the bindings release designed for libimagequant 2.12.5,BINDINGS_VERSIONandBINDINGS_VERSION_STRINGwould be 2120500 and'2.12.5.0', respectively.This will often match
LIQ_VERSIONandLIQ_VERSION_STRING(up to the extra segment), but is not guaranteed to always do so.Depending on your use case, you may want to use
LIQ_VERSIONandLIQ_VERSION_STRINGinstead.
Classes¶
-
class
libimagequant.Attr¶ Python equivalent of the
liq_attrstruct.The constructor for this class is the equivalent of
liq_attr_create().liq_attr_destroy()is handled automatically.-
max_colors¶ Python equivalent of
liq_get_max_colors()andliq_set_max_colors().Type: int
-
speed¶ Python equivalent of
liq_get_speed()andliq_set_speed().Type: int
-
min_opacity¶ Python equivalent of
liq_get_min_opacity()andliq_set_min_opacity().Type: int
-
min_posterization¶ Python equivalent of
liq_get_min_posterization()andliq_set_min_posterization().Type: int
-
min_quality¶ Python equivalent of
liq_get_min_quality()and (along withmax_quality)liq_set_quality().Type: int
-
max_quality¶ Python equivalent of
liq_get_max_quality()and (along withmin_quality)liq_set_quality().Type: int
-
last_index_transparent¶ Python equivalent of
liq_set_last_index_transparent().For consistency with the C API, this is a write-only property.
Note
Since the only meaningful values for this variable in the C API are “zero” and “non-zero,” it is presented as a
boolin these Python bindings.Type: bool
-
copy() → Attr¶ Python equivalent of
liq_attr_copy().Returns: A copy of this object. Return type: libimagequant.Attr
-
create_rgba(bitmap: bytes, width: int, height: int, gamma: float) → Image¶ Python equivalent of
liq_image_create_rgba().Returns: The new image created from the provided data. Return type: libimagequant.Image
-
set_log_callback(log_callback_function: Callable[[Attr, str, object], None], user_info: object)¶ Python equivalent of
liq_set_log_callback().The signature of the callback function should be
callback(attr: Attr, message: str, user_info: object).The
user_infoparameter can be any Python object, which will be passed to the callback as its third argument.Call this function with
log_callback_function = Noneto clear the callback.
-
set_progress_callback(progress_callback_function: Callable[[float, object], bool], user_info: object)¶ Python equivalent of
liq_attr_set_progress_callback().The signature of the callback function should be
callback(progress_percent: float, user_info: object) -> bool. If it returnsFalse, the quantization operation will be aborted (causingAbortedExceptionto be raised); thus, you should normally returnTruefrom the callback in order for the operation to proceed.The
user_infoparameter can be any Python object, which will be passed to the callback as its third argument.Call this function with
progress_callback_function = Noneto clear the callback.
-
-
class
libimagequant.Histogram(attr: Attr)¶ Python equivalent of the
liq_histogramstruct.The constructor for this class is the equivalent of
liq_histogram_create().liq_histogram_destroy()is handled automatically.-
add_image(attr: Attr, image: Image)¶ Python equivalent of
liq_histogram_add_image().
-
add_colors(attr: Attr, entries: List[HistogramEntry], gamma: float)¶ Python equivalent of
liq_histogram_add_colors().
-
add_fixed_color(color: Color, gamma: float)¶ Python equivalent of
liq_histogram_add_fixed_color().
-
quantize(options: Attr) → Result¶ Python equivalent of
liq_histogram_quantize().Returns: The result of the quantization. Return type: libimagequant.Result
-
-
class
libimagequant.HistogramEntry(color: Color, count: int)¶ Python equivalent of the
liq_histogram_entrystruct.-
color¶ Python equivalent of the
liq_histogram.colormember.Type: libimagequant.Color
-
count¶ Python equivalent of the
liq_histogram.countmember.Type: int
-
-
class
libimagequant.Image¶ Python equivalent of the
liq_imagestruct.This class cannot be instantiated directly. Use
Image.create_rgba()to create it.liq_image_destroy()is handled automatically.-
width¶ Python equivalent of
liq_image_get_width().This is a read-only property.
Type: int
-
height¶ Python equivalent of
liq_image_get_height().This is a read-only property.
Type: int
-
background¶ Python equivalent of
liq_image_set_background().For consistency with the C API, this is a write-only property.
Type: libimagequant.Image
-
importance_map¶ Python equivalent of
liq_image_set_importance_map().For consistency with the C API, this is a write-only property.
Type: bytes
-
add_fixed_color(color: Color)¶ Python equivalent of
liq_image_add_fixed_color().
-
quantize(options: Attr) → Result¶ Python equivalent of
liq_image_quantize().Returns: The result of the quantization. Return type: libimagequant.Result
-
-
class
libimagequant.Result¶ Python equivalent of the
liq_resultstruct.This class cannot be instantiated directly. Use
Histogram.quantize()orImage.quantize()to create it.liq_result_destroy()is handled automatically.-
dithering_level¶ Python equivalent of
liq_set_dithering_level().For consistency with the C API, this is a write-only property.
Type: float
-
output_gamma¶ Python equivalent of
liq_get_output_gamma()andliq_set_output_gamma().Type: float
-
quantization_error¶ Python equivalent of
liq_get_quantization_error().This is a read-only property.
Type: float
-
quantization_quality¶ Python equivalent of
liq_get_quantization_quality().This is a read-only property.
Type: int
-
remapping_error¶ Python equivalent of
liq_get_remapping_error().This is a read-only property.
Type: float
-
remapping_quality¶ Python equivalent of
liq_get_remapping_quality().This is a read-only property.
Type: int
-
get_palette() → List[Color]¶ Python equivalent of
liq_get_palette().Returns: The list of colors. Return type: listoflibimagequant.Colors
-
remap_image(input_image: Image) → bytes¶ Python equivalent of
liq_write_remapped_image().Returns: The pixel data for the remapped image. Return type: bytes
-
set_progress_callback(progress_callback_function: Callable[[float, object], bool], user_info: object)¶ Python equivalent of
liq_result_set_progress_callback().The signature of the callback function should be
callback(progress_percent: float, user_info: object) -> bool. If it returnsFalse, the remapping operation will be aborted (causingAbortedExceptionto be raised); thus, you should normally returnTruefrom the callback in order for the operation to proceed.The
user_infoparameter can be any Python object, which will be passed to the callback as its third argument.Call this function with
progress_callback_function = Noneto clear the callback.
-
-
class
libimagequant.Color¶ Python equivalent of the
liq_colorstruct.This is simply a collections.namedtuple with
r,g,b, andafields.Please note that the equivalent of a
liq_palettestruct in these bindings is alistof instances of this class.
Functions with no direct Python equivalent¶
liq_attr_create_with_allocator()Although “custom allocators” aren’t completely meaningless in Python (in the context of cffi, in particular), it’s an extremely uncommon case.
If you have a legitimate need for this feature, please open an issue (or, better, a pull request!). For 99% of cases,
Attr’s default constructor (corresponding toliq_attr_create()) should suffice.liq_set_log_flush_callback()This is unsupported due to issues that arise due to Python’s garbage collection. Since functions in Python are objects that get garbage-collected like all other types, there is no guarantee that the callback will actually still exist when the
Attrobject is deleted. This can lead to very weird and inconsistent issues.Since libimagequant is totally synchronous, the recommended workaround is to simply flush any logging resources after you finish using your libimagequant objects.
liq_image_create_rgba_rows()andliq_image_create_custom()These are unsupported because Python does not allow for the fine-grained raw pointer access that would make these functions useful.
Use
Image.create_rgba()(corresponding toliq_image_create_rgba()) instead.liq_image_set_memory_ownership()This is unsupported because it’s too low-level of a concern to expose to Python programs. Ensuring that memory is managed properly is the responsibility of the bindings themselves, not your application.
liq_write_remapped_image_rows()This is unsupported because Python does not allow for the fine-grained raw pointer access that would make it useful.
Use
Result.remap_image()(corresponding toliq_write_remapped_image()) instead.liq_version()Use
LIQ_VERSIONorBINDINGS_VERSIONinstead, depending on if you need to check the libimagequant version or the Python bindings version.liq_quantize_image()This is unsupported because it is deprecated in the C API. Use
Image.quantize()(corresponding toliq_image_quantize()) instead.