PASCAL ruft TOS Teil 2

Bild 1: Konvertiertes Degasbild in NEOchrome

Im letzten Teil wurde beschrieben, wie man mehrere Bildschirme erzeugen und zwischen ihnen umschalten kann. Dabei war es notwendig auf das Betriebssystem zurückzugreifen, da momentan in keinem Pascal-Compiler derartige Befehle implementiert sind. In diesem Teil geht es hauptsächlich um das Laden und Speichern von Grafikbildern. Als praktisches Beispiel stellen wir ein Konvertierprogramm vor, das Bilder verschiedener Zeichenprogramme angleicht, doch dazu später mehr.

Laden und Speichern

Was macht man mit den schönsten Grafiken, wenn man sie nicht für den späteren Gebrauch auf Diskette speichern und von dort wieder laden kann. Auch hier stellt das Betriebssystem die nötigen Routinen zur Verfügung, nämlich die GEMDOS-Routinen ’FREAD’ und ’FWRITE’.

Beginnen wir mit dem Lesen eines Bildes. Zunächst einmal muß die Datei geöffnet werden, und zwar mit der Funktion FOPEN. Als Variablen benötigt sie zum einen den Namen des Bildes, unter dem es auf Diskette abgespeichert ist, zum anderen einen Wert, der den Zugriffsmodus angibt (0 = Lesen, 1 = Schreiben und 2 = gemischter Zugriff).

Die Funktion liefert als Ergebnis die Kanalnummer (handle), unter der die Datei im Rechner verwaltet wird. Dies ist wichtig, da mehrere Dateien gleichzeitig geöffnet sein können. Konnte die Datei nicht geöffnet werden, übergibt die Funktion einen Fehlerwert, der grundsätzlich negativ ist. Ist die Datei erfolgreich geöffnet (handle > 5), kann mit der Funktion FREAD das Bild eingelesen werden.

FREAD an sich verlangt drei Parameter: die Kanalnummer (handle), die Länge der zu lesenden Information und die Adresse, an die das Bild geladen werden soll. Im folgenden Beispiel übergeben wir als Adresse die Anfangsadresse des Bildschirms.

Speichern

Bevor ein Bild auf Diskette geschrieben werden kann, muß die Datei, unter deren Namen das Bild erscheinen soll, zunächst erzeugt werden. Dazu bietet GEMDOS die Funktion FCREAT, die ähnliche Parameter wie FOPEN aufweist. Sie benötigt den Namen der neuen Datei und ein sogenanntes Dateiattribut, welches mehrere Werte annehmen kann (0 = normale Datei, 1 = Nur-lese-Datei, ...). Auch diese Funktion liefert eine Kanalnummer bzw. eine Fehlernummer. Jetzt können die Daten mit FWRITE geschrieben werden. FWRITE benötigt neben der Kanalnummer die Länge und die Anfangsadresse des abzuspeichernden Bereiches. Die Länge beträgt bei einem gesamten Grafikbild 32000 Bytes (640 ★ 400), die Adresse kann der Funktion durch LOGBASE zugespielt werden (siehe Teil 1).

~~~~~~~~~~~~~~~~~~~~~ program BILD_LADEN;

type nametyp - packed array[1..15] of char;

var kanal,i : integer; count : long_integer; bname : string; name : nametyp;

function LOGBASE: long_integer; xbios(2);

function FOPEN( var name: nametyp; mode: integer ): integer; gemdos($3d);

function FREAD( kanal: integer; size, buff: long_integer): long_integer; gemdos($3f);

begin bname := concat('joshua.pic',chr(0) ); { eventuell Laufwerk angeben ! } for i:=1 to length(bname) do name[i] := bname[i]; kanal := FOPEN( name,0 ); if kanal > 5 then count:=FREAD( kanal,32000,LOGBASE+1) else writeln('Datei kann nicht geoeffnet werden !!!'); readln end.


**Listing 1: FREAD**
</div>

# Grafik-Konverter

Viele ST-Anwender ärgerten sich sicherlich schon über die verschiedenen Bildformate, die die bekannten Zeichenprogramme benutzten. DEGAS beispielsweise generiert ein 32034 Byte langes Bild und zeigt sich äußerst ignorant, wenn man ihm ein anderes Bildformat anbietet. Ähnlich bei NEOchrome, das ein Bild der Länge 32128 Bytes erzeugt und darin noch so allerlei Informationen ablegt. Ein Doodle-Bild hingegen weist 32000 Bytes auf, also lediglich die Bildschirminformation ohne Farbpalette.

Zum Dank daß sie aufgerufen wurden, übergeben diese Routinen die Anzahl der gelesenen bzw. geschriebenen Daten oder eine Fehlernummer, die grundsätzlich negativ ist. Man sollte diese hier wie bei allen anderen TOS-Befehlen abfragen und somit die Betriebssicherheit des Programms sicherstellen.

Zu guter letzt sollten wir eine Datei auch wieder schließen, wozu wir die GEMDOS-Funktion FCLOSE benutzen.

