Monday, June 30, 2014

Epson LQ-2550 interpreter

I wanted to generate some epson dot matrix color output in linux but it was much harder than I planned. For one thing, CUPS didn't want to let me output to a file. So I had to edit /etc/cups/cups-files.conf, adding the line "FileDevice Yes". Then I could set a destination device of "file:///home/knoppix/file_print_output.bin".


The drivers don't seem to want to make color output for most of the epson printers. However, I was able to find a couple of printers that would generate color with the epsonc driver. The Epson LQ-2550 and the Fujitsu 2400 or Fujitsu 3400. I wrote an interpreter that would render the printer test page as a proof of concept. It is by no means complete as it only implements just enough ESC codes to work.













Epson LQ-2550 Javascript Interpreter

Sunday, June 29, 2014

Running in molasses with firefox and getImageData(x,y,1,16)

I don't know why firefox is so slow processing in 1x16 chunks. Anyway, here's the slow version of the JX-80 javascript interpreter.

JX-80 Javascript Interpreter SLOW VERSION

Saturday, June 28, 2014

Epson JX-80 Javascript Interpreter

After writing a Epson JX-80 graphics interpreter in QBasic, I figured that I should make one in javascript. It only interprets the ESC L 120 dpi graphics and not regular text printing. If I wanted to do regular text I reckon I'd have to duplicate the Epson font in the rom. The manual gives a full table of the rom characters if I remember correctly.

I did find some javascript problems with firefox. Performance under firefox was abysmal when I was using canvas2d getImageData(x,y,1,16). It was horribly slow, in fact totally unusable. After trying to get it to work with firefox and failing, I tried Chromium and it absolutely flew in comparison. The slowdown under firefox was around 100x slower.

My workaround is to use getImageData on a larger block size and that seemed to help tremendously.

Another bug is that firefox seems to have some numerical precision problems as I get a single pixel blank line gap near the bottom of my text sample. Again, Chromium doesn't have this issue.


I can't figure out why it has a gap here...




When I have more time, I may make it work on more than a single page at a time so that when it hits an FF it'll clear the canvas for the next page in the stream. Maybe I'll also upload the super-slow version that brings firefox to a crawl so you can see the difference.



Sample text rendered with firefox, note the gap in the last line of text.



Chromium renders the sample text perfectly, with no gap line.



JX-80 Javascript Interpreter

Wednesday, June 25, 2014

Epson JX-80 simulator

I always lamented the day that my Epson JX-80 died back in 1994. I really liked that printer because it was a color dot matrix. Today, we have color inkjets and color laser printers, but back then, the JX-80 was awesome. Even more awesome was that the Amiga printer drivers supported the JX-80. I used to love printing my DeluxePaint creations in color.

I remember the day I brought it home, hooked it up and printed graphics in color for the first time. Wow! Somehow everything was more precious in those days. I think our brains are wired for scarcity, not for abundance.

After writing a simulator for the ptouch, I thought, why not try a regular dot matrix printer. So I tried the Panasonic KX-P2123. It was pretty easy, as all I had to implement was the ESC * command (at 180 dpi) and a few other ESC codes.

Since I had the benefit of a esc p reference document it was quite straightforward.

https://files.support.epson.com/pdf/general/escp2ref.pdf

Then I thought, why not try the Epson JX-80? I ran it a few times to see what codes I hadn't implemented and saw that it printed graphics using ESC L which is 120 dpi horizontal graphics at 72 dpi vertically. The printer printhead is 72 dpi and it shifts it down 2/216 of an inch and prints again to make 144dpi vertically. So I added an interleave so that it would print a row spaced with lines spaced 2 apart, then fill in the gaps on the next pass.

I also noticed that the driver printed 4 passes for color, CMYK. I pondered on how to implement that.

Fortunately the VGA color palette for SCREEN 12 has CMYK colors.

cyan = 3
magenta = 5
yellow = 14

red = 4 (m+y)
green = 2 (c+y)
blue = 1 (c+m)

black = 0 (c+m+y)
white = 7

so all I had to do was to make a function that would convert CMY into a vga screen color. When I would print a color, I just take the screen pixel, convert that color into CMY, "add" the C,M, or Y that I'm printing by doing a binary OR for each color component (c = old c OR new c), and the PSET the pixel back to the screen, converting CMY to a vga screen color. If we are printing black, treat that as setting C,M and Y.


Once I figure out how to speed it up, either by rewriting it with more table lookups or using QB64, I'll hook it up to my Amiga and try to generate some "retro" output.

