1pub mod algorithms;
4pub mod params;
5
6use algorithms::{
7 blend_alpha, blend_destination_over, blend_disjoint_debug, blend_disjoint_over,
8 blend_disjoint_under, blend_first_bottom, blend_first_top, blend_mask_top,
9 blend_multiplicative, blend_source_over,
10};
11use image::{ImageBuffer, Rgba};
12use params::BlendAlgorithmParams;
13use std::fmt;
14use std::fmt::{Display, Formatter};
15use std::result;
16use std::str::FromStr;
17
18#[derive(Clone, Debug)]
20pub enum BlendAlgorithm {
21 Alpha,
22 Multiplicative,
23 SourceOver,
24 DestinationOver,
25 MaskTop,
26 FirstTop,
27 FirstBottom,
28 DisjointOver,
29 DisjointUnder,
30 DisjointDebug,
31}
32
33impl FromStr for BlendAlgorithm {
34 type Err = String;
35
36 fn from_str(s: &str) -> result::Result<Self, Self::Err> {
37 match s {
38 "alpha" => Ok(BlendAlgorithm::Alpha),
39 "multiplicative" => Ok(BlendAlgorithm::Multiplicative),
40 "source_over" => Ok(BlendAlgorithm::SourceOver),
41 "destination_over" => Ok(BlendAlgorithm::DestinationOver),
42 "mask_top" => Ok(BlendAlgorithm::MaskTop),
43 "first_top" => Ok(BlendAlgorithm::FirstTop),
44 "first_bottom" => Ok(BlendAlgorithm::FirstBottom),
45 "disjoint_over" => Ok(BlendAlgorithm::DisjointOver),
46 "disjoint_under" => Ok(BlendAlgorithm::DisjointUnder),
47 "disjoint_debug" => Ok(BlendAlgorithm::DisjointDebug),
48 s => Err(s.to_string()),
49 }
50 }
51}
52
53impl Display for BlendAlgorithm {
54 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
55 match self {
56 BlendAlgorithm::Alpha => write!(f, "alpha"),
57 BlendAlgorithm::Multiplicative => write!(f, "multiplicative"),
58 BlendAlgorithm::SourceOver => write!(f, "source_over"),
59 BlendAlgorithm::DestinationOver => write!(f, "destination_over"),
60 BlendAlgorithm::MaskTop => write!(f, "mask_top"),
61 BlendAlgorithm::FirstTop => write!(f, "first_top"),
62 BlendAlgorithm::FirstBottom => write!(f, "first_bottom"),
63 BlendAlgorithm::DisjointOver => write!(f, "disjoint_over"),
64 BlendAlgorithm::DisjointUnder => write!(f, "disjoint_under"),
65 BlendAlgorithm::DisjointDebug => write!(f, "disjoint_debug"),
66 }
67 }
68}
69
70pub fn blend_images(
97 bot: &mut ImageBuffer<Rgba<u8>, Vec<u8>>,
98 top: &ImageBuffer<Rgba<u8>, Vec<u8>>,
99 blending_algorithm: &impl Fn((&mut Rgba<u8>, &Rgba<u8>), &Option<BlendAlgorithmParams>),
100 algorithm_params: &Option<BlendAlgorithmParams>,
101) {
102 for pixel_pair in bot.pixels_mut().zip(top.pixels()) {
103 blending_algorithm(pixel_pair, algorithm_params);
104 }
105}
106
107pub fn demultiply_image(img: &mut ImageBuffer<Rgba<u8>, Vec<u8>>) {
114 for pixel in img.pixels_mut() {
115 demultiply_pixel(pixel);
116 }
117}
118
119pub fn multiply_image(img: &mut ImageBuffer<Rgba<u8>, Vec<u8>>) {
126 for pixel in img.pixels_mut() {
127 multiply_pixel(pixel);
128 }
129}
130
131pub fn get_blending_algorithm(
137 algorithm: &BlendAlgorithm,
138) -> impl Fn((&mut Rgba<u8>, &Rgba<u8>), &Option<BlendAlgorithmParams>) {
139 match algorithm {
140 BlendAlgorithm::Alpha => blend_alpha,
141 BlendAlgorithm::Multiplicative => blend_multiplicative,
142 BlendAlgorithm::SourceOver => blend_source_over,
143 BlendAlgorithm::DestinationOver => blend_destination_over,
144 BlendAlgorithm::MaskTop => blend_mask_top,
145 BlendAlgorithm::FirstTop => blend_first_top,
146 BlendAlgorithm::FirstBottom => blend_first_bottom,
147 BlendAlgorithm::DisjointOver => blend_disjoint_over,
148 BlendAlgorithm::DisjointUnder => blend_disjoint_under,
149 BlendAlgorithm::DisjointDebug => blend_disjoint_debug,
150 }
151}
152
153pub fn is_algorithm_multiplied(algorithm: &BlendAlgorithm) -> bool {
160 match algorithm {
161 BlendAlgorithm::Alpha => false,
162 BlendAlgorithm::Multiplicative => false,
163 BlendAlgorithm::SourceOver => false,
164 BlendAlgorithm::DestinationOver => false,
165 BlendAlgorithm::MaskTop => false,
166 BlendAlgorithm::FirstTop => false,
167 BlendAlgorithm::FirstBottom => false,
168 BlendAlgorithm::DisjointOver => true,
169 BlendAlgorithm::DisjointUnder => true,
170 BlendAlgorithm::DisjointDebug => true,
171 }
172}
173
174fn demultiply_pixel(pixel: &mut Rgba<u8>) {
175 let (r, g, b, a) = (pixel[0], pixel[1], pixel[2], pixel[3]);
176 let af = a as f32 / 255.0;
177
178 let r = (r as f32 * af).round() as u8;
179 let g = (g as f32 * af).round() as u8;
180 let b = (b as f32 * af).round() as u8;
181
182 pixel[0] = r;
183 pixel[1] = g;
184 pixel[2] = b;
185}
186
187fn multiply_pixel(pixel: &mut Rgba<u8>) {
188 let (r, g, b, a) = (pixel[0], pixel[1], pixel[2], pixel[3]);
189 let af = a as f32 / 255.0;
190
191 let r = (r as f32 / af).round() as u8;
192 let g = (g as f32 / af).round() as u8;
193 let b = (b as f32 / af).round() as u8;
194
195 pixel[0] = r;
196 pixel[1] = g;
197 pixel[2] = b;
198}