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:
- Dithering - Limiting the colour palette of a given image while still retaining more detail than a purely quantized approach would.
- 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}>>
- wherePixel
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 T
s 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
- Helps construct a gradient map from colours.