Crate image_effects

source ·
Expand description

This crate provides multiple effects that can be applied on an image.

Currently there’s two classes of effects:

  1. Dithering - Limiting the colour palette of a given image while still retaining more detail than a purely quantized approach would.
  2. Filtering - Some more common effects applied on an image, such as brightness, contrast, gradient mapping, and more.

The library lets these effects work on a variety of types, including some from the image crate. If you’re not using image however, you can rely on the implementations on intermediate types:

  • For pixels, it’s [u8; 3] for RGB and [u8; 4] for RGBA.
  • For images, it’s Vec<Vec<{Pixel}>> - where Pixel is anything listed above.

The prelude is useful for importing some common functionality, like the algorithms themselves alongside some traits.

Note: Colour palettes currently require the palette crate - as they are defined using its Srgb type.

Usage

This usage is simplified to focus on the logic in this crate, rather than on image or palette.

use image::DynamicImage;
use image_effects::{
    prelude::*
    dither::FLOYD_STEINBERG,
    palette::named,
}
 
fn get_image() -> DynamicImage { /* ... */ }
 
fn main() {
    let image = get_image();
    let palette = vec![
        named::BLACK, named::WHITE
    ];
 
    image
        .apply(&filters::HueRotate(180.0))
        .apply(&FLOYD_STEINBERG.with_palette(palette))
        .save("image.png");
}

Effects

Effect<T> is the trait to implement here, since Affectable<T, E> will be automatically implemented.

Basically, Effect<T> defines an effect that can be applied on T - so in turn Affectable can depend on this implementation to attach an .apply method onto T that accepts Effect<T>.

In other words, if I implement Effect<Image> on an effect called Brighten, I can then call .apply on any Image and pass in a reference to Brighten.

This also means that although you can define your own effects easily, the same isn’t for new kinds of image. You can implement Affectable, but not Effect due to the external trait rule:

When implementing a trait, you must either own the trait or the struct.

Since external crates don’t own Effect<T> nor the effects provided by this library, this effectively locks you out of defining new Ts directly.

However, since most effects get implemented using an intermediate format, such as [u8; 3] for an RGB pixel or Vec<Vec<[u8; 3]>> for an image, theoretically you just need to convert whatever image/medium you’d like to apply effects on into one of these intermediate formats.

Also, when creating an effect you don’t need to define every single image it’s compatible too - as auto-implementation happens here as well. For example, if you implement an effect that can be applied on [u8; 3], this will also result in implementations for RGBA [u8; 4], images, and beyond. As a result, it’s always best to define an Effect on the simplest possible type.

Modules

  • Colour related logic, such as distance functions, palettes, gradient generation, etc.
  • Various dithering algorithms, including both error propagation and ordered.
  • Traits and implementations for effects and anything that can be affected by them.
  • Filters that can be applied to the image - such as brightness, contrast, and more.
  • Prelude for including the useful elements from the library - including algorithms, traits, and constants.

Macros

Type Definitions