imagequant 1.1.2__cp313-cp313-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
imagequant/__init__.py ADDED
@@ -0,0 +1,204 @@
1
+ # The library can be used without PIL/Pillow
2
+ try:
3
+ from PIL import Image
4
+ except ImportError:
5
+ Image = None
6
+
7
+ from ._libimagequant import lib, ffi
8
+
9
+
10
+ def _get_error_msg(code):
11
+ """Get error string from libimagequant return codes.
12
+
13
+ :param int code: The code returned by libimagequant.
14
+
15
+ :rtype: str
16
+ """
17
+ if code == lib.LIQ_QUALITY_TOO_LOW:
18
+ return "Quality too low"
19
+ elif code == lib.LIQ_VALUE_OUT_OF_RANGE:
20
+ return "Value out of range"
21
+ elif code == lib.LIQ_OUT_OF_MEMORY:
22
+ return "Out of memory"
23
+ elif code == lib.LIQ_ABORTED:
24
+ return "Aborted"
25
+ elif code == lib.LIQ_BITMAP_NOT_AVAILABLE:
26
+ return "Bitmap not available"
27
+ elif code == lib.LIQ_BUFFER_TOO_SMALL:
28
+ return "Buffer too small"
29
+ elif code == lib.LIQ_INVALID_POINTER:
30
+ return "Invalid pointer"
31
+ elif code == lib.LIQ_UNSUPPORTED:
32
+ return "Unsupported"
33
+ else:
34
+ return "Unknown error"
35
+
36
+
37
+ def _pil_image_to_raw_bytes(image):
38
+ """Get raw bytes from a PIL/Pillow image.
39
+
40
+ :param PIL.Image.Image image: The image.
41
+
42
+ :rtype: bytes
43
+ :return: The image as raw bytes (``b"RGBARGBARGBA..."``).
44
+ """
45
+ return bytes([comp for pix in image.getdata() for comp in pix])
46
+
47
+
48
+ def _liq_palette_to_raw_palette(liq_palette):
49
+ """Converts a liq_palette to a raw RGBA palette usable with PIL/Pillow image.
50
+
51
+ :param liq_palette: The palette de convert.
52
+
53
+ :rtype: list
54
+ :return: The raw RGBA palette (``[r0, g0, b0, a0, r1, g1, b1, a1,...]``).
55
+ """
56
+ return sum(
57
+ [[color.r, color.g, color.b, color.a] for color in liq_palette.entries], []
58
+ )
59
+
60
+
61
+ def quantize_raw_rgba_bytes(
62
+ image_data,
63
+ width,
64
+ height,
65
+ dithering_level=1.0,
66
+ max_colors=256,
67
+ min_quality=0,
68
+ max_quality=100,
69
+ ):
70
+ """Converts an RGBA image to an optimized 8bit paletted image.
71
+
72
+ :param bytes image_data: Raw RGBA image data (format: ``b"RGBARGBARGBA..."``).
73
+ :param int width: Image's width.
74
+ :param int height: Image's height.
75
+ :param float dithering_level: The dithering level, from ``0.0`` (no
76
+ dithering) to ``1.0`` (default: ``1.0``).
77
+ :param int max_colors: Maximum number of color to use in the palette, from
78
+ ``1`` to ``256`` (default: ``256``).
79
+ :param int min_quality: Minimum acceptable quality. If the minimum quality
80
+ can’t be met, the quantization will be aborted and
81
+ a ``RuntimeError`` will be raised. From ``0`` to
82
+ ``100`` (default: ``0``).
83
+ :param int max_quality: The target quality, from ``0`` to ``100``
84
+ (default: ``100``).
85
+
86
+ :rtype: tuple(bytes, list)
87
+ :return: The processed image bytes (each byte represents a pixel and its
88
+ value is the index of a color from the palette), and the palette
89
+ (format: ``[r0, g0, b0, a0, r1, g1, b1, a1,...]``).
90
+
91
+ >>> import imagequant
92
+ >>> imagequant.quantize_raw_rgba_bytes(
93
+ ... b"\\xFF\\x00\\x00\\xFF"
94
+ ... b"\\x00\\xFF\\x00\\xFF"
95
+ ... b"\\x00\\x00\\xFF\\xFF"
96
+ ... b"\\xFF\\xFF\\xFF\\xFF",
97
+ ... 2, 2
98
+ ... )
99
+ (b'...', [...])
100
+ """
101
+ if len(image_data) != 4 * width * height:
102
+ raise ValueError("image_data length do not match the given width and height")
103
+
104
+ if not 0.0 <= dithering_level <= 1.0:
105
+ raise ValueError("dithering_level must be a float between 0.0 and 1.0")
106
+
107
+ if not 1 <= max_colors <= 256:
108
+ raise ValueError("max_colors must be an integer between 1 and 256")
109
+
110
+ if not 0 <= min_quality <= 100:
111
+ raise ValueError("min_quality must be an integer between 0 and 100")
112
+
113
+ if not 0 <= max_quality <= 100:
114
+ raise ValueError("max_quality must be an integer between 0 and 100")
115
+
116
+ if min_quality > max_quality:
117
+ raise ValueError("min_quality must be lower or equal to max_quality")
118
+
119
+ liq_attr = lib.liq_attr_create()
120
+ liq_attr.max_colors = max_colors
121
+ lib.liq_set_quality(liq_attr, min_quality, max_quality)
122
+
123
+ liq_image = lib.liq_image_create_rgba(liq_attr, image_data, width, height, 0)
124
+
125
+ liq_result_p = ffi.new("liq_result**")
126
+ code = lib.liq_image_quantize(liq_image, liq_attr, liq_result_p)
127
+ if code != lib.LIQ_OK:
128
+ raise RuntimeError(_get_error_msg(code))
129
+ lib.liq_set_dithering_level(liq_result_p[0], dithering_level)
130
+
131
+ raw_8bit_pixels = ffi.new("char[]", width * height)
132
+ lib.liq_write_remapped_image(
133
+ liq_result_p[0], liq_image, raw_8bit_pixels, width * height
134
+ )
135
+
136
+ pal = lib.liq_get_palette(liq_result_p[0])
137
+
138
+ output_image_data = ffi.unpack(raw_8bit_pixels, width * height)
139
+ output_palette = _liq_palette_to_raw_palette(pal)
140
+
141
+ lib.liq_result_destroy(liq_result_p[0])
142
+ lib.liq_image_destroy(liq_image)
143
+ lib.liq_attr_destroy(liq_attr)
144
+ ffi.release(raw_8bit_pixels)
145
+
146
+ return output_image_data, output_palette
147
+
148
+
149
+ def quantize_pil_image(
150
+ image,
151
+ dithering_level=1.0,
152
+ max_colors=256,
153
+ min_quality=0,
154
+ max_quality=100,
155
+ ):
156
+ """Converts an RGBA image to an optimized 8bit paletted image.
157
+
158
+ :param PIL.Image.Image image: The image to process.
159
+ :param float dithering_level: The dithering level, from ``0.0`` (no
160
+ dithering) to ``1.0`` (default: ``1.0``).
161
+ :param int max_colors: Maximum number of color to use in the palette, from
162
+ ``1`` to ``256`` (default: ``256``).
163
+ :param int min_quality: Minimum acceptable quality. If the minimum quality
164
+ can’t be met, the quantization will be aborted and
165
+ a ``RuntimeError`` will be raised. From ``0`` to
166
+ ``100`` (default: ``0``).
167
+ :param int max_quality: The target quality, from ``0`` to ``100``
168
+ (default: ``100``).
169
+
170
+ :rtype: PIL.Image.Image
171
+ :return: The processed image as a PIL/Pillow image.
172
+
173
+ >>> import imagequant
174
+ >>> input_image = Image.open("./example.png")
175
+ >>> imagequant.quantize_pil_image(input_image)
176
+ <PIL.Image.Image image mode=P size=... at ...>
177
+ """
178
+ if Image is None:
179
+ raise ImportError("PIL or Pillow is required to use this function.")
180
+
181
+ if image.mode != "RGBA":
182
+ image = image.convert(mode="RGBA")
183
+
184
+ input_image_data = _pil_image_to_raw_bytes(image)
185
+
186
+ output_image_data, output_palette = quantize_raw_rgba_bytes(
187
+ input_image_data,
188
+ image.width,
189
+ image.height,
190
+ dithering_level=dithering_level,
191
+ max_colors=max_colors,
192
+ min_quality=min_quality,
193
+ max_quality=max_quality,
194
+ )
195
+
196
+ output_image = Image.frombytes(
197
+ "P",
198
+ [image.width, image.height],
199
+ output_image_data,
200
+ decoder_name="raw",
201
+ )
202
+ output_image.putpalette(output_palette, rawmode="RGBA")
203
+
204
+ return output_image
Binary file
@@ -0,0 +1,37 @@
1
+ import os
2
+
3
+ from cffi import FFI
4
+ from distutils import ccompiler
5
+
6
+
7
+ _ROOT = os.path.abspath(os.path.dirname(__file__))
8
+ _LIBIMAGEQUANT_H = os.path.join(_ROOT, "libimagequant.h")
9
+ _LIBIMAGEQUANT_SRC = [
10
+ "blur.c",
11
+ "kmeans.c",
12
+ "mediancut.c",
13
+ "mempool.c",
14
+ "nearest.c",
15
+ "pam.c",
16
+ "libimagequant.c",
17
+ ]
18
+
19
+ CC_ARGS = []
20
+ if ccompiler.get_default_compiler() == "unix":
21
+ CC_ARGS = ["-Wno-incompatible-pointer-types"]
22
+
23
+
24
+ ffibuilder = FFI()
25
+ ffibuilder.set_source(
26
+ "imagequant._libimagequant",
27
+ "\n".join(['#include "%s"' % c for c in _LIBIMAGEQUANT_SRC]),
28
+ include_dirs=[
29
+ os.path.join(_ROOT, "..", "libimagequant"),
30
+ ],
31
+ extra_compile_args=CC_ARGS,
32
+ )
33
+ ffibuilder.cdef(open(_LIBIMAGEQUANT_H, "r").read())
34
+
35
+
36
+ if __name__ == "__main__":
37
+ ffibuilder.compile(verbose=True)
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2021, Wanadev <http://www.wanadev.fr/>
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+ * Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ * Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+ * Neither the name of Wanadev nor the
12
+ names of its contributors may be used to endorse or promote products
13
+ derived from this software without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL WANADEV BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,218 @@
1
+ Metadata-Version: 2.1
2
+ Name: imagequant
3
+ Version: 1.1.2
4
+ Summary: Image Quantization Library
5
+ Home-page: https://github.com/wanadev/imagequant-python
6
+ Author: Wanadev
7
+ Author-email: contact@wanadev.fr
8
+ Maintainer: Fabien LOISON
9
+ License: BSD-3-Clause
10
+ Project-URL: Source Code, https://github.com/wanadev/imagequant-python
11
+ Project-URL: Documentation, https://github.com/wanadev/imagequant-python#usage
12
+ Project-URL: Changelog, https://github.com/wanadev/imagequant-python#changelog
13
+ Project-URL: Issues, https://github.com/wanadev/imagequant-python/issues
14
+ Project-URL: Chat, https://discord.gg/BmUkEdMuFp
15
+ Keywords: image libimagequant pngquant cffi
16
+ License-File: LICENSE
17
+ Requires-Dist: cffi >=1.0.0
18
+ Requires-Dist: setuptools
19
+ Provides-Extra: dev
20
+ Requires-Dist: nox ; extra == 'dev'
21
+ Requires-Dist: flake8 ; extra == 'dev'
22
+ Requires-Dist: black ; extra == 'dev'
23
+ Requires-Dist: pytest ; extra == 'dev'
24
+ Provides-Extra: pil
25
+ Requires-Dist: pillow ; extra == 'pil'
26
+
27
+ Imagequant Python - Python Bindings for libimagequant
28
+ =====================================================
29
+
30
+ |Github| |Discord| |PYPI Version| |Build Status| |Black| |License|
31
+
32
+ **Imagequant Python** are bindings to allow using libimagequant_ from Python.
33
+
34
+ **Libimagequant** is a small, portable C library for high-quality conversion of RGBA images to 8-bit indexed-color (palette) images.
35
+
36
+ .. _libimagequant: https://github.com/ImageOptim/libimagequant
37
+
38
+
39
+ Install
40
+ -------
41
+
42
+ From PyPI::
43
+
44
+ pip3 install imagequant
45
+
46
+ NOTE: you may require compilation tools to build the library if you system is not suitable for the precompiled wheels. On Debian / Ubuntu you can install the build dependencies with the following command::
47
+
48
+ sudo apt install build-essential python3-dev
49
+
50
+
51
+ Usage
52
+ -----
53
+
54
+ With PIL / Pillow
55
+ ~~~~~~~~~~~~~~~~~
56
+
57
+ .. code-block:: python
58
+
59
+ from PIL import Image
60
+ import imagequant
61
+
62
+ input_image = Image.open("./example.png")
63
+ output_image = imagequant.quantize_pil_image(
64
+ input_image,
65
+ dithering_level=1.0, # from 0.0 to 1.0
66
+ max_colors=256, # from 1 to 256
67
+ min_quality=0, # from 0 to 100
68
+ max_quality=100, # from 0 to 100
69
+ )
70
+ output_image.save("./out.png", format="PNG")
71
+
72
+ |input_image| → |output_image|
73
+
74
+ .. |input_image| image:: ./example.png
75
+ .. |output_image| image:: ./example_out.png
76
+
77
+
78
+ With Raw Data
79
+ ~~~~~~~~~~~~~
80
+
81
+ .. code-block:: python
82
+
83
+ import imagequant
84
+
85
+ # 2×2px image
86
+ IMAGE_DATA = (
87
+ # | R | G | B | A |
88
+ b"\xFF\x00\x00\xFF" # red
89
+ b"\x00\xFF\x00\xFF" # lime
90
+ b"\x00\x00\xFF\xFF" # blue
91
+ b"\xFF\xFF\xFF\xFF" # white
92
+ )
93
+
94
+ output_image_data, output_palette = imagequant.quantize_raw_rgba_bytes(
95
+ IMAGE_DATA, # RGBA image data
96
+ 2, 2, # width, height
97
+ dithering_level=1.0, # from 0.0 to 1.0
98
+ max_colors=256, # from 1 to 256
99
+ min_quality=0, # from 0 to 100
100
+ max_quality=100, # from 0 to 100
101
+ )
102
+
103
+ # you can now encode image data and the palette in any image format...
104
+
105
+ Example ``output_image_data``:
106
+
107
+ .. code-block:: python
108
+
109
+ b'\x02\x03\x00\x01'
110
+
111
+ Example ``output_palette``:
112
+
113
+ .. code-block:: python
114
+
115
+ [0, 0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 0, 0, ...]
116
+ # color 0 | color 1 | color 2 | color 3 | color 4 | ...
117
+
118
+
119
+ Development of the Bindings
120
+ ---------------------------
121
+
122
+ Clone the repository and get the submodules::
123
+
124
+ git clone https://github.com/wanadev/imagequant-python.git
125
+ cd imagequant-python
126
+ git submodule init
127
+ git submodule update
128
+
129
+ Install some dependencies (preferably in a virtualenv)::
130
+
131
+ pip3 install nox cffi pillow
132
+
133
+ Build the binary part of the lib::
134
+
135
+ python imagequant/libimagequant_build.py
136
+
137
+ A ``.so`` file (or a ``.pyd`` file on Windows, or a ``.dylib`` file on MacOS) shoud now be present in the ``imagequant/`` folder. You will not need to run this command again until you change something in ``imagequant/libimagequant.h`` or in ``libimagequant/*.{c,h}``.
138
+
139
+ To check the coding style, you can run the lint with the following command::
140
+
141
+ nox -s lint
142
+
143
+ To run the tests, use the following command::
144
+
145
+ nox -s test
146
+
147
+
148
+ License
149
+ -------
150
+
151
+ **Imagequant Python** is licensed under the BSD 3 Clause. See the LICENSE_ file for more information.
152
+
153
+ **Libimagequant** is dual-licensed:
154
+
155
+ * For Free/Libre Open Source Software it's available under GPL v3 or later with additional copyright notices for older parts of the code.
156
+
157
+ * For use in closed-source software, AppStore distribution, and other non-GPL uses, you can obtain a commercial license.
158
+
159
+ Read its `license terms <https://github.com/ImageOptim/libimagequant#license>`_ for more information.
160
+
161
+ .. _LICENSE: https://github.com/wanadev/imagequant-python/blob/master/LICENSE
162
+
163
+
164
+ Changelog
165
+ ---------
166
+
167
+ * **[NEXT]** (changes on ``master`` that have not been released yet):
168
+
169
+ * Nothing yet ;)
170
+
171
+ * **v1.1.2:**
172
+
173
+ * misc: Removed PyPy wheels for Windows AMD64 as they won't build (@flozz)
174
+ * misc: Fixed libimagequant build on newer GCC versions (@flozz)
175
+ * misc: Added Python 3.13 support (@flozz)
176
+ * misc!: Removed Python 3.8 support (@flozz)
177
+
178
+ * **v1.1.1:**
179
+
180
+ * dist: Build and publish arm64 wheels for Linux and Windows (@laggykiller, #9, #10)
181
+
182
+ * **v1.1.0:**
183
+
184
+ * Added options to set minimal and target (maximal) quality (@injet-zhou, #4)
185
+
186
+ * **v1.0.5:**
187
+
188
+ * Added Python 3.12 support (@flozz)
189
+ * Removed Python 3.7 support (@flozz)
190
+
191
+ * **v1.0.4:**
192
+
193
+ * Added Python 3.11 support
194
+
195
+ * **v1.0.3:**
196
+
197
+ * ``arm64`` and ``universal2`` wheels for macOS M1
198
+ * ``x86`` and ``x68_64`` wheels for musl-based Linux distro (Alpine,...)
199
+ * ``x86`` wheels for Windows (``x86_64`` were already available)
200
+
201
+ * **v1.0.2:** Python 3.10 support and wheels
202
+ * **v1.0.1:** Fix encoding while reading the README in setup.py
203
+ * **v1.0.0:** Initial release with a minimal API.
204
+
205
+
206
+
207
+ .. |Github| image:: https://img.shields.io/github/stars/wanadev/imagequant-python?label=Github&logo=github
208
+ :target: https://github.com/wanadev/imagequant-python
209
+ .. |Discord| image:: https://img.shields.io/badge/chat-Discord-8c9eff?logo=discord&logoColor=ffffff
210
+ :target: https://discord.gg/BmUkEdMuFp
211
+ .. |PYPI Version| image:: https://img.shields.io/pypi/v/imagequant.svg
212
+ :target: https://pypi.python.org/pypi/imagequant
213
+ .. |Build Status| image:: https://github.com/wanadev/imagequant-python/actions/workflows/python-ci.yml/badge.svg
214
+ :target: https://github.com/wanadev/imagequant-python/actions
215
+ .. |Black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
216
+ :target: https://black.readthedocs.io/en/stable/
217
+ .. |License| image:: https://img.shields.io/pypi/l/imagequant.svg
218
+ :target: https://github.com/wanadev/imagequant-python/blob/master/LICENSE
@@ -0,0 +1,8 @@
1
+ imagequant/__init__.py,sha256=Zne82B1a_FXYKbwWMguJmgGfO3NLd7c7L2v00UA7QPg,7109
2
+ imagequant/_libimagequant.pyd,sha256=bcyOq2rCo5_kRg6PlUoCrk_r4A8l-Teyvp3xaCMbdq8,97792
3
+ imagequant/libimagequant_build.py,sha256=OL-3EjI_gjcwOpAaVoRcmYQj1G-rc5Y7jIbTvZgGays,840
4
+ imagequant-1.1.2.dist-info/LICENSE,sha256=WjuRuFXN2gXuJFKlhnK19ITS8sBlwOjdbRMCCU5oISA,1521
5
+ imagequant-1.1.2.dist-info/METADATA,sha256=w2W0JFyQlYTrAJVkYp_-EbkTP31fP_ZnIIr-flgCHBc,6988
6
+ imagequant-1.1.2.dist-info/WHEEL,sha256=UJbDlEYuWWwgv9Hu0As4Rgv2Qpdka2YFe6UlEKs4AoE,101
7
+ imagequant-1.1.2.dist-info/top_level.txt,sha256=9AzQ9NgvAz4fDBTQwr6nG2LtlMnV88Dm3IGIkx0ZfGo,11
8
+ imagequant-1.1.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.3.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp313-cp313-win_amd64
5
+
@@ -0,0 +1 @@
1
+ imagequant