En este post te voy a explicar cómo funciona el comando ESC POS para imprimir una imagen usando el Bit Image column format.
No importa el lenguaje de programación, te voy a enseñar cómo enviar los datos a partir de los pixeles de una imagen, ya que yo buscaba un ejemplo simple y me parece que no lo encontré.
Voy a explicarte el algoritmo para imprimir una imagen en una impresora térmica y al final te mostraré un ejemplo con una imagen real.
El comando ESC POS del que vamos a hablar es:
ESC * Select bit image
Y su descripción dice que en ASCII es ESC * m n1 n2 Data
Entonces tenemos el comando ESC *
, eso es muy fácil. Lo complejo es obtener m
, n1
, n2
y Data
. Justamente de eso hablaremos en todo este artículo.
La m representa la densidad e indica cómo se van a ampliar los pixeles de la imagen. En este caso la colocaré en 33 pero soporta más valores que mencionaré al final.
Recuerda que los datos también dependen de la densidad, así que si cambias la densidad ajusta los datos como sea necesario, sobre todo los bytes por columna.
Hablemos sobre el parámetro n1
y n2
. Estos son simples bytes que enviamos indicando el ancho de la imagen. Básicamente es separar un número en 2 bytes. Aquí hay que recordar un poco algunas cosas
Con esto podemos representar un número muy grande con 2 simples bytes. Para obtenerlos, se sigue lo siguiente:
n1
sacamos el residuo de dividir el ancho de la imagen entre 256. Esto se puede hacer con la operación módulo, que en varios lenguajes se obtiene con el operador %n2
dividimos el ancho de la imagen entre 256 y redondeamos hacia el entero más próximo hacia abajo. Hablando en términos de lenguajes de programación, sería usar la función floor de math.Ahora viene la parte más compleja: transformar una imagen en bytes que la impresora térmica entienda. Por ahora, recuerda lo siguiente:
Sabiendo lo anterior, para convertir la imagen en datos, debes:
24 * ancho de la imagen
, si todavía faltan más pixeles, vuelve a recorrer pero ahora el valor de Y será 24
, el de X será 0 de nuevo. Vas a recorrer desde 0,24
hasta 0,47
, y cuando termines esa fila, vas a recorrer desde 1,24
hasta 1,47
, repitiendo el mismo proceso hasta terminar de recorrer toda la imagen1
o un 0
. Haz las comparaciones necesarias o convierte la imagen a blanco y negro antes de procesarla, pero es importante que decidas si será un uno o un ceroSi tú no quieres obligar a que el alto de la imagen sea de 24 puedes crear y rellenar las filas que alojarán los bytes al siguiente múltiplo de 24 a partir del ancho de la imagen.
Una vez que tengas las filas, recorre ese arreglo fila por fila. Luego, envía los comandos así:
ESC * densidad n1 n2 bytes de la fila...
Debes enviar esos comandos por cada fila.
Ahora que te he explicado todos los detalles, veamos cómo convertir una imagen. Te repito que la densidad es de 33, así que se enviarán 3 bytes por columna y será necesario que el alto de la imagen sea múltiplo de 24.
Para este simple ejemplo he preparado una imagen de 24 pixeles de alto por 2 pixeles de ancho. La imagen más pequeña que podríamos enviar sería una de 24×1 (sin rellenar los bytes). Puedes ver la original a continuación: https://parzibyte.me/blog/wp-content/uploads/2024/01/min.png
La he ampliado y colocado en una rejilla con fondo transparente para que puedas apreciar el color de cada pixel así como la cantidad de pixeles que tiene.
Si te fijas, he coloreado cada byte de distinto color; obviamente esto no es obligatorio y en una imagen real eso cambiará. Ya vimos la imagen, ahora vamos a sacar los datos. Recuerda, el comando es:
ESC * m n1 n2 Data
En este caso la densidad es 33
. Para el caso de n1
y n2
, como el ancho es 2 los cálculos quedan así:
2
0
Luego vamos con los datos. Solo vamos a usar una fila, ya que el alto de la imagen es de 24. Si fuera de 48 serían 2 filas y así sucesivamente (recuerda que el 24 viene de multiplicar los bytes por columna que serán 3 al usar la densidad de 33).
Para el caso de los primeros 8 bits, será 11111111
, es decir, 255
o 0xFF
. Los segundos 8 bits serán 00000000
, 0
o 0x00
y los terceros bits serán 0xFF
.
Ahora vamos con la segunda columna de la imagen, empezamos con 0x00
, luego 0xFF
y finalmente 0x00
. Entonces la imagen que tenemos arriba, se puede representar así:
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00
Mira la misma imagen pero con su correspondencia de bytes:
Nota importante: en este caso, debido a la imagen de ejemplo, todos los bytes serán 255
o 0
, pero en una imagen real pueden ser otros valores. Por ejemplo, si el primer pixel del byte 1 fuera blanco, ahora su representación sería 01111111
, o sea, 127
o 0x7F
.
Y el comando en hexadecimal va quedando así; primero el ESC *
0x1B,0x2A
Luego la densidad que en decimal es 33
pero en hexadecimal es 0x21
Ahora viene n1 y n2 que son 2 y 0 respectivamente:
0x02, 0x00
Nuestro comando está así hasta el momento:
0x1B, 0x2A, 0x21, 0x02, 0x00
Agregamos la data de la imagen y queda así:
0x1B, 0x2A, 0x21, 0x02, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00
Al enviar esos datos, habremos impreso una imagen de 24 por 2 pixeles en una impresora térmica usando comandos ESC POS.
Si, por ejemplo, la imagen midiera 48×2 y tuviera los mismos pixeles, el comando enviado sería 2 veces el mismo:
0x1B, 0x2A, 0x21, 0x02, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00
Que, en otras palabras, sería:
0x1B, 0x2A, 0x21, 0x02, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x000, x1B, 0x2A, 0x21, 0x02, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00
Cuando la densidad es 0, 1, 2, 3, 4 o 6, los bytes por columna son 1. Cuando es 32, 33, 38, 39 o 40 los bytes por columna son 3. Finalmente, cuando es 71, 72 o 73 los bytes por columna son 6.
En la imagen anterior puedes apreciar la diferencia entre densidades. Si no ves un número de densidad, es porque en mi caso solo aparecían caracteres extraños. Desconozco si es debido al modelo de mi impresora o a algún problema en el algoritmo.
Como puedes ver, la mejor densidad es 3 y 33.
Lo que he expuesto en el post ya está integrado en mi plugin para impresoras térmicas. La impresión de imágenes es totalmente soportada en el plugin y también en el diseñador.
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…
Esta web usa cookies.