Skip to content

Commit 4a776fe

Browse files
committed
Alpha conversion helpers
1 parent dc30b3c commit 4a776fe

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

src/convert.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#[inline]
2+
pub(crate) fn premultiply(val: u8, alpha: u8) -> u8 {
3+
// TODO: Do we need to optimize this using bit shifts or similar?
4+
((val as u16 * alpha as u16) / 0xff) as u8
5+
}
6+
7+
#[inline]
8+
pub(crate) fn unpremultiply(val: u8, alpha: u8) -> u8 {
9+
// TODO: Can we find a cleaner / more efficient way to implement this?
10+
(val as u16 * u8::MAX as u16)
11+
.checked_div(alpha as u16)
12+
.unwrap_or(0)
13+
.min(u8::MAX as u16) as u8
14+
}

src/lib.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ extern crate core;
99
mod backend_dispatch;
1010
mod backend_interface;
1111
mod backends;
12+
mod convert;
1213
mod error;
1314
mod format;
1415
mod pixel;
@@ -567,6 +568,76 @@ impl Buffer<'_> {
567568
.map(move |(x, pixel)| (x as u32, y as u32, pixel))
568569
})
569570
}
571+
572+
/// Convert the alpha mode of the buffer in place.
573+
///
574+
/// # Examples
575+
///
576+
/// Write to the buffer as-if it was [`AlphaMode::Ignored`], and convert afterwards if
577+
/// necessary.
578+
///
579+
/// ```no_run
580+
/// # let buffer: Buffer<'_> = unimplemented!();
581+
///
582+
/// let needs_alpha_conversion = surface.supports_alpha_mode(AlphaMode::Ignored) {
583+
/// surface.set_alpha_mode(AlphaMode::Ignored);
584+
/// false
585+
/// } else {
586+
/// surface.set_alpha_mode(AlphaMode::Opaque);
587+
/// true
588+
/// };
589+
///
590+
/// for row in buffer.pixel_rows() {
591+
/// for pixel in row {
592+
/// // Write red pixels with an arbitrary alpha value.
593+
/// pixel = Pixel::new_rgba(0xff, 0x00, 0x00, 0x7f);
594+
/// }
595+
/// }
596+
///
597+
/// if needs_alpha_conversion {
598+
/// buffer.make_pixels_opaque();
599+
/// }
600+
///
601+
/// // Alpha value is ignored, either by compositor () or by us above.
602+
/// buffer.present();
603+
/// ```
604+
#[inline]
605+
pub fn make_pixels_opaque(&mut self) {
606+
for row in self.pixel_rows() {
607+
for pixel in row {
608+
// TODO: SIMD-optimize this somehow? Or maybe autovectorization is good enough.
609+
pixel.a = 0xff;
610+
}
611+
}
612+
}
613+
614+
/// Multiply pixel color components by the alpha component.
615+
#[inline]
616+
pub fn premultiply_pixels(&mut self) {
617+
for row in self.pixel_rows() {
618+
for pixel in row {
619+
// TODO: SIMD-optimize this somehow? Or maybe autovectorization is good enough.
620+
let a = pixel.a;
621+
pixel.r = convert::premultiply(pixel.r, a);
622+
pixel.g = convert::premultiply(pixel.g, a);
623+
pixel.b = convert::premultiply(pixel.b, a);
624+
}
625+
}
626+
}
627+
628+
/// Divide pixel color components by the alpha component.
629+
#[inline]
630+
pub fn unpremultiply_pixels(&mut self) {
631+
for row in self.pixel_rows() {
632+
for pixel in row {
633+
// TODO: SIMD-optimize this somehow? Or maybe autovectorization is good enough.
634+
let a = pixel.a;
635+
pixel.r = convert::unpremultiply(pixel.r, a);
636+
pixel.g = convert::unpremultiply(pixel.g, a);
637+
pixel.b = convert::unpremultiply(pixel.b, a);
638+
}
639+
}
640+
}
570641
}
571642

572643
/// Specifies how the alpha channel of the surface should be handled by the compositor.

0 commit comments

Comments
 (0)