Imprimir acentos en impresora térmica con JavaScript

Por mucho tiempo he buscado la manera de imprimir texto en español en un ticket con una impresora térmica desde JavaScript, incluyendo también la letra ñ, el signo de apertura de interrogación, etcétera.

Recibo de compra con acentos y letras ñ usando JavaScript e impresora térmica
Recibo de compra con acentos y letras ñ usando JavaScript e impresora térmica

Esto es necesario porque en varias ocasiones necesitamos colocar algo como ¡Gracias por su compra! al final del ticket, y si no contamos con el símbolo ¡ entonces el mensaje puede no verse bien.

Lo mismo pasa cuando el nombre de un cliente tiene acentos y necesitamos imprimirlo en el ticket. Por ello es que en este post te mostraré cómo imprimir texto con acentos en una impresora térmica usando JavaScript.

Configurando entorno

Para poder comunicarnos con impresoras térmicas desde JS vamos a usar un plugin. Mira antes el tutorial de instalación y uso básico:

Comunicar JavaScript con impresora térmica usando plugin v3

Ahora veamos el código en donde supondré que ya estás ejecutando el plugin, has impreso el ticket de prueba (además de haber compartido tu impresora) e importado el conector de JavaScript.

Probar si la impresora soporta acentos sin configurar nada

Algunas impresoras soportan la impresión de texto en español, acentos y eñes sin configurar nada. Solo debes imprimir el texto normalmente. Veamos el siguiente ejemplo:

Comenzamos creando una instancia del conector, una vez que la tenemos invocamos a EscribirTexto así:

const imprimirAcentosConTextoNormal = async (nombreImpresora) => {
    const conector = new ConectorPluginV3(null, "licencia opcional aquí");
    conector.Iniciar();
    conector.EscribirTexto("¡Gracias por su compra, María José!\nFeliz año nuevo");
    conector.Feed(1);
    const respuesta = await conector
        .imprimirEn(nombreImpresora);
    if (respuesta === true) {
        alert("Impreso correctamente");
    } else {
        alert("Error: " + respuesta);
    }
}

En la impresora GOOJPRT PT-210 funciona sin configurar y la salida es igual a la que se ve a continuación:

Imprimir acentos en impresora térmica con JavaScript

Si en tu caso tu impresora no lo soporta vamos a ver una solución, ya que yo tengo una Xprinter X-58 y aparecen caracteres chinos o letras extrañas pero no aparece el texto en español.

Imprimiendo acentos

Ahora vamos a forzar a que tu impresora imprima texto con acentos. Si tu impresora es china deberías invocar al método DeshabilitarElModoDeCaracteresChinos y después de eso invocar a TextoSegunPaginaDeCodigos enviando el número de página, la codificación y el texto.

En mi caso he usado la página número 2 pero en lugar de cp860 (como debería ser) especifico cp850

Así puedo imprimir lo siguiente con todo y acentos, signos, etcétera:

cp850 con numero 2 ¿EL VELOZ MURCIÉLAGO
HINDÚ COMÍA FELIZ CARDILLO Y KIWI? ¡LA CIGÜEÑA TOCABA EL SAXOFÓN DETRÁS DEL
PALENQUE DE PAJA!.

cp850 con número 2 ¿el veloz murciélago hindú comía feliz
cardillo y kiwi? ¡la cigüeña tocaba el saxofón detrás del palenque de paja!.

El código queda como se ve a continuación:

const imprimirAcentosConPaginaDeCodigos = async (nombreImpresora) => {
    const conector = new ConectorPluginV3(null, "licencia opcional aquí");
    conector.Iniciar();
    conector.DeshabilitarElModoDeCaracteresChinos(); // Recuerda que tal vez no necesites invocar a este método si tu impresora no es china
    conector.TextoSegunPaginaDeCodigos(2, "cp850", "cp850 con numero 2 ¿EL VELOZ MURCIÉLAGO HINDÚ COMÍA FELIZ CARDILLO Y KIWI? ¡LA CIGÜEÑA TOCABA EL SAXOFÓN DETRÁS DEL PALENQUE DE PAJA!.");
    conector.Feed(1);
    conector.TextoSegunPaginaDeCodigos(2, "cp850", "cp850 con numero 2 ¿el veloz murciélago hindú comía feliz cardillo y kiwi? ¡la cigüeña tocaba el saxofón detrás del palenque de paja!.");
    conector.Feed(1);
    const respuesta = await conector
        .imprimirEn(nombreImpresora);
    if (respuesta === true) {
        alert("Impreso correctamente");
    } else {
        alert("Error: " + respuesta);
    }
}

