Skip to content

Commit

Permalink
basic blending support for transparent BMPs
Browse files Browse the repository at this point in the history
  • Loading branch information
samcday committed Mar 27, 2024
1 parent 5e71cb5 commit 5b21102
Showing 1 changed file with 38 additions and 5 deletions.
43 changes: 38 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ pub use raw_iter::{RawPixel, RawPixels};
pub struct Bmp<'a, C> {
raw_bmp: RawBmp<'a>,
color_type: PhantomData<C>,
alpha_bg: Rgb888,
}

impl<'a, C> Bmp<'a, C>
Expand All @@ -225,9 +226,18 @@ where
Ok(Self {
raw_bmp,
color_type: PhantomData,
alpha_bg: Rgb888::BLACK,
})
}

/// If this image contains transparent pixels (pixels with an alpha channel), then blend these
/// pixels with the provided color. Note that this will only be used when drawing to a target.
/// It will not be applied when querying pixels from the image.
pub fn with_alpha_bg<BG: Into<Rgb888>>(mut self, alpha_bg: BG) -> Self {
self.alpha_bg = alpha_bg.into();
self
}

/// Returns an iterator over the pixels in this image.
///
/// The iterator always starts at the top left corner of the image, regardless of the row order
Expand Down Expand Up @@ -362,11 +372,34 @@ where
RawColors::<RawU32>::new(&self.raw_bmp)
.map(|raw| Rgb888::from(RawU24::new(raw.into_inner())).into()),
),
ColorType::Argb8888 => target.fill_contiguous(
&area,
RawColors::<RawU32>::new(&self.raw_bmp)
.map(|raw| Rgb888::from(RawU24::new(raw.into_inner() >> 8)).into()),
),
ColorType::Argb8888 => {
target.fill_contiguous(
&area,
RawColors::<RawU32>::new(&self.raw_bmp)
.map(|raw| {
// integer blending approach from https://stackoverflow.com/a/12016968
let v = raw.into_inner();
let mut alpha = v & 0xFF;
let inv_alpha = 256 - alpha;
alpha += 1;
if alpha == 0 {
// pixel is completely transparent, use bg color
self.alpha_bg
} else if alpha == 255 {
// pixel is completely opaque, just use its color
Rgb888::from(RawU24::new(v >> 8))
} else {
// pixel has transparency, blend with BG color
let col = Rgb888::from(RawU24::new(v >> 8));
Rgb888::new(
((alpha * col.r() as u32 + inv_alpha * self.alpha_bg.r() as u32) >> 8) as u8,
((alpha * col.g() as u32 + inv_alpha * self.alpha_bg.g() as u32) >> 8) as u8,
((alpha * col.b() as u32 + inv_alpha * self.alpha_bg.b() as u32) >> 8) as u8,
)
}.into()
}),
)
},
}
}

Expand Down

0 comments on commit 5b21102

Please sign in to comment.