ESC POS

Algoritmo imagen: Bit image column format ESC POS

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.

Descripción del comando

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 densidad: m

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.

n1 y n2: el ancho de la imagen

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

  • El número decimal más grande que se puede representar con un byte es 255. Se pueden representar 256 valores (incluyendo al cero)
  • En cambio, con dos bytes podemos representar 65536 valores, siendo el 65535 el número más grande.

Con esto podemos representar un número muy grande con 2 simples bytes. Para obtenerlos, se sigue lo siguiente:

  • Si queremos obtener 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 %
  • Para obtener 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.

Datos de la imagen: data

Ahora viene la parte más compleja: transformar una imagen en bytes que la impresora térmica entienda. Por ahora, recuerda lo siguiente:

  • Un byte contiene 8 bits. Cada bit puede tener un 1 o un 0
  • Un byte se puede representar como binario, decimal o hexadecimal. El decimal 255 sería 11111111 en binario y FF en hexadecimal
  • El MSB es el bit más significativo y cambia dependiendo del sistema, pero en la mayoría de casos el MSB es el primer bit de la izquierda. Esto es porque, de izquierda a derecha, las ocho posiciones representan a 128, 64, 32, 16, 8, 4, 2 y 1.
  • Se dice que el bit más significativo es el de 128 (el primero de izquierda a derecha) porque si por alguna razón cambia, tenemos una diferencia de 128. En cambio, el bit menos significativo es el último de izquierda a derecha, porque si por alguna razón cambia, tenemos solo una variación de 1.

Sabiendo lo anterior, para convertir la imagen en datos, debes:

  1. Definir cuántas líneas vas a crear. Si la densidad es 33, entonces debes enviar 3 bytes por columna, lo que se traduce en enviar 24 bits por columna. El alto de la imagen debe ser múltiplo de 24, ya que vamos a enviar la imagen en fragmentos de 24 pixeles de alto (sin importar el ancho).
  2. Recorrer la imagen pixel por pixel, pero de arriba hacia abajo. Es decir, primero sitúa tu cursor en la posición 0,0. Luego, avanza en Y hasta la cantidad de bits por columna. Cuando llegues a dicha cantidad, avanza en X y así sucesivamente hasta llegar al ancho.
  3. Al terminar de recorrer toda esa fila de 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 imagen
  4. En cada paso del recorrido, decide si el pixel es un 1 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 cero
  5. Acomoda cada pixel en un bit de un byte, avanzando el índice del bit. Dicho con otras palabras, los primeros 8 pixeles de la imagen estarán en un byte, comenzando por el MSB. Cuando acabes de usar ese byte vas a crear otro byte y comenzarás colocando el noveno pixel. Cuando tengas un byte completo, agrégalo a un arreglo de bytes que será una fila.
  6. Cada vez que termines de recorrer una fila (dada por la cantidad de bits por columna), agrega dicha fila a un arreglo de filas.
  7. En resumen, al final tendrás un arreglo de filas de bytes. Cada fila de bytes tendrá bytes por columna * ancho de la imagen, y el arreglo de filas tendrá alto de la imagen / bits por columna filas.

Si 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.

Ejemplo real

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.

Imagen para convertir a bit image ESC POS

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í:

  • n1 = 2 % 256 = 2
  • n2 = math.floor(2/256) = 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:

Imagen a bytes comando ESC POS bit image

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

Sobre la densidad

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.

Densidad de imagen – Bit image column format ESC POS

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.

Más herramientas

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.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Entradas recientes

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

3 días hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

3 días hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

3 días hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

3 días hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

3 días hace

Solución: Apache – Server unable to read htaccess file

Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…

3 días hace

Esta web usa cookies.