Plugin ESC POS v3

Imprimir tabla en impresora térmica

Las impresoras térmicas permiten la impresión de texto y la alineación del mismo, pero ¿qué pasa cuando queremos imprimir una tabla que sea alineada correctamente en caso de que el texto sobrepase el ancho? para ello debemos implementar un algoritmo propio.

Tabla impresa en impresora térmica

Por ello es que en este post te voy a enseñar a imprimir datos tabulados o básicamente imprimir una tabla bien alineada y con separadores en una impresora térmica, usando únicamente texto.

Verás que podremos imprimir las celdas y columnas de la tabla respetando el máximo ancho del ticket, ya sea dibujando los separadores o solo ordenando los datos.

Demostración

Sugiero leer el post completo para ver lo que está pasando, pero si quieres probarlo justo ahora entonces descarga y ejecuta el servidor local de la API ESC POSinstala y comparte tu impresora. Por favor, sigue los pasos que aparecen en la página previamente enlazada, ya que ahí está la API unificada.

Para finalmente ir al siguiente ejemplo, elegir tu impresora e imprimir una tabla formateada: probar en el área de pruebas.

Datos de ejemplo

Por esta ocasión voy a imprimir una lista de productos con distintos valores y longitud para demostrar cómo se puede imprimir una tabla en una impresora térmica. Lo voy a hacer con JavaScript pero se puede hacer con cualquier lenguaje de programación.

// Simple lista de ejemplo. Obviamente tú puedes traerla de cualquier otro lado,
// definir otras propiedades, etcétera
const listaDeProductos = [
  {
    nombre: "Impresora térmica 58mm",
    cantidad: 10,
    precio: 600,
  },
  {
    nombre: "The Legend of Zelda: Tears of the kingdom",
    cantidad: 1,
    precio: 1600,
  },
  {
    nombre: "Resident Evil 4: remake",
    cantidad: 1,
    precio: 1200,
  },
];

Crear tabla usando solo texto

Ahora necesitamos un algoritmo que pueda tabular datos agregando las líneas en blanco que sean necesarias según la cantidad máxima de filas, coloque un separador de columnas, rellene las celdas cuando sea necesario y separe el texto en una nueva línea cuando sobrepase el ancho máximo.

Todo eso ya lo hice en 3 funciones que puedes ver con detalle en el siguiente enlace, te recomiendo leerlas para que sepas lo que estamos haciendo:

Entonces voy a importar esas 3 funciones:

const separarCadenaEnArregloSiSuperaLongitud = (cadena, maximaLongitud) => {
  const resultado = [];
  let indice = 0;
  while (indice < cadena.length) {
    const pedazo = cadena.substring(indice, indice + maximaLongitud);
    indice += maximaLongitud;
    resultado.push(pedazo);
  }
  return resultado;
}
const dividirCadenasYEncontrarMayorConteoDeBloques = (contenidosConMaximaLongitud) => {
  let mayorConteoDeCadenasSeparadas = 0;
  const cadenasSeparadas = [];
  for (const contenido of contenidosConMaximaLongitud) {
    const separadas = separarCadenaEnArregloSiSuperaLongitud(contenido.contenido, contenido.maximaLongitud);
    cadenasSeparadas.push({ separadas, maximaLongitud: contenido.maximaLongitud });
    if (separadas.length > mayorConteoDeCadenasSeparadas) {
      mayorConteoDeCadenasSeparadas = separadas.length;
    }
  }
  return [cadenasSeparadas, mayorConteoDeCadenasSeparadas];
}
const tabularDatos = (cadenas, relleno, separadorColumnas) => {
  const [arreglosDeContenidosConMaximaLongitudSeparadas, mayorConteoDeBloques] = dividirCadenasYEncontrarMayorConteoDeBloques(cadenas)
  let indice = 0;
  const lineas = [];
  while (indice < mayorConteoDeBloques) {
    let linea = "";
    for (const contenidos of arreglosDeContenidosConMaximaLongitudSeparadas) {
      let cadena = "";
      if (indice < contenidos.separadas.length) {
        cadena = contenidos.separadas[indice];
      }
      if (cadena.length < contenidos.maximaLongitud) {
        cadena = cadena + relleno.repeat(contenidos.maximaLongitud - cadena.length);
      }
      linea += cadena + separadorColumnas;
    }
    lineas.push(linea);
    indice++;
  }
  return lineas;
}

