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.1.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.1-py3-none-any.whl (3.0 MB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: layeris-0.3.1.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.1.tar.gz
Algorithm Hash digest
SHA256 79a458db60891b2e7166ccbf15b9f159ee5d109309947b5e8bd18bc132f7520d
MD5 fab1210aed2d5f9f5c0d84f88d4880b0
BLAKE2b-256 d84f1fe5a376c65ec46cbda131023511b344a5ac17f69be3425e773e0f5bb38c

See more details on using hashes here.

File details

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

File metadata

  • Download URL: layeris-0.3.1-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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c19ba2dbb0511c691dfe7e52300e2ab6a6b1bd6c2e2f05b3d3515ac3daf083e1
MD5 105ae30a9b0b46794bd088376cf8d204
BLAKE2b-256 1712ca2f6a2c502f850271a6925e5eef5f666361ee52b78eee05326662f4fcc3

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