Skip to content

Commit 5b21102

Browse files
committed
basic blending support for transparent BMPs
1 parent 5e71cb5 commit 5b21102

File tree

1 file changed

+38
-5
lines changed

1 file changed

+38
-5
lines changed

src/lib.rs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ pub use raw_iter::{RawPixel, RawPixels};
209209
pub struct Bmp<'a, C> {
210210
raw_bmp: RawBmp<'a>,
211211
color_type: PhantomData<C>,
212+
alpha_bg: Rgb888,
212213
}
213214

214215
impl<'a, C> Bmp<'a, C>
@@ -225,9 +226,18 @@ where
225226
Ok(Self {
226227
raw_bmp,
227228
color_type: PhantomData,
229+
alpha_bg: Rgb888::BLACK,
228230
})
229231
}
230232

233+
/// If this image contains transparent pixels (pixels with an alpha channel), then blend these
234+
/// pixels with the provided color. Note that this will only be used when drawing to a target.
235+
/// It will not be applied when querying pixels from the image.
236+
pub fn with_alpha_bg<BG: Into<Rgb888>>(mut self, alpha_bg: BG) -> Self {
237+
self.alpha_bg = alpha_bg.into();
238+
self
239+
}
240+
231241
/// Returns an iterator over the pixels in this image.
232242
///
233243
/// The iterator always starts at the top left corner of the image, regardless of the row order
@@ -362,11 +372,34 @@ where
362372
RawColors::<RawU32>::new(&self.raw_bmp)
363373
.map(|raw| Rgb888::from(RawU24::new(raw.into_inner())).into()),
364374
),
365-
ColorType::Argb8888 => target.fill_contiguous(
366-
&area,
367-
RawColors::<RawU32>::new(&self.raw_bmp)
368-
.map(|raw| Rgb888::from(RawU24::new(raw.into_inner() >> 8)).into()),
369-
),
375+
ColorType::Argb8888 => {
376+
target.fill_contiguous(
377+
&area,
378+
RawColors::<RawU32>::new(&self.raw_bmp)
379+
.map(|raw| {
380+
// integer blending approach from https://stackoverflow.com/a/12016968
381+
let v = raw.into_inner();
382+
let mut alpha = v & 0xFF;
383+
let inv_alpha = 256 - alpha;
384+
alpha += 1;
385+
if alpha == 0 {
386+
// pixel is completely transparent, use bg color
387+
self.alpha_bg
388+
} else if alpha == 255 {
389+
// pixel is completely opaque, just use its color
390+
Rgb888::from(RawU24::new(v >> 8))
391+
} else {
392+
// pixel has transparency, blend with BG color
393+
let col = Rgb888::from(RawU24::new(v >> 8));
394+
Rgb888::new(
395+
((alpha * col.r() as u32 + inv_alpha * self.alpha_bg.r() as u32) >> 8) as u8,
396+
((alpha * col.g() as u32 + inv_alpha * self.alpha_bg.g() as u32) >> 8) as u8,
397+
((alpha * col.b() as u32 + inv_alpha * self.alpha_bg.b() as u32) >> 8) as u8,
398+
)
399+
}.into()
400+
}),
401+
)
402+
},
370403
}
371404
}
372405

0 commit comments

Comments
 (0)