mirror of
https://github.com/jhbruhn/catprint-rs.git
synced 2025-03-14 18:35:49 +00:00
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:
parent
2f379d2c81
commit
2b460a3956
3 changed files with 86 additions and 42 deletions
|
@ -45,6 +45,10 @@ struct Print {
|
||||||
/// Rotate picture by 90 degrees
|
/// Rotate picture by 90 degrees
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
rotate: bool,
|
rotate: bool,
|
||||||
|
|
||||||
|
/// Don't use compression
|
||||||
|
#[clap(long)]
|
||||||
|
no_compress: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(ArgEnum)]
|
#[derive(ArgEnum)]
|
||||||
|
@ -112,7 +116,8 @@ async fn main_print(mut device: device::Device, print: Print) -> Result<(), Box<
|
||||||
_ => protocol::DrawingMode::Image,
|
_ => 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_commands(&print);
|
||||||
device.queue_command(protocol::Command::Feed(
|
device.queue_command(protocol::Command::Feed(
|
||||||
|
|
|
@ -11,6 +11,7 @@ const TX_CHARACTERISTIC_UUID: Uuid = Uuid::from_u128(0x0000ae01_0000_1000_8000_0
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
peripheral: btleplug::platform::Peripheral,
|
peripheral: btleplug::platform::Peripheral,
|
||||||
|
supports_compression: bool,
|
||||||
tx_buffer: VecDeque<u8>,
|
tx_buffer: VecDeque<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,9 +42,16 @@ impl Device {
|
||||||
peripheral.connect().await?;
|
peripheral.connect().await?;
|
||||||
}
|
}
|
||||||
let _ = peripheral.discover_characteristics().await?;
|
let _ = peripheral.discover_characteristics().await?;
|
||||||
|
|
||||||
|
let supports_compression = match name {
|
||||||
|
"MX10" => false,
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
|
||||||
device_result = Ok(Device {
|
device_result = Ok(Device {
|
||||||
peripheral,
|
peripheral,
|
||||||
tx_buffer: VecDeque::new(),
|
tx_buffer: VecDeque::new(),
|
||||||
|
supports_compression,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -109,4 +117,8 @@ impl Device {
|
||||||
pub async fn destroy(self) {
|
pub async fn destroy(self) {
|
||||||
self.peripheral.disconnect().await.unwrap();
|
self.peripheral.disconnect().await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn supports_compression(&self) -> bool {
|
||||||
|
self.supports_compression
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
109
src/image.rs
109
src/image.rs
|
@ -66,55 +66,82 @@ impl Image {
|
||||||
pub fn line(
|
pub fn line(
|
||||||
&self,
|
&self,
|
||||||
y: u32,
|
y: u32,
|
||||||
|
use_compression: bool,
|
||||||
) -> Option<(bool, usize, [u8; crate::protocol::PIXELS_PER_LINE / 8])> {
|
) -> Option<(bool, usize, [u8; crate::protocol::PIXELS_PER_LINE / 8])> {
|
||||||
if y > self.image.height() {
|
if y > self.image.height() {
|
||||||
None
|
return 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()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
pub fn line_count(&self) -> u32 {
|
||||||
self.image.height()
|
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![
|
let mut commands = vec![
|
||||||
Command::SetQuality(quality),
|
Command::SetQuality(quality),
|
||||||
Command::SetEnergy(energy),
|
Command::SetEnergy(energy),
|
||||||
|
@ -123,7 +150,7 @@ impl Image {
|
||||||
|
|
||||||
commands.push(Command::MagicLattice(LatticeType::Start));
|
commands.push(Command::MagicLattice(LatticeType::Start));
|
||||||
for y in 0..self.line_count() {
|
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::Print(compressed, len, pixels));
|
||||||
}
|
}
|
||||||
commands.push(Command::MagicLattice(LatticeType::End));
|
commands.push(Command::MagicLattice(LatticeType::End));
|
||||||
|
|
Loading…
Reference in a new issue