Ticket impreso con Python en impresora térmica usando Plugin v3

Python Thermal Printing: A Comprehensive Guide for Printing on Thermal Printers

In this tutorial, we’ll explore how to effortlessly print receipts, invoices, and tickets on a thermal printer using Python. I’ll introduce you to a powerful plugin that I’ve developed, enabling seamless integration for Python-based applications.

With this plugin, you’ll gain the ability to effortlessly print tickets from Python, regardless of your preferred framework—whether it’s the terminal, Flask, Tkinter, Django, or any other Python-supported platform.

It provides extensive functionality, allowing you to print images, barcodes, text with accents, change fonts, rotate text, and much more, sending the ESC POS commands native to thermal printers.

Join me as we dive into the world of thermal printing using Python, empowering you to generate professional-quality prints effortlessly.

Setup environment

To make this work, you will need the plugin running in the background and your printer shared as explained in:

Print ticket in thermal printer directly from browser

I encourage you to read it first and print the “Hello ESC POS printer” receipt even if it is in another programming language.

Python ESC POS connector

To print on a thermal printer from Python, we need a connector that acts as a link between Python and the plugin. I have programmed it myself, and it looks like this:

import requests

URL_PLUGIN_POR_DEFECTO = "http://localhost:8000"
TAMAÑO_IMAGEN_NORMAL = 0
TAMAÑO_IMAGEN_DOBLE_ANCHO = 1
TAMAÑO_IMAGEN_DOBLE_ALTO = 2
TAMAÑO_IMAGEN_DOBLE_ANCHO_Y_ALTO = 3
ALINEACION_IZQUIERDA = 0
ALINEACION_CENTRO = 1
ALINEACION_DERECHA = 2
RECUPERACION_QR_BAJA = 0
RECUPERACION_QR_MEDIA = 1
RECUPERACION_QR_ALTA = 2
RECUPERACION_QR_MEJOR = 3


