Skip to main content
Back to articles
2026 / 10
| 4 min read

Printing invoices with PostScript and plain text

How a Business Basic customer's invoice forms led to a PostScript program that laid out pages and calculated bills from CSV records.

postscript unix printing small systems

Around 2000 or 2001, a customer asked me how they could print better invoices from their Business Basic system. They were buying preprinted sheets and then having to align the printing with the form, so there was both the cost of the paper and the work of getting the information into the right places. If we could print the form along with the invoice, we could get rid of the preprinted stock and have a bit more freedom with how the page looked.

I learned PostScript to do that. It is a programming language for describing pages, so I could specify where the text went and draw the rest of the form around it. The customer probably would have accepted something fairly plain. I thought we could make it look better at the same time, and with the whole page being generated together I could work on its appearance without having to line the values up with boxes that were already on the paper.

I thought the form generation might be useful for somebody else later, but the customer gave me an invoice to make and a business that needed it. There was enough there to work on without trying to account for every other invoice someone might want. After it was working for them, I adapted the idea for my own billing, and that was where the text files and the printer ended up doing rather more of the job.

For my own business, I kept the invoice and billable records in CSV files. A shell script assembled a printing job by taking the PostScript and appending the CSV as a data block at the end. The resulting text went to the printer, where the PostScript engine ran the program, read the values, did the accounting calculations and laid out the invoice. PostScript could do the arithmetic as well as position the text, so the instructions for handling the bill could live in the template files along with the instructions for drawing the page.

How the invoice printing job was assembledPostScript template files and CSV billing records were combined by a shell script. The printer executed the resulting job, reading the data, calculating amounts and laying out the page.

PostScript template files

Shell script assembles one job

CSV billing records

Printer reads data and runs PostScript

Calculate amounts and lay out page

Printed invoice

For a small example of the arithmetic and layout happening together, this PostScript would print 75 at a chosen position on the page:

%!PS
/Courier findfont 12 scalefont setfont
72 720 moveto
3 25 mul
20 string cvs show
showpage

The 3 and 25 go onto the operand stack. mul takes them off and leaves their product, then cvs converts that number into text for show to draw. The text is placed at the point set by moveto. This is a new, deliberately small illustration of the mechanism, not recovered code from the billing system; it leaves out reading the CSV, formatting money and everything else an invoice needs. The useful part is that the calculation and the page description are in the same language, running in the same interpreter.

The template was the program. Supplying a different block of data gave it another bill to calculate and print. Once that program knew how to read its appended records, the shell script only needed to put the pieces together; concatenating arbitrary CSV onto an arbitrary PostScript file wouldn’t provide that behaviour. I didn’t have to generate and store PDFs or use another application to fill out a document before sending it to the printer.

I liked being able to keep the records in text. I could edit a CSV over SSH, or Telnet at the time, in the same environment as the other work I was doing. When I knew what I wanted to enter or change, I could write it directly instead of finding the right screen, clicking through it and looking for the next place to put something. That fit the way I preferred to work, and I kept using the PostScript form generation as the core of my business’s invoicing for a number of years.