home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DTP en Graphics 1
/
dtpgraf1.zip
/
dtpgraf1
/
GRAPHICS
/
GRAPHICS.H_P
/
PCX2GIF
/
PCX2GIFU.PAS
< prev
Wrap
Pascal/Delphi Source File
|
1993-01-20
|
20KB
|
568 lines
UNIT PCX2GIFU;
{Unit contains the function PcxToGif which compresses the X and Y
dimensions of the PCX file by the amount of the constant Lines2Compress
and stores in the GIF file. Specifically designed for reducing by 3 fold
the large 2 color PCX files produced by the Logitech hand scanner to
smaller managable GIF files with 10 colors (3 squared plus black)
in gray scale. Uses no graphics functions and no graphics screen display.
Written by Rob Crockett [76167,1561] April 25, 1992. The include file
CMPRSS.INC written by Bob Berry [76555,167] 1988. Much of the PCX
routines are from the PCX.PAS unit written by
J. L. Allison [71565,303] Dec 30, 1989.}
INTERFACE
Uses {Graph,} Dos;
Function PcxToGif(PcxFileName,GifFileName: String; Compression: Integer):Integer;
IMPLEMENTATION
{I+} {no I/O checking}
{R-} {no variable range checking}
Const
top_two_bits =$C0;
bottom_six_bits =$3F;
NumberOfPlanes =4;
NumberBytesPerPlane=250; {x<=2000}
{ Lines2Compress =3;} {1 (no compression) to 6 times..}
{verticle and horizontal compression}
Type
rgb=array [1..3] of byte;
palette=array [0..15] of rgb;
pcx_header=record
manufacturer: byte; {10 => zsoft .pcx}
version: byte; { 0 => 2.5
2 => 2.8 w/palette information
3 => 2.8 w/o palette info
5 => 3.0 }
encoding: byte; { 1 => .pcx run length encoding}
bits_per_pixel: byte; { bits_per_pixel per plane }
x1,y1,x2,y2: word; { upper left, lower right corners }
hres: word; { horizontal resolution }
vres: word; { vertical resolution }
colormap: array[0..15,0..2] of byte; {rgb} {palette;}
reserved: byte;
nplanes: byte; {number of color planes}
bytes_per_line: word; {bytes_per_scan_line per plane
ALWAYS EVEN FOR .PCX FILES }
palette_info: word; { 1 => color/bw
2 => grayscale }
filler: array [1..58] of byte; {pad to 128 bytes total}
end;
FourPlaneLine =Array [0..(NumberOfPlanes-1),0..(NumberBytesPerPlane-1)] of Byte;
FourLineLine =Array [0..5,0..((NumberBytesPerPlane*8)-1)] of Byte;
OnePlaneLine =Array [0..((NumberBytesPerPlane*8)-1)] of Byte;
FourPlaneLinePointer=^FourPlaneLine;
FourLineLinePointer=^FourLineLine;
OnePlaneLinePointer=^OnePlaneLine;
Var
Lines2Compress: Integer;
pcx_file :file;
header :pcx_header;
BufferLine: FourPlaneLinePointer; {contains 4 bitplanes as bits}
ScreenLines: FourLineLinePointer; {contains color numbers as bytes}
CompressedLine: OnePlaneLinePointer; {compressed color numbers as bytes}
Type
ByteFile = File of Byte;
Var
Signature : Array[0..5] of Byte; {GIF signature}
SDescriptor : Array[1..7] of byte; {screen descriptor}
ColorMap : Array[0..2,0..255] of byte; {RGB color map}
IDescriptor : Array[1..10] of byte; {image descriptor}
GifFile : ByteFile; {output file}
Debugger : Boolean;
XX,YY,GetMaxXX,GetMaxYY,GetMaxCColor: Integer;
GifTerminator: Byte; {';' GIF terminator}
{$I CMPRSS.INC} {Include Bob Berry's LZW GIF compression routines}
Procedure SetMaxConstants;
Begin
GetMaxXX:=((Header.bytes_per_line*8) div Lines2Compress)-1;
GetMaxYY:=((Header.Y2-Header.Y1+1) div Lines2Compress)-1;
If Lines2Compress<4
Then GetMaxCColor:=15
Else GetMaxCColor:=255;
End;
Procedure OpenGifFile(FileName:String;Var GifFile: ByteFile);
Var
ErrorCode: Integer;
Begin
Assign(GifFile,FileName); {open output file}
{$I-}ReWrite(GifFile);{$I+}
ErrorCode:=IOResult;
If ErrorCode<>0 then
Begin
Writeln('Error #',ErrorCode,' while opening ',FileName);
Halt;
End;
End;
Procedure OpenPcxFile(FileName:String;Var PcxFile: File);
Var
ErrorCode: Integer;
Begin
Assign(PcxFile,filename); {open input file}
{$I-}Reset(PcxFile,1);{$I+}
ErrorCode:=IOResult;
If ErrorCode<>0 then
Begin
Writeln('Error #',ErrorCode,' while accessing ',FileName);
Halt;
End;
End;
Procedure ClosePcxFile(Var FileLabel: File);
Begin
Close(FileLabel);
End;
Procedure CloseGifFile(Var FileLabel: ByteFile);
Begin
Close(FileLabel);
End;
Procedure GetAllRGBPalette(ColorNum:Integer;Var RedNum,GreenNum,BlueNum:Byte);
{specialized palette for 10 color black and white where lines2compress=3}
Var
Color: Byte;
Begin
If (Header.nplanes>1)
Then
Begin
RedNum:=Header.ColorMap[ColorNum,0];
BlueNum:=Header.ColorMap[ColorNum,1];
GreenNum:=Header.ColorMap[ColorNum,2];
End
Else
Begin
If ColorNum<=SQR(Lines2Compress)
Then Color:=(ColorNum*255) div SQR(Lines2Compress)
Else Color:=1;
RedNum:=Color;GreenNum:=Color;BlueNum:=Color;
End;
End;
Procedure SaveDescriptor(Var GifFile:ByteFile);
Var
I,J :Integer;
Pixel,MaxColor :Byte;
Begin
For I:=0 to 5 do Write(GifFile,Signature[I]);
For I:=1 to 7 do Write(Giffile,SDescriptor[I]);
For J:=0 to GetMaxCColor {MaxColor} do
For I:=0 to 2 do Write(GifFile,ColorMap[I,J]);
For I:=1 to 10 do Write(GifFile,IDescriptor[I]);
End;
Procedure SetGifDescriptor;
{sets the gif signature 'Signature[0..5]', screen
descriptor array 'SDescriptor[1..7]', and global color
map as follows:
Signature = GIF87a as six bytes
Screen Descriptor as seven bytes:
bits
7 6 5 4 3 2 1 0 Byte #
+---------------+
| | 1
+-Screen Width -+ Raster width in pixels (LSB first)
| | 2
+---------------+
| | 3
+-Screen Height-+ Raster height in pixels (LSB first)
| | 4
+-+-----+-+-----+ M = 1, Global color map follows Descriptor
|M| cr |0|pixel| 5 cr+1 = # bits of color resolution
+-+-----+-+-----+ pixel+1 = # bits/pixel in image (bit 3 of word 5 reserved)
| background | 6 background=Color index of screen background
+---------------+ (color is defined from the Global color
|0 0 0 0 0 0 0 0| 7 map or default map if none specified)
+---------------+
Global Color Map has 3*GetMaxColor bytes.
}
Const
X = 1;
Y = 1;
X1 = 40;
Y1 = 1;
GIF87a: Array[0..5] of Byte = (71,73,70,56,55,97);
Var
I,J :Integer;
CR,Pixel :Byte;
{Regs: Registers;}
Begin
{*** SCREEN DESCRIPTOR ******************************}
{Signature}
For I:=0 to 5 do
Signature[I]:=GIF87a[I];
{Screen Width}
SDescriptor[1]:=(GetMaxXX+1) Mod 256;
SDescriptor[2]:=(GetMaxXX+1) Div 256;
{Screen Height}
SDescriptor[3]:=(GetMaxYY+1) Mod 256;
SDescriptor[4]:=(GetMaxYY+1) Div 256;
SDescriptor[5]:=0;
{M=1}
SDescriptor[5]:=SDescriptor[5] OR 128; {1000000}
{CR+1=bits color resolution}
CR:=1;
Case GetMaxCColor of {CR+1=color resolution=bits per RGB color componant}
1: CR:=0;
3: CR:=0;
15: CR:=1;
255: CR:=7;
End;
SDescriptor[5]:=SDescriptor[5] OR (CR shl 4);
{Pixel+1=bits per pixel in image}
Pixel:=3;
Case GetMaxCColor of
1: Pixel:=0;
3: Pixel:=1;
15: Pixel:=3;
255: pixel:=7;
End;
SDescriptor[5]:=SDescriptor[5] OR Pixel;
{Background color}
SDescriptor[6]:=0; {set as black}
{Reserved}
SDescriptor[7]:=0;
{****** Global Color Map *********************}
For I:=0 to GetMaxCColor do
GetAllRGBPalette(I,ColorMap[0,I],ColorMap[1,I],ColorMap[2,I]);
{*** IMAGE DESCRIPTOR *****************************}
{ImageSepChar ',' }
IDescriptor[1]:=Ord(',');
{Image Left}
IDescriptor[2]:=0 mod 256;
IDescriptor[3]:=0 div 256;
{Image Top}
IDescriptor[4]:=0 mod 256;
IDescriptor[5]:=0 div 256;
{Image Width}
IDescriptor[6]:=(GetMaxXX+1) mod 256;
IDescriptor[7]:=(GetMaxXX+1) div 256;
{Image Height}
IDescriptor[8]:=(GetMaxYY+1) mod 256;
IDescriptor[9]:=(GetMaxYY+1) div 256;
{ImageSpecByte}
IDescriptor[10]:=0;
{M=1 local color map follows, use 'pixel'}
{M=0 use global color map, ignore 'pixel'}
{IDescriptor[10]:=IDescriptor[10] OR 128;} {10000000}
{I=0 formatted in sequential order}
{I=1 formatted in interlaced order}
{IDescriptor[10]:=IDescriptor[10] OR 64;} {01000000}
{Pixel+1=bits per pixel for this image}
Case GetMaxCColor of
1: Pixel:=0;
3: Pixel:=1;
15: Pixel:=3;
255: pixel:=7;
End;
IDescriptor[10]:=IDescriptor[10] OR Pixel;
End;
Procedure step_line_pos(var pos:integer;var plane:byte);
begin
inc(pos);
if pos>=header.bytes_per_line
then
begin
pos:=0;
inc(plane);
if plane>header.nplanes then exit;
end;
end;
Procedure CompressLine;
{Compresses Lines2Compress*Lines2Compress color numbers stored
in ScreenLines and puts the result in Compressed line. If
Lines2Compress=3, then 9 color numbers are compressed to form one
pixel. In a black and white image, this increases the number of colors
from 2 to 10 (black plus 3*3=9).}
Var
I,J,K,L,M,N,X:Integer;
Begin
For X:=0 to GetMaxXX do
CompressedLine^[X]:=0;
M:=Lines2Compress-1;
K:=0;
N:=SQR(Lines2Compress);
If (Header.Nplanes>1) {color display--average the pixels}
Then
Begin
For X:=0 to GetMaxXX do
Begin
For I:=0 to M do {horizontal}
Begin
L:=K+I;
For J:=0 to M do {verticle}
CompressedLine^[X]:=CompressedLine^[X]
+ScreenLines^[J,L]; {add pixels}
End;
CompressedLine^[X]:=CompressedLine^[X] div N; {average pixels}
K:=K+Lines2Compress;
End;
End
Else {black and white--add the pixels}
Begin
For X:=0 to GetMaxXX do
Begin
For I:=0 to M do {horizontal}
Begin
L:=K+I;
For J:=0 to M do {verticle}
CompressedLine^[X]:=CompressedLine^[X]
+ScreenLines^[J,L]; {add pixels}
End;
K:=K+Lines2Compress;
End;
End;
End;
Procedure RefreshCompressedLine;
Var
count,value,plane :byte;
running_count,
X,Y,I,J,K,
PlaneNumber,
CmprssCntr :Integer;
Begin
For CmprssCntr:=0 to Lines2Compress-1 do
Begin
plane:=1;
running_count:=0; {byte count in X direction}
{****get bit plane bits from PCX file****}
{store up to 4 bit planes in BufferLine as bits}
repeat
blockread(pcx_file,count,1);
if (count and top_two_bits) = top_two_bits { top two are set }
then
begin
count:=count and bottom_six_bits;
blockread(pcx_file,value,1);
for I:=1 to count do
begin
BufferLine^[Plane-1,Running_Count]:=Value;
step_line_pos(running_count,plane);
end;
end
else
begin
BufferLine^[Plane-1,Running_Count]:=Count;
step_line_pos(running_count,plane);
end;
until plane>header.nplanes;
{****convert bit plane bits to color number bytes****}
{convert Bufferline bit plane bits to ScreenLines color number bytes}
For I:=0 to ((header.bytes_per_line*8)-1) do
ScreenLines^[CmprssCntr,I]:=0; {clear the buffer}
K:=0; {repeat for each Y line}
For J:=0 to (header.bytes_per_line-1) do {X direction byte count}
For I:=7 downto 0 do {high bit to low bit}
Begin
For PlaneNumber:=Header.nplanes-1 downto 0 do
{high plane to low plane}
Begin {convert bit planes to byte}
ScreenLines^[CmprssCntr,K]
:=ScreenLines^[CmprssCntr,K] shl 1; {advance prev bit}
If Odd(BufferLine^[PlaneNumber,J] shr I)
Then ScreenLines^[CmprssCntr,K]
:=Succ(ScreenLines^[CmprssCntr,K]);
End;
K:=Succ(K); {X direction color number cnt}
End;
End; {of for CmprssCntr:=0 to Lines2Compress-1}
{******Compress ScreenLine color numbers to CompressedLine color}
{numbers. Compress by factor of Lines2Compress}
CompressLine;
End; {of refreshcompressedline}
Function GetByte:Integer;
{Called by the LZW compression routines, GetByte produces
a byte representing the color value of a pixel.
The byte is packaged as the low byte of a word (integer).
GetByte uses the global variables XX,YY to keep track of
its position in the array CompressedLine, the source of the bytes, and
refreshes the CompressedLine array when empty (when
XX=GetMaxXX).}
Begin
If XX<GetMaxXX
Then
Begin
XX:=Succ(XX);
GetByte:=CompressedLine^[XX];
{PutPixel(XX,YY,CompressedLine^[XX]); }
End
Else
Begin
If YY<GetMaxYY {-Lines2Compress+1)}
Then
Begin
XX:=0;
YY:=Succ(YY);
RefreshCompressedLine;
GetByte:=CompressedLine^[XX];
{PutPixel(XX,YY,CompressedLine^[XX]);}
End
Else
Begin
GetByte:=(-1);
End;
End;
End;
Procedure PutByte(B:Integer);
{Called by the LZW compression routines, PutByte sends a byte
of data to the forming GIF file. The first byte sent by the LZW
compression routings is the 'Minimum Code Size', next byte is
the block size, then the bytes forming the data block, the next
block size byte, next block data bytes, etc. The byte is accepted
from the compression routines as the low byte of an integer.}
Var
ByteNum: Byte;
Begin
ByteNum:=Lo(B);
Write(GifFile,ByteNum);
End;
Function GetMinCodeSize: Byte;
{Produces the minimum number of bits required to represent
the actual pixel value (the color number). This would be the same
as the bits per pixel except that because of algorithmic constraints
of the LZW compression routines, black and white images with a
bits-per-pixel of 1 have a minimum code size of 2. Thus the
mincodesize can be from 2 (black and white) to 8 (256 colors).}
Var
Code: Byte;
Begin
Case GetMaxCColor of
1: Code:=2;
3: Code:=2;
15: Code:=4;
255: Code:=8;
End;
GetMinCodeSize:=Code;
End;
(*
Procedure PlotLine(Line: Word);
Var
XMax,Y,X: Integer;
Begin
XMax:=((header.bytes_per_line*8) div Lines2Compress);
For X:=0 to XMax do
PutPixel(X+Header.X1,Line+Header.Y1,CompressedLine^[X]);
End;
*)
Function GetSeconds:Real;
Var
Hour,Minute,Second,Sec100 :Word;
Begin
GetTime(Hour,Minute,Second,Sec100);
GetSeconds:=Hour*3600.0+Minute*60.0+Second+Sec100/100.0;
End;
{****MAIN PROGRAM**************************}
Function PcxToGif(PcxFileName,GifFileName: String; Compression:Integer):Integer;
{Master function to create a GIF file 'FileName' from the graphics screen.
Returns ScreenToGif=0 if no errors, ScreenToGif<>0 if some error
encountered.}
Var
GifResult,I,GraphDriver,
Graphmode :Integer;
T0,T1 :Real;
{global var XX,YY : Integer}
Begin
Lines2Compress:=Compression;
OpenPcxFile(PcxFileName,pcx_file); {open file for input}
OpenGifFile(GifFileName,GifFile); {open the file for output}
Blockread(pcx_file,header,sizeof(header)); {read PCX header}
SetMaxConstants; {set getmaxx,getmaxy,getmaxcolor}
Write('Input file ',PcxFileName,' width: ',Header.Bytes_per_line*8:4);
Writeln(' height: ',Header.Y2-Header.Y1+1:4);
Write('Output file ',GifFileName,' width: ',GetMaxXX+1:4);
Writeln(' height: ',GetMaxYY+1:4);
{ GraphDriver:=Detect;
InitGraph(GraphDriver,GraphMode,'');
}
New(BufferLine); {reserve space for arrays}
New(ScreenLines);
New(CompressedLine);
T0:=GetSeconds; {Time check T0}
RefreshCompressedLine; {get first several PCX lines}
T1:=GetSeconds; {Time check T1}
Writeln('Estimated Time (min): ',(((T1-T0)*GetMaxYY)/43.0):4:1);
Writeln('Working...');
SetGifDescriptor; {set up GIF file info header}
SaveDescriptor(GifFile); {send info header to GIF file}
XX:=-1; {set (X,Y) for screen location...}
YY:=0; {...used in GetByte function.}
T0:=GetSeconds;
GifResult:= CompressGif(GetMinCodeSize); {send pcx data to GIF file}
T1:=GetSeconds;
WriteLn('Time used (min): ',(T1-T0)/60.0:4:1);
GifTerminator:=$3B; {';'}
Write(GifFile,GifTerminator); {send ';' to end GIF mode}
Dispose(ScreenLines); {free up memory}
Dispose(BufferLine);
Dispose(CompressedLine);
CloseGifFile(GifFile); {close the file}
ClosePcxFile(pcx_file);
{ Readln;
CloseGraph;
}
PcxToGif:=GifResult; {pass along error codes}
End;
END.