Bit-Image Graphics

See all articles from The Plotter v6 n1

At our after-the-meeting meeting last month, Dick challenged me to show how the bit-image graphics mode of a dot-matrix printer works. (He has a rather subtle method of getting additional input!)

Anyway, not being able to accept that anything is impossible, I went home and attacked the problem. I found that it would not be as easy as I had at first assumed. The resulting program is listed herein, I hope!

You need to realize that all printers, interfaces and software are NOT the same. I use the Aerco printer interface with an Epson FX series printer. Please check your manuals to be sure that the following will fit your hardware.

The first source of frustration was that my favorite printer driver will not properly send printer control codes. I then discarded Jack Dohany’s relocatable driver and loaded in the Aerco driver. I never use the Aerco driver but, it came to the rescue.

I wrote the program as a series of subroutines in order to allow you to easily customize it to your needs. The demonstration program shows how you could send the first UDG (USR “A”) to the printer. It is very slow and could benefit from a conversion to assembly language but I resisted the urge in order to keep the technique where most would understand it.

You may notice that the listing was run on a TS2040 printer. This due to the fact that neither of my large printer drivers adequately handles the expansion of Timex keywords. You may also notice the fat lettering. Next month, I will give you an extremely short routine to create these characters.

Lines 10 and 20 LOAD in and setup my Aerco driver. The POKEs to 26703 and 26704 are to correct the channel information, so that LPRINT commands can find and use the Aerco driver. The POKE to 64456 changes the driver to accept printer control codes and the raw data we will send it.

Line 30 jumps to the main routine at line 1000.

Lines 100 to 140 convert any decimal number, N, into a binary string.

Lines 200 to 250 change any 8 character binary string, T$, into a decimal number.

Lines 1000 to 1050 get the UDG codes and call the subroutine at line 100 to convert the data to BINary strings. This is necessary as the binary digits represent the pixel information that would be printed to the screen. Line 1060 is a test line that I left in to show what is happening.

Lines 1100 to 1140 rotate the binary strings by 90 degrees in order to get the pixel information oriented as the printer needs to receive it. More on this in a minute. Line 1150 is another test line that I did not remove.

Lines 1200 to 1240 call the subroutine at 200 to calculate the decimal equivalent of our rotated strings (see the previous paragraph).

Lines 1300 to 1330 send the calculated decimal pixel information to the printer as bit-image data. I have the entire operation in one line as it needs to happen in the precise order and manner indicated.

The LPRINT CHR$ 27;”K”;CHR$ 8; CHR$ 0; command must end with a semi-colon. The CHR$ 8 and CHR$ 0 work together as a 16 bit count of the pixel columns, NOT character columns. In my example, I am only printing one character block, which is 8 pixel columns.

The LPRINT statement that sends the pixel data to the printer must also end with a semi-colon. This is to prevent the sending of a line-feed/carriage return which would terminate the line prior to completion of the pixel data transmission.

Again, the bit-image command may be different for your printer so, consult your printer manual. Many manuals are not very clear but, if you follow the instructions exactly as presented, you will be rewarded.

Now, why all the string manipulation and rotating? This is needed as the printer has vertical pins and prints each character in vertical rows as the print head moves across the paper. Unfortunately, the pixel information is stored in our computers as the horizontal pixel information that we see on the screen.

Additionally, the computer stores the pixel information in 8 bit bytes, whose values can be determined by multiplying the set bits by descending powers of 2 (see figure 1), from left to right. The printer needs its pixel information in a vertical columns of 8 bits and uses the same scheme of powers of 2 but, from top to bottom (see figure 2).

I know this sounds confusing but spend some time with the demonstration program and your printer manual and you will find it is not as complicated as it sounds.

Syd

  10 CAT "PrtCode.bin",:
REM Load in printer driver

20 POKE 26703,205: POKE 26704,
251: POKE 64456,0:
REM Set up printer driver
30 GO TO 1000
100 REM Make a binary number
from the UDG's
110 LET T$="00000000"
120 FOR i=7 TO 0 STEP -1
130 LET N=PEEK L: GO SUB 100
140 NEXT I: RETURN
200 REM Make a decimal number
from a binary string
210 LET T$=P$(L): LET A=0
220 FOR I=7 TO 0 STEP -1
230 IF T$(1)="1" THEN LET A=A+2
^I
240 LET T$=T$(2 TO )
250 NEXT I: RETURN
1000 REM Get one UDG's info
1010 DIM B$(8,8): LET C=1
1020 FOR L=USR "A" TO USR "A"+7
1030 LET N=PEEK L: GO SUB 100
1040 LET B$(C)=T$: LET C=C+1
1050 NEXT L
1060 FOR I=1 TO 8: PRINT B$(I):
NEXT I: PRINT "A"
1100 REM turn UDG info sideways
by 90 degrees
1110 DIM P$(8,8)
1120 FOR J=1 TO 8: FOR I=1 TO 8
1130 LET P$(J,I)=B$(I,J)
1140 NEXT I: NEXT J
1150 FOR I=1 TO 8: PRINT P$(I):
NEXT I: PRINT "A"
1200 REM Get print wire info
1210 DIM P(8)
1220 FOR L=1 TO 8
1230 GO SUB 200: LET P(L)=a
1240 NEXT L
1300 REM Now we can print it!
1310 LPRINT :
REM Empty printer buffer
1320 LPRINT CHR$ 27;"K";CHR$ 8;C
HR$ 0;: FOR I=1 TO 8: LPRINT CHR
$ p(I);: NEXT I
1330 LPRINT :
REM Empty printer buffer
7898 STOP
7899 MOVE "TestDick1.bas",1
                         Figure 1

Bit numbers    =   7   6   5   4   3   2   1   0
                 +---+---+---+---+---+---+---+---+
Pixel contents = | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | = 9Ch
                 +---+---+---+---+---+---+---+---+
Bit values     = 128  64  32  16   8   4   2   1

As you can see, the bit values are descending powers of 2 which range from 2^7 on the left, to 2^0 on the right. The decimal equivalents are given as bit values. Any byte’s decimal value can be calculated by adding the bit values for each of the set bits (the 1’s). In this example, the byte contains 128+16+8+4 or 156.

          Figure 2

  Pin       Pixel       Pin
numbers   contents     values
           +---+
   7       | 1 |         128
           +---+
   6       | 0 |          64
           +---+
   5       | 1 |          32
           +---+
   4       | 1 |          16
           +---+
   3       | 0 |           8
           +---+
   2       | 1 |           4
           +---+
   1       | 0 |           2
           +---+
   0       | 1 |           1
           +---+

The value of the pixels are 128+32+16+4+1 or 181, in this example. The printer sends pin fireing commands to the print head as vertical slices of data, as demonstrated. Assume that the pixels (bytes) in figures 1 and 2 are part of your favorite UDG which is coincidentally shown in figure 3. Can you see how we sliced of the first row of pixel data for the printer?

     Figure 3

1 0 0 1 1 1 0 0
0 0 1 1 1 0 0 0
1 1 1 1 0 0 0 0
1 1 1 1 0 0 0 0
0 0 1 1 1 0 0 0
1 1 1 1 0 0 0 0
0 1 1 1 1 0 0 0
1 1 1 1 0 0 0 0

Pixel data of your favorite UDG.

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.