How to send raw string to a dotmatrix printer using python in ubuntu?
Asked Answered
A

2

5

I have a dot-matrix printer LX-300 connected to my computer through the network. How do I send a raw string with ESCP characters directly to my printer in Python?

The computer is connected to the printer through another computer. I need to send a raw string because LX-300 image printing result is blurry.

Andromada answered 6/10, 2016 at 8:29 Comment(2)
Is the computer running python connected directly to the printer? How are the computers and printers connected? What is the method of communication you are using? Are you sure of your problem -- Can you explain how you've determined sending a raw string in Python to the printer will fix the blurry image?Acrilan
@Gator_Python It isn't connected directly, I use CUPS samba connection over network to a pc running on windows 7 on which the printer is directly connected. I am convinced because of my experience. I've tried both raw string printing and image printing and the raw string printing image quality and speed is far more superior. Not to mention the ESC/P capabilities to directly control the printer behavior.Andromada
O
6

The Problem

To send data down this route:

Client computer ---> Server (Windows machine) ---> printer (dot-matrix)

...and to not let Windows mess with the data; instead to send the raw data, including printer control codes, straight from the client computer.

My Solution

Here's how I solved a near-identical problem for a small in-house database application:

Step 1) Make the printer network-accessible without Windows getting its fingers in the data routed to it. I accomplished this by installing the printer using the "Generic/Text Only" driver, then installing RawPrintServer on the Windows machine connected to the printer.

Step 2) Send raw data over the network to the TCP/IP port specified when you set up RawPrintServer (default is 9100). There are various ways to do that, here's what I did:

data = b"\x1B@A String To Print\x1B@" # be sure to use the right codes for your printer
ip_addr = 123.123.123.123 # address of the machine with the printer
port = 9100 # or whatever you set it to
s = socket.socket()
try:
    s.connect((ip_addr, port))
    s.send(data)
except:
    # deal with the error
finally:
    s.close()

Background

I thought about the problem in two parts:

  1. Client machine: spitting out the data I need from Python with the correct formatting/control codes for my printer, and sending it across the network
  2. Print server machine: transmitting the data to the locally connected printer

Number 1 is the easy part. There are actually some libraries in PyPI that may help with all the printer codes, but I found most of them are aimed at the little point-of-sale label printers, and were of limited use to me. So I just hard-coded what I needed into my Python program.

Of course, the way you choose to solve number 2 will effect how you send the data from Python. I chose the TCP/IP route to avoid dealing with Samba and Windows print issues.

As you probably discovered, Windows normally tries very hard to convert whatever you want to print to a bitmap and run the printer in graphics mode. We can use the generic driver and dump the data straight into the (local) printer port in order to prevent this.

The missing link, then, is getting from the network to the local printer port on the machine connected to the printer. Again, there are various ways to solve this. You could attempt to access the Windows printer share in some way. If you go the TCP/IP route like I did, you could write your own print server in Python. In my case, the RawPrintServer program "just worked" so I didn't investigate any further. Apparently all it does is grab incoming data from TCP port 9100 and shove it into the local printer port. Obviously you'll have to be sure the firewall isn't blocking the incoming connections on the print server machine. This method does not require the printer to be "shared" as far as Windows is concerned.

Depending on your situation (if you use DHCP), you might need to do some extra work to get the server's IP address in Python. In my case, I got the IP for free because of the peculiarity of my application.

This solution seems to be working out very well for me. I've got an old Panasonic printer running in Epson ESC/P compatibility mode connected to a Windows 7 machine, which I can print to from any other computer on the local network. Incidentally, this general idea should work regardless of what OS the client computer is running.

Osculation answered 14/10, 2016 at 15:47 Comment(1)
UPDATE: Several years have passed, and we're on Windows 10 now, and our application is still using this method with great success.Osculation
I
2

Ultimately, you will need and want to write your own wrapper/script to do this. And since you are using a distribution of Linux, this is relatively easy.

On a Linux OS, the simplest way to issue a print job is to open a subprocess to the lpr. Generally, using lpr lets you access the printer without the need to be logged in as root (being a superuser), which is desirable considering the amount of damage that can be done while logged in as a "superuser".

Code like the following:

import subprocess
lpr = subprocess.Popen("/usr/bin/lpr", stdin=subprocess.PIPE)
lpr.stdin.write(data_to_send_to_printer)

Should be a good jumping off point for you. Essentially, this code should allow you to accomplish what you need.

Be careful though; depending on your privilege levels, a call to open a subprocess might need root level/Superuser permissions.

Subprocesses generally inherit the User IDs and access rights by the user that is running the command. For example, if the subprocess is created by a root user, then you will need root user/Superuser rights to access that subprocess.

For more information, check out the hyperlinks I've included in the post.

Good luck!

Inelegance answered 14/10, 2016 at 15:27 Comment(6)
How do I specify which printer I use?Andromada
I hyperlinked the page for the lpr command. If using the lpr command via a Terminal, pass lpr the -P parameter with the path to the printer. The lpr page should have most of the information needed to get you started. It also has a "quick start" guide, so-to-speak.Inelegance
So does this code work? lpr = subprocess.Popen("/usr/bin/lpr -P lx300", stdin=subprocess.PIPE). I am not sure how to pass the parameter to the subprocess.Andromada
You will need to check the printers under the /usr/bin/ directory. lpr can also be used as a command line command which is where the -P comes into play. If you don't need to write a custom program, you could save out the data you want to print into a raw text file and then using the following in a Terminal should send the (raw) data from the file to the printer cat <Path_To_Text_File_Here>.txt | lpr -P <Printer_Path_Here> using cat first and piping then piping to lpr, which will read the contents from standard input which should give you the desired results.Inelegance
I've tried that using the os module, but it doesn't allow me to use the printer default font, and I can't control the font it uses. Suppose the printer name is lx300 will lpr = subprocess.Popen("/usr/bin/lpr -P lx300", stdin=subprocess.PIPE) work then?Andromada
I find ASL's suggestion clearer and to the point, but thanks a lot for your help.Andromada

© 2022 - 2024 — McMap. All rights reserved.