{ As I follow this forum, many requests are made for PCX graphics file routines. Those that are looking for Read_PCX info can find it on the ZSoft BBS in a wonderful Pascal example: ShowPCX. On the other hand, there is next to zilch out there on how to Write_PCX files. I know.... I searched and searched and couldn't find a thing! So with a little brute force and a few ZSoft C language snippets , I got this together: PCX_W.Write_PCX (Name:Str80); given to the public domain and commonweal. pseudocode: set 640x480x16 VGAhi graphics mode only for now getimage 1 row at a time reorganize the BGI color planes into PCX format order encode the raw PCX line into a run length limited compressed PCX line blockwrite the compressed PCX line to your.PCX file } {$R-} {Range checking, turn off when debugged} unit PCX_W; { --------------------- Interface ----------------- } interface type Str80 = string [80]; procedure Write_PCX (Name:Str80); { ===================== Implementation ============ } implementation uses Graph; {-------------- Write_PCX --------------} procedure Write_PCX (Name:Str80); const RED1 = 0; GREEN1 = 1; BLUE1 = 2; type ArrayPal = array [0..15, RED1..BLUE1] of byte; const MAX_WIDTH = 4000; { arbitrary - maximum width (in bytes) of a PCX image } INTENSTART = $5; BLUESTART = $55; GREENSTART = $A5; REDSTART = $F5; type Pcx_Header = record {comments from ZSoft ShowPCX pascal example} Manufacturer: byte; { Always 10 for PCX file } Version: byte; { 2 - old PCX - no palette (not used anymore), 3 - no palette, 4 - Microsoft Windows - no palette (only in old files, new Windows version uses 3), 5 - with palette } Encoding: byte; { 1 is PCX, it is possible that we may add additional encoding methods in the future } Bits_per_pixel: byte; { Number of bits to represent a pixel (per plane) - 1, 2, 4, or 8 } Xmin: integer; { Image window dimensions (inclusive) } Ymin: integer; { Xmin, Ymin are usually zero (not always)} Xmax: integer; Ymax: integer; Hdpi: integer; { Resolution of image (dots per inch) } Vdpi: integer; { Set to scanner resolution - 300 is default } ColorMap: ArrayPal; { RGB palette data (16 colors or less) 256 color palette is appended to end of file } Reserved: byte; { (used to contain video mode) now it is ignored - just set to zero } Nplanes: byte; { Number of planes } Bytes_per_line_per_plane: integer; { Number of bytes to allocate for a scanline plane. MUST be an an EVEN number! Do NOT calculate from Xmax-Xmin! } PaletteInfo: integer; { 1 = black & white or color image, 2 = grayscale image - ignored in PB4, PB4+ palette must also be set to shades of gray! } HscreenSize: integer; { added for PC Paintbrush IV Plus ver 1.0, } VscreenSize: integer; { PC Paintbrush IV ver 1.02 (and later)} { I know it is tempting to use these fields to determine what video mode should be used to display the image - but it is NOT recommended since the fields will probably just contain garbage. It is better to have the user install for the graphics mode he wants to use... } Filler: array [74..127] of byte; { Just set to zeros } end; Array80 = array [1..80] of byte; ArrayLnImg = array [1..326] of byte; { 6 extra bytes at beginng of line that BGI uses for size info} Line_Array = array [0..MAX_WIDTH] of byte; ArrayLnPCX = array [1..4] of Array80; var PCXName : File; Header : Pcx_Header; { PCX file header } ImgLn : ArrayLnImg; PCXLn : ArrayLnPCX; RedLn, BlueLn, GreenLn, IntenLn : Array80; Img : pointer; {-------------- BuildHeader- -----------} procedure BuildHeader; const PALETTEMAP: ArrayPal= { R G B } (($00, $00, $00), { black } ($00, $00, $AA), { blue } ($00, $AA, $00), { green } ($00, $AA, $AA), { cyan } ($AA, $00, $00), { red } ($AA, $00, $AA), { magenta } ($AA, $55, $00), { brown } ($AA, $AA, $AA), { lightgray } ($55, $55, $55), { darkgray } ($55, $55, $FF), { lightblue } ($55, $FF, $55), { lightgreen } ($55, $FF, $FF), { lightcyan } ($FF, $55, $55), { lightred } ($FF, $55, $FF), { lightmagenta } ($FF, $FF, $55), { yellow } ($FF, $FF, $FF) );{ white } var i : word; begin with Header do begin Manufacturer := 10; Version := 5; Encoding := 1; Bits_per_pixel := 1; Xmin := 0; Ymin := 0; Xmax := 639; Ymax := 479; Hdpi := 640; Vdpi := 480; ColorMap := PALETTEMAP; Reserved := 0; Nplanes := 4; { Red, Green, Blue, Intensity } Bytes_per_line_per_plane := 80; PaletteInfo := 1; HscreenSize := 0; VscreenSize := 0; for i := 74 to 127 do Filler [i] := 0; end; end; {-------------- GetBGIPlane ------------} procedure GetBGIPlane (Start:word; var Plane:Array80); var i : word; begin for i:= 1 to Header.Bytes_per_line_per_plane do Plane [i] := ImgLn [Start +i -1] end; {-------------- BuildPCXPlane ----------} procedure BuildPCXPlane (Start:word; Plane:Array80); var i : word; begin for i := 1 to Header.Bytes_per_line_per_plane do PCXLn [Start] [i] := Plane [i]; end; {-------------- EncPCXLine -------------} procedure EncPCXLine (PlaneLine : word); { Encode a PCX line } var This, Last, RunCount : byte; i, j : word; {-------------- EncPut -----------------} procedure EncPut (Byt, Cnt :byte); const COMPRESS_NUM = $C0; { this is the upper two bits that indicate a count } var Holder : byte; begin {$I-} if (Cnt = 1) and (COMPRESS_NUM <> (COMPRESS_NUM and Byt)) then blockwrite (PCXName, Byt,1) { single occurance } {good place for file error handler!} else begin Holder := (COMPRESS_NUM or Cnt); blockwrite (PCXName, Holder, 1); { number of times the following color occurs } blockwrite (PCXName, Byt, 1); end; {$I+} end; begin i := 1; { used in PCXLn } RunCount := 1; Last := PCXLn [PlaneLine][i]; for j := 1 to Header.Bytes_per_line_per_plane -1 do begin inc (i); This := PCXLn [PlaneLine][i]; if This = Last then begin inc (RunCount); if RunCount = 63 then { reached PCX run length limited max yet? } begin EncPut (Last, RunCount); RunCount := 0; end; end else begin if RunCount >= 1 then Encput (Last, RunCount); Last := This; RunCount := 1; end; end; if RunCount >= 1 then { any left over ? } Encput (Last, RunCount); end; { - - -W-R-I-T-E-_-P-C-X- - - - - - - - } const XMAX = 639; YMAX = 479; var i, j, Size : word; begin BuildHeader; assign (PCXName,Name); {$I-} rewrite (PCXName,1); blockwrite (PCXName,Header,sizeof (Header)); {good place for file error handler!} {$I+} setviewport (0,0,XMAX,YMAX, ClipOn); Size := imagesize (0,0,XMAX,0); { size of a single row } getmem (Img,Size); for i := 0 to YMAX do begin getimage (0,i,XMAX,i,Img^); { Grab 1 line from the screen store in Img buffer } move (Img^,ImgLn,Size {326}); GetBGIPlane (INTENSTART, IntenLn); GetBGIPlane (BLUESTART, BlueLn ); GetBGIPlane (GREENSTART, GreenLn); GetBGIPlane (REDSTART, RedLn ); BuildPCXPlane (1, RedLn ); BuildPCXPlane (2, GreenLn); BuildPCXPlane (3, BlueLn ); BuildPCXPlane (4, IntenLn); { 320 bytes/line uncompressed } for j := 1 to Header.NPlanes do EncPCXLine (j); end; freemem (Img,Size); (* Release the memory *) {$I-} close (PCXName); (* Save the Image *) {$I+} end; end {PCX.TPU} . { -----------------------Test Program -------------------------- } program WritePCX; uses Graph, PCX_W; {-------------- DrawHorizBars ----------} procedure DrawHorizBars; var i, Color : word; begin cleardevice; Color := 15; for i := 0 to 15 do begin setfillstyle (solidfill,Color); bar (0,i*30,639,i*30+30); { 16*30 = 480 } dec (Color); end; end; {-------------- Main -------------------} var NameW : Str80; Gd, Gm : integer; begin writeln; if (ParamCount = 0) then { no DOS command line parameters } begin write ('Enter name of PCX picture file to write: '); readln (NameW); writeln; end else begin NameW := paramstr (1); { get filename from DOS command line } end; if (Pos ('.', NameW) = 0) then { make sure the filename has PCX extension } NameW := Concat (NameW, '.pcx'); Gd:=VGA; Gm:=VGAhi; {640x480, 16 colors} initgraph (Gd,Gm,'..\bgi'); { path to your EGAVGA.BGI } DrawHorizBars; readln; Write_PCX (NameW); { PCX_W.TPU } closegraph; { Close graphics } textmode (co80); { back to text mode } end. { Write_PCX } { OK, everybody, I hope this gets you started. I had a lot of fun setting it up. There are some obvious places that need optimization... especially the disk intensive blockwrites. If someone could please figure out holding about 4k or so in pointers of the encoded PCX file before writing, I'd sure appreciate it!. (please post for everyone, if you do.) }