class ConectorV3:

    def __init__(self, ruta=URL_PLUGIN_POR_DEFECTO, serial=""):
        self.operaciones = []
        self.ruta = ruta
        self.serial = serial

    def agregar_operacion(self, nombre, argumentos):
        self.operaciones.append({
            "nombre": nombre,
            "argumentos": argumentos,
        })

    def obtenerImpresoras(ruta=URL_PLUGIN_POR_DEFECTO):
        respuesta = requests.get(ruta+"/impresoras")
        return respuesta.json()

    def CargarImagenLocalEImprimir(self, ruta: str, tamaño: float, maximoAncho: float):
        return self.agregar_operacion("CargarImagenLocalEImprimir", [ruta, tamaño, maximoAncho])

    def Corte(self, lineas):
        return self.agregar_operacion("Corte", [lineas])

    def CorteParcial(self):
        return self.agregar_operacion("CorteParcial", [])

    def DefinirCaracterPersonalizado(self, caracterRemplazoComoCadena: str, matrizComoCadena: str):
        return self.agregar_operacion("DefinirCaracterPersonalizado", [caracterRemplazoComoCadena, matrizComoCadena])

    def DescargarImagenDeInternetEImprimir(self, urlImagen: str, tamaño: float, maximoAncho: float):
        return self.agregar_operacion("DescargarImagenDeInternetEImprimir", [urlImagen, tamaño, maximoAncho])

    def DeshabilitarCaracteresPersonalizados(self, ):
        return self.agregar_operacion("DeshabilitarCaracteresPersonalizados", [])

    def DeshabilitarElModoDeCaracteresChinos(self, ):
        return self.agregar_operacion("DeshabilitarElModoDeCaracteresChinos", [])

    def EscribirTexto(self, texto: str):
        return self.agregar_operacion("EscribirTexto", [texto])

    def EstablecerAlineacion(self, alineacion: float):
        return self.agregar_operacion("EstablecerAlineacion", [alineacion])

    def EstablecerEnfatizado(self, enfatizado: bool):
        return self.agregar_operacion("EstablecerEnfatizado", [enfatizado])

    def EstablecerFuente(self, fuente: float):
        return self.agregar_operacion("EstablecerFuente", [fuente])

    def EstablecerImpresionAlReves(self, alReves: bool):
        return self.agregar_operacion("EstablecerImpresionAlReves", [alReves])

    def EstablecerImpresionBlancoYNegroInversa(self, invertir: bool):
        return self.agregar_operacion("EstablecerImpresionBlancoYNegroInversa", [invertir])

    def EstablecerRotacionDe90Grados(self, rotar: bool):
        return self.agregar_operacion("EstablecerRotacionDe90Grados", [rotar])

    def EstablecerSubrayado(self, subrayado: bool):
        return self.agregar_operacion("EstablecerSubrayado", [subrayado])

    def EstablecerTamañoFuente(self, multiplicadorAncho: float, multiplicadorAlto: float):
        return self.agregar_operacion("EstablecerTamañoFuente", [multiplicadorAncho, multiplicadorAlto])

    def Feed(self, lineas):
        return self.agregar_operacion("Feed", [lineas])

    def HabilitarCaracteresPersonalizados(self):
        return self.agregar_operacion("HabilitarCaracteresPersonalizados", [])

    def HabilitarElModoDeCaracteresChinos(self):
        return self.agregar_operacion("HabilitarElModoDeCaracteresChinos", [])

    def ImprimirCodigoDeBarrasCodabar(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasCodabar", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasCode128(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasCode128", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasCode39(self, contenido: str, incluirSumaDeVerificacion: bool, modoAsciiCompleto: bool, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasCode39", [contenido, incluirSumaDeVerificacion, modoAsciiCompleto, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasCode93(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasCode93", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasEan(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasEan", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasEan8(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasEan8", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasPdf417(self, contenido: str, nivelSeguridad: float, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasPdf417", [contenido, nivelSeguridad, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasTwoOfFiveITF(self, contenido: str, intercalado: bool, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasTwoOfFiveITF", [contenido, intercalado, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasUpcA(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasUpcA", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoDeBarrasUpcE(self, contenido: str, alto: float, ancho: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoDeBarrasUpcE", [contenido, alto, ancho, tamañoImagen])

    def ImprimirCodigoQr(self, contenido: str, anchoMaximo: float, nivelRecuperacion: float, tamañoImagen: float):
        return self.agregar_operacion("ImprimirCodigoQr", [contenido, anchoMaximo, nivelRecuperacion, tamañoImagen])

    def ImprimirImagenEnBase64(self, imagenCodificadaEnBase64: str, tamaño: float, maximoAncho: float):
        return self.agregar_operacion("ImprimirImagenEnBase64", [imagenCodificadaEnBase64, tamaño, maximoAncho])

    def Iniciar(self, ):
        return self.agregar_operacion("Iniciar", [])

    def Pulso(self, pin: float, tiempoEncendido: float, tiempoApagado: float):
        return self.agregar_operacion("Pulso", [pin, tiempoEncendido, tiempoApagado])

    def TextoSegunPaginaDeCodigos(self, numeroPagina: float, pagina: str, texto: str):
        return self.agregar_operacion("TextoSegunPaginaDeCodigos", [numeroPagina, pagina, texto])

    def imprimirEn(self, nombreImpresora):
        payload = {
            "operaciones": self.operaciones,
            "nombreImpresora": nombreImpresora,
            "serial": self.serial,
        }
        respuesta = requests.post(self.ruta+"/imprimir", json=payload)
        return respuesta.json()

Note: You will need the requests package, which you can easily install with pip install requests.

What I showed you earlier is the connector. Your Python code uses the connector, and the connector communicates with the plugin to print on thermal printers. That’s it.

Hello Thermal printer from Python

So, in our file where we have our Python code, we are going to import the connector like this:

import ConectorPython

The connector should be in a file called ConectorPython.py. However, if you prefer not to import it, you can also copy and paste the entire code into your project. Just be careful not to get confused.

Now, you can obtain the list of printers like this:

impresoras = ConectorPython.ConectorV3.obtenerImpresoras()
print("Las impresoras son:")
print(impresoras)

That will return the list of printers. It is a list of strings and will be useful if you want to give the user the opportunity to choose their printer or perform similar tasks.

Now, let’s create an instance of ConectorV3 and print a “Hello, World” message:

nombreImpresora = "ZJ-58"; # Puede venir de la lista o puedes escribirlo si sabes el nombre
conector = ConectorPython.ConectorV3()
conector.Iniciar()
conector.EscribirTexto("Hola mundo")
conector.Feed(1)
respuesta = conector.imprimirEn(nombreImpresora)
if respuesta == True:
    print("Impreso correctamente")
else:
    print("Error: " + respuesta)

Please note that your printer’s name must be specified in nombreImpresora.

Note: If the plugin is listening on a different port, remember that you can specify the URL when constructing the ConectorV3 object or when invoking obtenerImpresoras.

Python Example: Printing a Ticket on a Thermal Printer using ESC POS

Discover a complete example of printing a ticket on a thermal printer using Python and ESC POS.

In this sample code, the printer name is provided directly, assuming you have prior knowledge of the desired printer. However, you can modify the code to allow users to choose from a printer list for more flexibility.

import ConectorPython

impresoras = ConectorPython.ConectorV3.obtenerImpresoras()
print("Las impresoras son:")
print(impresoras)

nombreImpresora = "PT210"  # Nota: esta impresora debe existir y estar compartida como se indica en https://parzibyte.me/blog/2017/12/11/instalar-impresora-termica-generica/
# Aquí va tu serial por si tienes uno:
serial = ""

amongUsComoCadena = """000001111000
000010000100
000100011110
000100100001
011100100001
010100100001
010100100001
010100011110
010100000010
011100000010
000100111010
000100101010
000111101110
000000000000
000000000000
000000000000
111010101110
100010101000
111010101110
001010100010
111011101110
000000000000
000000000000
000000000000"""
conector = ConectorPython.ConectorV3(serial=serial)
conector.Iniciar()
conector.DeshabilitarElModoDeCaracteresChinos()
conector.EstablecerAlineacion(ConectorPython.ALINEACION_CENTRO)
conector.DescargarImagenDeInternetEImprimir(
    "http://assets.stickpng.com/thumbs/587e32259686194a55adab73.png", 0, 216)
conector.Feed(1)
conector.EscribirTexto("Parzibyte's blog\n")
conector.EscribirTexto("Blog de un programador\n")
conector.TextoSegunPaginaDeCodigos(2, "cp850", "Teléfono: 123456798\n")
conector.EscribirTexto("Fecha y hora: 29/9/2022")
conector.Feed(1)
conector.EstablecerAlineacion(ConectorPython.ALINEACION_IZQUIERDA)
conector.EscribirTexto("____________________\n")
conector.TextoSegunPaginaDeCodigos(
    2, "cp850", "Venta de plugin para impresoras versión 3\n")
conector.EstablecerAlineacion(ConectorPython.ALINEACION_DERECHA)
conector.EscribirTexto("$25\n")
conector.EscribirTexto("____________________\n")
conector.EscribirTexto("TOTAL: $25\n")
conector.EscribirTexto("____________________\n")
conector.EstablecerAlineacion(ConectorPython.ALINEACION_CENTRO)
conector.HabilitarCaracteresPersonalizados()
conector.DefinirCaracterPersonalizado("$", amongUsComoCadena)
conector.EscribirTexto(
    "En lugar del simbolo de pesos debe aparecer un among us\n")
conector.EscribirTexto("TOTAL: $25\n")
conector.EstablecerEnfatizado(True)
conector.EstablecerTamañoFuente(1, 1)
conector.TextoSegunPaginaDeCodigos(2, "cp850", "¡Gracias por su compra!\n")
conector.Feed(1)
conector.ImprimirCodigoQr("https://parzibyte.me/blog", 160,
                          ConectorPython.RECUPERACION_QR_MEJOR, ConectorPython.TAMAÑO_IMAGEN_NORMAL)
conector.Feed(1)
conector.ImprimirCodigoDeBarrasCode128(
    "parzibyte.me", 80, 192, ConectorPython.TAMAÑO_IMAGEN_NORMAL)
conector.Feed(1)
conector.EstablecerTamañoFuente(1, 1)
conector.EscribirTexto("parzibyte.me\n")
conector.Feed(3)
conector.Corte(1)
conector.Pulso(48, 60, 120)
respuesta = conector.imprimirEn(nombreImpresora)
if respuesta == True:
    print("Impreso correctamente")
else:
    print("Error: " + respuesta)

It could be a little confusing at the beggining but once you know every function, you will be able to unlash your creativity and print any type of receipts.

When running that code, the output should be like this:

Python receipt printing - Using ESC POS Commands on thermal printer
Python receipt printing – Using ESC POS Commands on thermal printer

As you can see, we are printing images on a thermal printer using Python, along with QR codes, barcodes, styled text, and custom characters.

Now, what remains is to explore the documentation on the plugin’s webpage to familiarize yourself with all the available methods and the full extent of its capabilities.

You can find the documentation on the plugin’s webpage: https://parzibyte.me/blog/en/2019/10/13/print-ticket-in-thermal-printer-directly-from-browser/

Also, you can try online examples made with JavaScript and then port them to Python. The plugin works the same and does not mind which programming language do you use: https://parzibyte.github.io/ejemplos-javascript-plugin-v3/


I am available for hiring if you need help! I can help you with your project or homework feel free to contact me.
If you liked the post, show your appreciation by sharing it, or making a donation

Leave a Comment

Your email address will not be published. Required fields are marked *