Esta guía rápida fue escrita en base a pruebas en la terminal de Linux con la impresora Epson TM-T20X.
Cabe mencionar que para las funciones se convierte el valor decimal a hexadecimal: es por esto que a cada número le antecede un \x
.
Para más información, se adjunta la url del manual de la impresora.
GS ( k <fn=165>
# Seleccionar el modelo
# (función 165) https://www.epson-biz.com/modules/ref_escpos/index.php?content_id=140
# (se toman los valores por defecto para n1 (50 = QR Model 2) y n2 (0))
#GS ( k pL pH cn fn n1 n2
#1D 28 6B 04 00 31 41 50 00
'x1D\x28\x6B\x04\x00\x31\x41\x50\x00'
GS ( k <fn=167>
# Establecer el tamaño del módulo
# (función 167) https://www.epson-biz.com/modules/ref_escpos/index.php?content_id=141
# (el valor de n para el modelo TM-T20 es 3, ref: https://www.novopos.ch/client/EPSON/TM-T20/TM-T20_spc_f.pdf pág 168)
#GS ( k pL pH cn fn n
#1D 28 6B 03 00 31 43 03
'x1D\x28\x6B\x03\x00\x31\x43\x03'
GS ( k <fn=169>
# Seleccionar el nivel de corrección de error
# (función 169) https://www.epson-biz.com/modules/ref_escpos/index.php?content_id=142
# ([30 -> 7%, nivel L] [31-> 15%, nivel M] [32 -> 25%, nivel Q] [33 -> 30%, nivel H]; el valor por defecto es 30 (7% aprox. de capacidad de recuperación))
#GS ( k pL pH cn fn n
#1D 28 6B 03 00 31 45 30
'x1D\x28\x6B\x03\x00\x31\x45\x30'
GS ( k <fn=180>
# Almacenar los datos en el área de almacenamiento de símbolos
# (función 180) https://www.epson-biz.com/modules/ref_escpos/index.php?content_id=143
# La longitud del QR se obtiene sumando 3 a la longitud original (en HEX) de los datos: QRL = longitud(QR) + 3
# pL se obtiene con el módulo a 256 de la longitud del QR: pL = QRL % 256
# pH se obtiene dividiendo a 256 la longitud del QR: pH = QRL / 256
# d1...dk es la información que se enviará, ej.: un string con una url. d1…dk = cadena_QR
#GS ( k pL pH cn fn m d1...dk
#1D 28 6B ... ... 31 50 30 ..........
'x1D\x28\x6B<pL><pH>\x31\x50\x30<cadena_QR>'
GS ( k <fn=181>
# Imprimir los datos en el área de almacenamiento de símbolos
# (función 181) https://www.epson-biz.com/modules/ref_escpos/index.php?content_id=144
#GS ( k pL pH cn fn m
#1D 28 6B 03 00 31 51 30
'x1D\x28\x6B\x03\x00\x31\x51\x30'
GS ( k <fn=182>
# Transmitir la información del tamaño de los datos de los símbolos en el área de almacenamiento de símbolos
# (función 182) https://www.epson-biz.com/modules/ref_escpos/index.php?content_id=145
#GS ( k pL pH cn fn m
#1D 28 6B 03 00 31 52 30
'x1D\x28\x6B\x03\x00\x31\x52\x30'
echo -en
echo
escribe cada una de las cadenas dadas en su salida estándar, con un espacio en blanco entre cada una y un caracter “salto de línea” después de la última cadena.
(información deman echo
)
La opción -e
activa la interpretación de los escapes de barra invertida (como \n
, \r
, etc.), y -n
evita que se envíe el caracter “salto de línea” al final.
lp -d
lp
imprime un archivo. Con la opción -d
se indica el destino, el cual es el nombre de la impresora.
Con echo -en <cadena> | lp -d <nombre_de_impresora>
se envía la cadena en cuestión a la impresora seleccionada. Para fines prácticos, aquí la impresora tiene el nombre thermal (térmica).
Algunas expresiones están explicadas a través de los comentarios.
# Ej.: imprimir la url https://www.oracle.com/index.html como QR; longitud = 33 + 3 (\x24), pL = 36(\x24), pH = 0
echo -en '\x1D\x28\x6B\x04\x00\x31\x41\x50\x00' | lp -d thermal
echo -en '\x1D\x28\x6B\x03\x00\x31\x43\x03' | lp -d thermal
echo -en '\x1D\x28\x6B\x03\x00\x31\x45\x30' | lp -d thermal
echo -en '\x1D\x28\x6B\x24\x00\x31\x50\x30https://www.oracle.com/index.html' | lp -d thermal
echo -en '\x1D\x28\x6B\x03\x00\x31\x51\x30' | lp -d thermal
echo -en '\x1D\x28\x6B\x03\x00\x31\x52\x30' | lp -d thermal
#Mismo ejemplo en una línea, con salto de tres líneas (ESC d 3) y corte parcial de hoja, con un punto sin cortar (ESC i)
(echo -en '\x1D\x28\x6B\x04\x00\x31\x41\x50\x00'; echo -en '\x1D\x28\x6B\x03\x00\x31\x43\x03'; echo -en '\x1D\x28\x6B\x03\x00\x31\x45\x30'; echo -en '\x1D\x28\x6B\x24\x00\x31\x50\x30https://www.oracle.com/index.html'; echo -en '\x1D\x28\x6B\x03\x00\x31\x51\x30'; echo -en '\x1B\x64\x03'; echo -en '\x1B\x69') | lp -d thermal
# ídem, con dobles comillas
(echo -en "\x1D\x28\x6B\x04\x00\x31\x41\x50\x00"; echo -en "\x1D\x28\x6B\x03\x00\x31\x43\x03"; echo -en "\x1D\x28\x6B\x03\x00\x31\x45\x30"; echo -en "\x1D\x28\x6B\x24\x00\x31\x50\x30https://www.oracle.com/index.html"; echo -en "\x1D\x28\x6B\x03\x00\x31\x51\x30"; echo -en "\x1B\x64\x03"; echo -en "\x1B\x69") | lp -d thermal
#Mismo ejemplo (con otra cadena) y con variables:
CADENA_QR=https://www.set.gov.py/portal/PARAGUAY-SET/detail?content-id=/repository/collaboration/sites/PARAGUAY-SET/documents/facturacion-electronica/Presentacion%20Lanzamiento%20del%20Plan%20Piloto%20del%20SIFEN.pdf
LONG_QR_ORIG=${#CADENA_QR} #el "#" delante de la variable obtiene la longitud de la cadena
LONG_QR=$(($LONG_QR_ORIG+3)) #doble paréntesis para operaciones aritméticas
PL=$(printf "%x" $(($LONG_QR % 256))) #printf "%x" convierte el valor a hexadecimal
PH=$(printf "%x" $(($LONG_QR / 256)))
# (declaración de variables en una línea)
CADENA_QR=https://www.set.gov.py/portal/PARAGUAY-SET/detail?content-id=/repository/collaboration/sites/PARAGUAY-SET/documents/facturacion-electronica/Presentacion%20Lanzamiento%20del%20Plan%20Piloto%20del%20SIFEN.pdf; LONG_QR_ORIG=${#CADENA_QR} ; LONG_QR=$(($LONG_QR_ORIG+3)) ; PL=$(printf "%x" $(($LONG_QR % 256))) ; PH=$(printf "%x" $(($LONG_QR / 256)))
# envío de comandos
(echo -en '\x1D\x28\x6B\x04\x00\x31\x41\x50\x00'; echo -en '\x1D\x28\x6B\x03\x00\x31\x43\x03'; echo -en '\x1D\x28\x6B\x03\x00\x31\x45\x30'; echo -en '\x1D\x28\x6B\x'$PL'\x'$PH'\x31\x50\x30'$CADENA_QR; echo -en '\x1D\x28\x6B\x03\x00\x31\x51\x30'; echo -en '\x1B\x64\x03'; echo -en '\x1B\x69') | lp -d thermal
# envío de comandos, con dobles comillas
(echo -en "\x1D\x28\x6B\x04\x00\x31\x41\x50\x00"; echo -en "\x1D\x28\x6B\x03\x00\x31\x43\x03"; echo -en "\x1D\x28\x6B\x03\x00\x31\x45\x30"; echo -en "\x1D\x28\x6B\x"$PL"\x"$PH"\x31\x50\x30"$CADENA_QR; echo -en "\x1D\x28\x6B\x03\x00\x31\x51\x30"; echo -en "\x1B\x64\x03"; echo -en "\x1B\x69") | lp -d thermal
A mediados de 2022, en el trabajo nos designaron la tarea de generar códigos QR directamente a través de los comandos ESC/POS de la impresora, en lugar de generarlos con alguna librería de un lenguaje de programación. Todo esto es debido a que el sistema de facturación electrónica en Paraguay (SIFEN) exige que en las facturas se imprima el código QR en el KuDE (la versión gráfica del documento electrónico).
Si encuentran errores o notan que faltan comentarios que aporten mayor información, no duden en avisarme :)
Agradecimientos especiales a J.V. y G.K. por la orientación inicial para la impresión desde la terminal de Linux.