//! Comandos ESC/POS para impressoras térmicas 80mm //! Comandos Epson ESC/POS padrão — funciona com TM-T20 e compatíveis. /// Inicializar impressora pub const INIT: &[u8] = b"\x1B\x40"; /// Nova linha pub const LF: &[u8] = b"\x0A"; /// Cortar papel (parcial) pub const CUT: &[u8] = b"\x1D\x56\x01"; /// Cortar papel (total) #[allow(dead_code)] pub const CUT_FULL: &[u8] = b"\x1D\x56\x00"; /// Alimentar 3 linhas antes de cortar pub const FEED_CUT: &[u8] = b"\x1B\x64\x03"; /// Negrito ON / OFF pub const BOLD_ON: &[u8] = b"\x1B\x45\x01"; pub const BOLD_OFF: &[u8] = b"\x1B\x45\x00"; /// Alinhamento pub const ALIGN_LEFT: &[u8] = b"\x1B\x61\x00"; pub const ALIGN_CENTER: &[u8] = b"\x1B\x61\x01"; #[allow(dead_code)] pub const ALIGN_RIGHT: &[u8] = b"\x1B\x61\x02"; /// Fonte normal / dupla pub const FONT_NORMAL: &[u8] = b"\x1B\x21\x00"; pub const FONT_DOUBLE: &[u8] = b"\x1B\x21\x30"; /// Linha divisória (48 colunas para 80mm) pub const DIVIDER: &str = "--------------------------------"; /// Monta texto centralizado com negrito + fonte dupla pub fn title(text: &str) -> Vec { let mut out = Vec::new(); out.extend_from_slice(ALIGN_CENTER); out.extend_from_slice(BOLD_ON); out.extend_from_slice(FONT_DOUBLE); out.extend_from_slice(text.as_bytes()); out.extend_from_slice(LF); out.extend_from_slice(FONT_NORMAL); out.extend_from_slice(BOLD_OFF); out } /// Monta linha normal (alinhada à esquerda) #[allow(dead_code)] pub fn line(text: &str) -> Vec { let mut out = Vec::new(); out.extend_from_slice(ALIGN_LEFT); out.extend_from_slice(text.as_bytes()); out.extend_from_slice(LF); out } /// Monta linha centralizada pub fn line_center(text: &str) -> Vec { let mut out = Vec::new(); out.extend_from_slice(ALIGN_CENTER); out.extend_from_slice(text.as_bytes()); out.extend_from_slice(LF); out } /// Monta linha em negrito pub fn line_bold(text: &str) -> Vec { let mut out = Vec::new(); out.extend_from_slice(BOLD_ON); out.extend_from_slice(ALIGN_LEFT); out.extend_from_slice(text.as_bytes()); out.extend_from_slice(LF); out.extend_from_slice(BOLD_OFF); out } /// Monta linha com chave-valor alinhado (label 14 chars + espaço + valor 14 chars) pub fn kv(label: &str, value: &str) -> Vec { let padded_label = format!("{:<14}", label); let padded_value = format!("{:>14}", value); let line = format!("{} {}", padded_label, padded_value); let line = if line.len() > 48 { line[..48].to_string() } else { line }; let mut out = Vec::new(); out.extend_from_slice(ALIGN_LEFT); out.extend_from_slice(line.as_bytes()); out.extend_from_slice(LF); out } /// Monta linha divisória pub fn divider() -> Vec { let mut out = Vec::new(); out.extend_from_slice(ALIGN_LEFT); out.extend_from_slice(DIVIDER.as_bytes()); out.extend_from_slice(LF); out } /// Monta espaço em branco (N linhas) pub fn blank_lines(n: u8) -> &'static [u8] { const BLANK: &[u8] = b"\n\n\n\n\n\n\n\n"; &BLANK[..(n as usize).min(8)] }