1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-10 22:52:46 +00:00

feat(core): implement rgba8888 canvas blur

[no changelog]
This commit is contained in:
cepetr 2025-02-07 11:50:53 +01:00
parent 76e73f684a
commit db546d8bf8
3 changed files with 87 additions and 18 deletions

View File

@ -135,7 +135,31 @@ impl<'a> Canvas for Rgba8888Canvas<'a> {
}
#[cfg(feature = "ui_blurring")]
fn blur_rect(&mut self, _r: Rect, _radius: usize, _cache: &DrawingCache) {
// TODO
fn blur_rect(&mut self, r: Rect, radius: usize, cache: &DrawingCache) {
let clip = r.translate(self.viewport.origin).clamp(self.viewport.clip);
let ofs = radius as i16;
if clip.width() > 2 * ofs - 1 && clip.height() > 2 * ofs - 1 {
let mut blur_cache = cache.blur();
let (blur, _) = unwrap!(
blur_cache.get(clip.size(), radius, None),
"Too small blur buffer"
);
loop {
if let Some(y) = blur.push_ready() {
let row = unwrap!(self.row_mut(y + clip.y0)); // can't panic
blur.push(&row[clip.x0 as usize..clip.x1 as usize]);
}
if let Some(y) = blur.pop_ready() {
let row = unwrap!(self.row_mut(y + clip.y0)); // can't panic
blur.pop(&mut row[clip.x0 as usize..clip.x1 as usize], None);
if y + 1 >= clip.height() {
break;
}
}
}
}
}
}

View File

@ -197,14 +197,14 @@ impl<'a> Shape<'a> for JpegImage<'a> {
if let Some(y) = blur.push_ready() {
if y < row_r.y1 {
// should never fail
blur.push(unwrap!(jpeg_slice.row(y - row_r.y0)));
blur.push(unwrap!(jpeg_slice.row::<u16>(y - row_r.y0)));
} else {
return true; // need more data
}
}
if let Some(y) = blur.pop_ready() {
blur.pop(unwrap!(slice.row_mut(0)), Some(self.dim)); // should never fail
blur.pop(unwrap!(slice.row_mut::<u16>(0)), Some(self.dim)); // should never fail
let dst_r = Rect::from_top_left_and_size(bounds.top_left(), jpeg_size)
.translate(Offset::new(0, y));
canvas.draw_bitmap(dst_r, slice.view());

View File

@ -46,10 +46,8 @@ const MAX_WIDTH: usize = display::DISPLAY_RESX as usize;
pub type BlurBuff = [u8; MAX_WIDTH * (MAX_SIDE * 3 + size_of::<u16>() * 3) + 8];
type PixelColor = u16;
#[derive(Default, Copy, Clone)]
struct Rgb<T> {
pub struct Rgb<T> {
pub r: T,
pub g: T,
pub b: T,
@ -77,6 +75,17 @@ impl From<u16> for Rgb<u16> {
}
}
impl From<u32> for Rgb<u16> {
#[inline(always)]
fn from(value: u32) -> Self {
Self {
r: ((value >> 16) & 0xFF) as u16,
g: ((value >> 8) & 0xFF) as u16,
b: (value & 0xFF) as u16,
}
}
}
impl core::ops::AddAssign<u16> for Rgb<u16> {
#[inline(always)]
fn add_assign(&mut self, rhs: u16) {
@ -85,6 +94,14 @@ impl core::ops::AddAssign<u16> for Rgb<u16> {
}
}
impl core::ops::AddAssign<u32> for Rgb<u16> {
#[inline(always)]
fn add_assign(&mut self, rhs: u32) {
let rgb: Self = rhs.into();
*self += rgb;
}
}
impl core::ops::SubAssign<u16> for Rgb<u16> {
#[inline(always)]
fn sub_assign(&mut self, rhs: u16) {
@ -93,6 +110,14 @@ impl core::ops::SubAssign<u16> for Rgb<u16> {
}
}
impl core::ops::SubAssign<u32> for Rgb<u16> {
#[inline(always)]
fn sub_assign(&mut self, rhs: u32) {
let rgb: Self = rhs.into();
*self -= rgb;
}
}
impl core::ops::AddAssign for Rgb<u16> {
#[inline(always)]
fn add_assign(&mut self, rhs: Self) {
@ -121,6 +146,17 @@ impl From<Rgb<u8>> for u16 {
}
}
impl From<Rgb<u8>> for u32 {
#[inline(always)]
fn from(value: Rgb<u8>) -> u32 {
let r = (value.r as u32) << 16;
let g = (value.g as u32) << 8;
let b = value.b as u32;
let alpha = 0xFF000000;
alpha | r | g | b
}
}
impl From<Rgb<u16>> for Rgb<u8> {
#[inline(always)]
fn from(value: Rgb<u16>) -> Self {
@ -209,7 +245,10 @@ impl<'a> BlurAlgorithm<'a> {
/// as the floating average of n subsequent elements where n = 2 * radius +
/// 1. Finally, it stores it into the specifed row in the sliding
/// window.
fn average_to_row(&mut self, inp: &[PixelColor], row: usize) {
fn average_to_row<T>(&mut self, inp: &[T], row: usize)
where
T: Copy + Into<Rgb<u16>>,
{
let radius = self.radius;
let offset = self.size.x as usize * row;
let row = &mut self.window[offset..offset + self.size.x as usize];
@ -222,29 +261,29 @@ impl<'a> BlurAlgorithm<'a> {
// Prepare before averaging
for i in 0..radius {
sum += inp[0]; // Duplicate pixels on the left
sum += inp[i]; // Add first radius pixels
sum += inp[0].into(); // Duplicate pixels on the left
sum += inp[i].into(); // Add first radius pixels
}
// Process the first few pixels of the row
for i in 0..radius {
sum += inp[i + radius];
sum += inp[i + radius].into();
row[i] = sum.mulshift(multiplier, shift);
sum -= inp[0];
sum -= inp[0].into();
}
// Process the inner part of the row
for i in radius..row.len() - radius {
sum += inp[i + radius];
sum += inp[i + radius].into();
row[i] = sum.mulshift(multiplier, shift);
sum -= inp[i - radius];
sum -= inp[i - radius].into();
}
// Process the last few pixels of the row
for i in (row.len() - radius)..row.len() {
sum += inp[inp.len() - 1];
sum += inp[inp.len() - 1].into();
row[i] = sum.mulshift(multiplier, shift);
sum -= inp[i - radius]; // Duplicate pixels on the right
sum -= inp[i - radius].into(); // Duplicate pixels on the right
}
}
@ -305,7 +344,10 @@ impl<'a> BlurAlgorithm<'a> {
}
/// Takes the source row and pushes it into the sliding window.
pub fn push(&mut self, input: &[PixelColor]) {
pub fn push<T>(&mut self, input: &[T])
where
T: Copy + Into<Rgb<u16>>,
{
let row = self.row;
self.subtract_row(row);
@ -331,7 +373,10 @@ impl<'a> BlurAlgorithm<'a> {
}
/// Copies the current content of `totals[]` to the output buffer.
pub fn pop(&mut self, output: &mut [PixelColor], dim: Option<u8>) {
pub fn pop<T>(&mut self, output: &mut [T], dim: Option<u8>)
where
T: Copy + Into<Rgb<u16>> + From<Rgb<u8>>,
{
let divisor = match dim {
Some(dim) => {
if dim > 0 {