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.
160 lines
4.2 KiB
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
|
|
}
|
|
}
|