De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.
Colaboração: Rubens Queiroz de Almeida
Data de Publicação: 23 de Março de 2004
Para mais informações visite: http://eventos.temporeal.com.br
As inscrições podem ser feitas diretamente em: http://www.sp.senac.br/informatica
Colaboração: Eduardo Gielamo Oliveira & Rodolfo Broco Manin
Quando trocamos o sistema de quotas impresso aqui da FEA por uma alternativa em software livre usando o Samba, nos deparamos com um problema que acredito ser extremamente comum nesse tipo de sistema: contar as paginas do arquivo a ser impresso, estando ele em formato PCL.
Depois de muito procurar, me convenci de que no tinha jeito, e adotei a solução classica: mudar o sistema todo para PostScript e obter o numero de paginas contando as ocorrencias do comando PS 'showpage' no arquivo (visto que não podemos contar com aqueles comentarios que o drive do Windows coloca com o numero de paginas do arquivo).
O problema é que arquivos PostScript gerados pelo Windows costumam ser enormes: uma apresentação do PowerPoint com algumas fotos frequentemente fica mais de dez vezes maior em PS do que em PCL. Mesmo arquivos de texto puro ficam maiores em PS, visto que o Windows não usa as fontes da impressora e imprime letras como graficos, jogando fora toda a inteligncia do PS. Atualmente, acho que nenhum programa moderno usa as fontes da impressora e gera um PS civilizado - nem o dvips do LaTex faz isso.
Recentemente, o nosso colega Eduardo Gielamo Oliveira comecou a pesquisar sobre a 'linguagem' PCL para desenvolver um contador de paginas. Eu ja o adverti logo de cara que a coisa não ia ser simples, e que eu achava que não ia dar certo, mas... alguns dias depois, ele apareceu com um algoritmo extremamente simples e preciso!!! E o impossvel virou realidade.
O Eduardo identificou alguns comandos PCL que encabecam blocos binarios dentro dos quais o caractere de FormFeed pode aparecer. Esses comandos informam o tamanho dos respectivos blocos, de forma que é possivel "pula-los", e contar apenas os FormFeeds que sao realmente FormFeeds.
O Windows usa o mesmo driver para todas as impressoras PCL a que da suporte (PCL5EMS2.DLL), e não é um driver muito "ousado": utiliza apenas uns poucos comandos do PCL, o que faz com que o algoritmo funciona muito bem com esses drivers. Com drivers proprietarios, algumas funcionalidades de impressão - como imprimir dos dois lados, ou em mais de uma pagina por folha - usam sintaxes mais especficas, que podem confundir o algoritmo.
O programa que estou enviando aqui foi elaborado pelo Eduardo e por mim. Num script, um:
Pages=`pclcount $FileName`
é suficiente para colocar na variavel '$Pages' o numero de paginas do arquivo cujo nome esta em '$FileName'. Use 'pclcount -h' para um "help" das opcoes de linha de comandos.
O programa é distribuído segundo a GPL. Convidamos quem o quiser usar a nos manter informados de eventuais erros de contagem, para que possamos aprimorar o algoritmo. Em pouco menos de 1 mes funcionando aqui na FEA, o programa no errou nenhuma vez.
Para compilar o programa, use: 'gcc -Wall pclcount.c -o pclcount'.
/***************************************************************************\ |* pclcount --- Conta as paginas de um arquivo de impressao formato HP PCL *| |* Copyright (c) 2003, by Eduardo Gielamo Oliveira & Rodolfo Broco Manin *| |* *| |* Este programa e software livre; voce pode redistribui-lo e/ou *| |* modifica-lo sob os termos da Licenca Publica Geral GNU, conforme *| |* publicada pela Free Software Foundation; tanto a versao 2 da *| |* Licenca como (a seu criterio) qualquer versao mais nova. *| |* *| |* Este programa e distribuido na expectativa de ser util, mas SEM *| |* QUALQUER GARANTIA; sem mesmo a garantia implicita de *| |* COMERCIALIZACAO ou de ADEQUACAO A QUALQUER PROPOSITO EM *| |* PARTICULAR. Consulte a Licenca Publica Geral GNU para obter mais *| |* detalhes. *| |* *| |* Voce deve ter recebido uma copia da Licenca Publica Geral GNU *| |* junto com este programa; se nao, escreva para a Free Software *| |* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA *| |* 02111-1307, USA. *| |* ----------------------------------------- *| |* Este programa deve ser eficiente para contar o numero de paginas em *| |* arquivos PCL gerados pelos drivers padrao do Windows. *| |* Contamos com a colaboracao dos usuarios para aprimora-lo. *| |* *| |* Caso voce encontre algum arquivo nessas condicoes que produza uma *| |* contagem erronea, por favor entre em contato conosco por e-mail, *| |* anexando o arquivo PCL que foi contado errado e informando a versao *| |* do PCLCount que foi usada e o numero de paginas real do arquivo. *| |* *| |* Atualmente, nao suportamos arquivos PCL gerados por drivers fornecidos *| |* por terceiros. Apenas os drivers que acompanham o Windows sao *| |* suportados. *| |* *| |* oliveira@fea.unicamp.br *| |* rodolfo@fea.unicamp.br *| \***************************************************************************/ #define Version 20040107 #include <stdio.h> #include <libgen.h> // Mostra o help da linha de comandos void ShowUsage() { printf("pclcount (v.%d): Conta o numero de paginas em um arquivo PCL.\n" \ "Copyright (c) 2003, by Eduardo Gielamo Oliveira & Rodolfo Broco Manin\n" \ "Este programa e' distribuido nos termos da Licenca Publica GPL.\n" \ "Para maiores informacoes, consulte http://www.gnu.org/copyleft/gpl.html\n\n" \ "Sintaxe: pclcount <nome_do_arquivo> [-v][-h]\n" \ " -v -- Exibe informacoes detalhadas durante a execucao\n" \ " -h -- Informa os parametros validos para linha de comandos\n", Version); } int main (int argc, char **argv) { FILE *InputFile; char ch, EndTag, tag[2], *InputFileName; int n, BlockSize, Pages, Copies, Quiet; unsigned long FileSize, FilePos; BlockSize = Pages = FileSize = FilePos = 0; Copies = Quiet = 1; InputFileName = NULL; // Intepreta os parametros da linha de comandos for(n = 1; n <= argc - 1; n++) { if(! memcmp(argv[n], "-h", 2)) { ShowUsage(); exit(0); } else if(! memcmp(argv[n], "-v", 2)) Quiet = 0; else if(argv[n][0] == '-') { fprintf(stderr, "-- Parametro incorreto: '%s'.\n", argv[n]); exit(1); } else InputFileName = argv[n]; } if(InputFileName == NULL) { fprintf(stderr, "-- Nao foi informado um nome de arquivo.\n" \ " Use 'pclcount -h' para obter ajuda.\n"); exit(1); } // Tenta abrir o arquivo de entrada if(! (InputFile = fopen(InputFileName, "r"))) { fprintf(stderr, "--Erro abrindo arquivo: %s\n", argv[1]); exit(-1); }; // Obtem o tamanho do arquivo, para exibir as estatisticas caso especificado '-v' na linha de comandos if(! Quiet) { fseek(InputFile, 0, SEEK_END); FileSize = ftell(InputFile); fseek(InputFile, 0, SEEK_SET); } while(fread(&ch, 1, 1, InputFile)) { switch(ch) { case 12: // Encontrado FormFeed: incrementa o contador de paginas Pages ++; break; case 27: // Encontrado <ESC> fread(tag, 2, 1, InputFile); if(! (memcmp(tag, "*b", 2) && memcmp(tag, "(s", 2) && memcmp(tag, ")s", 2) && memcmp(tag, "&p", 2))) { /* Detecta os operadores: <ESC>*b###W -> Inicio de Bloco Binario <ESC>(s###W -> Inicio de Bloco de Descricao de Caracteres <ESC>)s###W -> Inicio de Bloco de Descricao de Fontes <ESC>&p###X -> Inicio de Bloco de Caracteres nao-imprimiveis Nesses operadores, '###' eh o tamanho do bloco respectivo. */ // Define o caracter terminador do bloco EndTag = memcmp(tag, "&p", 2) ? 'W' : 'X'; do { fread(&ch, 1, 1, InputFile); if((ch >= '0') && (ch <= '9')) { // Foi lido um numero: compoe o tamanho do bloco BlockSize = 10 * BlockSize + ch - '0'; } } while ((ch >= '0') && (ch <='9')); if(ch == EndTag) { // O operador terminou com 'W': eh um dos operadores esperados // Efetua um 'seek' para pular o bloco fseek(InputFile, BlockSize, SEEK_CUR); FilePos = ftell(InputFile); // Atualizando a mensagem de status aqui (inves de faze-lo o tempo todo) nao deixa o processamento tao lento if(! Quiet) printf("Processando... %ld de %ld bytes (%ld%%)\r", FilePos, FileSize, (FilePos * 100) / FileSize); } // Nao era um dos operadores esperados: reinicializa BlockSize BlockSize = 0; } else if(! (memcmp(tag, "&l", 2))) { // O operador <ESC>&l###X informa o numero de copias ('###') solicitadas n = 0; for(ch = '0'; (ch >= '0') && (ch <= '9'); fread(&ch, 1, 1, InputFile)) { n = 10 * n + ch - '0'; } if(ch == 'X') { // O operador terminou com 'X' (como esperado). Obtem o numero de copias Copies = n; } } break; } } fclose(InputFile); if(Quiet) // Caso nao tenha sido especificado '-v' na linha de comandos, imprime apenas o numero total de folhas do trabalho printf("%d\n", Pages * Copies); else printf("Processando... Conluido. \n" \ "Numero de Paginas.....: %d\n" \ "Numero de Copias......: %d\n" \ "Total de Paginas......: %d\n", Pages, Copies, Pages * Copies); return(0); }
This policy contains information about your privacy. By posting, you are declaring that you understand this policy:
This policy is subject to change at any time and without notice.
These terms and conditions contain rules about posting comments. By submitting a comment, you are declaring that you agree with these rules:
Failure to comply with these rules may result in being banned from submitting further comments.
These terms and conditions are subject to change at any time and without notice.
Comentários