Bluetooth POS Printer Utils
Classes base em Flutter/Dart para impressão em impressoras térmicas ESC/POS. Esta biblioteca é um fork turbinado da clássica flutter_esc_pos_utils, trazendo otimizações massivas de performance e um sistema revolucionário de renderização de imagem para recibos.
Esta é a biblioteca "base" responsável por gerar os comandos binários. Para enviar esses comandos para a impressora via Bluetooth, utilize o plugin de conexão em conjunto:
🚀 Os Dois Mundos de Impressão
Esta biblioteca fornece duas classes principais para você gerar os seus recibos, dependendo da sua necessidade:
ImageGenerator(Recomendado ⭐): Constrói o recibo renderizando uma imagem de alta qualidade (inclusive com Widgets do Flutter). Acaba de vez com problemas de formatação, letras embaralhadas, e incompatibilidade deCodeTables.Generator(Tradicional): Envia comandos de texto puro (byte a byte) para a impressora. Útil para impressoras muito antigas ou se você precisa do máximo extremo de velocidade, mas exige configuração de CodeTables.
🌟 1. Imprimir como Imagem (ImageGenerator)
A forma mais confiável e moderna de imprimir recibos complexos, caracteres internacionais (como €, ç, ã) e designs ricos em impressoras térmicas é renderizar o recibo inteiro como uma única imagem.
O ImageGenerator utiliza Isolates (processamento em background) e o protocolo nativo GS v 0 (Rasterização Ultra Rápida) da Epson. O resultado? Recibos complexos processados em menos de 50 milissegundos sem congelar a tela do seu App!
Como usar o ImageGenerator
import 'package:bluetooth_pos_printer_utils/bluetooth_pos_printer_utils.dart';
import 'package:flutter/material.dart';
Future<List<int>> generateTicketAsImage() async {
// 1. Defina o tamanho do papel da sua impressora (58mm ou 80mm)
final profile = await CapabilityProfile.load();
final generator = ImageGenerator(PaperSize.mm58, profile);
// 2. Adicione Textos
generator.text('SUPERMERCADO', styles: const PosStyles(bold: true, align: PosAlign.center));
// 3. Adicione Linha Divisória
generator.hr();
// 4. Renderize Tabelas Alinhadas
generator.row([
PosColumn(text: 'Item 1 - Produto', width: 6),
PosColumn(text: '€ 10.00', width: 6, styles: const PosStyles(align: PosAlign.right)),
]);
// 5. Inserir WIDGETS DO FLUTTER! (A maior vantagem do ImageGenerator)
generator.widget(
Container(
padding: const EdgeInsets.all(8),
color: Colors.black, // Fundo preto inverte a cor no papel térmico
child: const Text('WIDGET CUSTOMIZADO', style: TextStyle(color: Colors.white)),
)
);
// 6. Códigos de Barras e QR Codes
generator.barcode(Barcode.code128('123456789'));
generator.qrcode('https://example.com');
// 7. Adicione Imagens com Dithering (Meio Tom) e Cache Automático
final data = await rootBundle.load('assets/logo.png');
generator.image(
data.buffer.asUint8List(),
width: 200,
halftone: true, // true = pontilhado de foto, false = Preto/Branco puro
);
// 8. Corte o papel
generator.cut();
// 9. Construa os bytes em background (Isolate)
// O parâmetro threshold (opcional, padrão 127) controla o quão escuro o recibo fica (0-255)
final bytes = await generator.buildImageBytes(threshold: 150);
return bytes;
}
Funcionalidades do ImageGenerator
generator.text(): Suporta os estilos de alinhamento (align), negrito (bold), invertido (reverse) e tamanho 2x, 3x (height,width).generator.row(): Recebe uma lista dePosColumn(A soma das larguras das colunas deve ser 12).generator.hr(): Imprime uma linha horizontal tracejada (-).generator.image(): Possui cache automático! Se você imprimir a mesma logotipo em 50 recibos seguidos, ela só será processada (decode/dithering) no primeiro recibo! O argumentohalftone: trueaplica o algoritmo de Floyd-Steinberg para garantir que fotos e logos fiquem bonitas na impressora térmica.generator.widget(Widget widget): Renderiza qualquer componente do Flutter diretamente.generator.emptyLines(int n)/generator.feed(int n): Pula linhas.generator.cut(): Adiciona o comando de guilhotina (corte de papel).generator.buildImageBytes({int threshold = 127}): Gera os bytes do recibo. O parâmetrothreshold(0-255) controla o contraste: valores maiores deixam a impressão mais escura.
📜 2. Imprimir Textos (Método Tradicional: Generator)
Se você quer mandar comandos nativos, byte a byte. Pode sofrer com problemas de caracteres acentuados dependendo da procedência da impressora chinesa, exigindo a injeção manual de CodeTables.
Como usar o Generator Tradicional
List<int> testTicket() {
final profile = await CapabilityProfile.load();
final generator = Generator(PaperSize.mm80, profile);
List<int> bytes = [];
// Texto normal
bytes += generator.text('Teste de Impressão');
// Texto com acentos (pode exigir configuração de CodeTable)
bytes += generator.text('Atenção: Açaí €', styles: PosStyles(codeTable: PosCodeTable.westEur));
// Estilização Completa
bytes += generator.text('Negrito', styles: PosStyles(bold: true));
bytes += generator.text('Invertido', styles: PosStyles(reverse: true));
bytes += generator.text('Sublinhado', styles: PosStyles(underline: true));
bytes += generator.text('Centro', styles: PosStyles(align: PosAlign.center));
bytes += generator.text('Tamanho Duplo', styles: PosStyles(height: PosTextSize.size2, width: PosTextSize.size2));
// Imagens Nativas (Recomendado usar o comando GS v 0 que é o mais rápido)
// final img = decodeImage(bytes);
// bytes += generator.imageRaster(img);
// Gaveta de Dinheiro
bytes += generator.drawer();
// Bip da impressora
bytes += generator.beep();
bytes += generator.cut();
return bytes;
}
Funcionalidades Específicas do Generator
Além das lógicas de layout (text, row, hr), o modo binário clássico suporta comandos eletrônicos de hardware que não fazem sentido no modo de imagem:
generator.drawer(): Abre a gaveta de dinheiro conectada à impressora via RJ11.generator.beep(): Faz a impressora apitar (útil para sistema de cozinha).generator.setGlobalCodeTable('CP1252'): Força a impressora a utilizar um mapa de caracteres específico para corrigir acentos (á, ç, õ). A disponibilidade dessas tabelas varia de impressora para impressora.
Resolvendo problemas de Caracteres Estranhos (Code Tables)
Se os caracteres com acento estão saindo como "???" ou símbolos estranhos no modo Generator, você precisa forçar a CodeTable correta. Você pode procurar a CodeTable certa imprimindo a folha de teste da impressora:
// Exemplo: Configurando perfil para uma Xprinter XP-N160I
final profile = await CapabilityProfile.load('XP-N160I');
final generator = Generator(PaperSize.mm80, profile);
bytes += generator.setGlobalCodeTable('CP1252');
Dica: Se a dor de cabeça com acentos continuar, migre a sua impressão para o ImageGenerator.
🖨️ Testando o App de Exemplo (Example)
Este pacote acompanha um aplicativo de exemplo completo (example/lib/main.dart) que simula a conexão com impressoras Bluetooth e imprime:
- Um recibo completo no formato tradicional de Bytes (onde você pode testar se a sua impressora suporta acentuação).
- Um recibo completo idêntico no formato de Imagem (onde você pode conferir a perfeição do alinhamento e suporte nativo ao Flutter).
Para testar:
cd example
flutter run
🤝 Como Contribuir
- Adicionar Perfis: Tem uma impressora com quirks (defeitos) específicos? Adicione o perfil dela no arquivo
lib/resources/capabilities.json. - Issues e PRs: Sinta-se livre para abrir issues reportando bugs ou enviar Pull Requests com otimizações de código.