1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#![warn(clippy::pedantic)]
/*!

# image-blend
### Library to perform blending and alpha channel operations using the image crate

Implementation of support for type-agnostic blending algorithms such as screen, multiply, lighter, etc, for the [image](https://crates.io/crates/image) crate

Also 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

#### Type-agnostic: this library will automatically convert between input type when blending two images together.

The only limitation to this is that you cannot blend an Rgb/Rgba image into a Luma image.

## Usage:

Syntax is the same when working with Dynamic and Imagebuffer.

### Working with dynamic images
#### Blend two images together

```rust
use image::open;
use image_blend::DynamicChops;
use image_blend::pixelops::pixel_mult;

// Load an image
let mut img1_dynamic = open("test_data/1.png").unwrap();

// Load another image
let img2_dynamic = open("test_data/2.png").unwrap();

// Blend the images using the pixel_mult function
img1_dynamic.blend(&img2_dynamic, pixel_mult, true, false).unwrap();
img1_dynamic.save("tests_out/doctest_dynamic_blend_result.png").unwrap();
```

#### Get and set the alpha channels

```rust
use image::open;
use image_blend::DynamicChops;

// Load an image and get its alpha channel
let img1_dynamic = open("test_data/1.png").unwrap();
let img1_alpha = img1_dynamic.get_alpha().unwrap();
img1_alpha.clone().save("tests_out/doctest_dynamic_getalpha_alpha.png").unwrap();

// Load another image and set its alpha channel to the first image's alpha channel, using the copied alpha channel
let mut img2_dynamic = open("test_data/2.png").unwrap();
img2_dynamic.set_alpha(&img1_alpha).unwrap();
img2_dynamic.save("tests_out/doctest_dynamic_getalpha_result.png").unwrap();

```

#### Transplant an alpha channel directly from one image to another

```rust
use image::open;
use image_blend::DynamicChops;

// Load an image and get its alpha channel
let img1_dynamic = open("test_data/1.png").unwrap();

// Load another image and set its alpha channel to a copy of the first image's alpha channel.
let mut img2_dynamic = open("test_data/2.png").unwrap();
img2_dynamic.transplant_alpha(&img1_dynamic).unwrap();
img2_dynamic.save("tests_out/doctest_dynamic_transplantalpha_result.png").unwrap();
```

### Working with imagebuffers

Note how in these examples, the image buffers have different types but it doesn't matter as the library handles this.

#### Blend two images together

```rust
use image::open;
use image_blend::BufferBlend;
use image_blend::pixelops::pixel_mult;

// Load an image
let mut img1_dynamic = open("test_data/1.png").unwrap();
let mut img1_buffer = img1_dynamic.as_mut_rgba8().unwrap();

// Load another image
let img2_dynamic = open("test_data/2.png").unwrap();
let img2_buffer = img2_dynamic.to_rgba16();

// Blend the images using the pixel_mult function
img1_buffer.blend(&img2_buffer, pixel_mult, true, false).unwrap();
img1_buffer.save("tests_out/doctest_buffer_blend_result.png").unwrap();
```

#### Get and set alpha channels

```rust
use image::open;
use image_blend::{BufferGetAlpha, BufferSetAlpha};

// Load an image and get its alpha channel
let img1_dynamic = open("test_data/1.png").unwrap();
let img1_buffer = img1_dynamic.as_rgba8().unwrap();
let img1_alpha = img1_buffer.get_alpha().unwrap();
img1_alpha.clone().save("tests_out/doctest_buffer_getalpha_alpha.png").unwrap();

// Load another image and set its alpha channel to the first image's alpha channel, using the copied alpha channel
let mut img2_dynamic = open("test_data/2.png").unwrap();
let mut img2_buffer = img2_dynamic.to_rgba16();
img2_buffer.set_alpha(&img1_alpha).unwrap();
img2_buffer.save("tests_out/doctest_buffer_getalpha_result.png").unwrap();
```

#### Transplant an alpha channel directly from one image to another

```rust
use image::open;
use image_blend::{BufferGetAlpha, BufferSetAlpha};

// Load an image and get its alpha channel
let img1_dynamic = open("test_data/1.png").unwrap();
let img1_buffer = img1_dynamic.as_rgba8().unwrap();

// Load another image and set its alpha channel to a copy of the first image's alpha channel.
let mut img2_dynamic = open("test_data/2.png").unwrap();
let mut img2_buffer = img2_dynamic.to_rgba16();
img2_buffer.transplant_alpha(&img1_buffer).unwrap();
img2_buffer.save("tests_out/doctest_buffer_transplantalpha_result.png").unwrap();
```

## Custom blend operations

Using custom blend operations is easy. You just need a function that takes 2 f64s and returns an f64.

The 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.

`a` is self, `b` is other.

```rust
use image::open;
use image_blend::DynamicChops;

let closest_to_gray = |a: f64, b: f64| {
    let a_diff = (a - 0.5).abs();
    let b_diff = (b - 0.5).abs();
    if a_diff < b_diff {
        a
    } else {
        b
    }
};

// Load an image
let mut img1_dynamic = open("test_data/1.png").unwrap();

// Load another image
let img2_dynamic = open("test_data/2.png").unwrap();

// Blend the images using our custom function
img1_dynamic.blend(&img2_dynamic, closest_to_gray, true, false).unwrap();
img1_dynamic.save("tests_out/doctest_dynamic_custom_result.png").unwrap();

```
*/
pub(crate) mod blend_ops;
pub(crate) mod dynamic_blend;
pub(crate) mod alpha_ops;

mod enums;
mod error;
mod tests;

pub use error::Error;
pub mod pixelops;
pub use alpha_ops::BufferGetAlpha;
pub use alpha_ops::BufferSetAlpha;
pub use alpha_ops::BufferStripAlpha;
pub use blend_ops::BufferBlend;
pub use dynamic_blend::DynamicChops;