Erfahrene Pascal-Programmierer werden sicher bemerken, daß die meisten Routinen auch mit Standard-Befehlen (reset, rewrite usw.) realisiert werden können. Diese sind den GEMDOS-Routinen jedoch an Geschwindigkeit und den Möglichkeiten zur Fehleranalyse unterlegen.

<div class="textkasten bgyellow" markdown=1>

program BILD_SCHREIBEN;

type nametyp = packed array[1..15] of char;

var kanal,i : integer; count : long_integer; bname : string; name : nametyp;

function LOGBASE: long_integer; xbios(2);

function FCREATE( var name: nametyp; attr: integer): integer; gemdos($3c);

function FWRITE( kanal: integer; size, adresse: long_integer): long_integer; gemdos($40);

begin writeln(' dies ist das DEMOBILD '); bname := 'DEMO.PIC'; for i:=1 to length(bname) do name[i] := bname[i]; kanal := FCREATE( name,0 ); count:=FWRITE(kanal,32000,LOGBASE ); if count < 32000 then writeln('Achtung: Fehler beim Schreiben') else writeln('Bild ist korrekt geschrieben'); readln end.


**Listing 2: FWRITE**
</div>

Die Aufgabe des Programmes ist es nun, diese Formate umzuwandeln, so daß die Bilder auch in anderen Zeichenprogrammen verwendet werden können. Eine nützliche Sache, die übrigens für alle Auflösungen ausgelegt wurde, so daß man neben s/w-Bildern auch alle Farbauflösungen bearbeiten kann.

<figure>
  <img src="/stc1986/images/pascal-tos-2-2.jpg">
  <figcaption>Grafik 1: Bildformate</figcaption>
</figure>

Dazu liest das Programm CONVERTER ein beliebiges Bild zunächst mit FREAD ein. Abweichend vom oben Gesagten wird dabei anstatt der Zieladresse einfach ein ausreichend dimensioniertes Feld übergeben. Dies ist dadurch möglich, daß der Compiler automatisch die Anfangsadresse des Feldes als Zieladresse einsetzt. An der zurückgegebenen Anzahl der gelesenen Bytes läßt sich das Format des Bilds (siehe Abbildung) erkennen. Da sich die verschiedenen Bilder in ihrem Aufbau unterscheiden, werden wir ihn kurz erläutern. Die eigentliche Bildinformation, die in allen Formaten enthalten ist, nimmt 32000 Bytes Speicher ein (640 ★ 400 Bit). Sie wird bei DEGAS und NEOchrome durch die Farbpalette und andere Informationen ergänzt. Die Farbpalette enthält die Farbwerte, die beim Zeichnen des Bildes eingestellt waren. Sie sind äußerst wichtig, da sonst ein Bild, das z. B. einen Frühlingswald darstellt, leicht in grellen, bunten Farbtönen untergehen würde.

Das genaue Format, das die einzelnen Zeichenprogramme verwenden, ist in der folgenden Abbildung zu sehen.

An der Abbildung erkennt man, daß die Position der Bildinformation bei jedem Format anders liegt und deshalb berechnet werden muß. Das Bild wird nun durch eine kleine Zeigermanipulation sichtbar gemacht. Bei Farbbildern ist es wichtig, daß einerseits die Farbpalette in den Rechner übernommen und andererseits beim Abspeichern aus dem Rechner gelesen und mit dem gewandelten Bild gespeichert wird. Die hierzu verwendete SETCOLOR-Routine ist ein kleiner Vorgriff auf ein späteres Kapitel. Sie ermöglicht das Verändern der rechnerinternen Farbpalette, wobei man jede Farbe einzeln ändern kann. Bei Übergabe eines negativen Farbwertes wird der momentan eingestellte Farbwert geliefert.

Beim Bildspeichern erfragt das Programm das Zielformat und schiebt dementsprechend die Bild- und Farbinformationen an die richtige Stelle. Da hier aus Speicherplatzgründen nur ein Feld benutzt wurde, ist es wichtig, auf die Reihenfolge der Verschiebung zu achten, da sonst Daten verloren gehen.

Schließlich sollte der Bildschirminhalt auch auf Papier gebracht werden. Will man dies nicht durch ’Alt + Help’, sondern per Programmsteuerung erledigen, so benutzt man am besten die in Listing 4 dargestellte Prozedur SCRDMP (Screendump). Ihr Aufruf erfolgt ohne Parameter und druckt den logischen Bildschirm (LOGBASE).

Soviel für dieses Mal. In der Folge werden einige Befehle der Themen Floppy, Sound und Farbdefinition behandelt. Falls Ihnen etwas zu den angekündigten Themen oder zu anderen Pascal Tricks etwas einfällt, so lassen Sie es uns hören, - wir würden uns über Ihre Beteiligung sehr freuen. (MN)

<div class="textkasten bgyellow" markdown=1>

program converter_II;