Diseñar tabla para imprimir

Ahora que tenemos los datos de ejemplo y las funciones para crear una tabla de solo texto en JavaScript vamos a proceder a crear la tabla como una cadena para enviarla a una impresora térmica y así imprimir una tabla.

Vamos a necesitar una línea que separe cada fila. Yo la he diseñado con la siguiente función:

const obtenerLineaSeparadora = () => {
  const lineasSeparador = tabularDatos(
    [
      { contenido: "-", maximaLongitud: maximaLongitudNombre },
      { contenido: "-", maximaLongitud: maximaLongitudCantidad },
      { contenido: "-", maximaLongitud: maximaLongitudPrecio },
    ],
    "-",
    "+",
  );
  let separadorDeLineas = "";
  if (lineasSeparador.length > 0) {
    separadorDeLineas = lineasSeparador[0]
  }
  return separadorDeLineas;
}

Eso me va a devolver algo como: -------------------+-----+-----+

Puede que ahora no tenga mucho sentido pero ya verás cómo se usa a continuación. Lo que sigue es crear el encabezado (vendría siendo el equivalente al thead en HTML) así:

// Comenzar a diseñar la tabla
let tabla = obtenerLineaSeparadora() + "\n";


const lineasEncabezado = tabularDatos([
  { contenido: "Nombre", maximaLongitud: maximaLongitudNombre },
  { contenido: "Cantidad", maximaLongitud: maximaLongitudCantidad },
  { contenido: "Precio", maximaLongitud: maximaLongitudPrecio },
],
  relleno,
  separadorColumnas,
);

for (const linea of lineasEncabezado) {
  tabla += linea + "\n";
}

Es importante que recuerdes que la función tabularDatos nos va a devolver los datos tabulados en varias líneas (específicamente hablando, devolverá un arreglo de tipo string).

Es responsabilidad del invocador recorrerlas y agregar el salto de línea. En la línea 2 comenzamos diseñando la tabla con un separador, y siempre agregamos un salto de línea al final.

Luego en la línea 14 recorremos las líneas del encabezado y las concatenamos a la tabla. Por ahora nuestra tabla se ve así:

-------------------+-----+-----+
Nombre             |Canti|Preci|
                   |dad  |o    |

Finalmente recorremos el arreglo de productos, tabulamos los datos con los valores y concatenamos en la tabla:

tabla += obtenerLineaSeparadora() + "\n";
for (const producto of listaDeProductos) {
  const lineas = tabularDatos(
    [
      { contenido: producto.nombre, maximaLongitud: maximaLongitudNombre },
      { contenido: producto.cantidad.toString(), maximaLongitud: maximaLongitudCantidad },
      { contenido: producto.precio.toString(), maximaLongitud: maximaLongitudPrecio },
    ],
    relleno,
    separadorColumnas
  );
  for (const linea of lineas) {
    tabla += linea + "\n";
  }
  tabla += obtenerLineaSeparadora() + "\n";
}

Ahora ya tenemos la tabla en una simple string y se ve así:

-------------------+-----+-----+
Nombre             |Canti|Preci|
                   |dad  |o    |
-------------------+-----+-----+
Impresora térmica 5|10   |600  |
8mm                |     |     |
-------------------+-----+-----+
The Legend of Zelda|1    |1600 |
: Tears of the king|     |     |
dom                |     |     |
-------------------+-----+-----+
Resident Evil 4: re|1    |1200 |
make               |     |     |
-------------------+-----+-----+

Ya podemos conectarnos con la impresora térmica y enviarle ese texto. El ticket va a respetar los espacios y saltos de línea, así que se va a imprimir tal y como está.

