Support control over compression

Add a CLI option to allow compression to be disabled--useful for unknown
devices that don't support it. Also disables compression by default for
devices that are known not to support it.
This commit is contained in:
Wesley Moore 2024-03-26 20:30:50 +10:00
parent 2f379d2c81
commit 2b460a3956
No known key found for this signature in database
3 changed files with 86 additions and 42 deletions

View file

@ -45,6 +45,10 @@ struct Print {
/// Rotate picture by 90 degrees
#[clap(short, long)]
rotate: bool,
/// Don't use compression
#[clap(long)]
no_compress: bool,
}
#[derive(ArgEnum)]
@ -112,7 +116,8 @@ async fn main_print(mut device: device::Device, print: Print) -> Result<(), Box<
_ => protocol::DrawingMode::Image,
};
let print = image.print(mode, quality, energy);
let use_compression = device.supports_compression() && !print.no_compress;
let print = image.print(mode, quality, energy, use_compression);
device.queue_commands(&print);
device.queue_command(protocol::Command::Feed(

View file

@ -11,6 +11,7 @@ const TX_CHARACTERISTIC_UUID: Uuid = Uuid::from_u128(0x0000ae01_0000_1000_8000_0
#[derive(Debug)]
pub struct Device {
peripheral: btleplug::platform::Peripheral,
supports_compression: bool,
tx_buffer: VecDeque<u8>,
}
@ -41,9 +42,16 @@ impl Device {
peripheral.connect().await?;
}
let _ = peripheral.discover_characteristics().await?;
let supports_compression = match name {
"MX10" => false,
_ => true,
};
device_result = Ok(Device {
peripheral,
tx_buffer: VecDeque::new(),
supports_compression,
});
break;
}
@ -109,4 +117,8 @@ impl Device {
pub async fn destroy(self) {
self.peripheral.disconnect().await.unwrap();
}
pub fn supports_compression(&self) -> bool {
self.supports_compression
}
}

View file

@ -66,55 +66,82 @@ impl Image {
pub fn line(
&self,
y: u32,
use_compression: bool,
) -> Option<(bool, usize, [u8; crate::protocol::PIXELS_PER_LINE / 8])> {
if y > self.image.height() {
None
} else {
let mut compressed = Vec::<u8>::new();
let mut counter = 0_u32;
let mut last_val = 2;
for x in 0..crate::protocol::PIXELS_PER_LINE {
let x = x as u32;
let pixel = self.image.get((x, y)).unwrap();
let val = if pixel > &self.mean { 0 } else { 1 };
if val == last_val {
counter = counter + 1
} else if counter > 0 {
compressed.extend(rle_bytes(last_val, counter));
counter = 1;
}
last_val = val;
}
compressed.extend(rle_bytes(last_val, counter));
if compressed.len() > crate::protocol::PIXELS_PER_LINE / 8 {
let mut data = [0_u8; crate::protocol::PIXELS_PER_LINE / 8];
for x in 0..crate::protocol::PIXELS_PER_LINE {
let x = x as u32;
let pixel = self.image.get((x, y)).unwrap();
let val = if pixel > &self.mean { 0 } else { 1 };
let i = (x / 8) as usize;
let j = x % 8;
let current = data[i];
data[i] = current | (val << j);
}
Some((false, crate::protocol::PIXELS_PER_LINE / 8, data))
} else {
use std::convert::TryInto;
let len = compressed.len();
compressed.resize(crate::protocol::PIXELS_PER_LINE / 8, 0);
Some((true, len, compressed.try_into().unwrap()))
}
return None;
}
if use_compression {
self.line_compressed(y)
} else {
self.line_uncompressed(y)
.map(|(len, data)| (false, len, data))
}
}
pub fn line_compressed(
&self,
y: u32,
) -> Option<(bool, usize, [u8; crate::protocol::PIXELS_PER_LINE / 8])> {
let mut compressed = Vec::<u8>::new();
let mut counter = 0_u32;
let mut last_val = 2;
for x in 0..crate::protocol::PIXELS_PER_LINE {
let x = x as u32;
let pixel = self.image.get((x, y)).unwrap();
let val = if pixel > &self.mean { 0 } else { 1 };
if val == last_val {
counter = counter + 1
} else if counter > 0 {
compressed.extend(rle_bytes(last_val, counter));
counter = 1;
}
last_val = val;
}
compressed.extend(rle_bytes(last_val, counter));
if compressed.len() > crate::protocol::PIXELS_PER_LINE / 8 {
self.line_uncompressed(y)
.map(|(len, data)| (false, len, data))
} else {
use std::convert::TryInto;
let len = compressed.len();
compressed.resize(crate::protocol::PIXELS_PER_LINE / 8, 0);
Some((true, len, compressed.try_into().unwrap()))
}
}
pub fn line_uncompressed(
&self,
y: u32,
) -> Option<(usize, [u8; crate::protocol::PIXELS_PER_LINE / 8])> {
let mut data = [0_u8; crate::protocol::PIXELS_PER_LINE / 8];
for x in 0..crate::protocol::PIXELS_PER_LINE {
let x = x as u32;
let pixel = self.image.get((x, y)).unwrap();
let val = if pixel > &self.mean { 0 } else { 1 };
let i = (x / 8) as usize;
let j = x % 8;
let current = data[i];
data[i] = current | (val << j);
}
Some((crate::protocol::PIXELS_PER_LINE / 8, data))
}
pub fn line_count(&self) -> u32 {
self.image.height()
}
pub fn print(&self, mode: DrawingMode, quality: Quality, energy: u16) -> Vec<Command> {
pub fn print(
&self,
mode: DrawingMode,
quality: Quality,
energy: u16,
use_compression: bool,
) -> Vec<Command> {
let mut commands = vec![
Command::SetQuality(quality),
Command::SetEnergy(energy),
@ -123,7 +150,7 @@ impl Image {
commands.push(Command::MagicLattice(LatticeType::Start));
for y in 0..self.line_count() {
let (compressed, len, pixels) = self.line(y).unwrap();
let (compressed, len, pixels) = self.line(y, use_compression).unwrap();
commands.push(Command::Print(compressed, len, pixels));
}
commands.push(Command::MagicLattice(LatticeType::End));