[Back to GRAPHICS SWAG index] [Back to Main SWAG index] [Original]
{
Here a program to display files from deLux Paint II (*.LBM files)
drawings. It uses a PD BGI driver for 320x200x256 color mode. Other
drivers can also be used. Otherwise look in the SWAG lib for routines to
enter this graphics mode and set a pixel in a certain color.
Code isn't optimal and can be made much faster but works. It doesn't
display some brushes because of some undocumented sections in the LBM
file. If the defines are made active the file is decoded and dumped
textual to the screen. After the program a part of a small PD text file
I found and used as base for this program. It contained some bugs but
one evening works does a lot.
Btw. Does anybody know how to distinguish deLux Paint II and deLux Paint
II Enhanced files?
}
{---------------------------------------------------------}
{ Written by : Ir. G.W. van der Vegt }
{ Purpose : a Delux Paint II LBM file displayer/decoder}
{ displays 16 and 256 color bitmaps but no }
{ brushes and Delux Paint IIe files yet }
{ }
{ Displays at the moment only }
{ 320x200 or smaller pictures. }
{ }
{ Uses a PD SVGA driver to access MCGA mode. }
{ Substitute your own if you havn't got it. }
{ }
{ File format info by Bob Montgomery 9-21-90, although }
{ it wasn't very accurate (he forgot Motorola swaps }
{ lo & hi byes of words) and didn't cover the }
{ DPPV, CRNG & GRAB sections. }
{ }
{ Use the verbose (and rle) defines to get a dump of the }
{ lbm file. }
{---------------------------------------------------------}
PROGRAM lbm(INPUT,OUTPUT);
USES
crt,
dos,
graph;
routines;
{ DEFINE verbose}
{ DEFINE rle }
{$I SVGA256.INC}
TYPE
rgb = (r,g,b);
dp2l = ARRAY[0..3] OF BYTE; {read left to right}
dp2m = ARRAY[1..4] OF CHAR;
dp2t = ARRAY[rgb] OF BYTE;
dp2h = RECORD
msg1 : dp2m; { "FORM" }
flen : dp2l; { File length - 8 }
msg2, { "ILBM" }
msg3 : dp2m; { "BMHD" }
hlen : dp2l; { Length of header }
width,
Length,
xoff,
yoff : WORD;
planes,
masking,
compression,
pad : BYTE;
tansparent : INTEGER;
x_aspect,
y_aspect : BYTE;
screenwidth,
screenheight : WORD;
END;
CONST
max = 1023;
VAR
f : FILE;
dp2 : dp2h;
msg : dp2m;
len : dp2l;
col : dp2t;
i,
j,
k,
y : INTEGER;
c : BYTE;
bl,
h,
l : LONGINT;
w : WORD;
grmode,
grdriver : INTEGER;
lin : ARRAY[0..max] OF BYTE;
CONST
form : dp2m = ('F','O','R','M');
ilbm : dp2m = ('I','L','B','M');
bmhd : dp2m = ('B','M','H','D');
cmap : dp2m = ('C','M','A','P');
body : dp2m = ('B','O','D','Y');
{$F+}
FUNCTION Detectvga256 : INTEGER;
BEGIN
Detectvga256 := svga320x200x256;
END;
{$F-}
FUNCTION Len2long(a : dp2l) : LONGINT;
BEGIN
Len2long:=(((a[0]*256+a[1])*256+a[2])*256+a[3]);
END;
FUNCTION Msg2str(a : dp2m) : STRING;
BEGIN
Msg2str:=a[1]+a[2]+a[3]+a[4];
END;
FUNCTION Readnext : BYTE;
VAR
w : WORD;
c : BYTE;
BEGIN
Blockread(f,c,1,w);
IF (w<>1)
THEN
BEGIN
Closegraph;
Writeln('Unexpected EOF encountered');
Halt(3);
END
ELSE Readnext:=c;
END;
CONST
cnt : BYTE = 0;
rle : BOOLEAN = false;
dat : BYTE = 0;
vir : LONGINT = 0;
rel : LONGINT = 0;
FUNCTION Getnext : BYTE;
VAR
c : BYTE;
w : WORD;
BEGIN
(*
get a code BYTE from the data stream.
IF the msb is 1, the 'count' is (1 - code), max = 127. get the next
BYTE from the data stream, AND REPEAT it 'count' times.
IF the msb is 0, the 'count' is (1 + code), max = 128. get the next
'count' bytes from the data stream.
*)
IF (dp2.compression=0)
THEN Getnext:=Readnext
ELSE
IF (cnt=0)
THEN
BEGIN
c:=Readnext;
rle:=(c>127);
IF rle
THEN
BEGIN
cnt :=SHORTINT(1-c);
dat :=Readnext;
Getnext:=dat;
{$IFDEF rle}
Delay(500);
Writeln;
Write('RLE : ',byte2hex(c),' = ',cnt:3,'x',byte2hex(dat));
{$ENDIF}
END
ELSE
BEGIN
cnt :=1+c;
dat :=Readnext;
Getnext:=dat;
{$IFDEF rle}
Delay(500);
Writeln;
Write('UNC : ',byte2hex(c),' : ',byte2hex(dat));
{$ENDIF}
END;
END
ELSE
BEGIN
IF NOT(rle)
THEN dat:=Readnext;
Getnext:=dat;
{$IFDEF rle}
IF NOT(rle) THEN Write(' ',byte2hex(dat));
{$ENDIF}
END;
Dec(cnt);
rel:=Filepos(f)-h;
Inc(vir);
END;
BEGIN
Assign(f,Paramstr(1)+'.lbm');
Reset(f,1);
Blockread(f,dp2,Sizeof(dp2));
WITH dp2 DO
BEGIN
{$IFDEF verbose}
FOR i:=1 TO Sizeof(msg1) DO Write(msg1[i]); Writeln;
FOR i:=1 TO Sizeof(msg2) DO Write(msg2[i]); Writeln;
{$ENDIF}
IF (msg1<>form) OR (msg2<>ilbm) OR (msg3<>bmhd)
THEN
BEGIN
Writeln('No DeLux Paint LBM file.');
Halt(1);
END;
{$IFNDEF verbose}
grdriver:=Installuserdriver('SVGA256',@detectvga256);
grmode :=svga320x200x256;
grdriver:=detect;
Initgraph(grdriver,grmode,'');
{$ENDIF}
{----Low & high words/bytes are swapped (Motorola 680x0 convention)}
{$IFDEF verbose}
Writeln('filelength : ',Len2long(flen));
Writeln('headlength : ',Len2long(hlen));
{$ENDIF}
{----Low & high bytes are swapped (Motorola 680x0 convention)}
width :=Swap(width);
Length :=Swap(Length);
xoff :=Swap(xoff);
yoff :=Swap(yoff);
screenwidth :=Swap(screenwidth);
screenheight:=Swap(screenheight);
{$IFDEF verbose}
Writeln('W .L : ',width ,'x',Length);
Writeln('Xo.Yo : ',xoff ,'x',yoff );
Writeln('Xa.Ya : ',x_aspect ,'x',y_aspect);
Writeln('W. H : ',screenwidth,'x',screenheight);
Writeln('Planes: ',planes);
Writeln('Pad : ',pad);
{$ENDIF}
Blockread(f,msg,Sizeof(msg));
Blockread(f,len,Sizeof(len));
{$IFDEF verbose}
Writeln(Msg2str(msg));
Delay(1000);
{$ENDIF}
IF (msg=cmap)
THEN
BEGIN
l:=Len2long(len);
{$IFDEF verbose}
Writeln('CMAPlen : ',l);
{$ENDIF}
FOR i:=1 TO l DIV 3 DO
BEGIN
Blockread(f,col,Sizeof(col));
{$IFDEF verbose}
Delay(100);
Writeln(i-1:4,col[r]:4,col[g]:4,col[b]:4);
{$ELSE}
Setrgbpalette(i-1,col[r] DIV 4,col[g] DIV 4,col[b] DIV 4);
{$ENDIF}
END;
Blockread(f,msg,Sizeof(msg));
END;
{----dump unkown sections dppv
the 4 bytes Length is mostly 104 bytes
}
{----dump unkown sections grab
the 4 bytes Length is 4, section found IN a brush only,
}
{----dump 4 unkown sections crng :
seems each TO consist OF two entries WITH :
00 00 0a aa,00 00 01 0e
00 00 0a aa,00 00 00 00
00 00 0a aa,00 00 00 00
00 00 0a aa,00 00 00 00
brushes contain different values.
}
WHILE (msg<>body) DO
BEGIN
Blockread(f,len,Sizeof(len));
l:=Len2long(len);
Writeln(Msg2str(msg)+' : ',l);
FOR h:=1 TO l DO
BEGIN
Blockread(f,c,1);
Write(' ',byte2hex(c));
END;
Blockread(f,msg,Sizeof(msg));
Writeln;
END;
IF (msg=body)
THEN
BEGIN
{$IFDEF verbose}
Writeln(Msg2str(msg));
{$ENDIF}
Blockread(f,len,Sizeof(len));
l:=Len2long(len);
h :=Filepos(f);
{$IFDEF verbose}
Writeln('BODYlen : ',l);
{$ENDIF}
IF compression=0
THEN bl:=l DIV Length DIV planes
ELSE bl:=width DIV 8;
{$IFDEF verbose}
Writeln('Bytew : ',bl);
{$ENDIF}
FOR y:=1 TO Length DO
BEGIN
FOR i:=0 TO max DO lin[i]:=0;
{$R-}
FOR j:=0 TO planes-1 DO
FOR i:=0 TO bl-1 DO
BEGIN
c:=Getnext;
FOR k:=0 TO 7 DO
IF (c AND (128 SHR k))>0
THEN lin[(i*8)+k]:=lin[(i*8)+k] OR 1 SHL j;
END;
{$R+}
{$IFNDEF verbose}
FOR i:=1 TO width DO
Putpixel(i,y,lin[i])
{$ENDIF}
END;
END;
{$IFNDEF verbose}
WHILE NOT Keypressed DO;
Closegraph;
{$ELSE}
Writeln('image ',LONGINT(width)*Length*planes DIV 8);
Writeln('bodys ',h);
Writeln('files ',Filesize(f));
Writeln('filep ',Filepos(f));
Writeln('heads ',Sizeof(dp2h));
Writeln('virtu ',vir);
{$ENDIF}
Close(f);
END;
END.
(*
deluxe paint ii lbm & iff files
the deluxe paint lbm (AND iff) FILE header (40 bytes) has the following
content:
struct dp2
{ CHAR msg1[4]; "form"
BYTE a3, a2, a1, a0; FILE Length - 8 (Read left TO right)
CHAR msg2[8]; "ilbmbmhd"
BYTE b3, b2, b1, b0; Length OF header (Read left TO right)
Int width, Length, xoff, yoff;
BYTE planes, masking, compression, pad;
Int tansparent;
BYTE x_aspect, y_aspect;
Int screenwidth, screenheight;
} ;
there may be a color map following a STRING "cmap" IN the FILE. after cmap
is the Length OF the color map (4 bytes, Read left TO right). the color
map is BYTE triples (r, g, b) FOR each colors. the number OF colors is
1 shifted left by planes (1 << planes).
the actual picture data follows a STRING "body" AND Length OF the picture
data (4 bytes Read left TO right). the picture data is organized on a
color plane basis FOR dp2, AND on a pixel basis FOR dp2e (enhanced).
thus, FOR dp2:
there are (width / 8) bytes per row.
the data stream FOR each row consists OF all the bytes FOR plane 0,
followed by all the bytes FOR plane 1, etc.
AND FOR dp2e:
there are (width) bytes/row, where each BYTE is a pixel color.
IF the data is uncomperessed (compression flag = 0), the data stream bytes
are fed TO the OUTPUT unmodified. IF it is compressed, it is run Length
encoded as follows:
get a code BYTE from the data stream.
IF the msb is 1, the 'count' is (1 - code), max = 127. get the next
BYTE from the data stream, AND REPEAT it 'count' times.
IF the msb is 0, the 'count' is (1 + code), max = 128. get the next
'count' bytes from the data stream.
*)
[Back to GRAPHICS SWAG index] [Back to Main SWAG index] [Original]