Technical Article

Gerar Códigos de Barras Legíveis em PDF com o HotPDF no Delphi

Um código de barras não é uma imagem decorativa para embelezar um documento. É uma medição, e o leitor de códigos é o instrumento que a interpreta. Esta premissa determina quase todas as decisões sobre como o desenhar num PDF. As barras não contêm informação pela sua cor preta; a informação reside na proporção entre a largura das barras e a largura dos espaços, e o leitor recupera-a medindo o tempo das transições à medida que o laser ou sensor percorre o código. Se comprimir essa geometria, a desfocar ou reduzir as suas margens, obterá algo que se parece exatamente com um código de barras, mas que funcionará como uma mancha ilegível. O HotPDF disponibiliza duas formas de desenhar um código na página, e a diferença entre elas é precisamente a diferença entre controlar essa geometria ou abdicar do seu controlo.

Uma página PDF que mostra uma grelha de códigos de barras lineares em diferentes simbologias desenhados pelo HotPDF no Delphi
Simbologias de códigos de barras lineares desenhadas num único PDF com o HotPDF

O que o HotPDF consegue codificar

O HotPDF desenha simbologias lineares (unidimensionais), e o conjunto é mais amplo do que a maioria dos projetos exige. A enumeração THPDFBarcodeType abrange a família Code 2 of 5 nas suas variantes interleaved, industrial e matrix; o Code 39 e a sua variante estendida; os três subconjuntos do Code 128 (A, B e C); o Code 93 simples e estendido; MSI; PostNet; Codabar; o grupo de retalho UPC e EAN, nomeadamente EAN-8, EAN-13, UPC-A, as versões comprimidas UPC-E0 e UPC-E1, e os suplementos UPC de 2 e 5 dígitos; e ainda os subconjuntos GS1-128 (EAN-128). Isto é suficiente para cobrir etiquetas de cadeias de distribuição, pontos de venda a retalho e os códigos industriais antigos ainda presentes em armazéns.

O que o HotPDF não desenha é a família bidimensional. Não dispõe de suporte para códigos QR, Data Matrix ou PDF417. Estes últimos codificam bytes numa grelha com algoritmos próprios de correção de erros e, se o seu projeto exigir um deles, esta não é a ferramenta indicada. Para códigos unidimensionais, a questão prática resume-se a saber qual a simbologia adequada para os dados que possui, uma vez que as codificações não são intercambiáveis.

As restrições de dados são rígidas e manifestam-se no momento da geração. As variantes do Code 2 of 5 e o MSI aceitam apenas dígitos. O Code 39 suporta letras maiúsculas, dígitos e alguns sinais de pontuação; se necessitar de letras minúsculas ou de toda a gama ASCII, terá de recorrer ao Code 39 Extended ou a um subconjunto do Code 128. O Code 128C agrupa os dígitos dois a dois para maior densidade, pelo que exige uma sequência numérica de comprimento par. O EAN-13 exige doze dígitos e calcula o décimo terceiro como dígito de controlo; o EAN-8 exige sete e calcula o oitavo; o UPC-A requer doze. Se fornecer a uma simbologia dados que esta não consegue representar, não obterá uma exceção explicativa, mas sim um código de barras que codifica informação corrompida, o que é pior, porque parecerá correto até ser lido num leitor de caixa.

Dois caminhos de desenho, dois níveis de controlo

