Un código de barras en una etiqueta de envío o en una factura tiene una sola tarea: ser leído por un escáner en el primer intento. El que sobreviva a ese intento se decide mucho antes de que el paquete llegue al muelle de carga. Se decide por la forma en que se colocó el símbolo en la página. El error más común en una canalización de generación de reportes en Delphi consiste en renderizar el código de barras como un mapa de bits en otro lugar y colocar esa imagen en el PDF. El código se ve bien en pantalla con un nivel de zoom determinado y luego se degrada en cualquier otro lugar.
La alternativa consiste en dibujar el símbolo como contenido vectorial, directamente en la página. PDFlibPas expone una familia de llamadas de dibujo exactamente para esto, que abarca los símbolos de matriz 2D QR, PDF417 y DataMatrix, las familias lineales a través de Code128 y GS1-128, y USPS Intelligent Mail para automatización postal. El argumento a favor del formato vectorial no es estético. Se trata de que las barras se ubiquen exactamente donde el escáner espera encontrarlas.
Por qué el formato vectorial supera a un mapa de bits colocado
Un código de barras es un patrón de barras y espacios, o en dos dimensiones, una cuadrícula de módulos oscuros y claros. El decodificador funciona midiendo la relación de esos anchos. Cualquier cosa que distorsione las relaciones es ruido que consume el margen de error del símbolo. Una imagen rasterizada de código de barras contiene píxeles fijos. Cuando el PDF se renderiza en una impresora cuyos puntos no se dividen de manera uniforme en la cuadrícula de la imagen, el rasterizador tiene que volver a muestrear, y los bordes de los módulos que deberían ser nítidos se distribuyen entre dos píxeles del dispositivo. Una barra estrecha puede ensancharse, un espacio adyacente puede reducirse y la relación de ancho en la que confía el decodificador se desvía.
Dibujado como contenido vectorial, el mismo símbolo es un conjunto de rectángulos rellenos descritos en coordenadas del espacio de usuario de PDF. No hay una cuadrícula de píxeles fija con la que competir. Al momento de imprimir, el dispositivo renderiza cada rectángulo a la resolución que realmente tiene, de modo que cada borde de módulo es tan nítido como lo permite el hardware, a cualquier escala y tamaño de impresión. Aumente la escala de un símbolo vectorial para una etiqueta de paleta o redúzcala para un paquete y la geometría se mantendrá exacta. Esa precisión es lo que mantiene alta la tasa de lectura en el primer intento, que es el único propósito de colocar un código de barras en la página.
Códigos QR y los cuatro niveles de corrección
QR es un símbolo de matriz 2D que se lee en ambos ejes a la vez, por lo que empaqueta una gran cantidad de datos en un cuadrado pequeño. Su tolerancia a daños proviene de la corrección de errores Reed-Solomon, que se ofrece en cuatro niveles. El nivel L recupera aproximadamente el 7 por ciento de las palabras de código (codewords), el M al rededor del 15 por ciento, el Q cerca del 25 por ciento y el H aproximadamente el 30 por ciento. Una mayor corrección no es gratuita. Las palabras de código de recuperación ocupan la capacidad de los módulos, por lo que para una cantidad fija de datos, un nivel más alto obliga a usar un símbolo más denso o físicamente más grande.
La elección es una cuestión sobre el entorno en el que existirá el símbolo. Un documento digital limpio que solo se escaneará desde una pantalla puede permanecer en L y ser compacto. Una etiqueta que se imprimirá, manipulará, sufrirá raspaduras y posiblemente quede parcialmente cubierta por cinta adhesiva requiere Q o H, porque esa redundancia adicional es lo que permite a un decodificador reconstruir la carga útil a partir de un símbolo que ya no está en perfectas condiciones. DrawQRCode toma la posición y un SymbolSize que fija el ancho y alto dibujados, además de un valor EncodeOptions que selecciona el modo de datos (0 para automático, o variantes numéricas, alfanuméricas, ISO-8859-1 y UTF-8) y un valor DrawOptions para la orientación.
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;
El nivel de corrección en sí es elegido por el codificador para ajustar los datos en el símbolo que solicitó. Si necesita un nivel alto garantizado para un entorno hostil, dimensione el símbolo generosamente para que el codificador tenga el presupuesto de módulos necesario para destinarlo a la redundancia en lugar de verse obligado a reducirlo para que quepa.
PDF417 para identificaciones y etiquetas de envío
PDF417 es un símbolo lineal apilado. Cada fila es un código de barras lineal corto y las filas se apilan para formar un bloque, razón por la cual aparece en licencias de conducir, tarjetas de embarque y etiquetas de envío de transportistas donde una franja de datos más amplia debe ubicarse en un espacio rectangular. Su corrección de errores funciona en una escala de 0 a 8. Cada paso duplica aproximadamente el número de palabras de código de corrección, por lo que el nivel 5 aporta mucha más redundancia que el nivel 1, a costa de más palabras de código en la página.
La forma de un bloque PDF417 es ajustable, y eso importa porque la etiqueta tiene un área fija que llenar. DrawPDF417SymbolEx expone los controles que la llamada básica no ofrece. FixedColumns y FixedRows fijan el recuento de columnas de datos y de filas, donde 0 significa dejar que el codificador decida. ErrorLevel toma -1 para automático o un valor explícito de 0 a 8. ModuleSize es el ancho del elemento más estrecho en la unidad de medida actual, y HeightWidthRatio establece la altura de cada módulo en relación con su ancho, que es la forma en que se hace el bloque corto y ancho o alto y estrecho para adaptarse al espacio disponible.
// 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
Fijar las columnas es el recurso habitual en una plantilla de etiqueta. Un recuento de columnas constante le da al bloque un ancho predecible, por lo que el diseño circundante no se desplaza a medida que la carga útil codificada cambia de longitud de un documento a otro, mientras el codificador agrega filas hacia abajo para absorber la diferencia.
DataMatrix para marcas pequeñas
DataMatrix es el símbolo a elegir cuando la marca debe ser pequeña. Es una cuadrícula compacta en 2D que utiliza ECC 200, el esquema moderno de Reed-Solomon, y sigue siendo legible en tamaños en los que un símbolo QR con los mismos datos resultaría incómodo. Eso lo convierte en la opción estándar para el marcado directo de piezas, pequeños componentes electrónicos y etiquetas de logística densas.
DrawDataMatrixSymbol toma un ModuleSize para el paso de punto (dot pitch), un Encoding de 1 para ASCII y un SymbolSize que es 0 para automático o una de las dimensiones cuadradas y rectangulares estándar, desde 10x10 hasta 132x132. El parámetro Options combina la orientación con el ancho de la zona de silencio (quiet zone), donde sumar de 100 a 400 establece un borde blanco de uno a cuatro módulos. La zona de silencio no es un elemento decorativo. Un decodificador necesita ese margen despejado para encontrar el patrón de búsqueda del símbolo, y un símbolo apretado contra otra tinta es un símbolo que no se podrá capturar.
// 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
Dónde dominan todavía los códigos de barras 1D
Los símbolos bidimensionales captan la atención, pero los códigos de barras lineales siguen dominando gran parte del comercio minorista y la logística, y la razón es la base instalada de escáneres láser que leen un solo barrido. Code128 es el caballo de batalla para datos alfanuméricos y su eficiencia proviene de tres conjuntos de caracteres. El conjunto A abarca caracteres de control y mayúsculas, el conjunto B abarca el rango ASCII imprimible completo y el conjunto C es el que importa para los números. El subconjunto C codifica un par de dígitos en un solo carácter de símbolo, por lo que una serie de datos numéricos ocupa la mitad de los caracteres de símbolo que requeriría en los conjuntos A o B. Esa es la forma más compacta de colocar un código de barras numérico largo, y la implementación de Code128 de PDFlibPas combina automáticamente los conjuntos B y C para lograrlo.
GS1-128, el estándar anteriormente llamado EAN-128, se basa en Code128 al incluir Identificadores de Aplicación (Application Identifiers), los prefijos entre corchetes que indican a un sistema receptor si los dígitos siguientes son un número de serie, un código de lote o una fecha de vencimiento. La estructura está marcada por FNC1, un carácter especial que no contiene datos y que identifica al símbolo como codificado según GS1 y separa los campos de longitud variable. En PDFlibPas se dibuja un símbolo GS1-128 con DrawBarcode utilizando el tipo Code128 y el marcador literal [FNC1] colocado en la cadena de datos donde comienza cada identificador de aplicación.
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 el correo, USPS Intelligent Mail, también llamado OneCode, codifica datos de enrutamiento y seguimiento en un único código de barras modulado por altura para la automatización postal. DrawIntelligentMailBarcode toma valores geométricos explícitos para el ancho de la barra, la altura completa de la barra, la altura del seguidor (tracker) y el ancho del espacio, con los datos suministrados únicamente como una cadena de 20, 25, 29 o 31 dígitos. Las alturas explícitas de la barra y del seguidor existen porque el símbolo contiene información sobre si cada barra es una barra completa, ascendente o descendente, y el lector postal depende de que esas alturas se mantengan según la especificación.
Dibujo en la página y medición para el diseño
Cada llamada que se muestra aquí dibuja en el contenido de la página seleccionada actualmente, la misma superficie que recibe el texto y las imágenes, de modo que el código de barras se produce como parte de la generación normal del documento en lugar de importarse como un recurso independiente. Debido a que los símbolos son contenido vectorial, los datos que codifican y la geometría que ocupan se conocen al momento de dibujar, lo que le permite colocarlos de manera determinista.
El diseño de las familias lineales se beneficia de realizar mediciones primero. GetBarcodeWidth devuelve el ancho renderizado total de un código de barras para un ancho de barra estrecha y tipo de código de barras determinados, por lo que puede reservar el espacio horizontal exacto antes de confirmar el dibujo, en lugar de adivinar y descubrir una superposición después de construir la página. Los símbolos en 2D son más sencillos de colocar porque usted establece su tamaño dibujado directamente a través de SymbolSize o ModuleSize, y el símbolo ocupa ese espacio. En cualquier caso, la disciplina es la misma. Decida el tamaño físico a partir del entorno de escaneo, confirme que el símbolo quepa en el espacio asignado y deje que la geometría vectorial mantenga cada borde nítido desde la vista previa en pantalla hasta la impresión final.
Para el flujo de trabajo más amplio de construcción de páginas en el que se integran estos códigos de barras, las técnicas en nuestro artículo sobre extracción de texto, imágenes y fuentes cubren la lectura de contenido de vuelta desde un PDF, y la guía para la fusión y división de PDF grandes con acceso directo muestra cómo ensamblar documentos de gran volumen de manera eficiente. Ambos se complementan naturalmente con la API de dibujo descrita aquí, que se distribuye como parte de la Delphi PDF Library para Delphi y C++Builder, junto con las API de texto, gráficos, formularios y firmas cubiertas en otras partes de este blog.