Skip to content

Commit

Permalink
TUI/Art further alpha improvements
Browse files Browse the repository at this point in the history
Blended alpha against black should make uniform on images with saved
alpha colors.

Improved clip detection
  • Loading branch information
Beinsezii committed Aug 9, 2024
1 parent 145a6d3 commit e30d9ef
Showing 1 changed file with 27 additions and 13 deletions.
40 changes: 27 additions & 13 deletions src/tui/widgets/art.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ pub struct Art {
pub area: Rect,
}

// blend alpha onto black canvas
fn alpha([r, g, b, a]: [u8; 4]) -> [u8; 3] {
if a == u8::MAX {
return [r, g, b];
} else if a == 0 {
return [0, 0, 0];
};
let a = a as f32 / u8::MAX as f32;
[r, g, b].map(|c| (c as f32 * a).round() as u8)
}

impl ContainedWidget for Art {
fn draw(&mut self, frame: &mut ratatui::Frame, stylesheet: super::StyleSheet) {
if self.area.width == 0 || self.area.height == 0 {
Expand All @@ -23,6 +34,8 @@ impl ContainedWidget for Art {
let (w, h) = (self.area.width as usize, self.area.height as usize * 2);
if let Some(thumbnail) = library.thumbnail(w, h) {
let fill = stylesheet.base.bg.unwrap_or(Color::Black);
// clip at 5% or less
const CLIP: u8 = u8::MAX / 20;
let lines: Vec<Line> = thumbnail
.chunks(2)
.map(|rows| {
Expand All @@ -36,26 +49,27 @@ impl ContainedWidget for Art {

// no alpha blending because the 16 terminal colors aren't readable
let content = if let Some(bg) = bgiter.next() {
if bg == fg {
// All alpha only draw space to support
// terminal emulator transparency
if fg[3] == 0 {
style = style.bg(fill);
" "
// Uniform solid only draw block to avoid
// terminal emulator transparency
} else {
style = style.fg(Color::Rgb(fg[0], fg[1], fg[2]));
"█"
}
// All alpha only draw space to support
// terminal emulator transparency
if bg[3] <= CLIP && fg[3] <= CLIP {
style = style.bg(fill);
" "
// Uniform solid only draw block to avoid
// terminal emulator transparency
} else if bg == fg {
let fg = alpha(*fg);
style = style.fg(Color::Rgb(fg[0], fg[1], fg[2]));
"█"
} else {
let (fg, bg) = (alpha(*fg), alpha(*bg));
style = style.fg(Color::Rgb(fg[0], fg[1], fg[2])).bg(Color::Rgb(bg[0], bg[1], bg[2]));
"▀"
}
} else if fg[3] == 0 {
} else if fg[3] <= CLIP {
style = style.bg(fill);
" "
} else {
let fg = alpha(*fg);
style = style.fg(Color::Rgb(fg[0], fg[1], fg[2]));
"▀"
};
Expand Down

0 comments on commit e30d9ef

Please sign in to comment.