O método a utilizar em ambiente de produção é o DrawBarcode, presente no objeto da página. Este método recebe a simbologia, a posição, a altura e um parâmetro crucial: o MUnit, correspondente à largura do módulo. O módulo representa a largura da barra mais estreita, o elemento base a partir do qual todas as outras medidas do código são multiplicadas, sendo expresso em pontos. A capacidade de leitura do resultado impresso depende inteiramente deste valor inteiro.

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'label.pdf';
    Pdf.BeginDoc;

    // BCType, X, Y, Height, MUnit (module width in points), angle,
    // data, UseCheckSum, bar color, background color.
    Pdf.CurrentPage.DrawBarcode(
      bcCodeEAN13,           // symbology
      72, 680,               // X, Y in points from the bottom-left
      60,                    // bar height
      1,                     // MUnit: 1pt narrowest bar
      0,                     // no rotation
      '123456789012',        // 12 digits; the 13th is the check
      True,                  // append the modulo-10 check digit
      clBlack, clWhite);     // bars black, background white

    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Dois argumentos merecem particular atenção. A propriedade UseCheckSum anexa o dígito de controlo módulo-10 esperado pela simbologia e, para os códigos de retalho, deve ser definida quase sempre a True; desative-a apenas se os seus dados já incluírem um dígito de controlo pré-calculado, para evitar a sua duplicação. As cores das barras e do fundo são os dois últimos parâmetros, e a tentação de inovar neste aspeto representa um risco analisado abaixo. Tenha também em atenção a origem das coordenadas: tal como em qualquer outra chamada de desenho no HotPDF, o X e o Y medem-se a partir do canto inferior esquerdo da página em pontos, com o Y a crescer para cima, seguindo a mesma convenção apresentada no exemplo do Hello World.

O segundo caminho é o DirectDrawBarcode, que recebe os dados e um retângulo delimitador (X, Y, Width, Height), ajustando o padrão de barras para preencher essa largura. É prático para distribuir códigos numa grelha, pois define a área disponível e o método ajusta as barras ao espaço. Contudo, essa conveniência acarreta riscos. Ao especificar uma largura, deixa de controlar a dimensão do módulo; o método distribui o espaço concedido pelo número de barras necessárias e a barra mais estreita assumirá o tamanho que resultar dessa divisão. Se solicitar uma sequência densa de Code 128 num retângulo demasiado estreito, a largura das barras estreitas diminuirá de forma silenciosa para valores inferiores ao limite de leitura dos equipamentos. Para leituras fiáveis, prefira o método DrawBarcode e defina o MUnit explicitamente. Reserve o DirectDrawBarcode para pré-visualizações e cenários onde garanta que as barras resultantes mantêm a legibilidade mínima.

A largura do módulo é uma decisão de resolução

Este é o cálculo que determina se a sua etiqueta será utilizável. Um leitor laser ou uma câmara possuem um limite mínimo de detalhe que conseguem distinguir, e a barra mais estreita deve situar-se claramente acima desse valor após a impressão. O limite inferior habitualmente recomendado para códigos lineares de uso geral é uma barra estreita de 13 milésimos de polegada (cerca de 0,33 mm), sendo considerado o mínimo aceitável em várias especificações de retalho e indústria. Convertendo isto para unidades PDF: um ponto equivale a 1/72 de polegada (cerca de 0,353 mm), pelo que um módulo com a largura de um único ponto situa-se exatamente nesse limite inferior. É por isso que MUnit := 1 é o valor mínimo em que se deve confiar para leitura física, sendo aconselhável duplicar para 2 se dispuser de espaço suficiente na etiqueta.

Considere também a resolução de saída, uma vez que o módulo tem de resistir à impressão. Numa impressora laser de 300 DPI, um ponto do dispositivo equivale a 1/300 de polegada, pelo que um módulo de um ponto terá a largura aproximada de quatro pontos de impressão. Quatro pontos de impressão são escassos para garantir margens nítidas; a dispersão do toner e desvios de alinhamento afetarão o resultado, fazendo com que a barra impressa fique ligeiramente mais larga ou estreita do que o especificado. Aumentar o módulo para 2 pontos eleva a largura para os oito pontos de impressão, absorvendo essas oscilações. A regra a reter: a largura do módulo configurada em pontos deve traduzir-se num número inteiro e seguro de pontos de impressão na resolução real da sua impressora, e não numa resolução teórica. Um código lido sem problemas no ecrã mas que falha ao ser impresso decorre quase sempre da omissão desta verificação.

