home *** CD-ROM | disk | FTP | other *** search
- (* ------------------------------------------------------ *)
- (* SavePCX.PAS *)
- (* Unit SavePCX *)
- (* Turbo Pascal ab 5.0 *)
- (* (c) 1990 Gerald Arend, G. Huber & TOOLBOX *)
- (* ------------------------------------------------------ *)
- {$R-,S-,I-,V-,B-,N-,D-,F-,L-}
-
- UNIT SavePCX;
-
- INTERFACE
-
- USES Dos, Graph, Crt;
-
- TYPE
- PCX_HEADER = RECORD
- Creator : BYTE; { Immer 10 für ZSoft }
- Version : BYTE; { PCX-Version: }
- { 0 = Version 2.5 o. Palette }
- { 2 = Version 2.8 m. Palette }
- { oder Version 3.0 o. Pal.}
- { 3 = Version 2.8/3.0 o. Pal.}
- { 5 = Version 3.0 mit Pal. }
- Encoding : BYTE;
- { 1 = Run-Length-Encoded }
- Bits : BYTE; { Pixel pro Bit }
- { für CGA 320x200 2 Bits, }
- XMin, YMin,
- XMax, YMax : INTEGER;
- Hres, VRes : INTEGER;
- Palette : ARRAY[0..15, 0..2] OF BYTE;
- VMode : BYTE; { Reserviert }
- Planes : BYTE; { Farbebenen }
- BytePerLine: INTEGER; { Bytes/Scanzeile }
- PaletteInfo: INTEGER;
- { 1 = Farbe/Schwarz-Weiß }
- { 2 = Grauwerte }
- dummy : ARRAY[0..57] OF BYTE;
- END;
-
- PlaneType = ARRAY[0..90] OF BYTE;
- plane = ^Planetype;
- ScanLine = ARRAY[0..3] OF plane;
-
- CONST
- ActivePage : WORD = 0;
- EGAOnly: BOOLEAN = FALSE;
- DOSFehler: BOOLEAN = FALSE;
- MaxColors = 15;
- numpic : WORD = 1;
- AttrScreen : BOOLEAN = FALSE;
-
- VAR
- Xmin, Xmax, Ymin, Ymax, vmodus : WORD;
- Screen: BYTE;
- gd, gm: INTEGER;
- z: ScanLine;
-
- PROCEDURE WritePCXHeader(VAR PCXH : PCX_Header;
- name : STRING);
- PROCEDURE WritePCXByte(VAR F : FILE; wert, counter : BYTE);
- PROCEDURE WritePCXLine(VAR F : FILE;
- VAR buf : plane;
- count: BYTE);
- PROCEDURE BGIToPCX(gd, gm : INTEGER;
- name : STRING);
- FUNCTION HGCGrafik: BOOLEAN;
- PROCEDURE Screen2PCX(Name: STRING); { speichert Bildschirm als
- PCX-Datei ab. Der Name muß OHNE Endung angegeben werden ! }
-
- IMPLEMENTATION
-
- CONST
- HercBase = $B000;
- EgaBase = $A000;
- CgaBase = $B800;
- BLOCKSIZE: WORD = 512;
-
- VAR
- PCXbuf : ARRAY[1..512] OF BYTE;
- I, J : WORD;
- SPtr : POINTER;
- PCXH : PCX_Header;
-
- PROCEDURE ErrorSound;
- VAR
- i, n: BYTE;
- BEGIN
- FOR i:=1 TO 3 DO
- BEGIN
- FOR n:=1 TO 100 DO
- BEGIN
- Sound(440);
- Delay(1);
- Sound(480);
- Delay(1);
- END;
- NoSound;
- Delay(300);
- END;
- END;
-
- PROCEDURE ErrorCheck;
- BEGIN
- DOSFehler:=(IOResult<>0);
- IF DOSFehler THEN
- ErrorSound;
- END;
-
- PROCEDURE EGA2PCX(VAR Header: PCX_Header; Farben: PaletteType);
- VAR
- i, j, c: BYTE;
- CONST
- PCXDefaultPalette : ARRAY[0..15, 0..2] OF BYTE =
- ((0, 0, 0), (0, 0, 170), (0, 170, 0), (0, 170, 170),
- (170, 0, 0), (170, 0, 170), (170, 170, 0),
- (170, 170, 170),
- (85, 85, 85), (85, 85, 255), (85, 255, 85),
- (85, 255, 255),
- (255, 85, 85), (255, 85, 255), (255, 255, 85),
- (255, 255, 255));
- BEGIN
- IF EGAOnly THEN
- { Die Farbregister der EGA-Karte können nicht gelesen
- werden! Snapshot muß daher immer die Standard-EGA-Palette
- in den PCX-Header schreiben }
- Move(PCXDefaultPalette, PCXH.Palette, 48)
- ELSE { VGA emuliert EGA: Farbregister werden gelesen }
- FOR i:=0 TO MaxColors DO
- BEGIN
- WITH Header DO
- BEGIN
- c:=BYTE(Farben.Colors[i]);
- Palette[i, 0]:=
- ((c AND 32) SHR 5) OR ((c AND 4) SHR 1);
- Palette[i, 1]:=
- ((c AND 16) SHR 4) OR (c AND 2);
- Palette[i, 2]:=
- ((c AND 8) SHR 3) OR ((c AND 1) SHL 1);
- END;
- FOR j:=0 TO 2 DO
- CASE Header.Palette[i, j] OF
- 1: Header.Palette[i, j]:=85;
- 2: Header.Palette[i, j]:=170;
- 3: Header.Palette[i, j]:=225;
- END;
- END;
- END;
-
- PROCEDURE VGA2PCX(VAR Header: PCX_Header);
- VAR
- R: Registers;
- j: BYTE;
- VGAFarbNr: ARRAY[0..MaxColors] OF BYTE;
- BEGIN
- R.AH:=$10; { Alle Paletteneinträge lesen }
- R.AL:=$09;
- R.ES:=Seg(VGAFarbNr);
- R.DX:=Ofs(VGAFarbNr);
- Intr($10, R);
- FOR J:=0 TO 15 DO
- BEGIN
- R.AH:=$10;
- R.AL:=$15;
- R.BX:=VGAFarbNr[J];
- Intr($10, R);
- PCXH.Palette[J, 0]:=R.DH SHL 2;
- PCXH.Palette[J, 1]:=R.CH SHL 2;
- PCXH.Palette[J, 2]:=R.CL SHL 2;
- END;
- END;
-
- PROCEDURE DefPCXPalette(VAR PCXH : PCX_Header;
- ColTYPE : BYTE);
- VAR
- I, J : INTEGER;
- R: Registers;
- EGAFarben: PaletteType;
- BEGIN
- CASE ColType OF
- 0 : BEGIN
- FillChar(PCXH.Palette, 48, 255);
- FillChar(PCXH.Palette, 3, 0);
- END;
- 1 : FOR I := 0 TO 15 DO BEGIN
- IF Odd(I) THEN
- FOR J := 0 TO 2 DO
- PCXH.Palette[I, J] := 240
- ELSE
- FOR J := 0 TO 2 DO
- PCXH.Palette[I, J] := 0;
- END;
- 2 : IF EGAOnly THEN
- BEGIN
- GetPalette(EGAFarben);
- EGA2PCX(PCXH, EGAFarben);
- END
- ELSE
- VGA2PCX(PCXH);
- END;
- END;
-
- PROCEDURE SetReadPlane(Nr : BYTE);
- BEGIN
- Port[$3CE] := 4;
- Port[$3CF] := Nr;
- END;
-
- PROCEDURE WritePCXHeader(VAR PCXH : PCX_Header;
- name : STRING);
- VAR
- F: FILE;
- BEGIN
- Assign(F, name);
- {$I-}
- Rewrite(F, 1);
- ErrorCheck;
- IF DOSFehler THEN
- Exit;
- BlockWrite(F, PCXH, 128);
- ErrorCheck;
- IF DOSFehler THEN
- Exit;
- Close(F);
- {$I+}
- END;
-
- PROCEDURE WritePCXByte(VAR F : FILE;
- wert, counter: BYTE);
- BEGIN
- IF (counter = 1) AND ($C0 <> $C0 AND wert) THEN
- BlockWrite(F, wert, 1)
- ELSE
- BEGIN
- counter := $C0 OR counter;
- BlockWrite(F, counter, 1);
- BlockWrite(F, wert, 1);
- END;
- END;
-
- PROCEDURE WritePCXLine(VAR F : FILE;
- VAR buf : plane;
- count : BYTE);
- VAR
- n, OldByte, Zaehler: BYTE;
- BEGIN
- n:=0;
- OldByte:=buf^[0];
- Zaehler:=1;
- REPEAT
- Inc(n);
- IF buf^[n]=OldByte THEN { gleiches Byte }
- Inc(Zaehler)
- ELSE
- BEGIN
- WHILE Zaehler>63 DO { neues Byte: Alten Wert schreiben }
- BEGIN { nur 63 Wiederholungen maximal möglich }
- WritePCXByte(F, OldByte, 63);
- Dec(Zaehler, 63);
- END;
- IF Zaehler>0 THEN
- WritePCXByte(F, OldByte, Zaehler);
- Zaehler:=1;
- OldByte:=buf^[n];
- END;
- UNTIL n=count-1;
- WHILE Zaehler>63 DO { neues Byte: Alten Wert schreiben }
- BEGIN { nur 63 Wiederholungen maximal möglich }
- WritePCXByte(F, OldByte, 63);
- Dec(Zaehler, 63);
- END;
- IF Zaehler>0 THEN
- WritePCXByte(F, OldByte, Zaehler);
- END;
-
- PROCEDURE BGIToPCX(gd, gm : INTEGER;
- name : STRING);
- VAR
- F : FILE;
- Page : INTEGER;
-
-
- PROCEDURE ReOpenFile;
- BEGIN
- Assign(F, name);
- {$I-}
- Reset(f,1);
- {$I+}
- ErrorCheck;
- IF DOSFehler THEN
- Exit;
- Seek(F, 128);
- END;
-
- BEGIN
- FillChar(PCXH, 128, 0);
- PCXH.creator := 10;
- PCXH.version := 3;
- PCXH.encoding := 1;
- PCXH.bits := 1;
- PCXH.xmin := Xmin;
- PCXH.ymin := Ymin;
- PCXH.xmax := XMax;
- PCXH.ymax := YMax;
- PCXH.PaletteInfo := 1;
- CASE gd OF
- 3,4,5,9:
- BEGIN
- CASE gm OF
- 0 : BEGIN
- PCXH.HRes:=640;
- PCXH.VRes:=200;
- PCXH.Planes := 4;
- PCXH.BytePerLine := 80;
- DefPCXPalette(PCXH, 2);
- WritePCXHeader(PCXH, name);
- IF DOSFehler THEN
- Exit;
- ReOpenFile;
- FOR I := 0 TO 199 DO BEGIN
- SPTR := Ptr(EgaBase +
- $400 * ActivePage, I*80);
- FOR Page := 0 TO 3 DO BEGIN
- SetReadPlane(Page);
- Move(SPtr^, Z[0]^, 80);
- WritePCXLine(F, Z[0], 80);
- ErrorCheck;
- IF DOSFehler THEN
- Exit;
- END;
- END;
- END;
- 1 : BEGIN
- PCXH.HRes:=640;
- PCXH.VRes:=350;
- PCXH.Planes := 4;
- PCXH.BytePerLine := 80;
- DefPCXPalette(PCXH, 2);
- WritePCXHeader(PCXH, name);
- IF DOSFehler THEN
- Exit;
- ReOpenFile;
- FOR I := 0 TO 349 DO BEGIN
- SPTR := Ptr(EgaBase +
- $800 * ActivePage, I*80);
- FOR Page := 0 TO 3 DO BEGIN
- SetReadPlane(Page);
- Move(SPtr^, Z[0]^, 80);
- WritePCXLine(F, Z[0], 80);
- ErrorCheck;
- IF DOSFehler THEN
- Exit;
- END;
- END;
- END;
- 2 : BEGIN
- PCXH.HRes:=640;
- PCXH.VRes:=480;
- PCXH.Planes := 4;
- PCXH.BytePerLine := 80;
- DefPCXPalette(PCXH, 2);
- WritePCXHeader(PCXH, name);
- IF DOSFehler THEN
- Exit;
- ReOpenFile;
- FOR I := 0 TO 479 DO BEGIN
- SPTR := Ptr(EgaBase +
- $960 * ActivePage, I*80);
- FOR Page := 0 TO 3 DO BEGIN
- SetReadPlane(Page);
- Move(SPtr^, Z[0]^, 80);
- WritePCXLine(F, Z[0], 80);
- ErrorCheck;
- IF DOSFehler THEN
- Exit;
- END;
- END;
- END;
- 3 : BEGIN
- PCXH.HRes:=640;
- PCXH.VRes:=350;
- PCXH.Planes := 1;
- PCXH.BytePerLine := 80;
- PCXH.Version := 2;
- DefPCXPalette(PCXH, 0);
- WritePCXHeader(PCXH, name);
- IF DOSFehler THEN
- Exit;
- ReOpenFile;
- SetReadPlane(0);
- FOR I := 0 TO 349 DO BEGIN
- SPTR := Ptr(EgaBase +
- $800 * ActivePage, I*80);
- Move(SPtr^, Z[0]^, 80);
- WritePCXLine(F, Z[0], 80);
- ErrorCheck;
- IF DOSFehler THEN
- Exit;
- END;
- END;
- END;
- END;
- 7 : BEGIN { CASE gd OF 7 }
- PCXH.HRes:=720;
- PCXH.VRes:=348;
- PCXH.Planes := 1;
- PCXH.BytePerLine := 90;
- PCXH.Version := 2;
- DefPCXPalette(PCXH, 0);
- WritePCXHeader(PCXH, name);
- IF DOSFehler THEN
- Exit;
- ReOpenFile;
- FOR I := 0 TO 347 DO BEGIN
- SPtr := Ptr(HercBase, WORD((I AND 3) SHL 13
- + 90*(I SHR 2)));
- Move(SPtr^, Z[0]^, 90);
- WritePCXLine(F, Z[0], 90);
- ErrorCheck;
- IF DOSFehler THEN
- Exit;
- END;
- END;
-
- 1,2 : BEGIN { CASE gd OF 1, 2 }
- PCXH.HRes:=320;
- PCXH.VRes:=200;
- PCXH.Planes := 1;
- PCXH.Bits := 2;
- PCXH.BytePerLine := 80;
- IF (gd = 2) AND (gm = 5) THEN BEGIN
- J := 479;
- PCXH.Bits := 1;
- END ELSE J := 199;
- IF gm = 4 THEN PCXH.Bits := 1;
- PCXH.Version := 5;
- DefPCXPalette(PCXH, 1);
- WritePCXHeader(PCXH, name);
- IF DOSFehler THEN
- Exit;
- ReOpenFile;
- FOR I := 0 TO J DO BEGIN
- SPtr := Ptr(CgaBase, WORD((I AND 1)
- SHL 13 + 80*(I SHR 1)));
- Move(SPtr^, Z[0]^, 80);
- WritePCXLine(F, Z[0], 80);
- ErrorCheck;
- IF DOSFehler THEN
- Exit;
- END;
- END;
- END;
- Close(F);
- END;
-
- FUNCTION HGCGrafik: BOOLEAN;
- VAR
- LP: RECORD
- CASE INTEGER OF
- 0 : (LB, HB : BYTE); { Pos. 2 Bytes }
- 1 : (LW : INTEGER); { Pos. 1 Word }
- END;
- BEGIN
- Port[$3BB] := 0; { Reset des Light-Pen-Latch-Reg.}
- WHILE(Port[$3BA] AND $80 <> 0) DO {}; { Start }
- WHILE(Port[$3BA] AND $80 = 0) DO {}; { Ende }
- INLINE ($FA); { cli, Interrupts unterdrücken }
- WHILE(Port[$3BA] AND $80 <> 0 ) DO {};
- Port[$3B9]:=0; { Light-Pen-Position merken }
- INLINE ($FB); { sti, Interrupts wieder zulassen }
- Port[$3B4]:=$10; { Hi-Byte Light-Pen-Pos. auslesen }
- LP.HB:=Port[$3B5];
- Port[$3B4]:=$11; { Lo-Byte Light-Pen-Pos.lesen }
- LP.LB:=Port[$3B5];
- HGCGrafik:=(LP.LW)>(45*87);
- END;
-
- PROCEDURE TXTScreen(Name: STRING; Base: WORD);
- VAR
- S : STRING[160];
- R : STRING[80];
- i, J, Seg : WORD;
- P : POINTER;
- F : TEXT;
- BEGIN
- Assign(F, Name+'.TXT');
- {$I-}
- Rewrite(F);
- {$I+}
- ErrorCheck;
- IF DOSFehler THEN
- Exit;
- Seg:=Base+$100*ActivePage;
- FOR i:=0 TO 24 DO
- BEGIN
- P:=Ptr(Seg, i*160);
- S[0]:=#160;
- Move(P^, S[1], 160);
- R:='';
- J:=1;
- WHILE J<=160 DO
- BEGIN
- R:=R+S[J];
- Inc(J, 2);
- END;
- WriteLn(F, R);
- END;
- Close(F);
- END;
-
- PROCEDURE ATTScreen(Name: STRING; Base: WORD);
- VAR
- P: POINTER;
- F: FILE;
- BEGIN
- Assign(F, Name+ '.ATT');
- {$I-}
- Rewrite(F, 1);
- {$I+}
- ErrorCheck;
- IF DOSFehler THEN
- Exit;
- P:=Ptr(WORD(Base+$100*ActivePage), 0);
- BlockWrite(F, P^, 4000);
- Close(F);
- END;
-
- PROCEDURE Screen2PCX(Name: STRING);
- VAR
- Regs: Registers;
- BEGIN
- Regs.AH:=$0F;
- Intr($10, Regs);
- vmodus:=Regs.AL;
- ActivePage:=Regs.BH;
- XMin:=0;
- YMin:=0;
- Write(^G);
- CASE vmodus OF
- $3, $83: { Text-Modi 40x25 und 80x25 }
- IF AttrScreen THEN ATTScreen(Name, $B800)
- ELSE TXTScreen(Name, $B800);
- $10, $90:
- BEGIN { EGA-Modi }
- Xmax:=639;
- YMax:=349;
- BGIToPCX(3, 1, Name+'.PCX');
- END;
- $0F, $8F:
- BEGIN { EGA-Mono: }
- Xmax:=639;
- YMax:=349;
- BGIToPCX(3, 3, Name+'.PCX');
- END;
- $0E, $8E:
- BEGIN { EGA-Lo }
- Xmax:=639;
- YMax:=199;
- BGIToPCX(3, 0, Name+'.PCX');
- END;
- $06, $86:
- BEGIN { CGA }
- Xmax:=639;
- YMax:=199;
- BGIToPCX(1, 4, Name+'.PCX');
- END;
- $4, $5,
- $84, $85:
- BEGIN { CGA-Modi mit 320 x 200 }
- Xmax:=319;
- YMax:=199;
- BGIToPCX(1, 1, Name+'.PCX');
- END;
- $11, $91,
- $12, $92:
- BEGIN { VGA-Grafik-Modi }
- XMax:=639;
- YMax:=479;
- BGIToPCX(9, 2, Name+'.PCX');
- END;
- $07,$87:
- BEGIN
- IF HGCGrafik THEN
- BEGIN { Grafik-Modus }
- Xmax:=719;
- YMax:=347;
- BGIToPCX(7, 0, Name+'.PCX');
- END
- ELSE
- BEGIN { Text-Modus }
- ActivePage:=0;
- IF AttrScreen THEN ATTScreen(Name, $B000)
- ELSE TXTScreen(Name, $B000);
- END;
- END;
- END;
- IF NOT DOSFehler THEN
- Write(^G^G);
- END;
-
- BEGIN
- GetMem(z[0], 90);
- GetMem(z[1], 90);
- GetMem(z[2], 90);
- GetMem(z[3], 90);
- { ein Plane für CGA/EGA/VGA/Hercules: max 90 Bytes }
- END.
- (* ------------------------------------------------------ *)
- (* Ende von SAVEPCX.PAS *)
-