Processing and thermal printer

Hi everyone,
I’m working on a project where an EPSON TM-T20II thermal printer must be driven by a Processing sketch.
I’ve tried to make it work with the SimpleReceiptPrinter but without success.

I think it could be pretty easy if the printer should communicate via COM, the same way I’m used to communicate byte by byte with the Arduino.

I’m on WIndows and all this stuss seems to be pretty complicated. Is there someone who has son experience with that or, at least, with Epson thermal printers?
Any help is appreciated!
Thank you very much for your support!

1 Like

This was written by @gohai, who might have some suggestions. The more information you have located that you can share about your EPSON TM-T20II and what protocols it speaks, the more helpful for getting advice. Printer-driving often involves dark magicks.

1 Like

@moscardo You should be able to simply install printer drivers from the manufacturers website, and then the printer will work like a regular printer I am guessing.

https://epson.com/Support/Point-of-Sale/Thermal-Printers/Epson-TM-T20II/s/SPT_C31CD52062?review-filter=Windows+10+64-bit

1 Like

I tried the same library with the same Epson printer model and Windows 10 platform. To enable the COM serial communication with the PC and the printer, i have used a virtual port driver supplied by Epson (https://download.epson-biz.com/modules/pos/index.php?page=single_soft&cid=5485&pcat=6&scat=36&ml_lang=it) and it works perfectly with the Epson print utility. However, when i run the Processing sketch, the library starts to send data to the printer, but it seems that this one doesn’t receive them, cause nothing is been printed. Someone has had the same problem kind of problem?
Thank you very much

1 Like

@Phasor1 Which “library” are you using?

@gohai i’m using SimpleReceiptPrinter

@Phasor1 This only works with the printer from Adafruit or compatible models. If the Epson has a “real” Windows printing driver (meaning it shows up as a printer device in your system preferences), you should be able to use the regular Java APIs for printing graphics.

2 Likes

I’ve found this example which is using Java.
I was able to compile it and to get a list of available printers.
I was also able to send something to the printer (I see a new document in the printer queue) but, unfortunately, nothing seems to happen.

Here’s the code I’m using. This is the PrinterService.java file:

import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.util.ArrayList;
import java.util.List;

import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;

public class PrinterService implements Printable {

	public List<String> getPrinters(){

		DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
		PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();

		PrintService printServices[] = PrintServiceLookup.lookupPrintServices(flavor, pras);

		List<String> printerList = new ArrayList<String>();
		for(PrintService printerService: printServices){
			printerList.add( printerService.getName());
		}

		return printerList;
	}

	@Override
	public int print(Graphics g, PageFormat pf, int page)
			throws PrinterException {
		if (page > 0) { /* We have only one page, and 'page' is zero-based */
			return NO_SUCH_PAGE;
		}

		/*
		 * User (0,0) is typically outside the imageable area, so we must
		 * translate by the X and Y values in the PageFormat to avoid clipping
		 */
		Graphics2D g2d = (Graphics2D) g;
		g2d.translate(pf.getImageableX(), pf.getImageableY());
		/* Now we perform our rendering */

		g.setFont(new Font("Roman", 0, 8));
		g.drawString("Hello world !", 0, 10);

		return PAGE_EXISTS;
	}

	public void printString(String printerName, String text) {

		// find the printService of name printerName
		DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
		PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();

		PrintService printService[] = PrintServiceLookup.lookupPrintServices(flavor, pras);
		PrintService service = findPrintService(printerName, printService);

		DocPrintJob job = service.createPrintJob();

		try {

			byte[] bytes;

			// important for umlaut chars
			bytes = text.getBytes("CP437");

			Doc doc = new SimpleDoc(bytes, flavor, null);


			job.print(doc, null);

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void printBytes(String printerName, byte[] bytes) {

		DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
		PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();

		PrintService printService[] = PrintServiceLookup.lookupPrintServices(flavor, pras);
		PrintService service = findPrintService(printerName, printService);

		DocPrintJob job = service.createPrintJob();

		try {
			Doc doc = new SimpleDoc(bytes, flavor, null);
			job.print(doc, null);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private PrintService findPrintService(String printerName,
			PrintService[] services) {
		for (PrintService service : services) {
			if (service.getName().equalsIgnoreCase(printerName)) {
				return service;
			}
		}
		return null;
	}
}

And this is the Main.java:

public class Main {

	public static void main(String[] args) {

		PrinterService printerService = new PrinterService();
		String printerName = "EPSON TM-T20II Receipt";

		System.out.println(printerService.getPrinters());

		//print some stuff
		printerService.printString( printerName, "hello");

		// cut that paper!
		byte[] cutP = new byte[] { 0x1d, 'V', 1 };

		printerService.printBytes( printerName, cutP);

	}

}

What I’m doing wrong?
Thanks for your help, I really respect it.

1 Like

You should convert “Main.java” file into a “Main.pde” 1, so it is a sketch instead. :cowboy_hat_face:

That is, if you want that to work inside PDE (Processing’s IDE). :flushed:

2 Likes

Thank you @GoToLoop,
yes sure! I’m looking forward to do this but, from the moment the printer isn’t printing anything with this Java program, how will Porcessing be able to do that?
I think there’s something wrong in my Java code at the moment or maybe in the printer configuration on my system.
It must be said that I’m actually able to print via both the Register, Change and Delete EPSON TM Printer and the TM-T20II Utility on USB.

I do not know why I can not print otherwise…

If the only thing you will be printing is text to the receipt printer here is one possible solution. First, save the text you want to print to a text file (i.e. Myfile.txt). Then, use the launch command to open Windows Notepad.exe with the ‘/p’ option to automatically print the text file. See the code example below:

//Receipt Printer Test program
import processing.serial.*;                         //Use the serial library
import static javax.swing.JOptionPane.*;  //Use the option pane dialog box library


String TS_file="Timeslip.txt";                    //String variable for the Time Slip text file name
String Str1 = "";                                        //Working string variable
String Str2 = "";                                        //Working string variable
String Prt_Cmd = "";                                //String for holding print command
String File_Path = "C:/Users/Bill/Processing/6-Sandbox/receipt_printer_test/Timeslip.txt";
PrintWriter TS_output;                             //Create an output variable for writing to the Timeslip.txt file

void setup() {
  size(200,200);
  background(255);
  fill(0);
  text("Printer Test",90,100);
  Prt_Cmd = "notepad.exe /p " + File_Path;     //Build the time slip print command string
}

void draw() {
  Str1 = "PRINT REQUEST";
  Str2 = "Do you wish to print the timeslip text file?";
  int input = showConfirmDialog(null, Str2, Str1, YES_NO_OPTION);  //Prompt: 0=yes, 1=no
  if (input == 0) {                              //Did user respond with "YES"?
    Create_Timeslip();                     //Call subroutine to create timeslip text file
    println("Timeslip file created");   //Optional debug line to let you know file was created
    delay(100);
    launch(Prt_Cmd);                       //Launch Windows command to  print time slip
  }
  else {
    exit();                                           //Exit program if "NO" was selected
  }
  delay (100);
}

void Create_Timeslip() {                            //Create the Time Slip text file
  TS_output = createWriter(TS_file);         //Open Time Slip text file in the sketch directory
  TS_output.println("       DFW Winternationals");
  TS_output.println("     Snowmobile Drag Racing");
  TS_output.println("=================================");
  TS_output.println("       Date: 09/02/2018");
  TS_output.println("           Race# 04");
  TS_output.println(" -Lane 1-              -Lane 2-");
  TS_output.println("  00.276   React Time   00.271");
  TS_output.println("  03.781   60 Ft Time   03.632");
  TS_output.println("  27.641 Trap Speed MPH 36.320");
  TS_output.println("  07.934  Elapsed Time  07.725");
  TS_output.println("   - - -     Status     WINNER");
  TS_output.println("=================================");
  TS_output.println("   Thanks for racing with us");
  TS_output.println("        Bill V's Timers");
  TS_output.flush();                        //Writes any remaining data to the file
  TS_output.close();                        //Close the file
}
3 Likes