A zona de silêncio faz parte do símbolo

A razão mais comum pela qual um código de barras corretamente estruturado não é lido prende-se com a zona de silêncio (quiet zone), a margem em branco de cada lado das barras. Os leitores dependem desse espaço vazio para identificar o início e o fim do código; sem ele, o equipamento não distingue a primeira barra de qualquer outro elemento próximo na página. As normas são específicas: a maioria das simbologias lineares exige uma zona de silêncio correspondente a pelo menos dez vezes a largura do módulo em cada lado, e os códigos de retalho UPC e EAN requerem nove módulos à esquerda e sete à direita. Com um módulo de um ponto, isto representa cerca de dez pontos (aproximadamente 3,5 mm) de espaço em branco garantido de cada lado do código.

O HotPDF desenha as barras e nada mais. Não reserva a zona de silêncio de forma automática, pelo que esta responsabilidade recai sobre o programador e é facilmente descurada. O problema manifesta-se de forma subtil: posiciona o código encostado à borda de uma célula de tabela, ou coloca um logótipo demasiado próximo na página, e o código que funcionava isoladamente deixa de ser lido quando integrado no documento final. Garanta esta margem no design da página. Antes de executar o DrawBarcode, assegure um espaço livre de pelo menos dez vezes a largura do módulo de ambos os lados, e trate qualquer imagem, linha ou texto que invada esse espaço como uma inconformidade técnica e não como uma mera opção estética.

Cor, contraste e a linha legível por humanos

A possibilidade de configurar as cores das barras e do fundo destina-se a acompanhar a identidade visual de marcas, mas é a forma mais rápida de inviabilizar a leitura do código. Os leitores detetam o contraste, geralmente através de luz vermelha, esperando barras escuras sobre um fundo claro. Preto sobre branco é a única combinação que deve utilizar sem testes prévios. Azul escuro ou verde escuro sobre fundo branco podem funcionar, mas combinações de baixo contraste cromático (e em particular barras vermelhas, que a luz vermelha do leitor deteta como se fossem o próprio fundo) falharão. Se a equipa de design solicitar códigos de barras coloridos, a resposta recomendada é manter as barras a preto e aplicar a cor noutros elementos da etiqueta.

O método DrawBarcode também pode apresentar o texto legível por humanos por baixo do código (os dígitos que um operador introduz manualmente quando a leitura falha). Este texto é uma salvaguarda e não um elemento decorativo; se desenhar a sua própria legenda, mantenha-a fora da zona de silêncio, uma vez que textos encostados às margens laterais anulam o espaço em branco necessário para a leitura. As chamadas deste exemplo, incluindo o TextOut para textos adicionais, correspondem aos métodos detalhados no guia de relatórios, que deve consultar para integrar códigos de barras numa composição de página complexa.

O hábito de uma breve verificação

As barras em formato vetorial constituem uma vantagem assinalável. Dado que o método DrawBarcode escreve o código através de instruções de desenho PDF e não como uma imagem rasterizada, as barras mantêm-se nítidas em qualquer nível de ampliação e o ficheiro não possui uma resolução fixa; a única resolução relevante é a da impressora. Isto não dispensa a realização de testes, apenas significa que o teste final deve ser feito em papel. Gere uma amostra, imprima-a no dispositivo de menor resolução que os códigos encontrarão em produção e leia-a com o mesmo tipo de leitor que os seus utilizadores possuem. Meça as zonas de silêncio na impressão, confirme que a largura do módulo se manteve adequada na conversão para pontos de impressão e verifique se o valor lido corresponde ao codificado, incluindo o dígito de controlo. Cinco minutos de teste com um leitor físico identificam todos os problemas descritos e evitam incidentes de etiquetagem incorreta em lotes de stock.

Os métodos DrawBarcode e DirectDrawBarcode aqui demonstrados fazem parte do Componente HotPDF para Delphi e C++Builder.