home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics 16,000
/
graphics-16000.iso
/
msdos
/
viewers
/
shwpcx10
/
showpcx.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1991-12-29
|
28KB
|
810 lines
Program showpcx;
{ Free Software by TapirSoft Gisbert W.Selke, Dec 1991 }
{$A+,B-,D+,E+,F-,I-,L+,N-,O-,V- }
{$M 65520,0,128000 }
{$UNDEF DEBUG } { DEFINE while debugging }
{$IFDEF DEBUG }
{$R+,S+ }
{$ELSE }
{$R-,S- }
{$ENDIF }
Uses Graph, CRT, Dos;
Const progname = 'ShowPCX';
version = '1.0';
copyright= 'Free Software by TapirSoft Gisbert W.Selke, Dec 1991';
bufsize = 60000;
maxlinlen= 2048; { maximum length of screen line }
Tab = #9;
finishset: Set Of char = [#3,#27,'q','Q'];
Type headrec = Record
id : byte; { must be $0A }
version : byte; { 0, 2, 3, or 5 }
compr : byte; { 1 if RLE-coded }
bitsperpixel : byte;
xmin : word;
ymin : word;
xmax : word;
ymax : word;
horidpi : word; { horizontal resolution, dots per inch }
vertdpi : word; { vertical resolution, dots per inch }
colormap : Array [0..15,0..2] Of byte;
reserved : byte;
ncolplanes : byte; { number of colour planes; max 4 }
bytesperline : word; { must be even }
greyscale : word; { 1 if colour or b/w; 2 if greyscale }
filler : Array [1..58] Of byte;
End;
buffer = Array [1..bufsize ] Of byte;
linbuffer= Array [0..maxlinlen] Of byte;
Var listf : text;
inbufptr : ^buffer;
sr : SearchRec;
saveexit : Pointer;
dir, picname : string;
grdriver, grmode : integer;
maxx, maxy, maxcolour, deltime : word;
parampt, xscale, yscale, videomode : byte;
zverbose, zxcentre, zycentre, zprop, zmono, zconj, zebra : boolean;
zquiet, zgraph, zlist, zfirst, zfinish, zfound, zrepeat : boolean;
{ Link in graphics drivers for EGA, VGA and Hercules: }
Procedure egavga_driver; External;
{$L EGAVGA.OBJ }
Procedure svga256_driver; External;
{$L SVGA256.OBJ }
Procedure herc_driver; External;
{$L HERC.OBJ }
{$F+} function DetectVGA256 : integer; {$F-}
var
DetectedDriver : integer;
SuggestedMode : integer;
begin
DetectGraph(DetectedDriver, SuggestedMode);
DetectVGA256 := SuggestedMode;
if (DetectedDriver = VGA) or (DetectedDriver = MCGA) then
DetectVGA256 := 0 { Default video mode = 0 }
else
DetectVGA256 := grError; { Couldn't detect hardware }
end; { DetectVGA256 }
{$F+ } Procedure myexit; {$F- }
{ exit procedure to clean things up }
Var c : char;
Begin { myexit }
ExitProc := saveexit;
NoSound;
If zgraph Then
Begin
SetGraphMode(GetGraphMode);
CloseGraph;
zgraph := False;
End;
If Not zfound Then writeln('No matching PCX files found.');
While KeyPressed Do c := ReadKey;
End; { myexit }
Procedure beep;
{ emit a short beep }
Begin { beep }
If Not zquiet Then
Begin
Sound(440);
Delay(50);
NoSound;
End;
End; { beep }
Procedure abort(msg : string; ierr : byte);
{ show error message and die }
Begin { abort }
If zgraph Then CloseGraph;
zgraph := False;
If msg <> '' Then writeln(progname,': ',msg);
Halt(ierr);
End; { abort }
Procedure usage;
{ show usage hints and die }
Begin { usage }
writeln;
writeln(progname,' ',version,': display PCX files on screen');
writeln(copyright);
writeln;
writeln('Usage: ',progname,' [<options>] <filespec> [<filespec>...]');
writeln(' where <filespec> is the name of a PCX file, possibly ',
'containing');
writeln(' wildcard characters (default extension .PCX),');
writeln(' or "@", followed immediately by the name of a file ');
writeln(' containing names of PCX files.');
writeln(' Options: /c : centre image');
writeln(' /cx : centre image horizontally');
writeln(' /cy : centre image vertically');
writeln(' /d<num> : delay in milliseconds after each ',
'image');
writeln(' /e<num> : extended VGA mode (use at your own ',
'risk!)');
writeln(' /h : display help');
writeln(' /m : force monochrome mode');
writeln(' /p : use alternate packing strategy for scaling');
writeln(' /q : quiet behaviour (don''t beep)');
writeln(' /r : repeat indefinitely');
writeln(' /s<num> : scale image by factor ',
'1/<num> (0 = autoscale)');
writeln(' /sx<num> : scale horizontally only');
writeln(' /sy<num> : scale vertically only');
writeln(' /v : verbose image info');
writeln(' /z : zebra monochrome mode');
zfound := True;
abort('',1);
End; { usage }
Procedure strip(Var s : string);
{ remove leading and trailing white space }
Begin { strip }
While (s <> '') And (s[1] In [' ',Tab]) Do Delete(s,1,1);
While (s <> '') And (s[Length(s)] In [' ',Tab]) Do Delete(s,Length(s),1);
End; { strip }
Function getnextname : string;
{ get name of next file to display }
Var temp, nam, ext : string;
doserr : integer;
Begin { getnextname }
sr.name := '';
doserr := 0;
If zfirst Then
Begin
temp := '';
While zlist And (temp = '') Do
Begin
If EoLn(listf) And (Not EoF(listf)) Then readln(listf);
If IOResult <> 0 Then;
If zlist And EoF(listf) Then
Begin
Close(listf);
Dispose(inbufptr);
zlist := False;
End;
If zlist Then read(listf,temp);
If IOResult <> 0 Then;
strip(temp);
End;
If temp = '' Then
Begin
While (temp = '') And (parampt <= ParamCount) Do
Begin
If (parampt = ParamCount) And zrepeat And zfound Then parampt := 0;
Inc(parampt);
If parampt <= ParamCount Then temp := ParamStr(parampt);
If temp[1] In ['-','/'] Then temp := '';
End;
If temp[1] = '@' Then
Begin
Assign(listf,Copy(temp,2,255));
Reset(listf);
If IOResult <> 0 Then;
New(inbufptr);
SetTextBuf(listf,inbufptr^);
zlist := True;
temp := getnextname;
End;
End;
If temp <> '' Then
Begin
FSplit(temp,dir,nam,ext);
If ext = '' Then ext := '.PCX';
temp := dir + nam + ext;
FindFirst(temp,ReadOnly+Hidden+SysFile+Archive,sr);
doserr := DosError;
If doserr = 0 Then zfound := True;
zfirst := False;
End
Else
Begin
dir := '';
sr.name := '';
End;
End
Else
Begin
FindNext(sr);
doserr := DosError;
End;
If doserr = 18 Then
Begin
zfirst := True;
getnextname := getnextname;
End
Else getnextname := dir + sr.name;
End; { getnextname }
Procedure init;
{ do all necessary initializations }
Var temp : string;
l : integer;
i : byte;
Function getnumber(str : string; min, max, default : word) : word;
{ convert a string to a number, checling bounds }
Var num : longint;
ires : integer;
Begin { getnumber }
ires := 0;
{$R- }
If str = '' Then num := default
Else Val(str,num,ires);
{$IFDEF DEBUG }
{$R+ }
{$ENDIF }
If ires <> 0 Then num := default;
If num < min Then num := min;
If num > max Then num := max;
getnumber := num;
End; { getnumber }
Begin { init }
If RegisterBGIDriver(@egavga_driver) < 0 Then
abort('Illegal EGA/VGA graphics driver information',2);
If RegisterBGIDriver(@herc_driver) < 0 Then
abort('Illegal Hercules graphics driver information',2);
zgraph := False;
saveexit := ExitProc;
ExitProc := @myexit;
zfirst := True;
zfinish := False;
zlist := False;
zquiet := False;
zverbose := False;
zrepeat := False;
zmono := False;
zconj := False;
zebra := False;
zxcentre := False;
zycentre := False;
zprop := False;
deltime := 65535;
xscale := 255;
yscale := 255;
zfound := False;
parampt := 0;
FileMode := 0;
If ParamCount = 0 Then usage;
grdriver := Detect;
grmode := 0;
videomode:= 255;
InitGraph(grdriver,grmode,'');
If GraphResult <> 0 Then abort('Cannot find graphics driver',2);
zgraph := True;
For i := 1 To ParamCount Do
Begin
temp := ParamStr(i);
If (temp[1] In ['-','/']) And (Length(temp) >= 2) Then
Begin
Case UpCase(temp[2]) Of
'C' : Begin { centering }
If (Length(temp) >= 3) Then
Begin
Case UpCase(temp[3]) Of
'X' : zxcentre := True;
'Y' : zycentre := True;
End;
End
Else
Begin
zxcentre := True;
zycentre := True;
End;
End;
'E' : Begin { extended video mode }
If (Length(temp) >= 3) Then videomode :=
getnumber(Copy(temp,3,255),0,255,0)
Else videomode := 10;
End;
'D' : Begin { delay }
If (Length(temp) >= 3) Then deltime :=
getnumber(Copy(temp,3,255),0,65534,10)
Else deltime := 10;
End;
'H','?' : usage;
'M' : zmono := True;
{ monochrome }
'P' : Begin { packing strategy (for scaling) }
If (Length(temp) <= 2) Or (UpCase(temp[3]) = 'C') Then
zconj := True;
End;
'Q' : zquiet := True;
'R' : zrepeat := True;
'S' : Begin { scaling }
If (Length(temp) >= 3) Then
Begin
Case UpCase(temp[3]) Of
'X' : xscale := getnumber(Copy(temp,4,255),0,255,0);
'Y' : yscale := getnumber(Copy(temp,4,255),0,255,0);
Else Begin
xscale := getnumber(Copy(temp,3,255),0,255,0);
yscale := xscale;
zprop := True;
End;
End;
End
Else
Begin
xscale := 0;
yscale := 0;
zprop := True;
End;
End;
'V' : zverbose := True;
'Z' : Begin { zebra monochrome }
zmono := True;
zebra := True;
End;
Else usage;
End;
End;
End;
If (videomode <> 255) And (grdriver = VGA) Then
Begin
l := InstallUserDriver('SVGA256', @DetectVGA256);
If l > 0 Then
Begin
grdriver := l;
grmode := videomode;
CloseGraph;
If RegisterBGIDriver(@svga256_driver) < 0 Then
abort('Illegal SuperVGA graphics driver information',2);
InitGraph(grdriver,grmode,'');
End;
End;
maxx := GetMaxX;
maxy := GetMaxY;
maxcolour:= GetMaxColor;
If maxx > maxlinlen Then abort('Screen too wide for internal buffer',2);
End; { init }
Procedure showfile(nam : string);
{ display the given PCX file }
Var picf : File;
header : headrec;
linbuf : linbuffer;
picbuf : buffer;
ltemp : longint;
iread, x, y, x2, y2, j, thisbyte : word;
answer : char;
repeatct, b, b2, c, i, horisub, vertsub, horict, vertct : byte;
bitsperplane : byte;
zdecomp, zcompr : boolean;
Procedure showheader;
{ if in verbose mode, display info on PCX file }
Begin { showheader }
RestoreCRTMode;
ClrScr;
write('File: ',nam);
writeln(' (Size: ',FileSize(picf),')');
With header Do
Begin
write ('Version: ',version:4,'; ');
Case compr Of
0 : writeln('Uncompressed');
1 : writeln('RLE-compressed');
Else writeln('Unknown compression method');
End;
write ('Upper left corner: (',xmin:4,',',ymin:4,'); ');
writeln('lower right corner: (',xmax:4,',',ymax:4,')');
write ('Resolution: horizontal: ',horidpi:4,' dpi; ');
writeln('vertical: ',vertdpi:4,' dpi');
write ('Bits per pixel: ',bitsperpixel:4,'; ');
writeln('number of colour planes: ',ncolplanes:4);
write ('Bytes per line: ',bytesperline:4,'; ');
If greyscale = 2 Then writeln('display as grey scales')
Else writeln('display as colour rsp. b/w');
End;
write('Hit space bar to continue... ');
answer := ReadKey;
zfinish := answer In FinishSet;
If Not zfinish Then answer := #0;
SetGraphMode(grmode);
End; { showheader }
Function getnextbyte : byte;
{ reads next byte from input file, handling compression }
Procedure getnextchunk;
{ get next chunk from input file }
Begin { getnextchunk }
If EoF(picf) Then iread := 0
Else
Begin
BlockRead(picf,picbuf,SizeOf(picbuf),iread);
If IOResult <> 0 Then iread := 0;
End;
thisbyte := 0;
End; { getnextchunk }
Begin { getnextbyte }
If Not zdecomp Then
Begin
If thisbyte >= iread Then getnextchunk;
If thisbyte < iread Then
Begin
Inc(thisbyte);
If zcompr And (picbuf[thisbyte] >= 192) Then
Begin
repeatct := picbuf[thisbyte] And $3F;
zdecomp := repeatct > 0;
If thisbyte >= iread Then getnextchunk;
Inc(thisbyte);
End;
End;
End;
If zdecomp Then
Begin
getnextbyte := picbuf[thisbyte];
Dec(repeatct);
zdecomp := repeatct > 0;
End
Else
Begin
If iread > 0 Then
Begin
getnextbyte := picbuf[thisbyte];
End
Else getnextbyte := 0;
End;
End; { getnextbyte }
Procedure VGASetAllPalette(var P);
{ set all colour registers of the VGA quickly; values are RGB, 0..63 }
Var regs : Registers;
Begin { VGASetAllPalette }
With regs Do
Begin
ax := $1012;
bx := 0;
cx := 256;
es := Seg(P);
dx := Ofs(P);
End;
Intr($10, regs);
End; { VGASetAllPalette }
Begin { showfile }
ClearDevice;
Assign(picf,nam);
Reset(picf,1);
answer := #0;
If IOResult = 0 Then
Begin
BlockRead(picf,header,SizeOf(header),iread);
If iread <> SizeOf(header) Then abort('PCX file too short',3);
End;
If IOResult = 0 Then
Begin
If zverbose Then showheader;
With header Do
Begin
If id <> $0A Then abort('Illegal PCX header',3);
If Not (version In [0,2,3,5]) Then abort('Illegal PCX header',3);
If Not (compr In [0,1]) Then abort('Illegal PCX header',3);
If Not (ncolplanes In [0..4]) Then abort('Illegal PCX header',3);
If Odd(bytesperline) Then abort('Illegal PCX header',3);
If Not (greyscale In [1..2]) Then greyscale := 1;
End;
End;
With header Do
Begin
If ncolplanes = 0 Then ncolplanes := 1;
bitsperplane := bitsperpixel*ncolplanes;
i := grmode;
x := xmax - xmin + 1;
y := ymax - ymin + 1;
Case grdriver Of
CGA : Begin
If x <= 320 Then i := CGAC0
Else i := CGAHi;
End;
MCGA, ATT400 : Begin
If (x <= 320) And (y <= 200) Then i := MCGAC0
Else
Begin
If y <= 200 Then i := MCGAMed
Else i := MCGAHi;
End;
End;
EGA, EGA64, EGAMono : Begin
If y <= 200 Then i := EGALo
Else
Begin
If grdriver = EGAMono Then i := EGAMonoHi
Else i := EGAHi;
End;
End;
VGA : Begin
If y <= 200 Then i := VGALo
Else
Begin
If y <= 350 Then i := VGAMed
Else i := VGAHi;
End;
End;
End;
If i <> grmode Then
Begin
SetGraphMode(i);
grmode := GetGraphMode;
maxx := GetMaxX;
maxy := GetMaxY;
maxcolour := GetMaxColor;
End;
If (Not zmono) And (version In [2,5]) And
((grdriver In [EGA,EGA64,VGA]) Or (videomode <> 255)) Then
Begin
Case bitsperplane Of
4 : Begin
For i := 0 To 15 Do
SetRGBPalette(i,colormap[i,0],colormap[i,1],colormap[i,2]);
End;
8 : Begin
ltemp := FilePos(picf);
Seek(picf,FileSize(picf)-768);
BlockRead(picf,picbuf,768,x);
Seek(picf,ltemp);
If x = 768 Then
Begin
For y := 1 To 768 Do picbuf[y] := picbuf[y] ShR 2;
VGASetAllPalette(picbuf);
End;
End;
End;
End;
horisub := xscale;
If xscale = 255 Then horisub := 1;
If xscale = 0 Then
Begin
horisub := 1;
While ((xmax-xmin+horisub-1) Div horisub) > maxx+5 Do Inc(horisub);
End;
vertsub := yscale;
If yscale = 255 Then vertsub := 1;
If yscale = 0 Then
Begin
vertsub := 1;
While ((ymax-ymin+vertsub-1) Div vertsub) > maxy+5 Do Inc(vertsub);
End;
If zprop Then
Begin
If (horisub < vertsub) And (xscale = 0) Then horisub := vertsub;
If (vertsub < horisub) And (yscale = 0) Then vertsub := horisub;
End;
If zxcentre Then
Begin
x := (xmax-xmin+horisub-1) Div horisub;
If x < maxx Then
Begin
xmax := xmax - xmin + (maxx - x) Div 2;
xmin := (maxx - x) Div 2;
End;
End;
If zycentre Then
Begin
y := (ymax-ymin+vertsub-1) Div vertsub;
If y < maxy Then
Begin
ymax := ymax - ymin + (maxy - y) Div 2;
ymin := (maxy - y) Div 2;
End;
End;
zcompr := compr = 1;
thisbyte := Succ(iread);
zdecomp := False;
y := ymin;
y2 := ymin;
vertct := 0;
While (y <= ymax) And (y2 <= maxy) And (Not KeyPressed) And
(Not zfinish) Do
Begin
If y2 < maxy Then
Begin
If y2-ymin <= maxx Then PutPixel(y2-ymin,maxy,maxcolour);
End
Else
Begin
SetColor(Black);
Line(0,maxy,maxx,maxy);
End;
Case bitsperplane Of
1 : Begin
x := xmin;
x2 := xmin;
horict := 0;
If zconj Then b2 := $FF
Else b2 := 0;
For j := 1 To bytesperline Do
Begin
b := getnextbyte;
If vertct = 0 Then
Begin
For i := 1 To 8 Do
Begin
If (x <= xmax) And (x2 <= maxx) Then
Begin
If zconj Then b2 := b2 And b
Else b2 := b2 Or b;
Inc(horict);
If horict = horisub Then
Begin
If (b2 And $80) <> 0 Then PutPixel(x2,y2,maxcolour);
If zconj Then b2 := $FF
Else b2 := 0;
Inc(x2);
horict := 0;
End;
{$R- }
b := b ShL 1;
{$IFDEF DEBUG }
{$R+ }
{$ENDIF }
Inc(x);
End;
End;
End;
End;
End;
2..7 : Begin
FillChar(linbuf,Succ(maxx),#0);
For c := 1 To ncolplanes Do
Begin
x := xmin;
x2 := 0;
horict := 0;
If zconj Then b2 := $FF
Else b2 := 0;
For j := 1 To bytesperline Do
Begin
b := getnextbyte;
If vertct = 0 Then
Begin
For i := 1 To 8 Do
Begin
If (x <= xmax) And (x2 <= maxx) Then
Begin
If zconj Then b2 := b2 And b
Else b2 := b2 Or b;
Inc(horict);
If horict = horisub Then
Begin
linbuf[x2] := linbuf[x2] ShL 1;
If (b2 And $80) <> 0 Then Inc(linbuf[x2]);
If zconj Then b2 := $FF
Else b2 := 0;
Inc(x2);
horict := 0;
End;
{$R- }
b := b ShL 1;
{$IFDEF DEBUG }
{$R+ }
{$ENDIF }
Inc(x);
End;
End;
End;
End;
End;
If vertct = 0 Then
Begin
x := xmin;
x2 := 0;
While x <= xmax Do
Begin
If linbuf[x2] <> 0 Then
Begin
If zmono Then
Begin
If zebra Then
Begin
If Odd(linbuf[x2]) Then PutPixel(x,y2,maxcolour);
End
Else PutPixel(x,y2,maxcolour);
End
Else PutPixel(x,y2,linbuf[x2] Mod Succ(maxcolour));
End;
Inc(x2);
Inc(x,horisub);
End;
End;
End;
8 : Begin
If vertct = 0 Then
Begin
x := xmin;
j := 1;
While (j <= bytesperline) Do
Begin
If zconj Then b2 := $FF
Else b2 := 0;
For i := 1 To horisub Do
Begin
If j <= bytesperline Then
Begin
b := getnextbyte;
If zconj Then
Begin
If b < b2 Then b2 := b;
End
Else
Begin
If b > b2 Then b2 := b;
End;
Inc(j);
End;
End;
If (b2 <> 0) And (x <= xmax) Then
Begin
If zmono Then
Begin
If zebra Then
Begin
If Odd(b2) Then PutPixel(x,y2,maxcolour);
End
Else PutPixel(x,y2,maxcolour);
End
Else PutPixel(x,y2,b2 Mod Succ(maxcolour));
If (x > 20) And (y2 > 20) And (x < 750) And (y < 300) And
(b2 = 0) Then
Begin
b2 := b2;
End;
End;
Inc(x);
End;
End
Else
Begin
For j := 1 To bytesperline Do b := getnextbyte;
End;
End;
End;
Inc(y);
If vertct = 0 Then Inc(y2);
vertct := Succ(vertct) Mod vertsub;
End;
If y2 <= maxy Then
Begin
SetColor(Black);
Line(0,maxy,maxx,maxy);
End;
End;
Close(picf);
If IOResult <> 0 Then;
beep;
x := 0;
If KeyPressed Then answer := ReadKey;
While (x < deltime) And (answer = #0) Do
Begin
Delay(100);
If deltime < 65535 Then x := x + 100;
If KeyPressed Then answer := ReadKey;
End;
zfinish := answer in FinishSet;
SetGraphMode(grmode);
End; { showfile }
Begin { main }
init;
Repeat
picname := getnextname;
If picname <> '' Then showfile(picname);
Until (picname = '') Or zfinish;
End.