type screen = array[1..16000] of integer; bild_zeiger = ^screen; feldtyp = packed array[1..16064] of integer; bildtyp = packed array[1..16000] of integer; nametyp = packed array[1..15] of char;

var bild : bild_zeiger; feld : feldtyp; farb : packed array[0..15] of integer; filename,name_alt,name_neu : nametyp; i,j,kanal,schieb : integer; count : long_integer; ch : char;

function fcreate ( var name: nametyp: attr: integer): integer; gemdos($3c); function fopen ( var name: nametyp; mode: integer): integer; gemdos($3d); procedure fclose ( kanal: integer); gemdos($3e);

function fread ( kanal: integer; size: long_integer; var buff : feldtyp) : long_integer ; gemdos($3f);

function fwrite ( kanal: integer; size: long_integer; var feld : feldtyp) : long_integer ; gemdos($40);

function logbase: bild_zeiger; xbios(3); function getrez: integer; xbios(4);

function setcolor( colornum,color: integer): integer; xbios(7);

procedure farbe_raus; var farb_nr : integer; begin for farb_nr:=0 to 15 do farb[farb_nr] := setcolor(farb_nr,-l); end;

procedure farbe_rein (schieb:integer); var farb_nr,off : integer; begin case schieb of 17 : off:=2; 64 : off:=3; end; for farb_nr:=0 to 15 do farb[farb_nr]:*setcolor(farb_nr,feld[farb_nr+off]); end;

function offset : integer; var zahl : integer; begin writeln(chr(27),'H'); writeln('Speichern als : '); writeln(' '); writeln(' 1 Degas '); writeln(' 2 NEOchrome '); writeln(' 3 normal '); writeln(' 1); writeln(' 0 Abbruch ');

	repeat

	read(zahl); 
until zahl in [0 .. 3 ] ;
case zahl of
0	: offset:—1;
1	: offset:-17;
2	: offset:—64;
3	: offset:-0; 
end;

end; procedure Eingabe_Name (var name: nametyp); var eingabe : string; i : integer; begin write ('Welcher Filename ? '); { bei RAM: Laufwerk angeben } for i:=1 to 15 do hame[i]:=' '; readln (eingabe); eingabe:=concat(eingabe,chr(0)); { TOS-Format } for i: = 1 to length(eingabe) do name[i]:-eingabe[i] ; end;

procedure speichern ( schieb, offset : integer ); var i:integer; begin if offset<>-1 then begin { Abbruch? } Eingabe_Name(name_neu); case offset of 0 : begin { wandelt in DOODLE-Format } for i:=1 to 16000 do feld[i]:=feld[i+schieb]; end; 17 : begin { wandelt in DEGAS-Format } if schieb <> 64 then {für Degas & Doodle } for i:=16000 downto 1 do feld[i+17]:= feld[i+schieb] else for i:=1 to 16000 do { nur für NEOchrome } feld[i+17]:= feld[i+schieb]; feld[1]:=getrez; for i:=0 to 15 do feld[i+2]:=farb[i]; end; 64 : begin { wandelt in NEOchrome-Format } for i:=16000 downto 1 do Feld[i+64]:=feld[i+schieb]; feld[1]:=0; feld[2]:=0; for i:=0 to 15 do feld[i+3]:=farb[i]; for i:=1 to 46 do feld[i+18]:=0; end; end; { case }

		kanal := fcreate(name_neu,0);	 { neues File öffnen } 
		if kanal>0 then begin
			count := fwrite (kanal,32000+2*offset,feld); { Daten schreiben }
			if count<32000 then
				writeln ('Bild wurde nicht korrekt geschrieben !');
		end
		else writeln('der Kanal'.kanal,' kann nicht geöffnet werden !!!') 
	end
end;

begin { main } writeln(chr(27),'H','K O N V E R T E R'); writeln; bild := logbase; repeat Eingabe_Name(name_alt); kanal:= fopen(name_alt,0); if kanal>0 then begin writeln(‘Lade ',name_alt,' in den Bildspeicher'); count := fread(kanal,32128,feld); fclose(kanal); schieb:=int(count-32000) div 2; if schieb>0 then farbe_rein (schieb); {$P-} { Zeigerkontrolle ausschalten ) for i:=1 to 16000 do bild^[i] := feld[i+schieb] ; { Bild anzeigen } {$P+} { Zeigerkontrolle einschalten } farbe_raus; speichern( schieb, offset ); end else begin writeln('kein File mit diesem Namen !!!'); readln; end; writeln('wollen Sie noch ein Bild konvertieren ?'); readln(ch); until ch='n' end.


**Listing 3: KONVERTER**
</div>


<div class="textkasten bgyellow" markdown=1>

program Bildschirmausdruck;

{ Screendump }

procedure SCREENDUMP ;xbios(20);

begin writeln(' *** Screendump *** '); SCREENDUMP; end.


**Listing 4: SCRDMP**
</div>


Aus: ST-Computer 11 / 1986, Seite 99

Links

Copyright-Bestimmungen: siehe Über diese Seite