image_blend/lib.rs
1#![warn(clippy::pedantic)]
2/*!
3
4# image-blend
5### Library to perform blending and alpha channel operations using the image crate
6
7Implementation of support for type-agnostic blending algorithms such as screen, multiply, lighter, etc, for the [image](https://crates.io/crates/image) crate
8
9Also provide support for getting alpha channnels as grayscale images, setting alpha channels from grayscale images, and transplanting alpha channels directly from one image to another
10
11#### Type-agnostic: this library will automatically convert between input type when blending two images together.
12
13The only limitation to this is that you cannot blend an Rgb/Rgba image into a Luma image.
14
15## Usage:
16
17Syntax is the same when working with Dynamic and Imagebuffer.
18
19### Working with dynamic images
20#### Blend two images together
21
22```rust
23use image::open;
24use image_blend::DynamicChops;
25use image_blend::pixelops::pixel_mult;
26
27// Load an image
28let mut img1_dynamic = open("test_data/1.png").unwrap();
29
30// Load another image
31let img2_dynamic = open("test_data/2.png").unwrap();
32
33// Blend the images using the pixel_mult function
34img1_dynamic.blend(&img2_dynamic, pixel_mult, true, false).unwrap();
35img1_dynamic.save("tests_out/doctest_dynamic_blend_result.png").unwrap();
36```
37
38#### Get and set the alpha channels
39
40```rust
41use image::open;
42use image_blend::DynamicChops;
43
44// Load an image and get its alpha channel
45let img1_dynamic = open("test_data/1.png").unwrap();
46let img1_alpha = img1_dynamic.get_alpha().unwrap();
47img1_alpha.clone().save("tests_out/doctest_dynamic_getalpha_alpha.png").unwrap();
48
49// Load another image and set its alpha channel to the first image's alpha channel, using the copied alpha channel
50let mut img2_dynamic = open("test_data/2.png").unwrap();
51img2_dynamic.set_alpha(&img1_alpha).unwrap();
52img2_dynamic.save("tests_out/doctest_dynamic_getalpha_result.png").unwrap();
53
54```
55
56#### Transplant an alpha channel directly from one image to another
57
58```rust
59use image::open;
60use image_blend::DynamicChops;
61
62// Load an image that has an alpha channel
63let img1_dynamic = open("test_data/1.png").unwrap();
64
65// Load another image and set its alpha channel to a copy of the first image's alpha channel.
66let mut img2_dynamic = open("test_data/2.png").unwrap();
67img2_dynamic.transplant_alpha(&img1_dynamic).unwrap();
68img2_dynamic.save("tests_out/doctest_dynamic_transplantalpha_result.png").unwrap();
69```
70
71### Working with imagebuffers
72
73Note how in these examples, the image buffers have different types but it doesn't matter as the library handles this.
74
75#### Blend two images together
76
77```rust
78use image::open;
79use image_blend::BufferBlend;
80use image_blend::pixelops::pixel_mult;
81
82// Load an image
83let mut img1_dynamic = open("test_data/1.png").unwrap();
84let mut img1_buffer = img1_dynamic.as_mut_rgba8().unwrap();
85
86// Load another image
87let img2_dynamic = open("test_data/2.png").unwrap();
88let img2_buffer = img2_dynamic.to_rgba16();
89
90// Blend the images using the pixel_mult function
91img1_buffer.blend(&img2_buffer, pixel_mult, true, false).unwrap();
92img1_buffer.save("tests_out/doctest_buffer_blend_result.png").unwrap();
93```
94
95#### Get and set alpha channels
96
97```rust
98use image::open;
99use image_blend::{BufferGetAlpha, BufferSetAlpha};
100
101// Load an image and get its alpha channel
102let img1_dynamic = open("test_data/1.png").unwrap();
103let img1_buffer = img1_dynamic.as_rgba8().unwrap();
104let img1_alpha = img1_buffer.get_alpha().unwrap();
105img1_alpha.clone().save("tests_out/doctest_buffer_getalpha_alpha.png").unwrap();
106
107// Load another image and set its alpha channel to the first image's alpha channel, using the copied alpha channel
108let mut img2_dynamic = open("test_data/2.png").unwrap();
109let mut img2_buffer = img2_dynamic.to_rgba16();
110img2_buffer.set_alpha(&img1_alpha).unwrap();
111img2_buffer.save("tests_out/doctest_buffer_getalpha_result.png").unwrap();
112```
113
114#### Transplant an alpha channel directly from one image to another
115
116```rust
117use image::open;
118use image_blend::{BufferGetAlpha, BufferSetAlpha};
119
120// Load an image and get its alpha channel
121let img1_dynamic = open("test_data/1.png").unwrap();
122let img1_buffer = img1_dynamic.as_rgba8().unwrap();
123
124// Load another image and set its alpha channel to a copy of the first image's alpha channel.
125let mut img2_dynamic = open("test_data/2.png").unwrap();
126let mut img2_buffer = img2_dynamic.to_rgba16();
127img2_buffer.transplant_alpha(&img1_buffer).unwrap();
128img2_buffer.save("tests_out/doctest_buffer_transplantalpha_result.png").unwrap();
129```
130
131## Custom blend operations
132
133Using custom blend operations is easy. You just need a function that takes 2 f64s and returns an f64.
134
135The values passed to this function are `0..1` where `0.` is the darkest a pixel can be and `1.` the brightest. Type conversion and clamping of the return to `0..1` is handled for you.
136
137`a` is self, `b` is other.
138
139```rust
140use image::open;
141use image_blend::DynamicChops;
142
143let closest_to_gray = |a: f64, b: f64| {
144 let a_diff = (a - 0.5).abs();
145 let b_diff = (b - 0.5).abs();
146 if a_diff < b_diff {
147 a
148 } else {
149 b
150 }
151};
152
153// Load an image
154let mut img1_dynamic = open("test_data/1.png").unwrap();
155
156// Load another image
157let img2_dynamic = open("test_data/2.png").unwrap();
158
159// Blend the images using our custom function
160img1_dynamic.blend(&img2_dynamic, closest_to_gray, true, false).unwrap();
161img1_dynamic.save("tests_out/doctest_dynamic_custom_result.png").unwrap();
162
163```
164*/
165pub(crate) mod blend_ops;
166pub(crate) mod dynamic_blend;
167pub(crate) mod alpha_ops;
168
169mod enums;
170mod error;
171mod tests;
172
173pub use error::Error;
174pub mod pixelops;
175pub use alpha_ops::BufferGetAlpha;
176pub use alpha_ops::BufferSetAlpha;
177pub use alpha_ops::BufferStripAlpha;
178pub use blend_ops::BufferBlend;
179pub use dynamic_blend::DynamicChops;