En este post voy a presentarte una herramienta para poder imprimir imágenes grandes en una impresora térmica ESC POS dividiendo las imágenes en fragmentos pequeños que no superen el ancho del papel térmico.

Captura de pantalla de aplicación web. Se muestra una imagen grande dividida en fragmentos con opciones para configurar el ancho y el alto de división, así como con botones para imprimir o descargar todos o cada fragmento individual

Una vez impresos ya puedes unirlos como tú prefieras. De este modo podrás imprimir imágenes de cualquier tamaño separadas en fragmentos que quepan correctamente en el papel térmico.

Imagen impresa en impresora térmica. Se muestra la imagen impresa en resolución original impresa en distintos papeles y unida

Otras descripciones que puede tener esta herramienta:

  • Imprimir imagen completa en impresora térmica separándola en fragmentos
  • Cortar imágenes para imprimirla en impresora térmica
  • Cortar imagen en pedazos con JavaScript

Convertir File a imagen

Cuando el usuario elige un archivo usando el elemento <input type="file"> tenemos los archivos en $elemento.files que es un array de tipo File.

No necesitamos un File, necesitamos un ImageBitmap así que convertimos el File a ImageBitmap con createImageBitmap usando el primer archivo seleccionado ($imagen.files[0]):

$imagen.addEventListener("change", async () => {
  const imagen = await createImageBitmap($imagen.files[0]);
  $alto.value = imagen.height;
  generarCanvasPrevisualizaciones();
})

Dividir imagen en fragmentos

Y después se generan varios elementos de tipo canvas que contendrán un fragmento de la imagen completa. Estos fragmentos son importantes porque más adelante podremos descargarlos e imprimirlos ya sea en conjunto o individualmente.

Necesitamos hacer un ciclo para dividir la imagen en varios fragmentos, y en cada paso es necesario calcular las coordenadas x e y de inicio y fin, pues necesitamos un pedazo de la imagen para imprimirla más adelante en una impresora térmica.

    for (let yInicio = 0; yInicio < imagen.height; yInicio += altoMaximoEstablecidoPorUsuario) {
      let ancho = anchoMaximoEstablecidoPorUsuario;
      let alto = altoMaximoEstablecidoPorUsuario;
      if (xInicio + anchoMaximoEstablecidoPorUsuario > imagen.width) {
        ancho = imagen.width - xInicio;
      }
      if (yInicio + altoMaximoEstablecidoPorUsuario > imagen.height) {
        alto = imagen.height - yInicio;
      }
      const xFin = xInicio + ancho;
      const yFin = yInicio + alto;

Una vez que tenemos las coordenadas entonces dibujamos un fragmento de la imagen en un canvas recién creado con document.createElement:

const $canvasFragmento = document.createElement("canvas");
$canvasFragmento.width = ancho;
$canvasFragmento.height = alto;
const contextoCanvasRecienCreado = $canvasFragmento.getContext("2d");
contextoCanvasRecienCreado.drawImage(imagen, xInicio, yInicio, ancho, alto, 0, 0, ancho, alto);

Así es como logramos dividir la imagen completa en fragmentos pequeños. Además de dibujar el pedazo de la imagen también añadimos unos enlaces para descargar e imprimr cada uno de ellos.

Imprimir fragmentos de imagen en impresora térmica

El plugin de impresión permite imprimir imágenes en base64 así que simplemente mapeamos cada canvas a base64 y lo ajustamos para que respete la API de impresión ESC POS:

const canvasComoOperaciones = coleccionDeCanvas.map($canvas => {
    return {
    nombre: "ImprimirImagenEnBase64",
    argumentos: [
        $canvas.toDataURL(),
        $canvas.width,
        0,
        true
    ]
    };
})

Veamos la función que imprime un canvas de JavaScript en una impresora térmica.

Dicha función se llama imprimirColeccionDeCanvas y se comunica con mi plugin para impresoras térmicas para imprimir una colección de imágenes.

Tenemos una colección de elementos del DOM de tipo canvas. Podemos convertir dicho canvas a una imagen en base64 usando toDataURL.

He hecho la función de esta manera para que sirva para imprimir una o varias imágenes en el mismo código, y queda así:

const imprimirColeccionDeCanvas = (coleccionDeCanvas) => {
  const nombreImpresora = $impresoras.value;
  return new Promise(async (resolve, reject) => {
    const operaciones = [
      {
        "nombre": "Iniciar",
        "argumentos": []
      },
    ];
    const canvasComoOperaciones = coleccionDeCanvas.map($canvas => {
      return {
        nombre: "ImprimirImagenEnBase64",
        argumentos: [
          $canvas.toDataURL(),
          $canvas.width,
          0,
          true
        ]
      };
    })
    operaciones.push(...canvasComoOperaciones);
    operaciones.push(
      // Un Feed por si no tienen cortador
      {
        "nombre": "Feed",
        "argumentos": [1],
      },
      {
        "nombre": "Corte",
        "argumentos": [
          1
        ]
      }
    )
    const cargaUtil = {
      "serial": "",
      nombreImpresora,
      operaciones,
    };
    try {
      registrarMensaje("Imprimiendo ...");
      const respuestaHttp = await fetch("http://localhost:8000/imprimir",
        {
          method: "POST",
          body: JSON.stringify(cargaUtil),
        });

      const respuestaComoJson = await respuestaHttp.json();
      if (respuestaComoJson.ok) {
        registrarMensaje("Impreso correctamente");
        resolve();
      } else {
        // El error está en la propiedad message
        reject(respuestaComoJson)
      }
    } catch (e) {
      reject(e)
    }
  })
}

Después de eso invoco a la función imprimirColeccionDeCanvas cuando se quieren imprimir todas las imágenes:

const todosLosCanvas = document.querySelectorAll("canvas");
$imprimir.textContent = "Imprimiendo...";
await imprimirColeccionDeCanvas([...todosLosCanvas]);

O cuando solo se quiere imprimir una:

$pImprimir.addEventListener("click", async () => {
await imprimirColeccionDeCanvas([$canvasFragmento]);
})

De esta manera:

  1. Tenemos una imagen en resolución grande que no cabe en una impresora térmica
  2. Dividimos la imagen en fragmentos delgados que no superan el ancho del papel térmico
  3. Imprimimos cada imagen en una impresora térmica usando Dithering y ESC POS

Por cierto, esta herramienta también te permite dividir las imágenes y guardarlas para cualquier otra cosa. No es obligatorio imprimirlas en una impresora térmica, puedes usar la app como cortadora de imágenes y descargar todos los fragmentos en un zip.

Usar herramienta

Si quieres imprimir una imagen en tamaño completo dividida en pedazos en una impresora térmica necesitas:

  1. Instalar tu impresora como genérica y compartirla
  2. Descargar y ejecutar el plugin 3.5.2: http://parzibyte.me/static/ESC_POS_3.5.2_W64.zip
  3. Acceder a la siguiente web app en línea y dar los permisos necesarios: https://parzibyte.me/apps/cortador-imagenes-esc-pos/

Código fuente

El código fuente completo está en GitHub: https://github.com/parzibyte/cortador-imagenes-esc-pos

Necesitas Node v24.5.0. Una vez que hayas descargado el repositorio ejecuta:

  1. npm install
  2. npm run dev
  3. Cuando estés listo para distribuir ejecuta npm run build y distribuye la carpeta dist
Si el post ha sido de tu agrado te invito a que me sigas para saber cuando haya escrito un nuevo post, haya actualizado algún sistema o publicado un nuevo software. Facebook | X | Instagram | Telegram | También estoy a tus órdenes para cualquier contratación en mi página de contacto