7. Espacio de nombres codes:: — códigos de barras y QR
← prepress:: · Índice · Siguiente: fix:: →
13 funciones para detectar, decodificar y validar los códigos de barras y los códigos QR impresos en el documento.
El escaneo renderiza las páginas en alta resolución y se ejecuta una sola vez, en el primer uso de cualquier función
codes::. Los scripts que no usan el espacio de nombres no pagan ese coste.
Formatos reconocidos: EAN-8/13, UPC-A/E, Code 128, Code 39, ITF, código QR, Data Matrix, Aztec y PDF417, entre otros.
7.1 Detección
codes::detect_barcodes() y codes::detect_qrcodes()
check "El envase lleva código" {
assert codes::detect_barcodes(),
"no se encontró ningún código de barras en el arte"
// QR de trazabilidad
assert codes::detect_qrcodes(),
"falta el código QR de trazabilidad"
}
codes::count_barcodes()
Cantidad total de códigos detectados (barras + QR).
check "Cantidad de códigos" {
total = codes::count_barcodes()
print("códigos detectados:", total)
assert total == 2,
"esperaba 2 códigos (EAN + QR) y encontré #{total}"
}
codes::get_barcode_type(n)
Formato del enésimo código (1-based): "EAN_13", "QR_CODE", "CODE_128"...
check "Tipo del código principal" {
tipo = codes::get_barcode_type(1)
assert tipo == "EAN_13",
"el código principal debería ser EAN-13, y es #{tipo}"
}
check "Listándolos todos" {
// Recorre por índices, del 1 hasta la cantidad
print("primero:", codes::get_barcode_type(1))
print("segundo:", codes::get_barcode_type(2))
}
codes::get_barcode_location(n)
Dónde está el código: [pagina, x, y] en puntos (origen en la esquina inferior
izquierda).
check "Posición del código" {
lugar = codes::get_barcode_location(1)
print("página:", lugar.get(1), "x:", lugar.get(2), "y:", lugar.get(3))
// El código debe estar en la primera página
assert lugar.first() == 1,
"el código de barras no está en la portada"
}
7.2 Decodificación y validación
codes::decode_barcode(n)
El contenido decodificado del enésimo código.
check "Contenido del código" {
codigo = codes::decode_barcode(1)
print("código leído:", codigo)
assert codigo.starts_with("789"),
"el GTIN no es brasileño (debería empezar por 789): #{codigo}"
}
codes::validate_barcode_checksum(n)
Valida el dígito verificador GTIN del enésimo código detectado.
check "Dígito verificador" {
// Un GTIN con el dígito equivocado lo rechaza la caja del supermercado
assert codes::validate_barcode_checksum(1),
"dígito verificador inválido en el código #{codes::decode_barcode(1)}"
}
codes::validate_gtin(texto) y codes::validate_ean(texto)
Sinónimos. Validan el dígito verificador de una cadena (EAN-8/13, UPC-A, GTIN-14), útil para comprobar un número que viene de otra fuente.
check "GTIN indicado en el texto" {
require codes::validate_gtin("7891234567895")
require !codes::validate_gtin("7891234567890") // dígito erróneo
// Comprobando el número impreso debajo de las barras
impreso = text::extract_from_region(1, region(400, 20, 180, 15)).trim()
assert codes::validate_ean(impreso),
"el número impreso no es un GTIN válido: #{impreso}"
}
codes::validate_code128()
Verdadero si hay algún Code 128 decodificado con éxito (el checksum del Code 128 se valida en la propia decodificación).
check "Código logístico" {
assert codes::validate_code128(),
"falta el Code 128 de logística"
}
7.3 Comprobación cruzada
codes::compare_barcode_with_text()
Verdadero si el contenido de todos los códigos aparece en el texto del documento.
Esta es la comprobación que atrapa el error más caro del sector: el código de barras apuntando a un producto y el texto impreso diciendo otro.
check "El código coincide con el texto impreso" {
assert codes::compare_barcode_with_text(),
"el número del código de barras no aparece en el texto — ¿arte con datos cambiados?"
}
codes::validate_barcode_format(regex)
Verdadero si el contenido de todos los códigos casa con la expresión regular.
check "Formato esperado" {
// Solo EAN-13: exactamente 13 dígitos
assert codes::validate_barcode_format("^\d{13}$"),
"hay un código fuera del formato EAN-13"
}
check "El QR apunta al sitio oficial" {
assert codes::validate_barcode_format("^https://empresa\.com/.*"),
"el código QR apunta a una dirección no autorizada"
}
codes::validate_barcode_position(region) o (x0, y0, x1, y1)
Verdadero si todos los códigos están dentro del área. Acepta una region o
cuatro números en puntos.
check "Código en el área reservada" {
// Con una región con nombre: más legible
area = region(400, 20, 180, 80, "área del código")
assert codes::validate_barcode_position(area),
"código de barras fuera del área reservada del envase"
}
check "Con coordenadas directas" {
// x0, y0, x1, y1 en puntos
assert codes::validate_barcode_position(400, 20, 580, 100),
"código fuera de la posición especificada"
}
7.4 Ejemplo completo
// prospecto_farmaceutico.pdfl — validación del código de lote en un prospecto
// Uso: pdfl run prospecto_farmaceutico.pdfl prospecto.pdf
profile "prospecto-regulado" {
check "Presencia de los códigos" tags: ["codes"] {
assert codes::detect_barcodes(), "prospecto sin código de barras"
assert codes::count_barcodes() >= 1,
"esperaba al menos el EAN del producto"
}
check "Integridad del código" tags: ["codes"] {
codigo = codes::decode_barcode(1)
tipo = codes::get_barcode_type(1)
print("código:", tipo, "=", codigo)
assert tipo == "EAN_13", "el código principal no es EAN-13 (es #{tipo})"
assert codes::validate_barcode_checksum(1),
"dígito verificador inválido: #{codigo}"
assert codigo.starts_with("789"),
"el GTIN no es brasileño: #{codigo}"
}
check "Comprobación con el texto" tags: ["codes", "critico"] {
// El error más caro: el código de un producto y el texto de otro
assert codes::compare_barcode_with_text(),
"el número del código no aparece en el texto del prospecto"
}
check "Posición en el arte" tags: ["codes", "layout"] {
area_reservada = region(400, 20, 180, 90, "área del código")
assert codes::validate_barcode_position(area_reservada),
"código fuera del área reservada — puede cortarse en el acabado"
}
check "Cruce con la base de productos" tags: ["datos"] {
// Se integra con data:: — consulta el capítulo 9
codigo = codes::decode_barcode(1)
producto = data::query_gtin(codigo)
assert producto,
"el GTIN #{codigo} no consta en la base de productos homologados"
print("producto:", producto.get(2))
}
}