Daee pessoal, vou começar a postar a resolução de alguns problemas punks que encontrei durante minha vida de programador ^^. Começando pelo duro trabalho de fazer o Java imprimir dados em impressoras matriciais, no meu caso uma Okitada Microline 320. Para começar fui logo achando que o trabalho seria fácil, a meu ver era só montar um layout no iReports, gerar o .jasper, jogar no servidor acessar o pdf e mandar imprimir; quem me dera fosse tão fácil assim.
Os problemas começaram já na configuração da impressora, existe uma infinidade de drivers para impressora em questão, e conseguir configurar um que deixe a impressão aceitável vai consumir muito tempo e trabalho, além é claro de várias xícaras de café, cabelos brancos, palavrões ditos etc. etc..
A seguir descobri outro problema, mesmo como o melhor driver configurado a impressora não se comporta bem quando é necessário imprimir dados a partir de um pdf. A Okidata interpreta o pdf como se fosse uma imagem, e tenta converter essa imagem na impressão propriamente dita, mas ela não é muito feliz nessa tarefa, a impressão de números e letras fica bem estranha, e em alguns casos até ilegível.
Após mais algumas horas(várias), percebi que não teria alternativa, a solução para uma impressão de qualidade seria: Inserir comandos hexadecimais de impressão direto na porta(LPT) da impressora, então vamos ao trabalho, começando pelo material de apoio básico:
- Entender a API de impressão do Java.
- Conhecer os comandos básicos de impressão Hexadecimal, tambem conhecida como “printer control language”. A linguagem que utilizei na Okidata foi a Manual ESC/P2, a impressora possui esta forma de emulação.
Após estudar um pouco o material acima segui os seguintes passos:
- Configurei a impressora no computador/servidor onde a aplicação Java vai rodar, como faremos a impressão direta o driver é irrelevante, então podemos adicionar um driver genérico desta impressora.
- Configurar a impressora para utilizar o modo de emulação ESCP2. Verifique se a impressora esta com papel, pressione SHIFT + SEL. A impressora vai entrar em modo de seleção, pressione LF, a impressora vai imprimir o modo de emulação atual, vá apertando TEAR até o modo de emulação Epson® FX (ESC/P), pressione SHIFT + SEL para salvar e sair.
- Criar uma classe Java para realizar a impressão.
A Classe Java.
A minha classe comentada é basicamente o seguinte:
[sourcecode language='java']public void imprimir() throws URISyntaxException, FileNotFoundException, PrintException, IOException { //VARIAVEL PARA ARMAZENAR AS INSTRUÇÕES DE IMPRESSÃO StringBuffer conteudo = ""; //CRIA A STREAM A PARTIR DA STRING InputStream ps = null; ps = new ByteArrayInputStream(conteudo.getBytes()); //CRIA O DOCUMENTO DE IMPRESSAO DocFlavor flavor = DocFlavor.INPUT_STREAM.POSTSCRIPT; //LOCALIZA AS IMPRESSORAS DISPONIVEIS NO SERVIDOR/PC PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null); //CRIA UM SERVIÇO DE IMPRESSAO, NESTE PONTO A IMPRESSORA AINDA NAO ESTA DEFINIDA services = PrintServiceLookup.lookupPrintServices(null, null); //CRIA UM TRABALHO DE IMPRESSAO DocPrintJob job = null; //NESTE FOR EU FAÇO A SELEÇÃO DA IMPRESSORA, EU BUSCO A IMPRESSORA PELO NOME CONFIGURADO, // DESTA FORMA SE ALTERAR O IP OU SERVIDOR NAO É NECESSARIO MECHER NO CODIGO for (int i = 0; i < services.length; i++) { PrintService pserv = services[i]; if (pserv.getName().equalsIgnoreCase("Okidata")) { //INSTANCIA O TRABALHO DE IMPRESSAO job = services[i].createPrintJob(); //INSTANCIA O DOCUMENTO Doc doc = new SimpleDoc(ps, flavor, null); //VERIFICA QUANDO O TRABALHO ESTA COMPLETO PrintJobWatcher pjDone = new PrintJobWatcher(job); //IMPRIME job.print(doc, null); //AGUARDA A CONCLUSAO DO TRABALHO pjDone.waitForDone(); ps.close(); } } } /** * Classe para controle de impressões em impressoras matriciais. */ class PrintJobWatcher { // true iff it is safe to close the print job's input stream boolean done = false; /** * @author Jean C Becker * @version 1.0 * Método para verificar o trabalho de impressão em impressoras matriciais. * * @param DocPrintJog Objeto com o trabalho de impressão. * @return Não se aplica. */ PrintJobWatcher(DocPrintJob job) { // Add a listener to the print job job.addPrintJobListener(new PrintJobAdapter() { public void printJobCanceled(PrintJobEvent pje) { allDone(); } public void printJobCompleted(PrintJobEvent pje) { allDone(); } public void printJobFailed(PrintJobEvent pje) { allDone(); } public void printJobNoMoreEvents(PrintJobEvent pje) { allDone(); } void allDone() { synchronized (PrintJobWatcher.this) { done = true; PrintJobWatcher.this.notify(); } } }); } /** * @author Jean C Becker * @version 1.0 * Método para aguardar a finalização do trabalho de impressao. * @return Não se aplica. */ public synchronized void waitForDone() { try { while (!done) { wait(); } } catch (InterruptedException e) { } } }[/sourcecode]
A parte mais trabalhosa é alimentar a String que é enviada para impressora, nesta String vão estar contidos todos os comandos e dados a serem impressos, basicamente você terá que desenvolver todo o layout - quebra de linha, ajustes horizontais, negrito, sublinhado, itálico etc. - a partir de comandos Hexadecimais. A lógica é parecida com tags HTML, seguem abaixo algumas que considero importante, já no padrão Java:
"\u001b\u0040" - Inicio do conteúdo de impressão, define as configurações padrões de impressão.
"\u001B\u004A" + (char) valor - Deslocamento vertical do carro de impressão, valor é um conteúdo numérico que indica o tamanho do deslocamento em polegadas.
"\n\r" - Quebra linha.
Um pequeno exemplo:
String conteudo = "\u001b\u0040" + "TITULO PARA IMPRESSAO" + "\n\r";
conteudo += "IMPRIMINDO CONTEUDO EM IMPRESSORA MATRICIAL \n\r";
//AQUI A QUEBRA DE LINHA É MAIOR QUE A PADRÃO
conteudo += "IMPRIMINDO CONTEUDO EM IMPRESSORA MATRICIAL"+"\u001B\u004A" + (char) 100;
Bom, espero que esse post ajude quem estiver com os mesmo problemas que eu já tive, e no mais... Boa sorte =D