Nicht immer ist der gesamte Bildschirminhalt für eine Hardcopy interessant. Oft würde es genügen, nur den Inhalt der aktuellen Dialogbox auf dem Drucker wiederzugeben. Auf den altbekannten Desktop-Hintergrund kann man ja bei der Ausgabe verzichten. PRINTBOX erweitert die im ATARI ST eingebaute Hardcopy-Routine um diese Möglichkeit.
Eigentlich hatte ich mir die Programmierung einer erweiterten Hardcopy-Routine recht einfach vorgestellt. Das war sie im Prinzip auch, die Tücke steckte jedoch in der vom Betriebssystem zur Verfügung gestellten PRTBLK-Funktion des XBIOS. Mit ihrer Hilfe sollte es möglich sein, einen beliebigen Bildschirmausschnitt auf dem Drucker auszugeben. Dazu muß PRTBLK mit einem Parameterblock versehen werden, der folgenden Aufbau hat:
long blkprt | Startadresse des auszudruckenden Ausschnitts |
int offset | Offset relativ zur Startadresse |
int width | Breite des Ausschnitts in Pixeln |
int height | Höhe des Ausschnitts in Pixeln |
int left | linker Rand in Pixeln |
int right | rechter Rand in Pixeln |
int scrrez | Bildschirmauflösung |
int prrez | Druckerauflösung |
int colpal | Pointer auf Farbpaiette |
int type | Druckertyp (ATARI/Epson) |
int port | Drucker-Port (parallel = 0, seriell = 1) |
long mask | Pointer auf Halbtonmaske |
Wie man sieht, bietet die PRTBLK-Funktion vielfältige Möglichkeiten. Wichtig ist, daß die Summe von “width”, “left” und “right” die Anzahl der Pixel pro Rasterzeile in der aktuellen Auflösung ergibt. Andernfalls erinnert der Bildschirmausdruck an gewisse Richtungen moderner Kunst: Was es sein soll, kann niemand so recht sagen. Die Druckerauflösung entspricht der “Qualität”-Einstellung in der Druckeranpassung. Als Farbpalette benutzt PRINTBOX die aktuelle Farbpalette ab SFF8240. So weit gab es mit den Parametern keine Probleme. Allerdings war da noch die sogenannte “Halbtonmaske”..
Welche Aufgabe diese Maske genau erfüllt, konnte ich anhand der mir zur Verfügung stehenden Literatur nicht ermitteln, da die PRTBLK-Funktion stets nur sehr unzureichend beschrieben ist. Vermutlich hat die Halbtonmaske etwas mit der Umsetzung der Bildschirmfarben auf den Druckertyp zu tun. Gibt man hier einen Null-Pointer vor, wählt das XBIOS automatisch eine im System definierte Default-Halbtonmaske aus. Das sollte mir bei der Programmierung gerade recht sein, so daß ich in der ersten Programmversion mit dieser Default-Maske arbeitete. Leider mußte ich feststellen, daß die Ausdrucke zwar die gewünschte Dialogbox darstellten, daß jedoch der rechte Rand der Box oft nur unvollständig vorhanden war (siehe Ausdruck 1). Es hatte den Anschein, als ob die Druckerausgabe innerhalb einer Zeile nach einer gewissen Anzahl nicht gesetzter Pixel einfach abgebrochen wurde. Ob hier ein Fall falsch verstandener Optimierung des Ausdrucks vorliegt? Ein plausibler Grund für einen vorzeitigen Abbruch der Druckzeile war jedenfalls nicht vorhanden. Ein Blick ins ROM-Listing (ATARI ST intern) sollte da eigentlich weiterhelfen. Das einzige, was es dort jedoch zu sehen gab, waren viele überflüssige Assembler-Befehle in undurchsichtigen Befehlssequenzen. Fazit: Ein C-Compiler hatte wieder einmal zugeschlagen. Dennoch war zu erkennen, daß es einen Unterschied bezüglich der Druckbreite macht, wenn man statt der Default-Halbtonmaske eine eigene Komposition verwendet. Deshalb gab ich PRTBLK eine Maske mit auf den Weg, die keinen Unterschied zur Default-Maske aufweist. Halt, fast hätte ich es vergessen: Ein Unterschied kam doch zum Vorschein. Nun war die Hardcopy nämlich fehlerfrei (siehe Ausdruck 2). Welchen Sinn es macht, daß die interne Halbtonmaske anders behandelt wird als eine eigens erstellte, auch wenn beide Masken gleich aufgebaut sind, konnte ich nicht klären. Vielleicht ist hier ein Leser fündig geworden.
Soweit meine Ergüsse zum Thema “Halbtonmaske”. Der eigentliche Programmablauf sieht nun folgendermaßen aus:
Bei jedem form_dial-Aufruf überprüft PRINTBOX, ob Bildschirmspeicher für eine Dialogbox reserviert werden soll. Ist dies der Fall, merkt sich das Programm die Koordinaten sowie Breite und Höhe der Box in ihrer größten Größe. Wird die Tastenkombination SHIFT/ALTERNATE/HELP betätigt, und ist eine Dialogbox auf dem Bildschirm vorhanden, holt sich PRINTBOX die aktuelle Druckereinstellung und ruft anschließend PRTBLK auf, um eine Hardcopy der Box zu machen. Befindet sich keine Box auf dem Bildschirm, geschieht nichts.
Nun noch ein paar Worte zu den vom Programm geänderten Systemvektoren. Die Werte der alten Vektoren merkt sich PRINTBOX innerhalb einer sogenannten XBRA-Struktur. Speziell bei residenten Programmen können sich auf diese Weise installierte Programme leicht wieder aus einer Vektorkette ausklinken oder erkennen, ob sie bereits installiert sind. Voraussetzung ist jedoch, daß jedes Programm für veränderte Systemvektoren eine XBRA-Struktur zur Verfügung stellt. Nähere Informationen hierzu finden sich im ATARI ST Profibuch (SYBEX-Verlag).
Soweit die wichtigsten Erläuterungen zum Programm. Abschließend noch ein Hinweis für die Besitzer von 24-Nadeldruckern. Möglicherweise gibt es bei diesen Druk-kern Schwierigkeiten beim Ausdruck. Da der ST Hardcopies auf 24-Nadeldruckern nicht vernünftig unterstützt, geschieht ein Bildschirmausdruck normalerweise über ein spezielles Druckprogramm. Damit PRINTBOX seine Aufgabe erfüllen kann, muß der geladene 24-Nadeltreiber nicht nur in der Lage sein, eine Hardcopy des gesamten Bildschirms zu machen, sondern er muß zusätzlich die PRTBLK-Funktion des XBIOS unterstützen. Dieses dürfte jedoch nicht bei allen Treibern der Fall sein.
**************************
* PRINTBOX V1.00 *
* (C) 1988 by Uwe Seimet *
* Buchenlochstrasse 29 *
* 6750 Kaiserslautern *
**************************
GEMDOS = 1
PTERMRES= $31
MSHRINK = $4a
XBIOS = 14
SETPRT = 33
PRTBLK = 36
SUPEXEC = 38
sshiftmd = $44c
_v_bas_ad= $44e
_dumpflg = $4ee
_sysbase = $4f2
dump_vec = $502
text
move.l sp,a0
move.l 4(a0),a0 ;Pointer auf Basepage
move.l 12(a0),a6 ;Länge des TEXT-Segments
add.l 28(a0),a6 ;Länge des BSS-Segments
lea $100(a6),a6 ;Länge der Basepage
pea setvec(pc)
move #SUPEXEC,-(sp)
trap #XBIOS ;neue Systemvektoren setzen
addq.l #6,sp
clr -(sp)
move.l a6,-(sp)
move #PTERMRES,-(sp)
trap #GEMDOS ;zurück zum Desktop
setvec:
move.l _sysbase,a0 ;Pointer auf Systemheader
cmp #$0102,2(a0) ;altes TOS?
bcs.s oldtos ;ja-
move 38(a0),shift ;Adresse der kbshift-Variablen ab TOS 1.2
oldtos: move.l $088,gem-4
move.l #gem,$088
move.l dump_vec,hardcopy-4
move.l #hardcopy,dump_vec
rts
dc.b "XBRA"
dc.b "PBOX" ;Programmkennung für XBRA
dc.l 0
gem:
cmp #$c8,d0 ;AES-Aufruf?
bne.s oldgem ;nein-
move.l d1,a0 ;Pointer auf AES-Arrays
move.l (a0),a1 ;Pointer auf CONTROL-Array
cmp #51,(a1) ;form_dial?
bne.s oldgem ;nein—
move.l 8(a0),a1 ;Pointer auf INTIN-Array
tst (a1) ;Bildschirm reservieren?
beq.s reserve ;ja_
cmp #3,(a1) ;Bildschirm freigeben?
bne.s oldgem ;nein-
clr.l width
bra.s oldgem
reserve:move.l 10(a1),xy ;Koordinaten der Dialogbox
move.l 14(a1),width ;Breite und Höhe
oldgem: move.l gem-4(pc),a0
jmp (a0) ;weiter im GEM
dc.b "XBRA"
dc.b "PBOX" ;Programmkennung für XBRA
dc.l 0
hardcopy:
move shift(pc),a0
move.b (a0),d0 ;Status der Shift-Tasten
and.b #3,d0 ;Shift-Taste gedrückt?
bne.s boxcopy ;ja-
move.l hardcopy-4(pc),a0
jmp (a0) ;zur alten HC-Routine
boxcopy:tst.l width ;Dialogbox vorhanden?
beq nocopy ;nein-
move #-1,-(sp)
move #SETPRT,-(sp)
trap #XBIOS ;Druckerkonfiguration holen
addq.l #4,sp
move d0,d1
lsr #3,d1
and #1,d1
move d1,prrez ;Druckerauflösung
move d0,d1
lsr #4,d1
and #1,d1
move d1,port ;Druckerport
lea prtypes(pc),a0
and #7,d0
move.b (aO,d0),d0
move d0,type ;Druckertyp
move d7,-(sp)
clr d7
move.b sshiftmd,d7
move d7,scrrez ;Bildschirmauflösung
move xy,d0
move d0,left ;linke Ausschnittsbegrenzung
add width,d0
move #320,d1 ;320 Pixel pro Zeile annehmen
tst d7 ;niedrige Auflösung?
beq *+4 ;ja-
add d1,d1 ;sonst 640 Pixel pro Zeile
sub d0,d1
move d1,right ;rechte Ausschnittsbegrenzung
move xy+2,d0 ;y-Koordinate der Box
cmp #2,d7 ;hohe Auflösung7
beq *+4 ;ja-
add d0,d0 ;160 Bytes pro Pixelzeile
mulu #80,d0
moveq #0,d1
move xy,d1 ;x-Koordinate
divu #16,d1 ;Wort für x-Koordinate + 16-Bit-Offset
moveq #4,d2
lsr d7,d2 ;ergibt Anzahl der Planes
asl d2,d1 ;ergibt Byte für x-Koordinate
add d1,d0
clr d1
swap d1 ;16-Bit-Offset
divu #8,d1 ;auf 8 Bit umrechnen
add d1,d0
swap d1
move d1,offset
add.l _v_bas_ad,d0
move.l d0,blkprt ;Startadresse d. Ausschnitts
move.l #$ff8240,colpal ;Zeiger auf Farbpalette
move.l #pmask,mask ;Zeiger auf Halbtonmaske
move (sp)+,d7
pea defptr
move #PRTBLK,-(sp)
move #1,_dumpflg
trap #XBIOS ;Hardcopy starten
move #-1,_dumpflg
addq.l #6, sp
nocopy: rts
shift: dc.w $e1b ;Adresse von kbshift f.altes TOS
prtypes:dc.b 0,2,1,-1,3,-1,-1,-1 ;Tabelle der Druckertypen
*Tabelle der Halbtonmasken
pmask: dc.b $0f,$0f,$0d,$06,$09,$06,$08,$06
dc.b $08,$02,$08,$00,$08,$00,$08,$00
dc.b $00,$00
bss
defptr:
blkprt: ds.l 1 ;Start des auszudruckenden Ausschnitts
offset: ds.w 1 ;Offset für bis zu 7 Bits
width: ds.w 1 ;Breite des Ausschnitts in Punkten
height: ds.w 1 ;Höhe des Ausschnitts in Punkten
left: ds.w 1 ;linker Rand in Punkten
right: ds.w 1 ;rechter Rand in Punkten
scrrez: ds.w 1 ;Bildschirmauflösung
prrez: ds.w 1 ;Druckerauflösung
colpal: ds.l 1 ;Pointer auf Farbpalette
type: ds.w 1 ;Druckertyp
port: ds.w 1 ;Druckerport
mask: ds.l 1 ;Pointer auf Halbtonmasken
xy: ds.w 2 ;x und y Koordinate der Dialogbox