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(()) }