Skip to main content

An open source image processing library that supports blend modes, curve adjustment, and other adjustments that graphic designers or photographers frequently use

Project description

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

layeris-0.3.0.tar.gz (15.4 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

layeris-0.3.0-py3-none-any.whl (3.0 MB view details)

Uploaded Python 3

File details

Details for the file layeris-0.3.0.tar.gz.

File metadata

  • Download URL: layeris-0.3.0.tar.gz
  • Upload date:
  • Size: 15.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.27.0

File hashes

Hashes for layeris-0.3.0.tar.gz
Algorithm Hash digest
SHA256 34849f67569dde66dc2d15f3fddc2b07a7047a13de80dd3e5c757fadc6aeff2b
MD5 36b9f3e8631958c1b911b4806abb1ed5
BLAKE2b-256 f0d875d7de7f56b393f140c3b245f61f1a4a4b43a1402373d749783a69743d08

See more details on using hashes here.

File details

Details for the file layeris-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: layeris-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 3.0 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.27.0

File hashes

Hashes for layeris-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 76d827705a3d3cb150eb9755ec104d7de82fce5c68ababde3949ff373b40f7e5
MD5 82e51b267a95e02036a6061fa357bf78
BLAKE2b-256 d649b9e297c8f95277a83a29c341cfcd8b8c5e28c3f5b742d2a72329cb2f80ca

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page