Since it's rather slow, it won't keep up with a large output stream and get a buffer overflow error. But if you keep the picture small it will work.

I use the trick of setting the windows printer driver to send the output to COM1: instead of the LPT1: port in order to get the data to my qbasic program. I hope that the Amiga will work similarly by just choosing the serial port for output.

Hmmmm, now that I've uploaded the pictures I can see just how dingy white color 7 is. Maybe I'll set white to be color 15. I can't really tell on my lousy laptop screen.




setting up the CMY table, note that you don't see color 7 as it's black (c+m+y=black).



Epson4.BAS

Saturday, June 21, 2014

Wednesday, June 18, 2014

Adding QL-1060N

I added the QL-1060N to my PTSIM93.BAS program. Interestingly, the QL-1060N uses RLE compression with its graphics, unlike some of the other QL printers which use ULP uncompressed graphics. Also I added a sample of QL-1060 output to my javascript interpreter and fixed it to process the RLE data. Note that the output will be clipped unless you set the canvas to 1296 pixels high (for a 4x6 QL-1060 print at 300dpi).


for other QL printers,

g #1 #2 [data] 67 #1 #2 [data] Send raster line data consists of N=#2 bytes of uncompressed raster data

and for the QL-1060 it would be

g #1 #2 [data] 67 #1 #2 [data] Send raster line data consists of N=#2 bytes of RLE raster data after having been sent the M code to enable compression.

Friday, June 13, 2014

Pretending to be a Ptouch Printer in QBasic


I was always curious just exactly what the computer would actually send the PT-PC printer. So when I saw this webpage that stated that "the PTPC could only print 24 pixels wide" it piqued my interest.

"For arbitrary graphics, this printer can only print raster lines 24 pixels wide down the centre of the tape (and this way also arbitrary fonts in low resolution). It can print text using its built-in fonts, but that would require a special text-to-PT-PC driver."

I had to find some way to snoop the serial port and found this program:

Portmon for Windows v3.03 By Mark Russinovich

I fired it up, printed a couple of test labels, and then edited the output to make a binary file. I could see that it used only a few ESC commands, all of which were nicely documented in the PT-PC manual. It would be wonderful if every device that you bought came with complete technical documentation like that PT-PC. I remember my old Epson JX-80 printer included great technical documentation and tutorials. I really loved that old printer, horribly noisy but solid and most importantly, it had reinkable ribbons.

QBasic has always been kind of fun to hack with as it's very forgiving and gives you lots of feedback. I hacked up a little program that would open the binary file and draw the output on the screen.

Then I had an idea: Why not try to impersonate the PT-PC directly using the computer serial ports? All I have to do is to send a 32 byte sequence whenever the driver sends an "ESC i S" 1b 69 53 status request. QBasic supports up to 9600 baud serial communications which is great because the PT-PC uses 9600 baud.

The PT-PC uses a DB-9 serial port and I'm using a laplink cable to connect to it, so I've already got the cable.

So I wrote a little qbasic program to open the serial port and watch what it sent.

Unfortunately, it wouldn't send any bytes at all. I tried it over and over again and was totally stumped. I looked at the portmon snoop and how it opened the port. Somehow it was wanting to do a DSR handshake. I have a LED inline serial port display device and plugged that into the line. It looked exactly the same (the same leds were lit up) whether I plugged in the PT-PC or my laptop serial port. This was driving me crazy!!!

I left it for a day, came back to it, struggled again, left it for another day, came back, struggled again. It was horribly frustrating, like beating your head against the wall.

Then I had an insight: it's driving the PTCOM: port in the windows printer driver. Maybe I would specify the COM1: port instead! Once I selected COM1: it started sending bytes! WOO HOO!

The graphics looked funny because the MSB is not the lowest pixel of the byte. I got it to render the graphics properly by changing my renderdata routine to draw the ycoordinate with ypos+(7-bitpos) instead of ypos+bitpos.

There's something really cool and satisfying about watching it interpret the data and render the graphics to screen. Unfortunately, QBasic is terribly slow and it can't really keep up with 9600 baud data. For a decent sized PT-PC print job it can take many minutes (or more!!!). I suppose my junky 366 mhz laptop running win98 and qbasic could be swapped for something faster, but it works.

Then I said to myself, "hmmmm I've got other PTouch printers, why not try to simulate them?" Then after I got the PT2600 working I thought, "why not download the drivers for some of the PTouch printers I don't have?" So I got the PT-PC, PT2400, PT2600, PT9200, PT9500 and PT9700 drivers working with my QBasic program. The PT2600 is a USB printer and its USB printer drivers work fine with the COM1: port. But how to figure out what the printer code is that ESC i S is looking for?