El resultado del ejemplo es:

Texto con acentos y página de códigos

Ejemplo completo: ticket de venta

Recibo de compra con acentos y letras ñ usando JavaScript e impresora térmica
Recibo de compra con acentos y letras ñ usando JavaScript e impresora térmica

Para demostrar más las capacidades de este plugin voy a crear un pequeño ticket de venta. El código queda así:

const imprimirTicketConAcentos = async (nombreImpresora) => {
    const conector = new ConectorPluginV3(URLPlugin);
    conector.EstablecerTamañoFuente(1, 1);
    conector.EstablecerEnfatizado(false);
    conector.EstablecerAlineacion(ConectorPluginV3.ALINEACION_CENTRO);
    conector.DescargarImagenDeInternetEImprimir("https://ssb.wiki.gallery/images/f/f7/SSBU_spirit_Cuphead.png", ConectorPluginV3.TAMAÑO_IMAGEN_NORMAL, 160);
    conector.Feed(1);
    conector.EscribirTexto("Parzibyte's blog\n");
    conector.EscribirTexto("Blog de un programador\n");
    conector.DeshabilitarElModoDeCaracteresChinos();
    // Recuerda que si tu impresora soporta acentos sin configuración adicional solo debes invocar a EscribirTExto
    conector.TextoSegunPaginaDeCodigos(2, "cp850", "Teléfono: 123456789\n");
    conector.EscribirTexto("Fecha/Hora: 2021-02-08 16:57:55\n");
    conector.EstablecerEnfatizado(true);
    conector.EscribirTexto("Cliente: ");
    conector.EstablecerEnfatizado(false);
    conector.TextoSegunPaginaDeCodigos(2, "cp850", "María José\n");
    conector.EscribirTexto("--------------------------------\n");
    conector.EscribirTexto("Audífonos HyperX\n");
    conector.EstablecerAlineacion(ConectorPluginV3.ALINEACION_DERECHA);
    conector.EscribirTexto("25 USD\n");
    conector.EscribirTexto("--------------------------------\n");
    conector.EscribirTexto("TOTAL: 25 USD\n");
    conector.EscribirTexto("--------------------------------\n");
    conector.EstablecerAlineacion(ConectorPluginV3.ALINEACION_CENTRO);
    conector.TextoSegunPaginaDeCodigos(2, "cp850", "¡Muchas gracias por su compra y feliz año nuevo 2021!");
    conector.Feed(4);
    conector.Corte(1);
    conector.CorteParcial();
    const respuesta = await conector
        .imprimirEn(nombreImpresora);
    if (respuesta === true) {
        alert("Impreso correctamente");
    } else {
        alert("Error: " + respuesta);
    }
}

En este caso el nombre del cliente lleva acentos, el mensaje al final del ticket lleva la letra ñ así como el símbolo de apertura de exclamación.

Al final puedes diseñar tus tickets como te parezca, aquí solo te demuestro las capacidades del plugin.

Poniendo todo junto

El código completo del ejemplo que te mostré anteriormente queda así:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./bulma.min.css">
    <script src="./ConectorJavaScript.js" type="text/javascript"></script>
    <title>Páginas de códigos - By Parzibyte</title>
</head>

