você está aqui: Home  → Arquivo de Mensagens

Seminário - Desenvolvendo e-Commerce com PHP e MySQL

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

Contando paginas de arquivos PCL

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< A NAME="note#X informa o numero de copias ('" HREF="#textnote#X informa o numero de copias ('">< SUP>#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);
  }


 

 

Veja a relação completa dos artigos de Rubens Queiroz de Almeida

Opinião dos Leitores

Seja o primeiro a comentar este artigo
*Nome:
Email:
Me notifique sobre novos comentários nessa página
Oculte meu email
*Texto:
 
  Para publicar seu comentário, digite o código contido na imagem acima
 


Powered by Scriptsmill Comments Script