You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/embed/rust/src/ui/display/tjpgd.rs

160 lines
4.2 KiB

use trezor_tjpgdec::{BlackHoleOutput, JpegOutput};
pub use trezor_tjpgdec::{BufferInput, Error, JDEC};
use crate::{
trezorhal::{
buffers::{BufferJpeg, BufferJpegWork},
display::pixeldata,
},
ui::{
constant,
display::set_window,
geometry::{Offset, Point, Rect},
},
};
pub fn jpeg(data: &[u8], pos: Point, scale: u8) {
let mut buffer = BufferJpegWork::get_cleared();
let pool = buffer.buffer.as_mut_slice();
let mut out = PixelDataOutput(pos);
let mut inp = BufferInput(data);
if let Ok(mut jd) = JDEC::new(&mut inp, pool) {
let _ = jd.set_scale(scale);
let _ = jd.decomp(&mut inp, &mut out);
}
}
pub fn jpeg_info(data: &[u8]) -> Option<(Offset, i16)> {
let mut buffer = BufferJpegWork::get_cleared();
let pool = buffer.buffer.as_mut_slice();
let mut inp = BufferInput(data);
let result = if let Ok(jd) = JDEC::new(&mut inp, pool) {
let mcu_height = jd.mcu_height();
if mcu_height > 16 {
return None;
}
Some((Offset::new(jd.width(), jd.height()), mcu_height))
} else {
None
};
result
}
pub fn jpeg_test(data: &[u8]) -> bool {
let mut buffer = BufferJpegWork::get_cleared();
let pool = buffer.buffer.as_mut_slice();
let mut inp = BufferInput(data);
let result = if let Ok(mut jd) = JDEC::new(&mut inp, pool) {
if jd.mcu_height() > 16 {
return false;
}
let mut out = BlackHoleOutput;
let mut res = jd.decomp(&mut inp, &mut out);
while res == Err(Error::Interrupted) {
res = jd.decomp(&mut inp, &mut out);
}
res.is_ok()
} else {
false
};
result
}
pub struct BufferOutput {
buffer: BufferJpeg,
buffer_width: i16,
buffer_height: i16,
current_line: i16,
current_line_pix: i16,
}
impl BufferOutput {
pub fn new(buffer_width: i16, buffer_height: i16) -> Self {
Self {
buffer: BufferJpeg::get_cleared(),
buffer_width,
buffer_height,
current_line: 0,
current_line_pix: 0,
}
}
pub fn buffer(&mut self) -> &mut BufferJpeg {
&mut self.buffer
}
}
impl JpegOutput for BufferOutput {
fn write(
&mut self,
jd: &JDEC,
rect_origin: (u32, u32),
rect_size: (u32, u32),
bitmap: &[u16],
) -> bool {
let w = rect_size.0 as i16;
let h = rect_size.1 as i16;
let x = rect_origin.0 as i16;
if h > self.buffer_height {
// unsupported height, call and let know
return true;
}
let buffer_len = (self.buffer_width * self.buffer_height) as usize;
for i in 0..h {
for j in 0..w {
let buffer_pos = ((x + j) + (i * self.buffer_width)) as usize;
if buffer_pos < buffer_len {
self.buffer.buffer[buffer_pos] = bitmap[(i * w + j) as usize];
}
}
}
self.current_line_pix += w;
if self.current_line_pix >= jd.width() {
self.current_line_pix = 0;
self.current_line += jd.mcu_height();
// finished line, abort and continue later
return false;
}
true
}
}
pub struct PixelDataOutput(Point);
impl JpegOutput for PixelDataOutput {
fn write(
&mut self,
_jd: &JDEC,
rect_origin: (u32, u32),
rect_size: (u32, u32),
bitmap: &[u16],
) -> bool {
let pos = self.0;
let rect = Rect::from_top_left_and_size(
Point::new(rect_origin.0 as i16, rect_origin.1 as i16),
Offset::new(rect_size.0 as i16, rect_size.1 as i16),
);
let r = rect.translate(pos.into());
let clamped = r.clamp(constant::screen());
set_window(clamped);
for py in r.y0..r.y1 {
for px in r.x0..r.x1 {
let p = Point::new(px, py);
if clamped.contains(p) {
let off = p - r.top_left();
let c = bitmap[(off.y * rect.width() + off.x) as usize];
pixeldata(c);
}
}
}
true
}
}