labelo/p710bt/examples/p710bt_exp_image.rs

123 lines
4.2 KiB
Rust

use eyre::{bail, Context};
use labelo_p710bt::commander::P710btCommander;
use labelo_p710bt::protocol::{AdvancedModeSettings, VariousModeSettings, PIXELS_ON_TAPE_SIZES};
use labelo_p710bt::usb::UsbP710bt;
use std::env::args;
use std::path::Path;
use tracing::{info, warn};
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
pub fn main() -> eyre::Result<()> {
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "p710bt=debug,info".into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
let mut images = Vec::new();
for arg in args().skip(1) {
let image_path = Path::new(&arg);
let image = image::open(image_path)
.with_context(|| format!("failed to load image {image_path:?}"))?;
images.push(image.into_rgba8());
}
let mut devices = UsbP710bt::list_devices()?;
if devices.len() != 1 {
bail!("Found {} P710BT devices, aborting.", devices.len());
}
let device = UsbP710bt::open(devices.remove(0))?;
let mut printer = P710btCommander::new(device)?;
printer.invalidate_and_initialise()?;
let status = printer.status()?;
info!("Printer status: {status:?}");
let media_width_mm = status.media_width_mm as u32;
if media_width_mm == 0 {
bail!("Media width is 0; is there tape loaded?");
}
let Some(media_width_info) = PIXELS_ON_TAPE_SIZES.iter().find(|info| info.mm == media_width_mm) else {
bail!("Unrecognised tape width: this usually means support is needed in labelo ({media_width_mm} mm).");
};
info!("Media width information: {media_width_info:?}");
printer.set_raster_mode_and_automatic_notification()?;
for (page, image) in images.iter().enumerate() {
if image.height() > media_width_info.practical_px_limit {
bail!(
"Image/page {page} exceeds the practical print height limit of {} px ({} px).",
media_width_info.practical_px_limit,
image.height()
);
}
if image.height() > media_width_info.datasheet_px_limit {
warn!("Image/page {page} is {} px high which exceeds the datasheet print height of {} px but fits within the empirical print height limit of {} px.", image.height(), media_width_info.datasheet_px_limit, media_width_info.practical_px_limit);
}
}
for page in 0..images.len() {
let image = &images[page];
let lines = image.width();
printer
.print_information(
status.media_type.unwrap(),
status.media_width_mm,
lines,
page == 0,
)
.context("PIC")?;
let mut ams = AdvancedModeSettings::NO_BUFFER_CLEARING_WHEN_PRINTING;
if page == images.len() - 1 {
// TODO not always desirable, but for testing it is handy to have it cut on the last piece.
ams |= AdvancedModeSettings::NO_CHAIN_PRINTING;
}
// TODO Double-resolution printing in the x axis.
// ams |= AdvancedModeSettings::HIGH_RES_PRINTING;
printer.set_mode_settings(VariousModeSettings::AUTO_CUT, ams, 4)?;
// TODO this depends based on what tape is in use
// 128 lines (printer size)
// minus '84 dots' (1/width in manual 2.3.2)
// plus '7 dots' (5/width offset in manual 2.3.2).
// then halved......?
// let yoff = (128 - 84 + 7) >> 1;
// maybe you just center the printing?
let yoff = (128 - image.height()) >> 1;
for x in 0..lines {
let mut line = [0u8; 16];
for y in 0..(128 - yoff) {
let pix = y < image.height() && (image.get_pixel(x, y).0 == [0, 0, 0, 255]);
if pix {
let real_y = y + yoff;
line[(real_y >> 3) as usize] |= 128 >> (real_y & 0b0000_0111);
}
}
printer
.raster_line(line)
.with_context(|| format!("line {line:?}"))?;
}
printer.finish_printing(page == images.len() - 1)?;
}
Ok(())
}