Skip to content

Commit 4e611ed

Browse files
committed
Alpha conversion helpers
1 parent 304f431 commit 4e611ed

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;
@@ -506,6 +507,76 @@ impl Buffer<'_> {
506507
.map(move |(x, pixel)| (x as u32, y as u32, pixel))
507508
})
508509
}
510+
511+
/// Convert the alpha mode of the buffer in place.
512+
///
513+
/// # Examples
514+
///
515+
/// Write to the buffer as-if it was [`AlphaMode::Ignored`], and convert afterwards if
516+
/// necessary.
517+
///
518+
/// ```no_run
519+
/// # let buffer: Buffer<'_> = unimplemented!();
520+
///
521+
/// let needs_alpha_conversion = surface.supports_alpha_mode(AlphaMode::Ignored) {
522+
/// surface.set_alpha_mode(AlphaMode::Ignored);
523+
/// false
524+
/// } else {
525+
/// surface.set_alpha_mode(AlphaMode::Opaque);
526+
/// true
527+
/// };
528+
///
529+
/// for row in buffer.pixel_rows() {
530+
/// for pixel in row {
531+
/// // Write red pixels with an arbitrary alpha value.
532+
/// pixel = Pixel::new_rgba(0xff, 0x00, 0x00, 0x7f);
533+
/// }
534+
/// }
535+
///
536+
/// if needs_alpha_conversion {
537+
/// buffer.make_pixels_opaque();
538+
/// }
539+
///
540+
/// // Alpha value is ignored, either by compositor () or by us above.
541+
/// buffer.present();
542+
/// ```
543+
#[inline]
544+
pub fn make_pixels_opaque(&mut self) {
545+
for row in self.pixel_rows() {
546+
for pixel in row {
547+
// TODO: SIMD-optimize this somehow? Or maybe autovectorization is good enough.
548+
pixel.a = 0xff;
549+
}
550+
}
551+
}
552+
553+
/// Multiply pixel color components by the alpha component.
554+
#[inline]
555+
pub fn premultiply_pixels(&mut self) {
556+
for row in self.pixel_rows() {
557+
for pixel in row {
558+
// TODO: SIMD-optimize this somehow? Or maybe autovectorization is good enough.
559+
let a = pixel.a;
560+
pixel.r = convert::premultiply(pixel.r, a);
561+
pixel.g = convert::premultiply(pixel.g, a);
562+
pixel.b = convert::premultiply(pixel.b, a);
563+
}
564+
}
565+
}
566+
567+
/// Divide pixel color components by the alpha component.
568+
#[inline]
569+
pub fn unpremultiply_pixels(&mut self) {
570+
for row in self.pixel_rows() {
571+
for pixel in row {
572+
// TODO: SIMD-optimize this somehow? Or maybe autovectorization is good enough.
573+
let a = pixel.a;
574+
pixel.r = convert::unpremultiply(pixel.r, a);
575+
pixel.g = convert::unpremultiply(pixel.g, a);
576+
pixel.b = convert::unpremultiply(pixel.b, a);
577+
}
578+
}
579+
}
509580
}
510581

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

0 commit comments

Comments
 (0)