Die Beliebtheit des DeskJet 500C von Hewlett Packard ist spätestens seit der CeBIT ’92 stark angestiegen. Doch leider ist die mitgelieferte Software nicht sehr ST-Benutzer-freundlich. Mit folgendem Programm lassen sich Bilder vom DEGAS.PI1-Format in Farbe ausdrucken.
Kaum hat man den Drucker ausgepackt, schon geht das Problem los. Die Handbücher verweisen den Benutzer, der nun gleich einen Farbaus-druck machen möchte, auf die mitgelieferte Software. Doch leider wird diese nur für DOS- bzw. Microsoft Windows angeboten. Lediglich einen müden Dreizeiler als Testfarbdruck kann man sofort erzeugen. Oder man strapaziert sein Farbband und erzeugt mittels Druckerdüsenreinigung einen mehrzeiligen Dreifarbausdruck. Der Nicht-nur-Anwender wirft natürlich sofort einen Blick in das Handbuch und entdeckt folgende Steuercodes, um die Farbpalette Cyan-Yellow-Magenta einzustellen:
027, 042, 114, 045, 051,055
Doch leider führen anschließende Grafikausgaben nicht zum Erfolg. Um es kurz zu machen: Die Befehlsfolge ist leider falsch angegeben, und das Umschalten zwischen den Farben in einer Zeile ist erst überhaupt nicht erwähnt. Aber solche Fehler finden sich leider in vielen Druckerhandbüchem. Doch abgesehen von diesem Manko hat man einen hervorragenden Dmcker vor sich, der, hat man seine Funktionsweise erst einmal durchschaut, wunderschöne Mehrfarbbilder erzeugen kann.
Jeder Grafikausgabe sollte eine Initialisierung vorausgehen, die den Drucker auf die folgenden Grafikdaten vorbereitet. Zunächst erfolgt das Umschalten auf die Cyan-Yellow-Magenta-Farbpalette (CYM-Palette):
027, 042, 114, 045, 051,085
Die Grafikauflösung kann zwischen 75, 100, 150 und 300 Punkten pro Zoll betragen. Dazu muß die Anzahl der Punkte pro Zoll in ASCII-Werte umgerechnet werden.
,75' : ,7' (ASCII = 55), ,5' (ASCII = 53) -> 055, 053
,300': ,3' (ASCII = 51), ,0' (ASCII = 48) -> 051, 048, 048
Die allgemeine Einstellung lautet: 027, 042,116, #...#, 082, wobei #.. .# die ASCII-Werte der Auflösung sind, also stellt die Befehlsfolge:
027, 042, 116, 051,048, 048, 082
den Drucker auf 300 Punkte pro Zoll ein. Der relative vertikale Pixel-Versatz nach jeder Grafikzeile (früher Y-Offset) muß auf ,0‘ (ASCII = 48) gesetzt werden
027, 042, 098, 048, 089
Die eigentliche Grafikausgabe erfolgt zeilenweise. Es gibt dafür zwei Grafikbefehle. Der eine veranlaßt den Drucker, in der gerade aktuellen Farbe zu drucken, bleibt aber anschließend in der Zeile, um ein erneutes Drucken mit der nächsten Farbe zu ermöglichen. Der Befehl lautet:
027, 024, 098, #...#, 118 (#...# = Anzahl der Bytes)
Der andere druckt in der aktuellen Farbe, führt anschließend aber zu einem Sprung in die nächste Grafikzeile, quasi einem Carriage-Return bei normalem Textausdruck vergleichbar. Er lautet:
027, 042, 098, #...#, 087
Zuerst druckt man in Cyan, dann in Magenta, schließlich in Yellow, darauf erfolgt die nächste Zeile. Dies erreicht man durch folgende Befehlsfolge:
027, 042, 098, #...#, 118 + Grafikdaten für Farbe Cyan
027, 042, 098, #...#, 118 + Grafikdaten für Farbe Magenta
027, 042, 098, #...#, 087 + Grafikdaten für Farbe Yellow
Durch Übereinanderdrucken der drei Grundfarben erhält man weitere vier Farben. Cyan und Yellow ergeben Grün, Cyan und Magenta ergeben Blau, Yellow und Magenta ergeben Rot, alle drei Farben zusammen ergeben Schwarz. Mit Weiß sind es somit acht, echte4 Farben. Vor dem Ausdruck jeder Grafikzeile muß dem Computer die Anzahl der Bytes mitgeteilt werden, die gedruckt werden sollen, wobei jedes Byte acht Punkten nebeneinander entspricht. Bit 7 entspricht dem linken, Bit 0 dem rechten Punkt. Dabei muß die Anzahl der Bytes zunächst wieder so in ASCII-Werte umgerechnet werden, wie dies bereits oben beschrieben wurde, also z.B.: 40 Punkte nebeneinander entsprechen 5 Bytes. Der ASCII-Wert von ,5‘ ist 53. Der Befehl würde lauten:
027, 042, 098, 053, 118 + 5 weitere Bytes
Um 320 Punkte zu drucken, hieße dies: 320 Punkte entsprechen 40 Bytes. ASCII-Wert von ,4‘ ist 52, ASCII-Wert von ,0‘ ist 48.
027, 042, 098, 052, 048, 118 + 40 weitere Bytes
An einem Beispiel soll diese Theorie nun noch einmal verdeutlicht werden. Es sollen alle acht Farben nebeneinander in der niedriegsten Auflösung gedruckt werden und zwar in folgender Reihenfolge: Weiß, Cyan, Magenta, Yellow, Blau, Grün, Rot, Schwarz. Zum Drucken von acht Punkten reicht ein Grafik-Byte. Zuerst wird in Cyan gedruckt, welche in den Farben Cyan (logisch), Blau, Grün und Schwarz enthalten ist. Es müssen also die Bits 6, 3, 2 und 0 gesetzt werden (siehe Bild 3). Man erhält den Dezimal wert ,77‘. Magenta ist in den Farben Magenta, Blau, Rot und Schwarz enthalten, also sind die Bits 5,3,1 und 0 zu setzen (siehe Bild 3), man erhält den Dezimalwert ,43‘.Yellow schließlich ist in den Farben Yellow, Grün, Rot und Schwarz enthalten. Dies entspricht den Bits 4, 2, 1 und 0 (siehe Bild 3), der Dezimalwert beträgt ,23‘. Somit führen zusammenfassend folgende Befehle zu dem Gewünschten:
027, 042, 114, 045, 051, 085
CYM-Farbpalette
027, 042, 116, 055, 053, 082
75 Punkte pro Zoll
027, 042, 098, 048, 089
Y-Offset auf ,0'
027, 042, 098, 049, 118, 077
Farbe Cyan
027, 042, 098, 049, 118, 043
Farbe Magenta
027, 942, 098, 049, 087, 023
Farbe Yellow
Hat man einmal die Sucht nach Farbe überhaupt befriedigt, entsteht schnell der Wunsch nach mehr Farben. In diesem Fall hilft es nur, durch geschicktes Nebeneinandersetzen und Mischen der acht Grundfarben das menschliche Auge zu überlisten. Um einen farbigen Bildschirmpunkt auzudrucken, verwende ich daher eine Matrix aus 6x6 Punkten, in der die acht Grundfarben so angeordnet sind, daß man den Eindruck einer neuen Farbe erhält.
Der ATARI-ST stellt seine 512 Farben aus den drei Farben Rot, Grün und Blau mit je acht Helligkeitsstufen zusammen (888=512). Den Wert einer Farbe nenne ich RGB-Wert, der somit Werte von 000 bis 777 annehmen kann. Doch wie können diese Farben jetzt mit Hilfe der Druckerfarben Cyan, Magenta und Yellow dargestellt werden?
Am einfachsten ist es, wenn man sich zunächst den Ausdruck der acht Grundfarben Weiß, Cyan, Magenta, Yellow, Blau, Grün, Rot und Schwarz überlegt. Farbe Weiß (RGB-Wert 777) würde bedeuten, daß der Drucker keine Farbe druckt, d.h. die Grafikdaten für Cyan, Magenta und Yellow bestünden also nur aus Nullen. Diese Druckerfarbanweisung nenne ich CMY-Wert (Cyan-Magenta-Yellow-Wert), also in diesem Falle: CMY-Wert = 000. Reines Rot hat den RGB-Wert 700, auf dem Drucker müßten die Farben Yellow und Magenta gedruckt werden. Der CMY-Wert erhält den Wert 077. Dabei bedeutet ,0‘ daß kein Cyan enthalten ist. Die erste ,7‘ steht vorerst für Magenta drucken, die zweite ,7‘ für Yellow drucken. Schwarz hat den RGB-Wert 000; da alle Druckerfarben miteinander gemischt werden müssen, um Schwarz zu erhalten, ist der CMY-Wert 777. Daraus folgt, daß sich die Farben Rot-Cyan, Grün-Magenta sowie Blau-Yellow komplementär zueinander verhalten, d.h. ist die Farbe Grün auf dem Bildschirm vorhanden, müssen Cyan und Yellow, nicht aber Magenta gedruckt werden. (Daher auch die Bezeichnung CMY und nicht CYM!). Damit sind bisher nur die acht Grundfarben berücksichtigt; wie sieht es aber mit den anderen 504 Farben aus?
Analog zu obiger Feststellung könnte man annehmen, daß eine Bildschirmfarbe, die Rot ganz, Grün zur Hälfte und kein Blau enthält, also den RGB-Wert 730 hat, den CMY-Wert 047 haben müßte, und tatsächlich liegt man mit dieser Überlegung goldrichtig. Doch was bedeutet ein CMY-Wert von 047 für den Drucker? Wie kann man, wenn ,0‘ bedeutet: ,keine Farbe drucken‘ und ,7‘ bedeutet: ,Farbe drucken1, den Wert ,4‘ drucken? Die Lösung heißt: man erstelle sich eine Matrix (oh Gott, schon wieder Mathematik), die die Werte 1 bis 7 enthält, z.B.
1742653
5317426
2653174
7426531
3174265
6531742
4265317
Diese Matrix (die allgemeine Druckermaske) gilt für jede der drei Druckerfarben. Hat Cyan wie im obigen Beispiel (CMY-Wert 047) den Wert ,0‘, bedeutet das, daß an keiner Stelle dieser Matrix die Farbe Cyan gedruckt werden soll. Magenta hat den Wert ,4‘, d.h. an allen Stellen der Matrix mit den Werten 1 bis 4 soll Magenta gedruckt werden. Yellow schließlich hat den Wert ,7‘, d.h. an allen Stellen der Matrix wird Yellow gedruckt. Anhand zweier grafischer Beispiele sei das Verfahren noch einmal verdeutlicht (siehe Bild 4). Jeweils links befindet sich die Originalfarbe mit zugehörigem RGB-Wert. Rechts daneben sieht man in abnehmender Auflösung die Farbe, wie sie vom Drucker anhand der Matrix erstellt wird. Man erkennt, wie nach und nach die vom Drucker erstellte ,Mischfarbe1 den Eindruck der linken Originalfarbe annimmt. Je kleiner ein Druckerpunkt, d.h. je besser die Druckerauflösung dabei ist, desto besser das Ergebnis.
Zunächst muß das Degas-PI1-Bild ab Speicheradresse filepos geladen werden. Diese Routine ist im Listing nicht enthalten. Sie kann auch von einem anderen Programm aus erfolgen, wichtig ist nur, daß am Ende ab Speicheradresse filepos das Bild im Speicher steht. Die ersten 32034 KBytes eines jeden Degas-PI1-Bildes sind für uns von Interesse. Die zwei ersten Bytes geben die Auflösung und die Speicherart (compressed oder uncompressed) an. Die folgenden 32 Bytes enthalten Informationen zu den 16 Farben, gefolgt von den 32000 Bytes für das eigentliche Bild.
Listing 1 enthält das Hauptprogramm. Da nicht jeder ST-Besitzer ohne weiteres knapp 1 MByte zur Verfügung stellen kann, die ein komplettes Bild belegen würde, wird immer eine Bildschirmzeile berechnet (bestehend aus 320 Bildpunkten, die aus jeweils 6x6 Druckerpunkten bestehen, das ganze für alle drei Druckerfarben) und diese ausgedruckt. Dadurch belegt das gesamte Programm nur maximal 70 KByte. Zunächst werden die Grundfarbmasken für die 16 Farben erstellt. Das sind jene Masken, die für jede der 16 Farben eine Matrix für jede der drei Druckerfarben enthalten. Somit braucht der Computer anschließend nur noch den Bildschirm Punkt für Punkt abzufragen und kann den Bildschirmpunkt entsprechend dieser Masken ausgeben (ab m2 stehen die allgemeinen Druckermasken, ab filepos2 die 16 Farben des Bildes, ab filepos3 das eigentliche Bild, ab/die fertigen Masken im Speicher). Dies geschieht ab schleife 11. Da der Drucker immer 8 Bits auf einmal ausgibt, die Druckermatrix für einen Bildschirmpunkt jedoch 6x6 Pixel enthält, müssen Teile der Punkte auf die zu druckenden Bytes verteilt werden. D.h. das erste gedruckte Byte enthält 6 Pixel des ersten Bildschirmpunktes und zwei Pixel des zweiten, das zweite Byte enthält die restlichen 4 Pixel des zweiten Bildschirmpunktes und die ersten vier Pixel des dritten Punktes, das dritte Byte enthält die letzten zwei Pixel des dritten Bildschirmpunktes und alle 6 Pixel des vierten Punktes. Danach wiederholt sich alles von vorne. Die Routinen, die dieses Verschieben berechnen, wiederholen sich zum Teil und sind daher gesondert abgedruckt (Listing 2 + 3). Sie sind an die entsprechende Stelle in das Hauptprogramm (siehe Listing 1) einzufügen. Hierzu gehe man wie folgt vor: Man gebe zunächst Listing 1 ein. An der Stelle, wo man auf die Listings 2 und 3 verwiesen wird, fahre man mit der Eingabe von Listing 2 fort. Dieses Listing 2 wird insgesamt viermal hintereinander benötigt. Die jeweiligen Unterschiede kann man dem Listing 3 entnehmen. D.h. an den Stellen A-G sind beim ersten Mal die Befehle von A1-G1 aus Listing 3 einzusetzen, beim zweiten Mal die Befehle A2-G2 usw. Am Ende fahre man mit der Eingabe von Listing 1 ab weiter8: fort.
Ab Schleife_8 schließlich wird die entsprechende Bildschirmzeile ausgedruckt. Listing 4 enthält die Unterprogramme, um das Bild zu zentrieren (ab leer), um eine bestimmte Anzahl von Zeichen zu drucken (ab druck) und um die Grundfarbmasken zu erstellen (ab mask).
Die entsprechenden Labels/Zeiger für verschiedene Zwischenspeicher, das eigentliche Bild (ab filepos), die Grundfarbmasken (ab f), Druckermasken für Cyan (d_0), Magenta (d_1) und Yellow (d_2) sowie die allgemeine Druckermaske (ab m2) sind in Listing 5 definiert.
Ich habe bewußt mehr Wert daraufgelegt, das Verfahren zu beschreiben als das Assembler-Listing. Auf GEM-Einbindung wurde verzichtet, um das Programm nicht unnötig in die Länge zu ziehen.
Durch die Einbindung eines Drucker-Spoolers könnte der Druckvorgang, der momentan bei ca. 15 Minuten/Bild liegt, im Hintergrund stattfinden. Noch interessanter wäre allerdings das Ausdrucken von Grafiken mit 512 Farben (z.B. Spektrum 512). Aufgrund der Länge des vollständigen Listings wurden hier nur die wichtigen Routinen abgedruckt. Das fertige Programm und das gesamte Listing findet sich auf der Monatsdiskette zur ST-Computer.
; Ausdruck von DEGAS-PI1-Bildern auf HP DeskJet 500C
; (c) 1992 MAXON Computer
; Listing 1
weiter: lea filepos2,A0
clr.w D0
schleife_1: clr.l D1
move.w (A0),D1
divu #256,D1
and.w #7,D1
move.w #7,D2
sub.w D1,D2
move.w #0,D1
bsr mask
clr.l D1
move.w (A0),D1
divu #16,D1
and.w #7,D1
move.w #7,D2
sub.w D1,D2
move.w #1,D1
bsr mask
clr.l D1
move.w (A0),D1
and.w #7,D1
move.w #7,D2
sub.w D1,D2
move.w #2,D1
bsr mask
adda.l #2,A0
addq.w #1,D0
cmp.w #16,D0
bne schleife_1
oben: lea drucker_inst,A0
move.w #23,D0
bsr druck
lea filepos3,A0
lea a_speich,A1
move.l A0,(A1)
clr.w D1
lea d_speich1,A1
schleife_11: move.w D1,(A1)
lea d_0,A1
move.w #4320,D1
schleife_6: clr.w (A1)
adda.l #2,A1
subq.w #1,D1
cmp.w #0,D1
bne schleife_6
clr.w D1
lea d_speich2,A1
schleife_10: move.w D1,(A1)
move.l #32768,D1
lea d_speich3,A1
move.l D1,(A1)
clr.w D1
lea d_speich4,A1
schleife_9: move.w D1,(A1)
lea d_speich3,A1
move.l (A1),D0
clr.w D2
lea a_speich,A1
movea.l (A1),A0
move.w 0(A0),D1
and.w D0,D1
cmp.w #0,D1
beq weiter1
move.w #1,D2
weiter1: move.w 2(A0),D1
and.w D0,D1
cmp.w #0,D1
beq weiter2
mulu #480,D3
lea d_2,A0
adda.w D3,A0
move.w #240,D0
bsr druck
addq.w #1,D1
cmp.w #6,D1
bne schleife_8
lea d_speich1,A1
move.w (A1),D1
addq.w #1,D1
cmp.w #200,D1
bne schleife_11
rts
; Ausdruck von DEGAS-PI1-Bildern auf HP DeskJet 500C
; (c) 1992 MAXON Computer
; Listing 2
;--> A
clr.w D1
;--> B
mulu #480,D2
clr.l D3
move.w (A2),D3
;--> C
adda.w #28,A2
lea d_0,A1
adda.w D0,A1
adda.w D2,A1
or.w D3,(A1)
;--> D
adda.w #28,A2
lea d_1,A1
adda.w D0,A1
adda.w D2,A1
or.w D3,(A1)
;--> E
adda.w #28,A2
lea d_2,A1
adda.w D0,A1
adda.w D2,A1
or.w D3,(A1)
;--> F
addq.w #1,D1
cmp.w #6,D1
;--> G
bra weiter8
; Ausdruck von DEGAS-PI1-Bildern auf HP DeskJet 500C
; (c) 1992 MAXON Computer
; Listing 3
A1 cmp.w #0,D2
bne weiter5
B1 schleife_12: move.w D1,D2
C1 lsl.w #2,D3
D1 move.w (A2),D3
lsl.w #2,D3
E1 wie D1
F1 leer
G1 bne schleife_12
A2 weiter5: cmp.w #2,D2
bne weiter6
B2 schleife_13: move.w D1,D2
C2 leer
D2 move.w (A2),D3
E2 wie D2
F2 leer
G2 bne schleife_13
A3 weiter6: cmp.w #4,D2
bne weiter7
B3 schleife_14: move.w D1,D2
C3 move.w D3,D4
lsr.w #2,D3
and.w #3,D4
lsl.w #6,D4
D3 adda.w #2,A1
or.w D4,(A1)
clr.l D3
move.w (A2),D3
move.w D3,D4
lsr.w #2,D3
and.w #3,D4
lsl.w #6,D4
E3 wie D3
F3 adda.w #2,A1
or.w D4,(A1)
G3 bne schleife_14
A4 weiter7:
B4 schleife_15: move.w D1,D2
C4 move.w D3,D4
lsr.w #4,D3
and.w #15,D4
lsl.w #4,D4
D4 adda.w #2,A1
or.w D4,(A1)
clr.l D3
move.w (A2),D3
move.w D3,D4
lsr.w #4,D3
and.w #15,D4
lsl.w #4,D4
E4 wie D4
F4 adda.w #2,A1
or.w D4,(A1)
G4 bne schleife_15
; Ausdruck von DEGAS-PI1-Bildern auf HP DeskJet 500C
; (c) 1992 MAXON Computer
; Listing 4
leer: move.w #30,D0
schleife_7: movem.l D0-D1,-(SP)
move.w #0,-(SP)
move.w #5,-(SP)
trap #1
addq.l #4,SP
movem.l (SP)+,D0-D1
subq.w #1,D0
cmp.w #0,D0
bne schleife_7
rts
druck: movem.l D0-D1/A0,-(SP)
move.w (A0),D1
move.w D1,-(SP)
move.w #5,-(SP)
trap #1
addq.l #4,SP
movem.l (SP)+,D0-D1/A0
adda.l #2,A0
subq.w #1,D0
cmp.w #0,D0
bne druck
rts
mask: clr.w D3
schleife_3: clr.w D4
schleife_2: move.w D3,D6
lsl.w #2,D6
move.w D6,D7
move.w D2,D6
mulu #80,D6
add.w D6,D7
lea m2,A1 <----
adda.w D7,A1
move.l (A1),D6
move.w D4,D5
weiter10: cmp.w #13,D5
beq weiter9
lsr.l #1,D6
addq.w #1,D5
bra weiter10
weiter9: and.w #63,D6 <----
move.w D4,D5
lsl.w #1,D5
move.w D5,D7
move.w D1,D5
mulu #28,D5
add.w D5,D7
move.w D3,D5
mulu #84,D5
add.w D5,D7
move.w D0,D5
mulu #1680,D5
add.w D5,D7
lea f,A2
adda.w D7,A2
move.w D6,(A2)
addq.w #1,D4
cmp.w #14,D4
bne schleife_2
addq.w #1,D3
cmp.w #20,D3
bne schleife_3
rts
; Ausdruck von DEGAS-PI1-Bildern auf HP DeskJet 500C
; (c) 1992 MAXON Computer
; Listing 5
a_speich: DC.L 0
d_speich1: DC.W 0
d_speich2: DC.W 0
d_speich3: DC.L 0
d_speich4: DC.W 0
drucker_inst: DC.W 27,38,108,48,72
DC.W 27,42,114,45,51,85,27
DC.W 42,116,51,48,48,82,27
DC.W 42,98,48,89
farb_1: DC.W 27,42,98,50,55,48,118
farb_2: DC.W 27,42,98,50,55,48,87
filepos: DC.W 0
filepos2: DS.B 32
filepos3: DS.B 32000
f: DS.B 27000
d_0: DS.B 2880
d_1: DS.B 2880
d_2: DS.B 2880
m2: DC.L 0,0,0,0,0,0,0,0,0,0
DC.L 0,0,0,0,0,0,0,0,0,0
DC.L 524320,1024,32770,64,2048
DC.L 65540,128,4096,131080,256
DC.L 8192,262160,512,16385,524320
DC.L 1024,32770,64,2048,65540
DC.L 589860,1152,36866,131144
DC.L 2304,73732,262288,4608
DC.L 147465,524576
DC.L 9216,294930, 576,184 33, 589860
DC.L 1152,36866,131144,2304,73732
DC.L 593956,132232,37122,139336
DC.L 264464,74244,278673,528928
DC.L 148489,557346
DC.L 9280,296978,66116,18561
DC.L 593956,132232,37122,139336
DC.L 264464,74244
DC.L 594468,148617,561442,140360
DC.L 297234,74308,280721,594468
DC.L 148617,561442
DC.L 140360,297234,74308,280721
DC.L 594468,148617,561442,140360
DC.L 297234,74308
DC.L 594532,150665,626982,140488
DC.L 301330,205388,280977,602660
DC.L 410777,561954
DC.L 156745,821554,75332,313491
DC.L 594532,150665,626982,140488
DC.L 301330,205388
DC.L 733804,413081,635686,419033
DC.L 826162,222797,838067,603748
DC.L 445595,627558
DC.L 158921,891190,206540,317843
DC.L 733804,413081,635686,419033
DC.L 826162,222797
DC.L 1048575,1048575,1048575
DC.L 1048575,1048575,1048575
DC.L 1048575,1048575,1048575
DC.L 1048575,1048575,1048575
DC.L 1048575,1048575,1048575
DC.L 1048575,1048575,1048575
DC.L 1048575,1048575