v0.4.0

API Reference

The package exports one class, LayerImage, and __version__. Operations change the image in place and return it, so calls can be chained. Call clone() first to keep an unchanged copy. Pixel values are floats in [0, 1].

Creating an Image

LayerImage.from_file(file_path)

Open an image file with Pillow. EXIF orientation is applied, so photos from cameras and phones load upright. Any color mode is converted to RGB, or to RGBA when the image has transparency. Metadata such as EXIF data and ICC profiles is not kept.

file_pathstr | Path
Path to any image file Pillow can open.

LayerImage.from_url(url, timeout=30.0)

Download an image over HTTP(S) with Requests, then open it the same way as from_file().

urlstr
Address of the image.
timeoutfloat = 30.0
Seconds to wait for the server.

LayerImage.from_array(image_data)

Wrap a NumPy array of floats with values in [0, 1].

image_dataNDArray[float64]
Shape (height, width, 3) for RGB or (height, width, 4) for RGBA.

Saving and Output

In a Jupyter notebook, a LayerImage displays as the image itself. Its repr shows the mode and size, for example <LayerImage RGB 1536x1024>.

image.save(filename, quality=95)

Write the image to a file. The format comes from the file extension: JPEG, PNG, BMP, TIFF, WebP or any other format Pillow can write. An RGBA image saved as JPEG is composited onto a white background.

filenamestr | Path
Output path.
qualityint = 95
JPEG quality from 0 to 100. Other formats ignore it.

image.get_image_as_array()

Return the pixels as a float64 array with values in [0, 1] and shape (height, width, 3) or (height, width, 4). This is the underlying array, not a copy. For a photo loaded from a file or URL, it applies any pending per-channel operations and keeps the image in float64 from then on.

image.clone()

Return an independent copy, including any operations still pending in the lookup table. Changes to the copy do not affect the original.

Adjustments

image.grayscale()

Convert to grayscale with the ITU-R 601 luminance weights (0.2989, 0.5870, 0.1140). The alpha channel is kept.

image.brightness(factor)

Multiply every channel by 1 + factor and clip to [0, 1]. A factor above 0 brightens, below 0 darkens.

factorfloat
0 leaves the image unchanged.

image.contrast(factor)

Scale each value around mid-gray, factor * (value - 0.5) + 0.5, and clip to [0, 1]. Above 1 increases contrast; between 0 and 1 decreases it.

factorfloat
1 leaves the image unchanged.

image.hue(target_hue)

Set every pixel's hue to target_hue while keeping saturation and value. This is a colorize-style adjustment.

target_huefloat
Hue in [0, 1].

image.saturation(factor)

Multiply saturation by 1 + factor and clip to [0, 1]. Above 0 boosts color, below 0 mutes it.

factorfloat
-1 removes all color. 0 leaves the image unchanged.

image.lightness(factor)

Blend toward white when factor is above 0, or toward black when it is below 0.

factorfloat
From -1 (black) to 1 (white). 0 leaves the image unchanged.

image.curve(channels="rgb", curve_points=None)

Remap tones through control points spaced evenly across [0, 1], on any combination of the red, green and blue channels.

channelsstr = "rgb"
Any non-empty combination of r, g and b, such as "rgb", "r" or "gb".
curve_pointslist[float] | None = None
Output levels in [0, 1]. The default, [0, 1], leaves the image unchanged.

image.resize(width, height)

Resize with Lanczos resampling. A photo loaded from a file or URL stays 8-bit.

widthint
New width in pixels, at least 1.
heightint
New height in pixels, at least 1.

Blend Modes

image.blend_mode(blend_data, opacity=1.0)

Every blend mode has this signature: replace blend_mode with one of the 14 methods below. Each combines the image (the base, A) with a blend layer (B), then mixes the result back with the original by opacity. A hex color, or an array with one value per channel, keeps an 8-bit photo on the lookup-table path. A per-pixel array converts it to float64 first.

blend_datastr | NDArray[float64]
A hex color such as "#e8743b", or a float array in [0, 1] that broadcasts to the image: shape (3,) for one color, or (height, width, 3) for a per-pixel layer such as a gradient or another photo.
opacityfloat = 1.0
From 0 (no change) to 1 (full effect).

Operations as Data

image.apply_from_dict(data)

Run a sequence of operations described in a dictionary, in order. The operation types below list the keys each one takes.

datadict
A dict with an "operations" list.
image.apply_from_dict({
    "operations": [
        {"type": "grayscale"},
        {"type": "brightness", "factor": 0.2},
        {"type": "multiply", "hex": "#ff0000", "opacity": 0.5},
        {"type": "resize", "width": 800, "height": 600},
        {"type": "curve", "channels": "rgb", "curve_points": [0, 0.5, 1]},
    ]
})

image.apply_from_json(filepath)

Load a JSON file with the same structure and pass it to apply_from_dict().

filepathstr | Path
Path to the JSON file.
image.apply_from_json("pipeline.json")

JSON Operation Types

Each entry in the "operations" list is an object with a "type" and the keys below. Operations run in order. An entry with an unknown type or a missing required key is skipped without an error.

TypeKeysCalls
grayscalenonegrayscale()
brightnessfactorbrightness(factor)
contrastfactorcontrast(factor)
saturationfactorsaturation(factor)
lightnessfactorlightness(factor)
huehuehue(hue)
curvechannels, curve_pointscurve(channels, curve_points)
resizewidth, heightresize(width, height)
any blend mode, such as multiplyhex, opacity (optional, default 1.0)multiply(hex, opacity)

In a dict or JSON file, blend modes take a hex color only. To blend with a NumPy array, call the method directly.