Layer.is
A library that supports all blend modes in Photoshop, brightness, contrast, hue, saturation, lightness adjustments, and curve adjustments on separate RGB channels.
This project was a part of the 2019 Open Source Software Competition.
Why use Layer.is?
- Supports all frequently used blend modes in Photoshop
- Chain operations for concise, readable image pipelines
- Straightforward API to manipulate images
- Load a sequence of operations from JSON
- Apply curve adjustments selectively to individual RGB channels
Requirements
Python 3.10 or higher.
Installation
From PyPI
pip install layeris
From source
git clone https://github.com/subwaymatch/layer-is-python.git
cd layer-is-python
pip install .
To install with development dependencies (includes pytest):
pip install -e ".[dev]"
# or, using hatch:
hatch env create
Quick Start
Load an image
from layeris import LayerImage
# From a local file
image = LayerImage.from_file('/path/to/image.jpg')
# From a URL
image = LayerImage.from_url('https://example.com/photo.jpg')
# From a NumPy array (float64, values in [0, 1], shape HxWx3 or HxWx4)
import numpy as np
data = np.random.random((100, 100, 3))
image = LayerImage.from_array(data)
Save an image
# Default quality is 95 for JPEG
image.save('output.jpg')
# Specify JPEG quality (0–100)
image.save('output.jpg', quality=85)
# Save as PNG (lossless)
image.save('output.png')
Basic adjustments
# Grayscale
image.grayscale()
# Brightness (factor > 0 brightens, factor < 0 darkens)
image.brightness(0.2)
# Contrast (factor > 1 increases, 0 < factor < 1 decreases)
image.contrast(1.5)
# Hue (value in [0, 1])
image.hue(0.3)
# Saturation (factor > 0 increases, factor < 0 decreases; -1 fully desaturates)
image.saturation(-0.5)
# Lightness (factor > 0 lightens toward white, factor < 0 darkens toward black)
image.lightness(0.4)
# Curve adjustment (apply an S-curve to the RGB channels)
image.curve('rgb', [0, 0.1, 0.4, 0.65, 0.9, 1])
# Curve on a single channel
image.curve('r', [0, 0.2, 0.8, 1])
Resize
image.resize(width=800, height=600)
Blend modes
All blend mode methods accept a hex colour string or a NumPy array, plus an optional opacity parameter (0.0–1.0).
Darken group
image.darken('#3fe28f')
image.multiply('#3fe28f', opacity=0.8)
image.color_burn('#7fe3f8')
image.linear_burn('#e1a8ff')
Lighten group
image.lighten('#ff3ce1')
image.screen('#e633ba')
image.color_dodge('#490cc7')
image.linear_dodge('#490cc7')
Contrast group
image.overlay('#ffb956')
image.soft_light('#ff3cbc')
image.hard_light('#df5dff')
image.vivid_light('#ac5b7f')
image.linear_light('#9fa500')
image.pin_light('#005546')
Method chaining
All operations return self, so calls can be chained:
result = (
LayerImage.from_file('photo.jpg')
.grayscale()
.brightness(0.1)
.multiply('#3fe28f', opacity=0.7)
.curve('rgb', [0, 0.2, 0.8, 1])
.save('output.jpg')
)
Clone
# Create an independent copy before branching
copy = image.clone()
copy.darken('#000000') # original is unaffected
Get image data as a NumPy array
arr = image.get_image_as_array()
# arr.shape → (height, width, 3) for RGB
# → (height, width, 4) for RGBA
# arr.dtype → float64
# values in [0.0, 1.0]
Apply operations from a dictionary or JSON file
Operations can be described as a Python dict (or a JSON file) and applied in sequence:
ops = {
"operations": [
{"type": "grayscale"},
{"type": "brightness", "factor": 0.15},
{"type": "multiply", "hex": "#3fe28f", "opacity": 0.6},
{"type": "curve", "channels": "rgb", "curve_points": [0, 0.1, 0.9, 1]},
{"type": "resize", "width": 800, "height": 600},
]
}
image.apply_from_dict(ops)
# Or load directly from a JSON file
image.apply_from_json('pipeline.json')
Supported operation types: grayscale, resize, brightness, contrast, hue,
saturation, lightness, curve, darken, multiply, color_burn,
linear_burn, lighten, screen, color_dodge, linear_dodge, overlay,
soft_light, hard_light, vivid_light, linear_light, pin_light.
Running tests
Install development dependencies and run the test suite with pytest:
# Using pip (editable install)
pip install -e .
pip install pytest pytest-cov
pytest
# Using hatch (recommended)
hatch run test
# With coverage report
hatch run test-cov
Run a specific test file or test:
pytest tests/test_layer_image.py
pytest tests/test_utils.py
pytest tests/test_layer_image.py::TestBlendModes::test_multiply_by_white_no_change -v
Blend mode reference
| Group | Method | Formula (A = base, B = blend) |
|---|---|---|
| Darken | darken |
min(A, B) |
| Darken | multiply |
A × B |
| Darken | color_burn |
1 − (1 − A) / B |
| Darken | linear_burn |
A + B − 1 |
| Lighten | lighten |
max(A, B) |
| Lighten | screen |
1 − (1 − A)(1 − B) |
| Lighten | color_dodge |
A / (1 − B) |
| Lighten | linear_dodge |
A + B |
| Contrast | overlay |
2AB if A ≤ 0.5 else 1 − 2(1−A)(1−B) |
| Contrast | soft_light |
Pegtop formula |
| Contrast | hard_light |
2AB if B ≤ 0.5 else 1 − 2(1−A)(1−B) |
| Contrast | vivid_light |
Color burn / dodge based on B |
| Contrast | linear_light |
A + 2B − 1 |
| Contrast | pin_light |
Conditional replace |
All results are clamped to [0, 1].
Roadmap
- Imitate Photoshop's auto brightness & auto contrast features
- Add filter presets
Metadata
Release files for layeris 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| layeris-0.3.1.tar.gz | 15.4 MB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| layeris-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 18.4 MB
Release files / layeris-0.3.1.tar.gz
| Download URL | layeris-0.3.1.tar.gz |
|---|---|
| Size | 15.4 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
79a458db60891b2e7166ccbf15b9f159ee5d109309947b5e8bd18bc132f7520d
|
|
BLAKE2b-256 checksum How to use checksums |
d84f1fe5a376c65ec46cbda131023511b344a5ac17f69be3425e773e0f5bb38c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
python-httpx/0.27.0
|
Release files / layeris-0.3.1-py3-none-any.whl
| Download URL | layeris-0.3.1-py3-none-any.whl |
|---|---|
| Size | 3.0 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c19ba2dbb0511c691dfe7e52300e2ab6a6b1bd6c2e2f05b3d3515ac3daf083e1
|
|
BLAKE2b-256 checksum How to use checksums |
1712ca2f6a2c502f850271a6925e5eef5f666361ee52b78eee05326662f4fcc3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
python-httpx/0.27.0
|
Security for layeris 0.3.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.