First I snooped the USB port for the PT2600. Analyzing the print jobs gave the "B0H0" code.

Then I figured, why not just "try every combination". If I specify ptmodel$="UNKNOWN" in my code, every time it gets a status request it increments the ptunit$. So it tries "B000", then "B010"... If you keep pressing the "play" button in the windows print driver it cycles through and when it says "Wrong cassette inserted" instead of "Connected Ptouch is not the PT-2600" you know what the ptunit$ code is.

One thing to note is that QBasic can not keep up with the print job in realtime. So I've done a couple of things to compensate. I enlarged the serial receive buffer to the maximum 65535 bytes. Also, when it requests the status with (ESC i S) we reply with not just the 32 byte status block but also a few other 32 byte status blocks that it will expect later. Since it doesn't empty the receive buffer, those blocks will be there when it is ready to look for them. Otherwise it will timeout and give you a "Communication Error".

The sequence it looks for is

printstatus 0,0,0,0
printstatus 0,0,0,0
printstatus 6,1,0,0
printstatus 1,1,0,0
printstatus 6,0,0,0

A couple of the printer drivers will clear the receive buffer so we just put a little delay to wait until after it's done that. So the code looks like

printstatus 0,0,0,0
sleep 2 'wait for the buffer clear
printstatus 0,0,0,0
printstatus 6,1,0,0
printstatus 1,1,0,0
printstatus 6,0,0,0

Before I was able to get the timing right, I made it send the printstatus on hitting a "1" keystroke. It watches the INKEY$ and sends printstatus when inkey$="1". So I'd let the program respond to the initial ESC i S with a normal printstatus 0,0,0,0 and then midway through the print job I would type the "1" key.

You can send as many printstatus 0,0,0,0 as you like and the printer driver will gobble them without complaining.

So for the 7 people in the world who would be interested in this, here's my PTSIM.BAS qbasic program.

What good is this program? It could be very useful to someone developing printer drivers to check the output without burning up expensive Ptouch cartridges on test prints. It's also useful to "dump" the binary data coming over the COM1: port. Just set logfile$ to a valid filename and it will record every byte to a file. You may also set the inputfile$ to a filename if you want to take the input from a file on disk instead of the COM1: port. If you want the "perfect" printout without wasting a lot of ptouch cassettes, you can print to this simulator to see exactly what output will be generated, so you can try all of the different dithering styles.

For example, to take the input from a file:

ptmodel$ = "ql500"
ptunit$ = "O" 'uppercase Oscar
inputfile$ = "ql500.bin"
outputfile$ = ""
dorender = 1
tapewidth = 62 'for dk-1202
tapewidth = 29 'for dk-1201
mediatype = 10

To take the input from the COM1: port and just save it quickly to ql500.bin without rendering:

ptmodel$ = "ql500"
ptunit$ = "O" 'uppercase Oscar
inputfile$ = "com"
outputfile$ = "ql500.bin"
dorender = 0
tapewidth = 62 'for dk-1202
tapewidth = 29 'for dk-1201
mediatype = 10

My qbasic code isn't pretty and there's a lot of vestigial stuff, but it's not too complex to understand. Mostly I hate getting the indents right as the qbasic editor is worthless in that regard.

Oh, and the instructions for the "user interface": m to set the model, up and down arrow to change the selected item, t to set tape width, i to set input file, o to set output file, d to set the "dorender mode" (0, 1 or 2 to delay the render which makes two passes, first dorender=0 then dorender=1) and g to "go". Please watch the caps lock as it's not very clever about matching uppercase M.







PTSIM90.BAS

Wednesday, June 11, 2014

Ptouch Javascript Interpreter

Here's my Ptouch Javascript interpreter page. It's just a fun little javascript project to interpret the Ptouch protocol to generate an image from a binary printer file. I just print the label to a file and then browse to the saved file to render. The code is pretty simple and uses XMLHttpRequest to open up a file that resides in the webpage directory and FileReader to open a file with the file input box. It's a neat example of how to read and parse arbitrary binary data in javascript.

If you click on the row of buttons in the third row, there are demos of output from various P-Touch printers like the pt9200, pt9500 and the pt9700. Every time you click on one of these it will fetch the binary data and add an image at the end of the webpage. You can also scroll down and see how it processed the binary data.

If you click on the button that says 384 pixels or the one that says 720 pixels it will set the height of the canvas to 384 and 720 pixels respectively.

It's also kind of cool to right click on the canvas area and view it as an image.




PTouch Javascript Interpreter