Um código de barras numa etiqueta de envio ou numa fatura tem uma única função, que é ser lido por um leitor na primeira passagem. A sua sobrevivência a essa leitura é decidida muito antes de a embalagem chegar ao cais de embarque. É decidida pela forma como o símbolo foi inserido na página. O erro mais comum num fluxo de geração de relatórios em Delphi consiste em renderizar o código de barras como um bitmap noutro local e colocar essa imagem no PDF. Visualiza-se de forma correta no ecrã a um determinado nível de zoom, deteriorando-se em todos os outros cenários.
A alternativa consiste em desenhar o símbolo como conteúdo vetorial, diretamente na página. O PDFlibPas disponibiliza um conjunto de funções de desenho precisamente para este fim, cobrindo os símbolos matriciais 2D QR, PDF417 e DataMatrix, as famílias lineares Code128 e GS1-128, e o USPS Intelligent Mail para automatização postal. O argumento a favor do formato vetorial não é estético. Prende-se com a precisão com que as barras são impressas onde o leitor espera encontrá-las.
Porque é que o formato vetorial supera um bitmap posicionado
Um código de barras é um padrão de barras e espaços ou, em duas dimensões, uma grelha de módulos claros e escuros. O descodificador funciona medindo a proporção destas larguras. Qualquer fator que distorça as proporções constitui ruído que consome a tolerância a erros do símbolo. Uma imagem rasterizada de um código de barras contém píxeis fixos. Quando o PDF é renderizado numa impressora cujos pontos não se alinham perfeitamente com a grelha da imagem, o rasterizador tem de efetuar uma reamostragem, e as arestas dos módulos que deveriam ser nítidas espalham-se por dois píxeis do dispositivo. Uma barra estreita pode alargar, um espaço adjacente pode encolher, e a proporção de largura na qual o descodificador confia desvia-se.
Desenhado como conteúdo vetorial, o mesmo símbolo consiste num conjunto de retângulos preenchidos descritos em coordenadas de espaço de utilizador do PDF. Não existe uma grelha fixa de píxeis para combater. No momento da impressão, o dispositivo renderiza cada retângulo na sua resolução real, assegurando que cada aresta do módulo seja tão nítida quanto o hardware permita, em qualquer escala ou tamanho de impressão. Amplie um símbolo vetorial para uma etiqueta de palete ou reduza-o para um pacote e a geometria permanece exata. Essa precisão é o que mantém elevada a taxa de leitura à primeira tentativa, o que é o principal objetivo de colocar um código de barras na página.
Códigos QR e os quatro níveis de correção
O QR é um símbolo matricial 2D lido em ambos os eixos simultaneamente, razão pela qual acomoda muitos dados num quadrado pequeno. A sua tolerância a danos provém da correção de erros Reed-Solomon, oferecida em quatro níveis. O Nível L recupera cerca de 7 por cento das palavras-código (codewords), o M cerca de 15 por cento, o Q cerca de 25 por cento e o H cerca de 30 por cento. Uma maior correção não é gratuita. As palavras-código de recuperação ocupam capacidade de módulo, pelo que, para uma quantidade fixa de dados, um nível mais elevado obriga a um símbolo mais denso ou fisicamente maior.
A escolha resume-se a uma questão sobre o ambiente onde o símbolo existirá. Um documento digital limpo que apenas seja lido a partir de um ecrã pode utilizar o nível L e manter-se compacto. Uma etiqueta que seja impressa, manuseada, desgastada e possivelmente coberta por fita adesiva requer o nível Q ou H, porque a redundância extra é o que permite a um descodificador reconstruir a carga de dados (payload) a partir de um símbolo que já não está intacto. A função DrawQRCode recebe a posição e um SymbolSize que define a largura e altura desenhadas, além de um valor EncodeOptions que seleciona o modo de dados (0 para automático, ou variantes numéricas, alfanuméricas, ISO-8859-1 e UTF-8) e um valor DrawOptions para a orientação.
var
Pdf: TPDFlib;
begin
Pdf := TPDFlib.Create(nil);
try
Pdf.NewDocument;
Pdf.SetPageSize('A4');
Pdf.SetMeasurementUnits(1); // 1 = millimetres
Pdf.NewPage;
// 30 mm square QR, automatic encoding, normal orientation
Pdf.DrawQRCode(20, 20, 30, 'https://www.loslab.com/', 0, 0);
Pdf.SaveToFile('Label_QR.pdf');
finally
Pdf.Free;
end;
end;
O próprio nível de correção é escolhido pelo codificador para ajustar os dados ao símbolo solicitado. Se necessitar de um nível elevado garantido para um ambiente adverso, dimensione o símbolo de forma generosa para que o codificador tenha margem de módulos para aplicar em redundância, em vez de ser forçado a reduzir o nível para caber no espaço disponível.
PDF417 para identificações e etiquetas de envio
O PDF417 é um símbolo linear empilhado. Cada linha é um pequeno código de barras linear, e as linhas empilham-se para formar um bloco, razão pela qual surge em cartas de condução, cartões de embarque e etiquetas de envio onde uma faixa de dados mais larga tem de caber numa área retangular. A sua correção de erros funciona numa escala de 0 a 8. Cada passo duplica aproximadamente a quantidade de palavras-código de correção, pelo que o nível 5 fornece muito mais redundância do que o nível 1, à custa de mais palavras-código na página.
O formato de um bloco PDF417 é ajustável, o que é importante porque a etiqueta dispõe de uma área fixa para preencher. A função DrawPDF417SymbolEx disponibiliza os controlos que a chamada básica não oferece. FixedColumns e FixedRows fixam a contagem de colunas e linhas de dados, com 0 a indicar que o codificador decide. ErrorLevel recebe -1 para automático ou um valor explícito de 0 a 8. ModuleSize indica a largura do elemento mais estreito na unidade de medida atual, e HeightWidthRatio define a altura de cada módulo em relação à sua largura, permitindo desenhar o bloco mais curto e largo ou mais alto e estreito, conforme o espaço disponível.
// Fixed 10 data columns, automatic rows, error level 5,
// module 0.30 mm wide, rows three times the module width tall
Pdf.DrawPDF417SymbolEx(20, 60, 'PDF417 PAYLOAD 0123456789',
0, // Options: 0 = normal orientation
10, // FixedColumns
0, // FixedRows: 0 = automatic
5, // ErrorLevel: 0 to 8
0.30, // ModuleSize, in the current measurement unit
3.0); // HeightWidthRatio
DataMatrix para marcações de pequena dimensão
O DataMatrix é a escolha ideal quando a marcação necessita de ser pequena. Consiste numa grelha 2D compacta que utiliza o ECC 200, o esquema moderno de Reed-Solomon, e mantém-se legível em dimensões em que um código QR com os mesmos dados seria inviável. Isso torna-o a escolha padrão para marcação direta de peças, pequenos componentes eletrónicos e etiquetas logísticas densas.
A função DrawDataMatrixSymbol recebe um ModuleSize para o tamanho do ponto, um Encoding de 1 para ASCII, e um SymbolSize que pode ser 0 para automático ou uma das dimensões padrão quadradas e retangulares, de 10x10 a 132x132. O parâmetro Options combina a orientação com a largura da zona de silêncio (quiet zone), em que a adição de 100 a 400 define uma margem branca de um a quatro módulos. A zona de silêncio não é um adorno. O descodificador precisa dessa margem limpa para detetar o padrão de localização do símbolo, e um símbolo encostado a outros elementos gráficos é um símbolo que não será lido.
// Auto-sized ASCII DataMatrix, 0.5 mm module, normal orientation
// with a one-module quiet zone (Options 0 + 100)
Pdf.DrawDataMatrixSymbol(20, 110, 0.5, 'DMX-SN-4408812',
1, // Encoding: 1 = ASCII
0, // SymbolSize: 0 = automatic
100); // Options: normal + one-module quiet zone
Onde os códigos de barras 1D ainda dominam
Os símbolos bidimensionais atraem as atenções, mas os códigos de barras lineares ainda dominam grande parte do comércio a retalho e da logística, sendo a razão disso a base instalada de leitores laser que efetuam uma única passagem de varrimento. O Code128 é o motor para dados alfanuméricos, e a sua eficiência advém de três conjuntos de caracteres. O conjunto A abrange caracteres de controlo e maiúsculas, o conjunto B cobre o intervalo ASCII imprimível completo, e o conjunto C é o relevante para números. O subconjunto C codifica um par de dígitos num único caractere do símbolo, pelo que uma sequência de dados numéricos consome metade dos caracteres que utilizaria no conjunto A ou B. Trata-se do método mais compacto de desenhar um código de barras numérico longo, e a implementação Code128 do PDFlibPas combina os conjuntos B e C automaticamente para o conseguir.
O GS1-128, norma anteriormente denominada EAN-128, baseia-se no Code128 ao incluir Identificadores de Aplicação, os prefixos entre parênteses que indicam a um sistema de receção se os dígitos seguintes são um número de série, um lote ou uma data de validade. A estrutura é sinalizada por FNC1, um caractere especial sem dados que marca o símbolo como codificado em GS1 e separa campos de comprimento variável. No PDFlibPas, desenha-se um símbolo GS1-128 com DrawBarcode utilizando o tipo Code128 e o marcador literal [FNC1] inserido na string de dados onde cada identificador de aplicação se inicia.
var
W: Double;
begin
// Code128, with FNC1 markers this becomes a GS1-128 symbol.
// AI 21 (serial) = ABC123, AI 20 (variant) = 13
Pdf.DrawBarcode(20, 150, 60, 18, '[FNC1]21ABC123[FNC1]2013',
3, // Barcode: 3 = Code128
0); // Options: 0 = default drawing
// Measure the rendered width for a 0.30 mm narrow bar before laying out
W := Pdf.GetBarcodeWidth(0.30, '[FNC1]21ABC123[FNC1]2013', 3);
end;
Para correio, o USPS Intelligent Mail, também designado OneCode, codifica dados de encaminhamento e rastreio num único código de barras de altura modulada para automatização postal. A função DrawIntelligentMailBarcode recebe a geometria explícita para a largura da barra, a altura total da barra, a altura do marcador (tracker) e a largura do espaço, sendo os dados fornecidos como uma sequência composta apenas por 20, 25, 29 ou 31 dígitos. As alturas explícitas da barra e do marcador existem porque o símbolo transporta informação no facto de cada barra ser uma barra completa, ascendente ou descendente, e o leitor postal depende de essas alturas estarem em conformidade com as especificações.
Desenhar na página e medir para paginação
Cada chamada mostrada aqui desenha no conteúdo da página selecionada no momento, a mesma superfície que recebe o seu texto e imagens, assegurando que um código de barras seja produzido como parte da geração normal de documentos em vez de importado como um recurso separado. Como os símbolos são conteúdo vetorial, os dados que codificam e a geometria que ocupam são conhecidos no momento do desenho, permitindo posicioná-los de forma determinística.
A disposição de elementos gráficos das famílias lineares beneficia da realização de medições prévias. O método GetBarcodeWidth retorna a largura total desenhada de um código de barras para uma determinada largura de barra estreita e tipo de código de barras, para que possa reservar o espaço horizontal exato antes de efetuar o desenho, em vez de adivinhar e deparar-se com uma sobreposição após a página estar montada. Os símbolos 2D são mais simples de posicionar porque define o seu tamanho diretamente através de SymbolSize ou ModuleSize, e o símbolo preenche essa área ocupada. De qualquer forma, a disciplina é a mesma. Decida o tamanho físico com base no ambiente de leitura, confirme se o símbolo cabe no espaço disponível e deixe a geometria vetorial manter todas as arestas nítidas, desde a pré-visualização no ecrã até à impressão final.
For the broader page-building workflow these barcodes drop into, the techniques in our article on text, image, and font extraction cover reading content back out of a PDF, and the guide to large PDF merge and split with direct access shows how to assemble high-volume documents efficiently. Both pair naturally with the drawing API described here, which ships as part of the Delphi PDF Library for Delphi and C++Builder alongside the text, graphics, form, and signature APIs covered elsewhere on this blog.