14
.
11
.
2023
14
.
02
.
2020
Backend
Tutorial
Software

Thermal Printer Protocols for Image and Text

Burak Aybar
Ruby Developer

Epson TM-T20II Thermal Printer [1]

What is a Thermal Printer?

Technically;

Thermal printing (or direct thermal printing) is a digital printing process which produces a printed image by selectively heating the coated thermochromic paper, or thermal paper as it is commonly known when the paper passes over the thermal print head. The coating turns black in the areas where it is heated, producing an image [2].

Basically;

A thermal printer is a printer that makes use of heat to produce the image on paper [3].

Due to the quality of the print, speed, and technological advances, it has become increasingly popular. These printers are widely used in supermarkets, libraries, restaurants, bars, transport industry, lottery and betting, kiosks, petroleum stations, POS systems and in the medical industry, such as heart monitoring machines, or geological engineering (it records the real-time images of subsurface activities and earthquakes). These are just a few broad examples of the usage of thermal printers. The list will be endless if you think of places that you get a receipt every day.

Now that you understand the idea at a broad level, let's dive into the technical details of Thermal Printers.

How can we print an image on Thermal Printer?

In order to print an image on the thermal printer, you have to process the image pixel by pixel using ESC/POS, which is a native command language of thermal printers. ESC/POS developed by EPSON and is used by many other printer manufacturers, mainly on POS (Point Of Services or Point of Sales). Most of the manufacturers sustain all or some commands which you can access easily; however, some manufacturers still do not support it. Besides that edge case, the usage of commands is mostly the same in general [4][5].

ESC/POS derives its name from the start of the escape sequences used, which start with the escape character ESC (ASCII code 1B). As an example, ESC D will set the horizontal tab position, while ESC M selects the character font.

Let's understand the ESC/POS commands

First things first, we need to initialise the printer, which will help to clear data from the printer buffer and sets its default settings. For initialising ESC @ command needs to be used.

ESC @ command

Therefore, Hex or Decimal notation needs to be sent to the printer (it does not support ASCII format). In the above example, 1B 40 is the command for the initialising printer, which is 'ESC @'. Let's analyse more complex command 'ESC *', which will help us to print the image.

ESC * command

As can be seen in this example, there are two parts of the code, namely constant and parameters. 1B 2A is a constant part, and the following part needs to be specified as it is written in the document. Otherwise, the printer can print weird symbols or even can get blocked. Therefore one question might be coming to mind, what is the meaning of the parameters?

The m parameter is a mode for dot density. The nL and nH stand for the width of the image in pixels. To find nL and nH, firstly calculate modulo of the width of the image respect to 256 (since nL and nH can be between 0 and 255). The remainder and the quotient will be represented nL and nH, respectively. For instance, if there is an image width with 200px, the two values for nL and nH will be 0xC8(200 in decimal value) and 0x00(0 in decimal value), respectively. If the image width had 340px, the values would be 0x54(84 in decimal) and 0x01(1 in decimal). So, basically width equals to nL + nH x 256. The d indicates the bit-image data. Bits that correspond to the dots to print are 1 and the bits that correspond to the dots that are not printed are 0.

The image is usually drawn pixel by pixel, left to right, top to bottom but on these printers, it is done top to bottom, then left to right.

The m parameter can be four different values each of them changes the method of how we designed the image data bytes. In the following example, m equals to 33, which means 24-dot double density mode. The head of the printer is 1 dot wide by 24 dots long, and it moves left to right, burns up to 24 dots in the vertical direction for each 1 dot in the horizontal direction. The following figures also illustrate how 8 and 24 dot density or single and double density work:

8-dot density(top) --- 24-dot density(bottom)

Let's check with one example

If you send the following array to the printer;

[0x1B, 0x2A, 0x0, 0x4, 0x0, 0xFF 0x7E, 0x3C, 0x18]

it's going to print pyramid:

Therefore, for the image with a 4px width, we have chosen the 8-bit density mode. The 1s represent the dots, for instance, the first column is full with 1s and we assigned 0xFF(255 in decimal) which comes from 2⁷ + 2⁶ + 2⁵ + 2⁴ + 2³ + 2² + 2¹ + 2⁰ = 255.

Where to go from here

Now that you know the basics of ESC/POS commands, you can try out some of the examples. If you want to get your hand's dirty check my next article which is WebUSB - Print Image and Text in Thermal Printers.

If you're interested in more blog posts like this, please visit our Visuality Blog.

Want-more-Visit-our-You-Tube-Channel

Resources