<body>
    <div class="container">
        <div class="columns">
            <div class="column">
                <h1 class="is-size-1">Acentos</h1>
            </div>
        </div>
        <div class="columns">
            <div class="column">
                <div class="select is-rounded">
                    <select id="listaDeImpresoras"></select>
                </div>
                <br>
                <button id="btnImprimir" class="button is-success mt-2">Imprimir normalmente</button>
                <button id="btnImprimirSegunPaginaDeCodigos" class="button is-info mt-2">Imprimir usando página de
                    códigos</button>
                <button id="btnImprimirTicket" class="button is-warning mt-2">Imprimir ticket con acentos</button>
            </div>
            <div class="column">
                <div class="notification is-warning">
                    <p>
                        Al imprimir, el resultado debería ser parecido al siguiente:
                    </p>
                </div>
                <img src="./Texto con acentos y página de códigos.jpg" alt="Ticket con acentos">
                <img src="./Imprimir-acentos-en-impresora-termica-con-JavaScript.jpg"
                    alt="Imprimir acentos en impresora térmica con JavaScript">
            </div>
        </div>
        <div class="columns has-text-centered">
            <div class="column">
                <p>
                    <a href="https://parzibyte.me/blog">Proudly brought to you by Parzibyte</a>
                </p>
            </div>
        </div>
    </div>
    <script>

        const obtenerListaDeImpresoras = async () => {
            return await ConectorPluginV3.obtenerImpresoras();
        }
        const URLPlugin = "http://localhost:8000"
        const $listaDeImpresoras = document.querySelector("#listaDeImpresoras"),
            $btnImprimir = document.querySelector("#btnImprimir"),
            $btnImprimirSegunPaginaDeCodigos = document.querySelector("#btnImprimirSegunPaginaDeCodigos"),
            $btnImprimirTicket = document.querySelector("#btnImprimirTicket");

        const init = async () => {
            const impresoras = await ConectorPluginV3.obtenerImpresoras(URLPlugin);
            for (const impresora of impresoras) {
                $listaDeImpresoras.appendChild(Object.assign(document.createElement("option"), {
                    value: impresora,
                    text: impresora,
                }));
            }
            $btnImprimir.addEventListener("click", () => {
                const nombreImpresora = $listaDeImpresoras.value;
                if (!nombreImpresora) {
                    return alert("Por favor seleccione una impresora. Si no hay ninguna, asegúrese de haberla compartido como se indica en: https://parzibyte.me/blog/2017/12/11/instalar-impresora-termica-generica/")
                }
                imprimirAcentosConTextoNormal(nombreImpresora);
            });

            $btnImprimirSegunPaginaDeCodigos.addEventListener("click", () => {
                const nombreImpresora = $listaDeImpresoras.value;
                if (!nombreImpresora) {
                    return alert("Por favor seleccione una impresora. Si no hay ninguna, asegúrese de haberla compartido como se indica en: https://parzibyte.me/blog/2017/12/11/instalar-impresora-termica-generica/")
                }
                imprimirAcentosConPaginaDeCodigos(nombreImpresora);
            });

            $btnImprimirTicket.addEventListener("click", () => {
                const nombreImpresora = $listaDeImpresoras.value;
                if (!nombreImpresora) {
                    return alert("Por favor seleccione una impresora. Si no hay ninguna, asegúrese de haberla compartido como se indica en: https://parzibyte.me/blog/2017/12/11/instalar-impresora-termica-generica/")
                }
                imprimirTicketConAcentos(nombreImpresora);
            });
        }

        const imprimirTicketConAcentos = async (nombreImpresora) => {
            const conector = new ConectorPluginV3(URLPlugin);
            conector.EstablecerTamañoFuente(1, 1);
            conector.EstablecerEnfatizado(false);
            conector.EstablecerAlineacion(ConectorPluginV3.ALINEACION_CENTRO);
            conector.DescargarImagenDeInternetEImprimir("https://ssb.wiki.gallery/images/f/f7/SSBU_spirit_Cuphead.png", ConectorPluginV3.TAMAÑO_IMAGEN_NORMAL, 160);
            conector.Feed(1);
            conector.EscribirTexto("Parzibyte's blog\n");
            conector.EscribirTexto("Blog de un programador\n");
            conector.DeshabilitarElModoDeCaracteresChinos();
            // Recuerda que si tu impresora soporta acentos sin configuración adicional solo debes invocar a EscribirTExto
            conector.TextoSegunPaginaDeCodigos(2, "cp850", "Teléfono: 123456789\n");
            conector.EscribirTexto("Fecha/Hora: 2021-02-08 16:57:55\n");
            conector.EstablecerEnfatizado(true);
            conector.EscribirTexto("Cliente: ");
            conector.EstablecerEnfatizado(false);
            conector.TextoSegunPaginaDeCodigos(2, "cp850", "María José\n");
            conector.EscribirTexto("--------------------------------\n");
            conector.EscribirTexto("Audífonos HyperX\n");
            conector.EstablecerAlineacion(ConectorPluginV3.ALINEACION_DERECHA);
            conector.EscribirTexto("25 USD\n");
            conector.EscribirTexto("--------------------------------\n");
            conector.EscribirTexto("TOTAL: 25 USD\n");
            conector.EscribirTexto("--------------------------------\n");
            conector.EstablecerAlineacion(ConectorPluginV3.ALINEACION_CENTRO);
            conector.TextoSegunPaginaDeCodigos(2, "cp850", "¡Muchas gracias por su compra y feliz año nuevo 2021!");
            conector.Feed(4);
            conector.Corte(1);
            conector.CorteParcial();
            const respuesta = await conector
                .imprimirEn(nombreImpresora);
            if (respuesta === true) {
                alert("Impreso correctamente");
            } else {
                alert("Error: " + respuesta);
            }
        }

        const imprimirAcentosConPaginaDeCodigos = async (nombreImpresora) => {
            const conector = new ConectorPluginV3(URLPlugin);
            conector.Iniciar();
            conector.DeshabilitarElModoDeCaracteresChinos(); // Recuerda que tal vez no necesites invocar a este método si tu impresora no es china
            conector.TextoSegunPaginaDeCodigos(2, "cp850", "cp850 con numero 2 ¿EL VELOZ MURCIÉLAGO HINDÚ COMÍA FELIZ CARDILLO Y KIWI? ¡LA CIGÜEÑA TOCABA EL SAXOFÓN DETRÁS DEL PALENQUE DE PAJA!.");
            conector.Feed(1);
            conector.TextoSegunPaginaDeCodigos(2, "cp850", "cp850 con numero 2 ¿el veloz murciélago hindú comía feliz cardillo y kiwi? ¡la cigüeña tocaba el saxofón detrás del palenque de paja!.");
            conector.Feed(1);
            const respuesta = await conector
                .imprimirEn(nombreImpresora);
            if (respuesta === true) {
                alert("Impreso correctamente");
            } else {
                alert("Error: " + respuesta);
            }
        }
        const imprimirAcentosConTextoNormal = async (nombreImpresora) => {
            const conector = new ConectorPluginV3(URLPlugin);
            conector.Iniciar();
            conector.EscribirTexto("¡Gracias por su compra, María José!\nFeliz año nuevo");
            conector.Feed(1);
            const respuesta = await conector
                .imprimirEn(nombreImpresora);
            if (respuesta === true) {
                alert("Impreso correctamente");
            } else {
                alert("Error: " + respuesta);
            }
        }
        init();
    </script>
</body>

</html>

Puedes ver el código completo y otros ejemplos en este repositorio de GitHub: https://github.com/parzibyte/ejemplos-javascript-plugin-v3

También puedes probar la demostración aquí: https://parzibyte.github.io/ejemplos-javascript-plugin-v3/acentos.html

Recuerda que para probarla el plugin debe estar ejecutándose en segundo plano en el equipo donde pruebes.

Sobre las páginas de códigos

Las páginas de códigos cambian dependiendo de la impresora. Al imprimir en la impresora no es necesario indicar la codificación, pero yo lo hago porque convierto los caracteres usando iconv.

Si no te funciona con una página de códigos deberías probar combinando el número y el nombre de la página o leyendo la documentación de tu impresora.

Por cierto, en este caso lo hicimos con JavaScript pero el plugin también funciona en Python, Java y cualquier lenguaje que hable HTTP. Los conectores están listados en: https://parzibyte.me/blog/2022/09/30/plugin-impresoras-termicas-version-3/

Recuerda que si necesitas ayuda puedes enviarme un mensaje en https://parzibyte.me/#contacto.

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.

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *