Skip to content

Commit 512c09e

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

1 file changed

Lines changed: 41 additions & 5 deletions

File tree

src/lib.rs

Lines changed: 41 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,37 @@ 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).map(|raw| {
379+
// integer blending approach from https://stackoverflow.com/a/12016968
380+
let v = raw.into_inner();
381+
let mut alpha = v & 0xFF;
382+
let inv_alpha = 256 - alpha;
383+
alpha += 1;
384+
if alpha == 0 {
385+
// pixel is completely transparent, use bg color
386+
self.alpha_bg
387+
} else if alpha == 255 {
388+
// pixel is completely opaque, just use its color
389+
Rgb888::from(RawU24::new(v >> 8))
390+
} else {
391+
// pixel has transparency, blend with BG color
392+
let col = Rgb888::from(RawU24::new(v >> 8));
393+
Rgb888::new(
394+
((alpha * col.r() as u32 + inv_alpha * self.alpha_bg.r() as u32)
395+
>> 8) as u8,
396+
((alpha * col.g() as u32 + inv_alpha * self.alpha_bg.g() as u32)
397+
>> 8) as u8,
398+
((alpha * col.b() as u32 + inv_alpha * self.alpha_bg.b() as u32)
399+
>> 8) as u8,
400+
)
401+
}
402+
.into()
403+
}),
404+
)
405+
}
370406
}
371407
}
372408

0 commit comments

Comments
 (0)