[1]https://theuniformsolution.com/product/epson-tm-t20ii-thermal-printer/

[2]https://en.wikipedia.org/wiki/Thermal_printing

[3]https://www.techopedia.com/definition/3629/thermal-printer

[4]http://www.starmicronics.com/support/mannualfolder/escposcmen.pdf [5]https://reference.epson-biz.com/modules/refescpos/index.php?contentid=72

Burak Aybar
Ruby Developer

Check my Twitter

Check my Linkedin

Did you like it? 

Sign up To VIsuality newsletter

READ ALSO

LLM Embeddings in Ruby - Paweł Strzałkowski

LLM Embeddings in Ruby

17
.
03
.
2024
Paweł Strzałkowski
Ruby
LLM
Embeddings
ChatGPT
Ollama
Handling Errors in Concurrent Ruby, Michał Łęcicki

Handling Errors in Concurrent Ruby

14
.
11
.
2023
Michał Łęcicki
Ruby
Ruby on Rails
Tutorial
Recap of Friendly.rb 2024 conference

Insights and Inspiration from Friendly.rb: A Ruby Conference Recap

02
.
10
.
2024
Kaja Witek
Conferences
Ruby on Rails

Covering indexes - Postgres Stories

14
.
11
.
2023
Jarosław Kowalewski
Ruby on Rails
Postgresql
Backend
Ula Sołogub - SQL Injection in Ruby on Rails

The Deadly Sins in RoR security - SQL Injection

14
.
11
.
2023
Urszula Sołogub
Backend
Ruby on Rails
Software
Michal - Highlights from Ruby Unconf 2024

Highlights from Ruby Unconf 2024

14
.
11
.
2023
Michał Łęcicki
Conferences
Visuality
Cezary Kłos - Optimizing Cloud Infrastructure by $40 000 Annually

Optimizing Cloud Infrastructure by $40 000 Annually

14
.
11
.
2023
Cezary Kłos
Backend
Ruby on Rails

Smooth Concurrent Updates with Hotwire Stimulus

14
.
11
.
2023
Michał Łęcicki
Hotwire
Ruby on Rails
Software
Tutorial

Freelancers vs Software house

02
.
10
.
2024
Michał Krochecki
Visuality
Business

Table partitioning in Rails, part 2 - Postgres Stories

14
.
11
.
2023
Jarosław Kowalewski
Backend
Postgresql
Ruby on Rails

N+1 in Ruby on Rails

14
.
11
.
2023
Katarzyna Melon-Markowska
Ruby on Rails
Ruby
Backend

Turbo Streams and current user

29
.
11
.
2023
Mateusz Bilski
Hotwire
Ruby on Rails
Backend
Frontend

Showing progress of background jobs with Turbo

14
.
11
.
2023
Michał Łęcicki
Ruby on Rails
Ruby
Hotwire
Frontend
Backend

Table partitioning in Rails, part 1 - Postgres Stories

14
.
11
.
2023
Jarosław Kowalewski
Postgresql
Backend
Ruby on Rails

Table partitioning types - Postgres Stories

14
.
11
.
2023
Jarosław Kowalewski
Postgresql
Backend

Indexing partitioned table - Postgres Stories

14
.
11
.
2023
Jarosław Kowalewski
Backend
Postgresql
SQL Views in Ruby on Rails

SQL views in Ruby on Rails

14
.
11
.
2023
Jan Grela
Backend
Ruby
Ruby on Rails
Postgresql
Design your bathroom in React

Design your bathroom in React

14
.
11
.
2023
Bartosz Bazański
Frontend
React
Lazy Attributes in Ruby - Krzysztof Wawer

Lazy attributes in Ruby

14
.
11
.
2023
Krzysztof Wawer
Ruby
Software

Exporting CSV files using COPY - Postgres Stories

14
.
11
.
2023
Jarosław Kowalewski
Postgresql
Ruby
Ruby on Rails
Michał Łęcicki - From Celluloid to Concurrent Ruby

From Celluloid to Concurrent Ruby: Practical Examples Of Multithreading Calls

14
.
11
.
2023
Michał Łęcicki
Backend
Ruby
Ruby on Rails
Software

Super Slide Me - Game Written in React

14
.
11
.
2023
Antoni Smoliński
Frontend
React
Jarek Kowalewski - ILIKE vs LIKE/LOWER - Postgres Stories

ILIKE vs LIKE/LOWER - Postgres Stories

14
.
11
.
2023
Jarosław Kowalewski
Ruby
Ruby on Rails
Postgresql