Dot matrix printing

From XPUB & Lens-Based wiki

Dot-matrix printing as pedagogical devices

Today we will work with the dot-matrix printers as pedagogical devices.

And zoom into the layers of "languages" that are at play when producing graphics and layout produced with text.

BUT. Computers don’t actually work with text.
Computers are calculators that work with numbers.

This means that any kind of input to the computer and any kind of output from the computer exists as numbers somewhere in between.

To explore the layers and complexities of these encoding and decoding processes and the politics that these systems are entangled with, dot-matrix printers are great to work with.

What can we learn from the printers today? Which questions come up?

Dot-matrix materiality

What is the materiality of dot-matrix printers?

Before was the daisy wheel printer (close to typewriter), but with the dot-matrix printers work with a printer head and pins.. so you can make your own characters. Which helped to promote it and sell it internationally. Other character cards were also distributed, with fonts etc, which you could load into your printer.

EXERCISE: Warm up and turn the printers on

Taking an exploratory approach...

  1. Pick one printer
  2. Print the self-tests of the machine (see #Howto section below)
  3. Print the menu with the current settings (see #Howto section below)

Now, let's try to talk with printer from a computer.

  1. Connect to the printer, you can follow the #Howto section below.
  2. Once you are connected, print some words or plain text files from the command line. See which command works for you:
$ echo "hello" > /dev/usb/lp1
$ echo "hello" | lp
$ lpr hello.txt

What language does the printer speak?

Let's zoom into the text we just sent to the printer...

We just sent hello to the printer... so the characters h, e, l, l, o.

But good to know is... that when you send these characters.. you are actually not sending the character itself, you are sending a number.

Your computer and the printer both have their own understanding of characters.. They represent each character with a number. a often is represented by 97 for example these days (and there is a reason for that)!

But back in the days.. the different machines that were made represented characters in all different ways, each device did it differently. When the moment came that there was a need to send text from device A to device B, it was clear that this needed to be resolved somehow, and that there was a need for a shared way to represent characters.

And this is why we have: 💀encoding systems💀

ASCII imperialism

One famous one... is... ASCII, first published in 1963.

$ man ascii
  Binary      Dec   Hex   Char                        Binary      Dec   Hex   Char
  ────────────────────────────────────────────────────────────────────────────────
  0000 0000   0     00    NUL '\0' (null character)   0100 0000   64    40    @
  0000 0001   1     01    SOH (start of heading)      0100 0001   65    41    A
  0000 0010   2     02    STX (start of text)         0100 0010   66    42    B
  0000 0011   3     03    ETX (end of text)           0100 0011   67    43    C
  0000 0100   4     04    EOT (end of transmission)   0100 0100   68    44    D
  0000 0101   5     05    ENQ (enquiry)               0100 0101   69    45    E
  0000 0110   6     06    ACK (acknowledge)           0100 0110   70    46    F
  0000 0111   7     07    BEL '\a' (bell)             0100 0111   71    47    G
  0000 1000   8     08    BS  '\b' (backspace)        0100 1000   72    48    H
  0000 1001   9     09    HT  '\t' (horizontal tab)   0100 1001   73    49    I
  0000 1010   10    0A    LF  '\n' (new line)         0100 1010   74    4A    J
  0000 1011   11    0B    VT  '\v' (vertical tab)     0100 1011   75    4B    K
  0000 1100   12    0C    FF  '\f' (form feed)        0100 1100   76    4C    L
  0000 1101   13    0D    CR  '\r' (carriage ret)     0100 1101   77    4D    M
  0000 1110   14    0E    SO  (shift out)             0100 1110   78    4E    N
  0000 1111   15    0F    SI  (shift in)              0100 1111   79    4F    O
  0001 0000   16    10    DLE (data link escape)      0101 0000   80    50    P
  0001 0001   17    11    DC1 (device control 1)      0101 0001   81    51    Q
  0001 0010   18    12    DC2 (device control 2)      0101 0010   82    52    R
  0001 0011   19    13    DC3 (device control 3)      0101 0011   83    53    S
  0001 0100   20    14    DC4 (device control 4)      0101 0100   84    54    T
  0001 0101   21    15    NAK (negative ack.)         0101 0101   85    55    U
  0001 0110   22    16    SYN (synchronous idle)      0101 0110   86    56    V
  0001 0111   23    17    ETB (end of trans. blk)     0101 0111   87    57    W
  0001 1000   24    18    CAN (cancel)                0101 1000   88    58    X
  0001 1001   25    19    EM  (end of medium)         0101 1001   89    59    Y
  0001 1010   26    1A    SUB (substitute)            0101 1010   90    5A    Z
  0001 1011   27    1B    ESC (escape)                0101 1011   91    5B    [
  0001 1100   28    1C    FS  (file separator)        0101 1100   92    5C    \  
  0001 1101   29    1D    GS  (group separator)       0101 1101   93    5D    ]
  0001 1110   30    1E    RS  (record separator)      0101 1110   94    5E    ^
  0001 1111   31    1F    US  (unit separator)        0101 1111   95    5F    _
  0010 0000   32    20    SPACE                       0110 0000   96    60    `
  0010 0001   33    21    !                           0110 0001   97    61    a
  0010 0010   34    22    "                           0110 0010   98    62    b
  0010 0011   35    23    #                           0110 0011   99    63    c
  0010 0100   36    24    $                           0110 0100   100   64    d
  0010 0101   37    25    %                           0110 0101   101   65    e
  0010 0110   38    26    &                           0110 0110   102   66    f
  0010 0111   39    27    '                           0110 0111   103   67    g
  0010 1000   40    28    (                           0110 1000   104   68    h
  0010 1001   41    29    )                           0110 1001   105   69    i
  0010 1010   42    2A    *                           0110 1010   106   6A    j
  0010 1011   43    2B    +                           0110 1011   107   6B    k
  0010 1100   44    2C    ,                           0110 1100   108   6C    l
  0010 1101   45    2D    -                           0110 1101   109   6D    m
  0010 1110   46    2E    .                           0110 1110   110   6E    n
  0010 1111   47    2F    /                           0110 1111   111   6F    o
  0011 0000   48    30    0                           0111 0000   112   70    p
  0011 0001   49    31    1                           0111 0001   113   71    q
  0011 0010   50    32    2                           0111 0010   114   72    r
  0011 0011   51    33    3                           0111 0011   115   73    s
  0011 0100   52    34    4                           0111 0100   116   74    t
  0011 0101   53    35    5                           0111 0101   117   75    u
  0011 0110   54    36    6                           0111 0110   118   76    v
  0011 0111   55    37    7                           0111 0111   119   77    w
  0011 1000   56    38    8                           0111 1000   120   78    x
  0011 1001   57    39    9                           0111 1001   121   79    y
  0011 1010   58    3A    :                           0111 1010   122   7A    z
  0011 1011   59    3B    ;                           0111 1011   123   7B    {
  0011 1100   60    3C    <                           0111 1100   124   7C    |
  0011 1101   61    3D    =                           0111 1101   125   7D    }
  0011 1110   62    3E    >                           0111 1110   126   7E    ~
  0011 1111   63    3F    ?                           0111 1111   127   7F    DEL

Thanks to the power of the US Military and US corporations the American computing industry became the global computing industry. Computers that we use today are rooted in American networking history, and so is the ASCII standard. However, the reality is that ASCII can only represent 26 Latin letters in the English alphabet but computers are used all over the world, by people speaking different languages. They would often end up with American computers that could not represent their language in ASCII. Think for example of scripts like Greek, Cyrillic and Arabic or even Latin scripts that use accents such as the ü or ø. Altough 128 might sound like a lot of characters, it is not enough to represent all different languages.[1]

As you can see in the table above, it lists all sorts of characters, also ones that are not represented on our keyboards (like "ESC").

Some of these are legacy characters from a teletype/typewriter past.. Like the "bell" character.

In order to type these characters, like a line feed character (LF), you use the code point representation of that particular character.

For a time people used the 8th bit, numbers 1000 0000 to 1111 1111 (or 128 to 256) to encode the specific parts of their own language. That way there was an overlap with ASCII but the own language could also be encoded.[2]

ASCII exercise

  • take a piece of paper and a pen, and:
    • count to 10 in decimal
    • count to 10 in binary
    • count to 10 in hex

Unicode universalism

The Unicode Standard supports three character encoding forms: UTF-32, UTF-16, and UTF-8. Each encoding form maps the Unicode code points U+0000..U+D7FF and U+E000..U+10FFFF to unique code unit sequences.[3]

Let's explore these code points!

In Python, you can use the chr() function to print Unicode code points. You give it a decimal.

chr(97)

returns: "a"

And if you want to find the code point of a character, you can use ord():

ord("a")

returns: 97

You can explore all the code points, which are organized in code blocks, here:

Unicode exercise

  • let's print U+0000 until U+D7FF and U+E000 until E+10FFFF with python
  • first convert the numbers of the code blocks from hex to decimal
  • then loop through these blocks by printing them

Extra

  • some characters are printed as (so-called) "tofu's".. install a font that has coverage (glyphs) for these characters, like Unifont!
  • find a nice range of code points and make a small terminal animation in python

Model specific printer commands

Each printer comes with a different set of special commands, different character sets and different fonts.

The special commands can change the behavior of the printer (like superscript, bold, alignment, and even loops!).

To switch to italic for instance on the NEC P60, you need to send esc and 4. And to send the esc key in hex in Python, you send: chr(27).

To find these special commands... we need to dive into the specific manual of a printer.

The character set of a printer can be changed, to support different languages. Each printer supports a different range of character sets.

And of course, each printer comes with different fonts installed. And some of them have the option to install extra fonts using a card ridge.

Printer commands exercise

  • pick a dot-matrix printer to work with
  • use the python script below to send a "hello" to the printer
  • find the manual of the printer and find the list of special commands this printer can work with
  • work with the special commands using your python script
    • we can't type these special commands with our keyboards directly, but we can execute them using the hex code points listed in the manual!
    • use chr() and the hex code point and see what they do
  • pick one special command and try to make a prototype with it (use it to draw something, make a playful layout, a mini poem, etc!)
msg = "hello"

# Linux/OSX?
printer = open("/dev/usb/lp1", "w")
printer.write(msg)
printer.close()

# Windows/OSX
import os
printer = open("tmp.txt", "w")
printer.write(msg)
printer.close()
cmd = "lpr tmp.txt"
#cmd = "cat tmp.txt | lp"
os.system(cmd)

Control individual pins

Exciting thing to try one day: There are also special commands to control the individual pins (!).

This means that you can print without using a driver. A driver translates the pixelated image into the pins of the printer.

Here you can find dithering strategies to convert an image into a type of image that could be printed on the dot-matrix printer.

So dithering was a technical limitation. These days, it's often an aesthetic choice, which is different.

Dot-matrix printers @ XPUB

OKI Microline 320

Oki-microline-320.png

Test report 5 Feb 2025:

Joseph and Manetta tried to get this printer to work, we changed the settings to match the NEC printer, but this did not help.

Current intuition is that it is a hardware issue.

NEC PINWRITER P60

Screenshot from 2025-02-05 13-35-48.png

This printer has 21 pins. One is broken, you can see it.

In the back there are magnets, one for each pin, and when the electricity hits the magnet, the pin is being activated or not.

There are 2 rows of pins, one is slightly shifted (you can see it!), which makes the resolution higher. It is divided into 2 rows, because there is no mechanical space to have so many pins so narrowly next to each other in one row.

The printer works with 80 columns.

NEC PINWRITER P20

NEC-Pinwriter-P20.jpg

Running the self test: see page 5 in the manual (page 13 in the pdf)

Printing the menu with current settings: see page 17 in the manual (page 25 in the pdf) [SELECT + Power on]

Citizen Swift 90e

Citizen-swift-90-printer.jpg

The printer works, but the continuous paper feed (for the paper with holes on the sides) is a bit slippery, so you need to help the printer a bit sometimes. If you use the external paper feed adapter and work with A4, it's much smoother.

Did manage to print test pages and the menu! But did not manage to change the settings in the menu... the printer gives an error.

How to print test pages? See page 29 in the manual: Printer Self-Tests.

How to print the menu? See page 25 in the manual: Making A Print Out Of The Printer’s Default Settings.

More info on codepages? See page 32 in the manual: Codepages - International Characters.

Sending printer control commands works when you use the build-in Epson FX1170 emulation (found this in the technical sheet). See Epson FX1170 manual chapter 8 "Command Summary" for a listing of special commands.

Star SG-10

Star-SG-10.jpg

The language in the manual is funny, very conversational :).

You can switch between character sets, "modes" and character pitch (size) using the dip switches. See page 133 in the manual.

Howto

Printing on OSX

Using CUPS:

  1. Connect the printer with the USB cable
  2. Install the printer with CUPS, go to http://localhost:631 in your browser and select Administration → Add printer
  3. Select "Unknown" in the Local Printers section
  4. You can add a "name" and "location", mostly for yourself, so you can find the printer back later.. "connection" should say something like: usb://USB2.0-Print/
  5. For "make" (which is the manufacturer) you select "Generic" and for "model" you select "Generic Text-Only Printer", click "Add Printer"
  6. Your printer is installed!
  7. Now go to "Printers" and select your printer
  8. Now make this printer your default printer: click on "Administration" and select "Set as server default"
  9. You can now send files to the printer with: $ lpr myfile.txt or $ echo "hello" | lp

Backup option, without CUPS:

  1. Connect the printer with the USB cable.
  2. Go to System Settings → Printers → Add printer
  3. Select the USB one (the printer will start to print stuff, don't worry, you can ignore this)
  4. Choose "General PostScript printer" (even though this is not true!)
  5. Make the printer your default printer
  6. You can now send files to the printer with: $ lpr -o raw myfile.txt or $ echo "hello" | lp -o raw

Printing on Windows

Once installed, you should be able to send files to the printer with:

> lpr myfile.txt

But! This only prints files, not output of commands like echo.. But maybe there is a way.. this might work, it looks like it's worth a try:

Claudio's notes

First things first, I used the "CITIZEN Swift 90e" printer. On Windows I had multiple unexpected errors but after all Joseph helped and we did not end up using lpr but we used the Out-Printer command.

and the final commands were:

cat yourfile.txt | Out-Printer

or to write directly a string avoiding using a file:

"The text you want to print" | Out-Printer

Printing on Linux

Search for the printer by running this command with the USB cable unplugged and plugged:

$ ls /dev/usb/

Mine appears at: /dev/usb/lp2

Then send stuff to the printer by using > /dev/usb/lp2, so for instance:

$ echo "hello" > /dev/usb/lp2
$ cat hello.txt > /dev/usb/lp2

Or, if you install the printer with CUPS and make it the default printer on the system (see above at OSX section), you can use:

$ cat hello.txt | lp
$ lpr hello.txt

ASCII art

jp2a

lightweight tool to convert images into ascii, written by Christian Stigen Larsen

https://web.archive.org/web/20200517095853/https://csl.name/jp2a/

$ jp2a

Examples

Testing the PINWRITER P60 (during SI26)

linefeed = chr(10)
tab = chr(11)
italic = chr(27) + chr(4) # does not work
linespacing_big = chr(27) + chr(48)
linespacing_small = chr(27) + chr(50)
superscript = chr(27) + chr(83) + chr(0)
subscript = chr(27) + chr(83) + chr(1)
condensed = chr(27) + chr(15)
spacing_wide = chr(27) + chr(32) + chr(127) # 0 - 127
loop_start = chr(27) + chr(86) + chr(255) # 0 - 255
loop_stop = chr(27) + chr(86) + chr(0)

# printer = open("NEC_PINWRITER_P60", "w")
printer = open("/dev/usb/lp2", "w")
# printer.write("hello\n")
printer.write(loop_start + "hello " + loop_stop)
# printer.write("hello\n")
printer.close()

Pruning Station with Irmak and Aglaia (SI19)

The magic of scanner, OCR and dotmatrix printer

Pruning Station in progress

See: How_do_We_Library_That???#Pruning_Station_with_Irmak-_The_magic_of_scanner,_OCR_and_dotmatrix_printer

Python script to scan a page from a book, apply OCR (optical character recognition) and print it on the dot matrix printer.

import os
print("starting the pruning process")
scanning = "sudo scanimage --resolution 300 --mode color -o image.png"
os.system(scanning)
os.system("tesseract  image.png text.txt -l eng")
fantasyname = open("text.txt.txt" , "r")
fantasyname = fantasyname.readlines() 
for line in fantasyname: 
    line = line.split(" ")
    for l in line:
        if l!="" or l != ['\n', '\r\n']:            
            print(l)
            os.system("echo '"+l+"' > /dev/usb/lp0")

Related links

Footnotes