Python wrapper for multithreaded .png image file optimizer
oxipng (written in Rust). Use
pyoxipng
to reduce the file size of your PNG images.
Jump to a section
Install from PyPI:
pip install pyoxipng
Import in your Python code:
import oxipng
Optimize a file on disk.
Parameters:
- input (str | bytes | PathLike) – path to input file to optimize
- output (str | bytes | PathLike, optional) – path to optimized output result file. If not specified, overwrites input. Defaults to None
- **kwargs – Options
Returns
- None
Raises
- oxipng.PngError – optimization could not be completed
Examples:
Optimize a file on disk and overwrite
oxipng.optimize("/path/to/image.png")
Optimize a file and save to a new location:
oxipng.optimize("/path/to/image.png", "/path/to/image-optimized.png")
Optimize raw data from a PNG file loaded in Python as a bytes
object:
Parameters:
- data (bytes) – raw PNG data to optimize
- **kwargs – Options
Returns
- (bytes) – optimized raw PNG data
Raises
- oxipng.PngError – optimization could not be completed
Examples:
data = ... # bytes of png data
optimized_data = oxipng.optimize_from_memory(data)
with open("/path/to/image-optimized.png", "wb") as f:
f.write(optimized_data)
Create an optimized PNG file from raw image data:
raw = oxipng.RawImage(data, width, height)
optimized_data = raw.create_optimized_png()
By default, assumes the input data is 8-bit, row-major RGBA, where every 4 bytes represents one pixel with Red-Green-Blue-Alpha channels. To interpret non-RGBA data, specify a color_type
parameter with the oxipng.ColorType
class:
Method | Description |
---|---|
oxipng.ColorType.grayscale(int | None) |
Grayscale, with one color channel. Specify optional shade of gray that should be rendered as transparent. |
oxipng.ColorType.rgb(tuple[int, int, int]) |
RGB, with three color channels. Specify optional color value that should be rendered as transparent. |
oxipng.ColorType.indexed(list[[tuple[int, int, int, int]]) |
Indexed, with one byte per pixel representing a color from the palette. Specify palette containing the colors used, up to 256 entries. |
oxipng.ColorType.grayscale_alpha() |
Grayscale + Alpha, with two color channels. |
oxipng.ColorType.rgba() |
RGBA, with four color channels. |
Parameters:
- data (bytes | bytearray) – Raw image data bytes. Format depends on
color_type
andbit_depth
parameters - width (int) – Width of raw image, in pixels
- height (int) – Height of raw image, in pixels
- color_type ([oxipng.ColorType, optional) – Descriptor for color type used to represent this image. Optional, defaults to
oxipng.ColorType.rgba()
- bit_depth (int, optional) – Bit depth of raw image. Optional, defaults to 8
Examples:
Save RGB image data from a JPEG file, interpreting black pixels as transparent.
from PIL import Image
import numpy as np
# Load an image file with Pillow
jpg = Image.open("/path/to/image.jpg")
# Convert to RGB numpy array
rgb_array = np.array(jpg.convert("RGB"), dtype=np.uint8)
height, width, channels = rgb_array.shape
# Create raw image with sRGB color profile
data = rgb_array.tobytes()
color_type = oxipng.ColorType.rgb((0, 0, 0)) # black is transparent
raw = oxipng.RawImage(data, width, height, color_type=color_type)
raw.add_png_chunk(b"sRGB", b"\0")
# Optimize and save
optimized = raw.create_optimized_png(level=6)
with open("/path/to/image/optimized.png", "wb") as f:
f.write(optimized)
Save with data where bytes reference a color palette
data = b"\0\1\2..." # get index data
palette = [[0, 0, 0, 255], [1, 23, 234, 255], ...]
color_type = oxipng.ColorType.indexed(palette)
raw = oxipng.RawImage(data, 100, 100, color_type=color_type)
optimized = raw.create_optimized_png()
Methods:
Add a png chunk, such as b"iTXt"
, to be included in the output
Parameters:
- name (bytes) – PNG chunk identifier
- data (bytes | bytarray)
Returns:
- None
Add an ICC profile for the image
Parameters:
- data (bytes) – ICC profile data
Returns:
- None
Create an optimized png from the raw image data using the options provided
Parameters:
- **kwargs – Options
Returns:
- (bytes) optimized PNG image data
optimize
, optimize_from_memory
and RawImage.create_optimized_png
accept the following options as keyword arguments.
Example:
oxipng.optimize("/path/to/image.png", level=6, fix_errors=True, interlace=oxipng.Interlacing.Adam7)
Option | Description | Type | Default |
---|---|---|---|
level |
Set the optimization level to an integer between 0 and 6 (inclusive) | int | 2 |
fix_errors |
Attempt to fix errors when decoding the input file rather than throwing PngError |
bool | False |
force |
Write to output even if there was no improvement in compression | bool | False |
filter |
Which filters to try on the file. Use Use enum values from oxipng.RowFilter |
Sequence[RowFilter] | [RowFilter.NoOp] |
interlace |
Whether to change the interlacing type of the file. None will not change current interlacing type |
Interlacing | None | None |
optimize_alpha |
Whether to allow transparent pixels to be altered to improve compression | bool | False |
bit_depth_reduction |
Whether to attempt bit depth reduction | bool | True |
color_type_reduction |
Whether to attempt color type reduction | bool | True |
palette_reduction |
Whether to attempt palette reduction | bool | True |
grayscale_reduction |
Whether to attempt grayscale reduction | bool | True |
idat_recoding |
If any type of reduction is performed, IDAT recoding will be performed regardless of this setting | bool | True |
scale_16 |
Whether to forcibly reduce 16-bit to 8-bit by scaling | bool | False |
strip |
Which headers to strip from the PNG file, if any. Specify with oxipng.StripChunks |
StripChunks | StripChunks.none() |
deflate |
Which DEFLATE algorithm to use. Specify with oxipng.Deflaters |
Deflaters | Deflaters.libdeflater() |
fast_evaluation |
Whether to use fast evaluation to pick the best filter | bool | False |
timeout |
Maximum amount of time to spend (in seconds) on optimizations. Further potential optimizations skipped if the timeout is exceeded | float | None | None |
Initialize a filter
list or tuple with any of the following oxipng.RowFilter
enum options:
oxipng.RowFilter.NoOp
oxipng.RowFilter.Sub
oxipng.RowFilter.Up
oxipng.RowFilter.Average
oxipng.RowFilter.Paeth
oxipng.RowFilter.Bigrams
oxipng.RowFilter.BigEnt
oxipng.RowFilter.Brute
Set interlace
to None
to keep existing interlacing or to one of following oxipng.Interlacing
enum options:
oxipng.Interlacing.Off
(interlace disabled)oxipng.Interlacing.Adam7
(interlace enabled)
Initialize the strip
option with one of the following static methods in the
oxipng.StripChunks
class.
Method | Description |
---|---|
oxipng.StripChunks.none() |
None |
oxipng.StripChunks.strip(Sequence[bytes]) |
Strip chunks specified in the given list |
oxipng.StripChunks.safe() |
Strip chunks that won't affect rendering (all but cICP, iCCP, sRGB, pHYs, acTL, fcTL, fdAT) |
oxipng.StripChunks.keep(Sequence[bytes]) |
Strip all non-critical chunks except those in the given list |
oxipng.StripChunks.all() |
Strip all non-critical chunks |
Initialize the deflate
option with one of the following static methods in the
oxipng.Deflaters
class.
Method | Description |
---|---|
oxipng.Deflaters.libdeflater(int) |
Libdeflater with compression level [0-12] |
oxipng.Deflaters.zopfli(int) |
Zopfli with number of compression iterations to do [1-255] |
- Install Rust
- Install Python 3.8+
- Install Pipenv
- Clone this repository and navigate to it via command line
git clone https://github.com/nfrasser/pyoxipng.git cd pyoxipng
- Install dependencies
pipenv install --dev
- Activate the dev environment
pipenv shell
- Build
maturin develop
- Run tests
pytest
- Format code
ruff check . ruff format .
MIT