Nota: obviamente puedes cambiar el separador, el relleno y el ancho máximo de cada columna. También puedes tener columnas infinitas.

Imprimiendo tabla con impresora térmica

Lo que sigue es imprimir una tabla en una POS printer o thermal printer. Yo usaré mi plugin gratuito presentado en:

Como ya tenemos el texto formateado como tabla, enviaremos la lista de operaciones indicando que queremos hacer la operación para escribir texto pasándole lo que nos devolvieron las otras funciones:

const cargaUtil = {
  "serial": "",
  "nombreImpresora": "",
  "operaciones": [
    {
      "nombre": "Iniciar",
      "argumentos": []
    },
    {
      "nombre": "EscribirTexto",
      "argumentos": [
        "-------------------+-----+-----+\nNombre             |Canti|Preci|\n                   |dad  |o    |\n-------------------+-----+-----+\nImpresora térmica 5|10   |600  |\n8mm                |     |     |\n-------------------+-----+-----+\nThe Legend of Zelda|1    |1600 |\n: Tears of the king|     |     |\ndom                |     |     |\n-------------------+-----+-----+\nResident Evil 4: re|1    |1200 |\nmake               |     |     |\n-------------------+-----+-----+"
      ]
    }
  ]
};
const respuestaHttp = await fetch("http://localhost:8000/imprimir", {
    method: "POST",
    body: JSON.stringify(cargaUtil)
});
const respuesta = await respuestaHttp.json();
if (respuesta.ok) {
    console.log("Impreso correctamente")
} else {
    console.error("Petición ok pero error en el plugin: " + respuesta.message);
}

Así que básicamente es hacer 2 cosas: crear la tabla en formato de texto y luego enviar ese texto a la impresora térmica, ya que la impresora no cuenta con un comando ESC POS para imprimir una tabla. Otra alternativa sería imprimir una tabla HTML.

Y con eso obtenemos el siguiente resultado:

Tabla impresa en impresora térmica

Obviamente puedes imprimir más cosas además de la tabla.

Poniendo todo junto

Puedes ver el código completo viendo el código fuente generado en el área de pruebas.

También tengo un vídeo de YouTube por si quieres revisarlo:

A continuación te enseño algunos ejemplos de cómo he usado este algoritmo para imprimir tickets en mi sistema para restaurantes. Primero vemos un reporte:

Imprimir corte de caja en software gratis para restaurante

También sirve para un ticket con los platillos solicitados:

Ticket con detalle de pedido impreso con impresora térmica usando programa para administrar un restaurante

Y por aquí tengo una versión preliminar de cuando apenas estaba diseñando ese sistema:

Datos formateados como tabla en ticket en impresora térmica

Puedes hacer esto con cualquier lenguaje de programación, solo es cuestión de traducir el código a otro lenguaje, ya que el plugin funciona sin importar cuál de ellos utilices.

Por aquí te dejo más tutoriales con JavaScript y también más entradas sobre mi plugin para impresoras térmicas.

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

Servidor HTTP en Android con Flutter

El día de hoy te mostraré cómo crear un servidor HTTP (servidor web) en Android…

4 días hace

Imprimir automáticamente todos los PDF de una carpeta

En este post te voy a enseñar a designar una carpeta para imprimir todos los…

5 días hace

Guía para imprimir en plugin versión 1 desde Android

En este artículo te voy a enseñar la guía para imprimir en una impresora térmica…

1 semana hace

Añadir tasa de cambio en sistema de información

Hoy te voy a mostrar un ejemplo de programación para agregar un módulo de tasa…

2 semanas hace

Comprobar validez de licencia de plugin ESC POS

Los usuarios del plugin para impresoras térmicas pueden contratar licencias, y en ocasiones me han…

2 semanas hace

Imprimir euro € en impresora térmica

Hoy voy a enseñarte cómo imprimir el € en una impresora térmica. Vamos a ver…

4 semanas hace

Esta web usa cookies.