Thermal Printer Hack

July 29, 2024

After seeing a few online projects revolving around thermal printers, I decided to give it a shot.

Here's the inspiration for the project:

I was soon driving around Satwa to find some used Epson printers, the ones that are basically used in shops to print receipts.

I brought the device home and installed the ESC POS Python library.

After a few hours tweaking the configuration and troubleshooting, I was left with some pictures that would not print fully. I then modified my script to send the images as fragments to the printer in order to take into account the (very) small buffer size of the device. I also added a few lines of code to rotate landscape photos based on their EXIF metadata.

Finally I added a few filters to enhance the image before printing it.

Here's the full script:


from escpos.printer import Usb

import usb.core

import usb.util

import usb.backend.libusb1

from PIL import Image, ImageOps, ImageEnhance, ImageFilter

import sys

import numpy as np

import random


def add_vhs(image_path, output_path):
    
    image = Image.open(image_path)
    
    enhancer = ImageEnhance.Brightness(image)
    
    image = enhancer.enhance(1.5) # Reduce brightness to 80%
    
    enhancer = ImageEnhance.Contrast(image)
    
    image = enhancer.enhance(1.5) # Reduce contrast to 70%
    
    image = image.filter(ImageFilter.GaussianBlur(radius=0.5))
    
    image.save(output_path)

  
  

p = Usb(0x04b8, 0x0e15, 0, 0x81, 0x82, profile="TM-T20II")

img = Image.open(sys.argv[1])

img = ImageOps.exif_transpose(img)

if len(sys.argv) > 3:

    if sys.argv[3] == "rotate":

        img = img.rotate(90, expand=True)

img.save("lastPrint.bmp")

img = Image.open("lastPrint.bmp")

original_width, original_height = img.size

new_width = 576

new_height = int(original_height * (new_width / original_width))

img = img.resize((new_width, new_height))

img.save("lastPrint.bmp")

add_vhs("lastPrint.bmp","lastPrint.bmp")



p.text("\n")

p.set(align='center')

p.text(sys.argv[2])

p.text("\n")

p.image("lastPrint.bmp", impl=u'bitImageRaster', fragment_height=200)

p.text("\n")

p.cut()