Visit our Sponsor   Visit our Sponsor
delphi3000.com - the free delphi knowledge platform
delphi3000.com - the free delphi knowledge platform
Have a look at your member-status

connecting people's knowledge


  - Recent ArticlesRSS feed for Recent Articles on delphi3000.com
  - List of All Articles
  - Top Viewed Articles
  - Articles (+Attachem.)
  - Articles Of Interest
  - Categories
  - Top Uploader
  - Search
  - Index

  - My Home
  - Submit an Article
  - My Articles
  - My Personal Data
  - My Bookmarks
  - Activities
  - Login/Logout

  - Sign Up
  - Why Sign Up
  - Newsletter

  - Press
  - Advertise

  - Contact
  - Feedback





Community
Borland
ClubeDelphi
Dr. Bob
UK-BUG
Delphi Meetings
Planeta Delphi







Startblatt.de






Share this article with friendsShare this article with friends
Rate this articleRate this article - to keep the quality of delphi3000.com !
Comment this article or read through previous comments (1)


PCXImageFormat this article printer-friendly!Bookmark function is only available for registered users!
Product:
Delphi 5.x (or higher)
Category:
Component Writing
Skill Level:
Scoring:
Last Update:
05/13/2002
Search Keys:
delphi delphi3000 article borland vcl code-snippet TPCXImage Image Component ZSoft PCPaintBrush
Times Scored:
5
Visits:
2954
Uploader: Maarten de Haan
Company: TNO Industrial Technology
Reference: N/A
 
Question/Problem/Abstract:
How to write a graphic component?
Answer:



///////////////////////////////////////////////////////////////////////
//                                                                   //
//                           TPCXImage                               //
//                           =========                               //
//                                                                   //
// Completed: The 10th of August 2001                                //
// Author:    M. de Haan                                             //
// Email:     M.deHaan@inn.nl                                        //
// Tested:    under W95 SP1, NT4 SP6                                 //
// Version:   1.0                                                    //
//-------------------------------------------------------------------//
// Update:    The 14th of August 2001 to version 1.1.                //
// Reason:    Added version check.                                   //
//            Added comment info on version.                         //
//            Changed PCX header ID check.                           //
//-------------------------------------------------------------------//
// Update:    The 19th of August 2001 to version 2.0.                //
// Reason:    Warning from Delphi about using abstract methods,      //
//            caused by not implementing ALL TGraphic methods.       //
//            (Thanks goes to R.P. Sterkenburg for his diagnostic.)  //
// Added:     SaveToClipboardFormat, LoadFromClipboardFormat,        //
//            GetEmpty.                                              //
//-------------------------------------------------------------------//
// Update:    The 13th of October 2001 to version 2.1.               //
// Reason:    strange errors, read errors, EExternalException, IDE   //
//            hanging, Delphi hanging, Debugger hanging, windows     //
//            hanging, keyboard locked, and so on.                   //
// Changed:   Assign procedure.                                      //
//-------------------------------------------------------------------//
// Update:    The 5th of April 2002 to version 2.2.                  //
// Changed:   RLE compressor routine.                                //
// Reason:    Incompatibility problems with other programs caused    //
//            by the RLE compressor.                                 //
//            Other programs encode: $C0 as: $C1 $C0.                //
//            ($C0 means: repeat the following byte 0 times          //
//            $C1 means: repeat the following byte 1 time.)          //
// Changed:   File read routine.                                     //
// Reason:    Now detects unsupported PCX data formats.              //
// Added:     'Unsupported data format' in exception handler.        //
// Added:     1 bit PCX support in reading.                          //
// Added:     Procedure Convert1BitPCXDataToImage.                   //
// Renamed:   Procedure ConvertPCXDataToImage to                     //
//            Convert24BitPCXDataToImage.                            //
//-------------------------------------------------------------------//
// Update:    The 14th of April 2002 to version 2.3.                 //
//            Now capable of reading and writing 1 and 24 bit PCX    //
//            images.                                                //
// Added:     1 bit PCX support in writing.                          //
// Added:     Procedure ConvertImageTo1bitPCXData.                   //
// Changed:   Procedure CreatePCXHeader.                             //
// Changed:   Procedure TPCXImage.SaveToFile.                        //
//-------------------------------------------------------------------//
// Update:    The 19th of April 2002 to version 2.4.                 //
//            Now capable of reading and writing: 1, 8 and 24 bit    //
//            PCX images.                                            //
// Added:     8 bit PCX support in reading and writing.              //
// Renamed:   Procedure ConvertImageTo1And8bitPCXData.               //
// Renamed:   Procedure Convert1And8bitPCXDataToImage.               //
// Changed:   Procedure fSetPalette, fGetPalette.                    //
//-------------------------------------------------------------------//
// Update:    The 7th of May 2002 to version 2.5.                    //
// Reason:    The palette of 8-bit PCX images couldn't be read in    //
//            the calling program.                                   //
// Changed:   Procedures Assign, AssignTo, fSetPalette, fGetPalette. //
// Tested:    All formats were tested with the following programs:   //
//            - import in Word 97,                                   //
//            * (Word ignores the palette of 1 bit PCX images!)      //
//            - import and export in MigroGrafX.                     //
//            * (MicroGrafX also ignores the palette of 1 bit PCX    //
//              images.)                                             //
//            No problems were detected.                             //
//                                                                   //
//===================================================================//
//                                                                   //
//         The PCX image file format is copyrighted by:              //
//           ZSoft, PC Paintbrush, PC Paintbrush plus                //
//                        Trademarks: N/A                            //
//                       Royalty fees: NONE                          //
//                                                                   //
//===================================================================//
//                                                                   //
// The author can not be held responsable for using this software    //
// in anyway.                                                        //
//                                                                   //
// The features and restrictions of this component are:              //
// ----------------------------------------------------              //
//                                                                   //
// The reading and writing (import / export) of files / images:      //
//     - PCX version 5 definition, PC Paintbrush 3 and higher,       //
//     - RLE-compressed,                                             //
//     - 1 and 8 bit PCX images WITH palette and                     //
//     - 24 bit PCX images without palette,                          //
//     are supported by this component.                              //
//                                                                   //
// Known issues                                                      //
// ------------                                                      //
//                                                                   //
// 1) GetEmpty is NOT tested.                                        //
//                                                                   //
// 2) SaveToClipboardFormat is NOT tested.                           //
//                                                                   //
// 3) LoadFromClipboardFormat is NOT tested.                         //
//                                                                   //
// 4) 4 bit PCX images (with palette) are NOT (yet) implemented.     //
//                                                                   //
///////////////////////////////////////////////////////////////////////

Unit
   PCXImage;

Interface

Uses
   Windows,
   SysUtils,
   Classes,
   Graphics;

Const
   WIDTH_OUT_OF_RANGE    = 'Illegal width entry in PCX file header';
   HEIGHT_OUT_OF_RANGE   = 'Illegal height entry in PCX file header';
   FILE_FORMAT_ERROR     = 'Invalid file format';
   VERSION_ERROR         = 'Only PC Paintbrush (plus) V3.0 and ' +
                           'higher are supported';
   FORMAT_ERROR          = 'Illegal identification byte in PCX file' +
                           ' header';
   PALETTE_ERROR         = 'Invalid palette signature found';
   ASSIGN_ERROR          = 'Can only Assign a TBitmap or a TPicture';
   ASSIGNTO_ERROR        = 'Can only AssignTo a TBitmap';
   PCXIMAGE_EMPTY        = 'The PCX image is empty';
   BITMAP_EMPTY          = 'The bitmap is empty';
   INPUT_FILE_TOO_LARGE  = 'The input file is too large to be read';
   IMAGE_WIDTH_TOO_LARGE = 'Width of PCX image is too large to handle';
   // added 19/08/2001
   CLIPBOARD_LOAD_ERROR  = 'Loading from clipboard failed';
   // added 19/08/2001
   CLIPBOARD_SAVE_ERROR  = 'Saving to clipboard failed';
   // added 14/10/2001
   PCX_WIDTH_ERROR       = 'Unexpected line length in PCX data';
   PCX_HEIGHT_ERROR      = 'More PCX data found than expected';
   PCXIMAGE_TOO_LARGE    = 'PCX image is too large';
   // added 5/4/2002
   ERROR_UNSUPPORTED     = 'Unsupported PCX format';

Const
   sPCXImageFile         = 'PCX V3.0+ image';

// added 19/08/2001
Var
   CF_PCX                : WORD;

///////////////////////////////////////////////////////////////////////
//                                                                   //
//                            PCXHeader                              //
//                                                                   //
///////////////////////////////////////////////////////////////////////

Type
   QWORD                 = Cardinal; // Seems more logical to me...

Type
   fColorEntry = packed record
      ceRed             : BYTE;
      ceGreen           : BYTE;
      ceBlue            : BYTE;
   End; // of packed record fColorEntry

Type
   TPCXImageHeader = packed record
      fID               : BYTE;
      fVersion          : BYTE;
      fCompressed       : BYTE;
      fBitsPerPixel     : BYTE;
      fWindow           : packed record
         wLeft,
         wTop,
         wRight,
         wBottom        : WORD;
         End; // of packed record fWindow
      fHorzResolution   : WORD;
      fVertResolution   : WORD;
      fColorMap         : Array[0..15] of fColorEntry;
      fReserved         : BYTE;
      fPlanes           : BYTE;
      fBytesPerLine     : WORD;
      fPaletteInfo      : WORD;
      fFiller           : Array[0..57] of BYTE;
      End; // of packed record TPCXImageHeader

///////////////////////////////////////////////////////////////////////
//                                                                   //
//                             PCXData                               //
//                                                                   //
///////////////////////////////////////////////////////////////////////

Type
   TPCXData = Object
      fData : Array of BYTE;
   End; // of Type TPCXData

///////////////////////////////////////////////////////////////////////
//                                                                   //
//                             ScanLine                              //
//                                                                   //
///////////////////////////////////////////////////////////////////////

Const
   fMaxScanLineLength = $FFF; // Max image width: 4096 pixels

Type
   mByteArray = Array[0..fMaxScanLineLength] of BYTE;
   pmByteArray = ^mByteArray;

// The "standard" pByteArray from Delphi allocates 32768 bytes,
// which is a little bit overdone here, I think...

Const
   fMaxImageWidth = $FFF; // Max image width: 4096 pixels

Type
   xByteArray = Array[0..fMaxImageWidth] of BYTE;

///////////////////////////////////////////////////////////////////////
//                                                                   //
//                          PCXPalette                               //
//                                                                   //
///////////////////////////////////////////////////////////////////////

Type
   TPCXPalette = packed record
      fSignature : BYTE;
      fPalette   : Array[0..255] of fColorEntry;
   End; // of packed record TPCXPalette

///////////////////////////////////////////////////////////////////////
//                                                                   //
//                             Classes                               //
//                                                                   //
///////////////////////////////////////////////////////////////////////

Type
   TPCXImage = Class;
   TPCXFile  = Class;

///////////////////////////////////////////////////////////////////////
//                                                                   //
//                           PCXFile                                 //
//                                                                   //
//                         File handler                              //
//                                                                   //
///////////////////////////////////////////////////////////////////////

TPCXFile = Class(TPersistent)

   Private
      fHeight                         : Integer;
      fWidth                          : Integer;
      fPCXHeader                      : TPCXImageHeader;
      fPCXData                        : TPCXData;
      fPCXPalette                     : TPCXPalette;
      fColorDepth                     : QWORD;
      fPixelFormat                    : BYTE; // added 5/4/2002
      fCurrentPos                     : QWORD;
      fHasPalette                     : Boolean; // added 7/5/2002

   Protected
      // Protected declarations

   Public
      // Public declarations
      Constructor Create;
      Destructor Destroy; override;
      Procedure LoadFromFile(Const Filename : String);
      Procedure LoadFromStream(Stream : TStream);
      Procedure SaveToFile(Const Filename : String);
      Procedure SaveToStream(Stream : TStream);

   Published
      // Published declarations
      // The publishing is done in the TPCXImage section

End;

///////////////////////////////////////////////////////////////////////
//                                                                   //
//                         TPCXImage                                 //
//                                                                   //
//                       Image handler                               //
//                                                                   //
///////////////////////////////////////////////////////////////////////

TPCXImage = Class(TGraphic)

   Private
      // Private declarations
      fBitmap                         : TBitmap;
      fPCXFile                        : TPCXFile;
      fRLine                          : xByteArray;
      fGLine                          : xByteArray;
      fBLine                          : xByteArray;
      fP                              : pmByteArray;
      fhPAL                           : HPALETTE;

      Procedure fConvert24BitPCXDataToImage;
      Procedure fConvert1And8BitPCXDataToImage;
      Procedure fConvertImageTo24BitPCXData;
      Procedure fConvertImageTo1And8BitPCXData(ImageWidthInBytes :
         QWORD);
      Procedure fFillDataLines(Const fLine : Array of BYTE);
      Procedure fCreatePCXHeader(Const byBitsPerPixel : BYTE;
         Const byPlanes : BYTE; Const wBytesPerLine : DWORD);
      Procedure fSetPalette(Const wNumColors : WORD);
      Procedure fGetPalette(Const wNumColors : WORD);
      Function fGetPixelFormat : TPixelFormat; // Added 07/05/2002
      Function fGetBitmap : TBitmap; // Added 07/05/2002

   Protected
      // Protected declarations
      Procedure Draw(ACanvas : TCanvas; Const Rect : TRect); override;
      Function GetHeight : Integer; override;
      Function GetWidth : Integer; override;
      Procedure SetHeight(Value : Integer); override;
      Procedure SetWidth(Value : Integer); override;
      Function GetEmpty : Boolean; override;

   Public
      // Public declarations
      Constructor Create; override;
      Destructor Destroy; override;
      Procedure Assign(Source : TPersistent); override;
      Procedure AssignTo(Dest : TPersistent); override;
      Procedure LoadFromFile(const Filename : String); override;
      Procedure LoadFromStream(Stream : TStream); override;
      Procedure SaveToFile(const Filename : String); override;
      Procedure SaveToStream(Stream : TStream); override;
      Procedure LoadFromClipboardFormat(AFormat : WORD;
          AData : THandle; APalette : HPALETTE); override;
      Procedure SaveToClipboardFormat(Var AFormat : WORD;
         Var AData : THandle; Var APalette : HPALETTE); override;

   Published
      // Published declarations
      Property Height : Integer
         read GetHeight write SetHeight;
      Property Width : Integer
          read GetWidth write SetWidth;
      Property PixelFormat : TPixelFormat
         read fGetPixelFormat;
      Property Bitmap : TBitmap
         read fGetBitmap; // Added 7/5/2002

End;

Implementation

///////////////////////////////////////////////////////////////////////
//                                                                   //
//                           TPCXImage                               //
//                                                                   //
//                         Image handler                             //
//                                                                   //
///////////////////////////////////////////////////////////////////////
Constructor TPCXImage.Create;

Begin
Inherited Create;
// Init HPALETTE
fhPAL := 0;

// Create a private bitmap to hold the image
If not Assigned(fBitmap) then
   fBitmap := TBitmap.Create;

// Create the PCXFile
If not Assigned(fPCXFile) then
   fPCXFile := TPCXFile.Create;

End;
//---------------------------------------------------------------------
Destructor TPCXImage.Destroy;

Begin
// Reversed order of create
// Free fPCXFile
fPCXFile.Free;
// Free private bitmap
fBitmap.Free;
// Delete palette
If fhPAL <> 0 then
   DeleteObject(fhPAL);
// Distroy all the other things
Inherited Destroy;
End;
//---------------------------------------------------------------------
Procedure TPCXImage.SetHeight(Value : Integer);

Begin
If Value >= 0 then
   fBitmap.Height := Value;
End;
//---------------------------------------------------------------------
Procedure TPCXImage.SetWidth(Value : Integer);

Begin
If Value >= 0 then
   fBitmap.Width := Value;
End;
//---------------------------------------------------------------------
Function TPCXImage.GetHeight : Integer;

Begin
Result := fPCXFile.fHeight;
End;
//---------------------------------------------------------------------
Function TPCXImage.GetWidth : Integer;

Begin
Result := fPCXFile.fWidth;
End;
//---------------------------------------------------------------------
Function TPCXImage.fGetBitmap : TBitmap;

Begin
Result := fBitmap;
End;
//-------------------------------------------------------------------//
// The credits for this procedure go to his work of TGIFImage by     //
// Reinier P. Sterkenburg                                            //
// Added 19/08/2001                                                  //
//-------------------------------------------------------------------//
// NOT TESTED!
Procedure TPCXImage.LoadFromClipboardFormat(AFormat : WORD;
   ADAta : THandle; APalette : HPALETTE);

Var
   Size           : QWORD;
   Buf            : Pointer;
   Stream         : TMemoryStream;
   BMP            : TBitmap;

Begin
If (AData = 0) then
   AData := GetClipBoardData(AFormat);
If (AData <> 0) and (AFormat = CF_PCX) then
   Begin
   Size := GlobalSize(AData);
   Buf := GlobalLock(AData);
   Try
      Stream := TMemoryStream.Create;
      Try
         Stream.SetSize(Size);
         Move(Buf^,Stream.Memory^,Size);
         Self.LoadFromStream(Stream);
      Finally
         Stream.Free;
         End;
   Finally
      GlobalUnlock(AData);
      End;
   End
else
   If (AData <> 0) and (AFormat = CF_BITMAP) then
      Begin
      BMP := TBitmap.Create;
      Try
         BMP.LoadFromClipboardFormat(AFormat,AData,APalette);
         Self.Assign(BMP);
      Finally
         BMP.Free;
         End;
      End
   else
      Raise Exception.Create(CLIPBOARD_LOAD_ERROR);
End;
//-------------------------------------------------------------------//
// The credits for this procedure go to his work of TGIFImage by     //
// Reinier P. Sterkenburg                                            //
// Added 19/08/2001                                                  //
//-------------------------------------------------------------------//
// NOT TESTED!
Procedure TPCXImage.SaveToClipboardFormat(Var AFormat : WORD;
   Var AData : THandle; Var APalette : HPALETTE);

Var
   Stream        : TMemoryStream;
   Data          : THandle;
   Buf           : Pointer;

Begin
If Empty then
   Exit;
// First store the bitmap to the clipboard
fBitmap.SaveToClipboardFormat(AFormat,AData,APalette);
// Then try to save the PCX
Stream := TMemoryStream.Create;
try
   SaveToStream(Stream);
   Stream.Position := 0;
   Data := GlobalAlloc(HeapAllocFlags,Stream.Size);
   try
   If Data <> 0 then
      Begin
      Buf := GlobalLock(Data);
      try
      Move(Stream.Memory^,Buf^,Stream.Size);
      finally
         GlobalUnlock(Data);
         End;
      If SetClipBoardData(CF_PCX,Data) = 0 then
         Raise Exception.Create(CLIPBOARD_SAVE_ERROR);
      End;
   except
      GlobalFree(Data);
      raise;
      End;
   finally
      Stream.Free;
   End;
End;
//-------------------------------------------------------------------//
// NOT TESTED!
Function TPCXImage.GetEmpty : Boolean; // Added 19/08/2002

Begin
If Assigned(fBitmap) then
   Result := fBitmap.Empty
else
   Result := (fPCXFile.fHeight = 0) or (fPCXFile.fWidth = 0);
End;
//---------------------------------------------------------------------
Procedure TPCXImage.SaveToFile(Const Filename : String);

Var
   fPCX : TFileStream;
   W,WW : QWORD;

Begin
If (fBitmap.Width = 0) or (fBitmap.Height = 0) then
   Raise Exception.Create(BITMAP_EMPTY);
W := fBitmap.Width;
WW := W div 8;
If (W mod 8) > 0 then
   Inc(WW);
Case fBitmap.PixelFormat of
   pf1bit  : Begin
             // Fully supported by PCX and by this component
             fCreatePCXHeader(1,1,WW);
             fConvertImageTo1And8BitPCXData(WW);
             fGetPalette(2);
             End;
   pf4bit  : Begin
             // I don't have 4-bit PCX images to test with
             // It will be treated as a 24 bit image
             fCreatePCXHeader(8,3,W);
             fConvertImageTo24BitPCXData;
             End;
   pf8bit  : Begin
             // Fully supported by PCX and by this component
             fCreatePCXHeader(8,1,W);
             fConvertImageTo1And8BitPCXData(W);
             fGetPalette(256);
             End;
   pf15bit : Begin
             // Is this supported in PCX?
             // It will be treated as a 24 bit image
             fCreatePCXHeader(8,3,W);
             fConvertImageTo24BitPCXData;
             End;
   pf16bit : Begin
             // Is this supported in PCX?
             // It will be treated as a 24 bit image
             fCreatePCXHeader(8,3,W);
             fConvertImageTo24BitPCXData;
             End;
   pf24bit : Begin
             // Fully supported by PCX and by this component
             fCreatePCXHeader(8,3,W);
             fConvertImageTo24BitPCXData;
             End;
   pf32bit : Begin
             // Not supported by PCX
             fCreatePCXHeader(8,3,W);
             fConvertImageTo24BitPCXData;
             End;
   else
      Begin
      fCreatePCXHeader(8,3,W);
      fConvertImageTo24BitPCXData;
      End; // of else
   End; // of Case
fPCX := TFileStream.Create(Filename,fmCreate);
Try
   fPCX.Position := 0;
   SaveToStream(fPCX);
finally
   fPCX.Free;
   End; // of finally
SetLength(fPCXFile.fPCXData.fData,0);
End; // of Procedure SaveToFile
//-------------------------------------------------------------------//
Procedure TPCXImage.AssignTo(Dest : TPersistent);

Var
   bAssignToError     : Boolean;

Begin
bAssignToError := True;

If Dest is TBitmap then
   Begin
   // The old AssignTo procedure was like this.
   // But then the palette was couldn't be accessed in the calling
   // program for some reason.
   // --------------------------
   // (Dest as TBitmap).Assign(fBitmap);
   // --------------------------

   // Do the assigning
   (Dest as TBitmap).Assign(fBitmap);

   If fPCXFile.fHasPalette then
      (Dest as TBitmap).Palette := CopyPalette(fhPAL);
      // Now the calling program can access the palette
      // (if it has one)!
   bAssignToError := False;
   End;

If Dest is TPicture then
   Begin
   (Dest as TPicture).Graphic.Assign(fBitmap);
   bAssignToError := False;
   End;

If bAssignToError then
   Raise Exception.Create(ASSIGNTO_ERROR);

// You can write other assignments here, if you want...

End;
//-------------------------------------------------------------------//
Procedure TPCXImage.Assign(Source : TPersistent);

Var
   iX,iY            : DWORD;
   bAssignError     : Boolean;

Begin
bAssignError := True;

If (Source is TBitmap) then
   Begin
   fBitmap.Assign(Source as TBitmap);
   If (Source as TBitmap).Palette <> 0 then
      Begin
      fhPAL := CopyPalette((Source as TBitmap).Palette);
      fBitmap.Palette := fhPAL;
      End;
   bAssignError := False;
   End;

If (Source is TPicture) then
   Begin
   iX := (Source as TPicture).Width;
   iY := (Source as TPicture).Height;
   fBitmap.Width := iX;
   fBitmap.Height := iY;
   fBitmap.Canvas.Draw(0,0,(Source as TPicture).Graphic);
   bAssignError := False;
   End;

// You can write other assignments here, if you want...

If bAssignError then
   Raise Exception.Create(ASSIGN_ERROR);

End;
//---------------------------------------------------------------------
Procedure TPCXImage.Draw(ACanvas : TCanvas; Const Rect : TRect);

Begin
// Faster
// ACanvas.Draw(0,0,fBitmap);

// Slower
ACanvas.StretchDraw(Rect,fBitmap);
End;
//---------------------------------------------------------------------
Procedure TPCXImage.LoadFromFile(const Filename : String);

Begin
fPCXFile.LoadFromFile(Filename);
// added 5/4/2002
Case fPCXFile.fPixelFormat of
   1  : fConvert1And8BitPCXDataToImage;
   8  : fConvert1And8BitPCXDataToImage;
   24 : fConvert24BitPCXDataToImage;
   End;
End;
//---------------------------------------------------------------------
Procedure TPCXImage.SaveToStream(Stream : TStream);

Begin
fPCXFile.SaveToStream(Stream);
End;
//---------------------------------------------------------------------
Procedure TPCXImage.LoadFromStream(Stream : TStream);

Begin
fPCXFile.LoadFromStream(Stream);
End;
///////////////////////////////////////////////////////////////////////
//                                                                   //
//                       Called by RLE compressor                    //
//                                                                   //
///////////////////////////////////////////////////////////////////////
Procedure TPCXImage.fFillDataLines(Const fLine : Array of BYTE);

Var
   By         : BYTE;
   Cnt        : WORD;
   I          : QWORD;
   W          : QWORD;

Begin
I := 0;
By := fLine[0];
Cnt := $C1;
W := fBitmap.Width;

Repeat

   Inc(I);

   If By = fLine[I] then
      Begin
      Inc(Cnt);
      If Cnt = $100 then
         Begin
         fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] :=
            BYTE(Pred(Cnt));
         Inc(fPCXFile.fCurrentPos);
         fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := By;
         Inc(fPCXFile.fCurrentPos);
         Cnt := $C1;
         By := fLine[I];
         End;
      End;

      If (By <> fLine[I]) then
      Begin
      If (Cnt = $C1) then
         Begin
         // If (By < $C1) then
         If (By < $C0) then // changed 5/4/2002
            Begin
            fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := By;
            Inc(fPCXFile.fCurrentPos);
            End
         else
            Begin
            fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := BYTE(Cnt);
            Inc(fPCXFile.fCurrentPos);
            fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := By;
            Inc(fPCXFile.fCurrentPos);
            End;
         End
      else
         Begin
         fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := BYTE(Cnt);
         Inc(fPCXFile.fCurrentPos);
         fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := By;
         Inc(fPCXFile.fCurrentPos);
         End;

      Cnt := $C1;
      By := fLine[I];
      End;

Until I = W - 1;

// Write the last byte(s)
If (Cnt > $C1) then
   Begin
   fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := BYTE(Cnt);
   Inc(fPCXFile.fCurrentPos);
   End;

If (Cnt = $C1) and (By > $C0) then
   Begin
   fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := BYTE(Cnt);
   Inc(fPCXFile.fCurrentPos);
   End;

fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := By;
Inc(fPCXFile.fCurrentPos);

End;
//-------------------------------------------------------------------//
//                  RLE Compression algorithm                        //
//-------------------------------------------------------------------//
Procedure TPCXImage.fConvertImageTo24BitPCXData; // Renamed 5/4/2002

Var
   H,W                  : QWORD;
   X,Y                  : QWORD;
   I                    : QWORD;

Begin
H := fBitmap.Height;
W := fBitmap.Width;
fPCXFile.fCurrentPos := 0;
SetLength(fPCXFile.fPCXData.fData,6 * H * W); // To be sure...
fBitmap.PixelFormat := pf24bit; // Always do this if you're using
                                // ScanLine!

For Y := 0 to H - 1 do
   Begin
   fP := fBitmap.ScanLine[Y];
   I := 0;
   For X := 0 to W - 1 do
      Begin
      fRLine[X] := fP[I]; Inc(I);  // Extract a red line
      fGLine[X] := fP[I]; Inc(I);  // Extract a green line
      fBLine[X] := fP[I]; Inc(I);  // Extract a blue line
      End;

   fFillDataLines(fBLine); // Compress the blue line
   fFillDataLines(fGLine); // Compress the green line
   fFillDataLines(fRLine); // Compress the red line

   End;

// Correct the length of fPCXData.fData
SetLength(fPCXFile.fPCXData.fData,fPCXFile.fCurrentPos);
End;
//-------------------------------------------------------------------//
Procedure TPCXImage.fConvertImageTo1And8BitPCXData(ImageWidthInBytes :
   QWORD);

Var
   H,W,X,Y              : QWORD;
   oldByte,newByte      : BYTE;
   Cnt                  : BYTE;

Begin
H := fBitmap.Height;
W := ImageWidthInBytes;
fPCXFile.fCurrentPos := 0;
SetLength(fPCXFile.fPCXData.fData,2 * H * W); // To be sure...
oldByte := 0; // Otherwise the compiler issues a warning about
              // oldByte not being initialized...
Cnt := $C1;
For Y := 0 to H - 1 do
   Begin
   fP := fBitmap.ScanLine[Y];
   For X := 0 to W - 1 do
      Begin

      newByte := fP[X];

      If X > 0 then
         Begin
         If (Cnt = $FF) then
            Begin
            fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := Cnt;
            Inc(fPCXFile.fCurrentPos);
            fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := oldByte;
            Inc(fPCXFile.fCurrentPos);
            Cnt := $C1;
            End
         else
            If newByte = oldByte then
               Inc(Cnt);

         If newByte <> oldByte then
            Begin
            If (Cnt > $C1) or (oldByte >= $C0) then
               Begin
               fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := Cnt;
               Inc(fPCXFile.fCurrentPos);
               Cnt := $C1;
               End;
            fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := oldByte;
            Inc(fPCXFile.fCurrentPos);
            End;

         End;
      oldByte := newByte;
      End;
   // Write last byte of line
   If (Cnt > $C1) or (oldByte >= $C0) then
      Begin
      fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := Cnt;
      Inc(fPCXFile.fCurrentPos);
      Cnt := $C1;
      End;

   fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := oldByte;
   Inc(fPCXFile.fCurrentPos);
   End;

// Write last byte of image
If (Cnt > $C1) or (oldByte >= $C0) then
   Begin
   fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := Cnt;
   Inc(fPCXFile.fCurrentPos);
   // Cnt := 1;
   End;
fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := oldByte;
Inc(fPCXFile.fCurrentPos);

// Correct the length of fPCXData.fData
SetLength(fPCXFile.fPCXData.fData,fPCXFile.fCurrentPos);
End;
//-------------------------------------------------------------------//
//                  RLE Decompression algorithm                      //
//-------------------------------------------------------------------//
Procedure TPCXImage.fConvert24BitPCXDataToImage; // Renamed 5/4/2002

Var

   I                    : QWORD;
   By                   : BYTE;
   Cnt                  : BYTE;
   H,W                  : QWORD;
   X,Y                  : QWORD;
   K,L                  : QWORD;

Begin
H := fPCXFile.fPCXHeader.fWindow.wBottom -
   fPCXFile.fPCXHeader.fWindow.wTop + 1;
W := fPCXFile.fPCXHeader.fWindow.wRight -
   fPCXFile.fPCXHeader.fWindow.wLeft + 1;
Y := 0;                          // First line of image
fBitmap.Width := W;              // Set bitmap width
fBitmap.Height := H;             // Set bitmap height
fBitmap.PixelFormat := pf24bit;  // Always do this if you're using
                                 // ScanLine!
I := 0;                          // Pointer to data byte of fPXCFile
Repeat

   // Process the red line
   // ProcessLine(fRLine,W);

   X := 0; // Pointer to position in Red / Green / Blue line
   Repeat
      By := fPCXFile.fPCXData.fData[I];
      Inc(I);

      // one byte
      If By < $C1 then
         If X <= W then // added 5/4/2002
            Begin
            fRLine[X] := By;
            Inc(X);
            End;

      // multiple bytes (RLE)
      If By > $C0 then
         Begin
         Cnt := By and $3F;

         By := fPCXFile.fPCXData.fData[I];
         Inc(I);

         //FillChar(fRLine[J],Cnt,By);
         //Inc(J,Cnt);

         For K := 1 to Cnt do
            If X <= W then // added 5/4/2002
               Begin
               fRLine[X] := By;
               Inc(X);
               End;

         End;

   Until X >= W;

   // Process the green line
   // ProcessLine(fGLine,W);

   X := 0;
   Repeat
      By := fPCXFile.fPCXData.fData[I];
      Inc(I);

      // one byte
      If By < $C1 then
         If X <= W then  // added 5/4/2002
            Begin
            fGLine[X] := By;
            Inc(X);
            End;

      // multiple bytes (RLE)
      If By > $C0 then
         Begin
         Cnt := By and $3F;

         By := fPCXFile.fPCXData.fData[I];
         Inc(I);

         For K := 1 to Cnt do
            If X <= W then // added 5/4/2002
               Begin
               fGLine[X] := By;
               Inc(X);
               End;

         End;

   Until X >= W;

   // Process the blue line
   // ProcessLine(fBLine,W);

   X := 0;
   Repeat
      By := fPCXFile.fPCXData.fData[I];
      Inc(I);

      // one byte
      If By < $C1 then
         If X <= W then // added 5/4/2002
            Begin
            fBLine[X] := By;
            Inc(X);
            End;

      // multiple bytes (RLE)
      If By > $C0 then
         Begin
         Cnt := By and $3F;

         By := fPCXFile.fPCXData.fData[I];
         Inc(I);

         For K := 1 to Cnt do
            If X <= W then // added 5/4/2002
               Begin
               fBLine[X] := By;
               Inc(X);
               End;

         End;

   Until X >= W;

   // Write the just processed data RGB lines to the bitmap
   fP := fBitmap.ScanLine[Y];
   L := 0;
   For X := 0 to W - 1 do
      Begin
      fP[L] := fBLine[X]; Inc(L);
      fP[L] := fGLine[X]; Inc(L);
      fP[L] := fRLine[X]; Inc(L);
      End;

   Inc(Y); // Process the next RGB line

Until Y >= H;

SetLength(fPCXFile.fPCXData.fData,0);
End;
//-------------------------------------------------------------------//
Procedure TPCXImage.fConvert1And8BitPCXDataToImage; // added 5/4/2002

Var
   I,J                  : QWORD;
   By                   : BYTE;
   Cnt                  : BYTE;
   H,W,WW               : QWORD;
   X,Y                  : QWORD;

Begin
H := fPCXFile.fPCXHeader.fWindow.wBottom -
   fPCXFile.fPCXHeader.fWindow.wTop + 1;
W := fPCXFile.fPCXHeader.fWindow.wRight -
   fPCXFile.fPCXHeader.fWindow.wLeft + 1;
fBitmap.Width := W; // Set bitmap width
fBitmap.Height := H; // Set bitmap height
WW := W;

// 1 bit PCX
If fPCXFile.fPixelFormat = 1 then
   Begin
                                   // All 1 bit images have a palette
   fBitmap.PixelFormat := pf1bit;  // Always do this if you're using
                                   // ScanLine!
   WW := W div 8; // Correct width for pf1bit
   If W mod 8 > 0 then
      Begin
      Inc(WW);
      fBitMap.Width := WW * 8;
      End;
   fSetPalette(2);
   End;

// 8 bit PCX
If fPCXFile.fPixelFormat = 8 then
   Begin
   // All 8 bit images have a palette!
   // This is how to set the palette of a bitmap
   // 1. First set the bitmap to pf8bit;
   // 2. then set the palette of the bitmap;
   // 3. then set the pixels with ScanLine or with Draw.
   // If you do it with StretchDraw, it won't work. Don't ask me why.
   // If you don't do it in this order, it won't work either! You'll
   // get strange colors.
   fBitmap.PixelFormat := pf8bit;  // Always do this if you're using
                                   // ScanLine!
   fSetPalette(256);
   End;

I := 0;
Y := 0;
Repeat
   fP := fBitmap.ScanLine[Y];
   X := 0; // Pointer to position in line
   Repeat
      By := fPCXFile.fPCXData.fData[I];
      Inc(I);

      // one byte
      If By < $C1 then
         If X <= WW then
            Begin
            fP[X] := By;
            Inc(X);
            End;

      // multiple bytes (RLE)
      If By > $C0 then
         Begin
         Cnt := By and $3F;

         By := fPCXFile.fPCXData.fData[I];
         Inc(I);

         For J := 1 to Cnt do
            If X <= WW then
               Begin
               fP[X] := By;
               Inc(X);
               End;

         End;

   Until X >= WW;

   Inc(Y); // Next line

Until Y >= H;
End;
//---------------------------------------------------------------------
Procedure TPCXImage.fCreatePCXHeader(Const byBitsPerPixel : BYTE;
   Const byPlanes : BYTE; Const wBytesPerLine : DWORD);

Var
   H,W    : WORD;

Begin
W := fBitmap.Width;
H := fBitmap.Height;

// PCX header
fPCXFile.fPCXHeader.fID                 := BYTE($0A);  // BYTE (1)
fPCXFile.fPCXHeader.fVersion            := BYTE(5);    // BYTE (2)
fPCXFile.fPCXHeader.fCompressed         := BYTE(1);    // BYTE (3)
// 0 = uncompressed, 1 = compressed
// Only RLE compressed files are supported by this component
fPCXFile.fPCXHeader.fBitsPerPixel       := BYTE(byBitsPerPixel);
                                                       // BYTE (4)
fPCXFile.fPCXHeader.fWindow.wLeft       := WORD(0);    // WORD (5,6)
fPCXFile.fPCXHeader.fWindow.wTop        := WORD(0);    // WORD (7,8)
fPCXFile.fPCXHeader.fWindow.wRight      := WORD(W - 1);// WORD (9,10)
fPCXFile.fPCXHeader.fWindow.wBottom     := WORD(H - 1);// WORD (11,12)
fPCXFile.fPCXHeader.fHorzResolution     := WORD(72);   // WORD (13,14)
fPCXFile.fPCXHeader.fVertResolution     := WORD(72);   // WORD (15,16)

FillChar(fPCXFile.fPCXHeader.fColorMap,48,0);          // Array of Byte
                                                       // (17..64)

fPCXFile.fPCXHeader.fReserved           := BYTE(0);    // BYTE (65)
fPCXFile.fPCXHeader.fPlanes             := BYTE(byPlanes);
                                                       // BYTE (66)
fPCXFile.fPCXHeader.fBytesPerLine       := WORD(wBytesPerLine);
                                                       // WORD (67,68)
                                                       // must be even
                                                       // rounded above
fPCXFile.fPCXHeader.fPaletteInfo        := WORD(1);    // WORD (69,70)

FillChar(fPCXFile.fPCXHeader.fFiller,58,0);            // Array of Byte
                                                       // (71..128)

fPCXFile.fPixelFormat := fPCXFile.fPCXHeader.fPlanes *
   fPCXFile.fPCXHeader.fBitsPerPixel;
fPCXFile.fColorDepth := 1 shl fPCXFile.fPixelFormat;
End;
//---------------------------------------------------------------------
(*
// From Delphi 5.0, graphics.pas
Function CopyPalette(Palette: HPALETTE): HPALETTE;

Var
   PaletteSize    : Integer;
   LogPal         : TMaxLogPalette;

Begin
Result := 0;
If Palette = 0 then
   Exit;
PaletteSize := 0;
If GetObject(Palette,SizeOf(PaletteSize),@PaletteSize) = 0 then
   Exit;
If PaletteSize = 0 then
   Exit;
With LogPal do
   Begin
   palVersion := $0300;
   palNumEntries := PaletteSize;
   GetPaletteEntries(Palette,0,PaletteSize,palPalEntry);
   End;
Result := CreatePalette(PLogPalette(@LogPal)^);
End;
*)
//---------------------------------------------------------------------
// From Delphi 5.0, graphics.pas
(*
Procedure TPCXImage.fSetPixelFormat(Value : TPixelFormat);

Const
  BitCounts : Array [pf1Bit..pf32Bit] of BYTE = (1,4,8,16,16,24,32);

Var
   DIB     : TDIBSection;
   Pal     : HPALETTE;
   DC      : hDC;
   KillPal : Boolean;

Begin
If Value = GetPixelFormat then
   Exit;
Case Value of
      pfDevice : Begin
                 HandleType := bmDDB;
                 Exit;
                 End;
      pfCustom : InvalidGraphic(@SInvalidPixelFormat);
   else
      FillChar(DIB,sizeof(DIB), 0);

   DIB.dsbm := FImage.FDIB.dsbm;
   KillPal := False;
   With DIB, dsbm,dsbmih do
      Begin
      bmBits := nil;
      biSize := SizeOf(DIB.dsbmih);
      biWidth := bmWidth;
      biHeight := bmHeight;
      biPlanes := 1;
      biBitCount := BitCounts[Value];
      Pal := FImage.FPalette;
      Case Value of
            pf4Bit  : Pal := SystemPalette16;
            pf8Bit  : Begin
                      DC := GDICheck(GetDC(0));
                      Pal := CreateHalftonePalette(DC);
                      KillPal := True;
                      ReleaseDC(0, DC);
                      End;
            pf16Bit : Begin
                      biCompression := BI_BITFIELDS;
                      dsBitFields[0] := $F800;
                      dsBitFields[1] := $07E0;
                      dsBitFields[2] := $001F;
                      End;
         End; // of Case
      Try
      CopyImage(Handle, Pal, DIB);
      PaletteModified := (Pal <> 0);
      Finally
         if KillPal then
            DeleteObject(Pal);
            End; // of Try
      Changed(Self);
      End; // of With
   End; // of Case
End; // of Procedure
*)
//---------------------------------------------------------------------
Procedure TPCXImage.fSetPalette(Const wNumColors : WORD);

(* From Delphi 5.0, graphics.pas

Type
   TPalEntry = packed record
      peRed     : BYTE;
      peGreen   : BYTE;
      peBlue    : BYTE;
      End;

Type
   tagLOGPALETTE = packed record
      palVersion     : WORD;
      palNumEntries  : WORD;
      palPalEntry    : Array[0..255] of TPalEntry
      End;

Type
   TMAXLogPalette = tagLOGPALETTE;
   PMAXLogPalette = ^TMAXLogPalette;

Type
   PRGBQuadArray = ^TRGBQuadArray;
   TRGBQuadArray = Array[BYTE] of TRGBQuad;

Type
   PRGBQuadArray = ^TRGBQuadArray;
   TRGBQuadArray = Array[BYTE] of TRGBQuad;
*)

Var
   pal        : TMaxLogPalette;
   W          : WORD;

Begin
pal.palVersion := $300; // The "Magic" number
pal.palNumEntries := wNumColors;
For W := 0 to 255 do
   Begin
   pal.palPalEntry[W].peRed   :=
      fPCXFile.fPCXPalette.fPalette[W].ceRed;
   pal.palPalEntry[W].peGreen :=
      fPCXFile.fPCXPalette.fPalette[W].ceGreen;
   pal.palPalEntry[W].peBlue  :=
      fPCXFile.fPCXPalette.fPalette[W].ceBlue;
   pal.palPalEntry[W].peFlags := 0;
   End;

(* Must we delete the old palette first here? I don't know.
If fhPAL <> 0 then
   DeleteObject(fhPAL);
*)

fhPAL := CreatePalette(PLogPalette(@pal)^);
if fhPAL <> 0 then
   fBitmap.Palette := fhPAL;
End;
//---------------------------------------------------------------------
Function TPCXImage.fGetPixelFormat : TPixelFormat;

// Only pf1bit, pf4bit and pf8bit images have a palette.
// pf15bit, pf16bit, pf24bit and pf32bit images have no palette.
// You can change the palette of pf1bit images in windows.
// The foreground color and the background color of pf1bit images
// do not have to be black and white. You can choose any tow colors.
// The palette of pf4bit images is fixed.
// The palette entries 0..9 and 240..255 of pf8bit images are reserved
// in windows.
Begin
Result := pfDevice;
Case fPCXFile.fPixelFormat of
   01 : Result := pf1bit;     // Implemented WITH palette.
   // 04 : Result :=  pf4bit; // Not yet implemented in component,
                              // is however implemented in PCX format.
   08 : Result := pf8bit;     // Implemented WITH palette.
   // 15 : Result := pf15bit; // Not implemented in PCX format?
   // 16 : Result := pf16bit; // Not implemented in PCX format?
   24 : Result := pf24bit;    // Implemented, has no palette.
   // 32 : Result := pf32bit; // Not implemented in PCX format.
   End;
End;
//---------------------------------------------------------------------
Procedure TPCXImage.fGetPalette(Const wNumColors : WORD);

Var
   pal          : TMaxLogPalette;
   W            : WORD;

Begin
fPCXFile.fPCXPalette.fSignature := $0C;

pal.palVersion := $300; // The "Magic" number
pal.palNumEntries := wNumColors;
GetPaletteEntries(CopyPalette(fBitmap.Palette),0,wNumColors,
   pal.palPalEntry);
For W := 0 to 255 do
   If W < wNumColors then
      Begin
      fPCXFile.fPCXPalette.fPalette[W].ceRed   :=
         pal.palPalEntry[W].peRed;
      fPCXFile.fPCXPalette.fPalette[W].ceGreen :=
         pal.palPalEntry[W].peGreen;
      fPCXFile.fPCXPalette.fPalette[W].ceBlue  :=
         pal.palPalEntry[W].peBlue;
      End
   else
      Begin
      fPCXFile.fPCXPalette.fPalette[W].ceRed   := 0;
      fPCXFile.fPCXPalette.fPalette[W].ceGreen := 0;
      fPCXFile.fPCXPalette.fPalette[W].ceBlue  := 0;
      End;
End;
//=====================================================================

///////////////////////////////////////////////////////////////////////
//                                                                   //
//                         TPCXFile                                  //
//                                                                   //
///////////////////////////////////////////////////////////////////////
Constructor TPCXFile.Create;

Begin
Inherited Create;
fHeight := 0;
fWidth := 0;
fCurrentPos := 0;
End;
//---------------------------------------------------------------------
Destructor TPCXFile.Destroy;

Begin
SetLength(fPCXData.fData,0);
Inherited Destroy;
End;
//---------------------------------------------------------------------
Procedure TPCXFile.LoadFromFile(Const Filename : String);

Var
   fPCXStream : TFileStream;

Begin
fPCXStream := TFileStream.Create(Filename,fmOpenRead);
Try
   fPCXStream.Position := 0;
   LoadFromStream(fPCXStream);
finally
   fPCXStream.Free;
   End;
End;
//---------------------------------------------------------------------
Procedure TPCXFile.SaveToFile(Const Filename : String);

Var
   fPCXStream : TFileStream;

Begin
fPCXStream := TFileStream.Create(Filename,fmCreate);
Try
   fPCXStream.Position := 0;
   SaveToStream(fPCXStream);
finally
   fPCXStream.Free;
   End;
End;
//---------------------------------------------------------------------
Procedure TPCXFile.LoadFromStream(Stream : TStream);

Var
   fFileLength          : Cardinal;

Begin
// Read the PCX header
Stream.Read(fPCXHeader,SizeOf(fPCXHeader));

// Check the ID byte
If fPCXHeader.fID <> $0A then
   Raise Exception.Create(FORMAT_ERROR);

(*
Check PCX version byte
======================
Versionbyte = 0 => PC PaintBrush V2.5
Versionbyte = 2 => PC Paintbrush V2.8 with palette information
Versionbyte = 3 => PC Paintbrush V2.8 without palette information
Versionbyte = 4 => PC Paintbrush for Windows
Versionbyte = 5 => PC Paintbrush V3 and up, and PC Paintbrush Plus
                   with 24 bit image support
*)
// Check the PCX version
If fPCXHeader.fVersion <> 5 then
   Raise Exception.Create(VERSION_ERROR);

// Calculate width
fWidth := fPCXHeader.fWindow.wRight - fPCXHeader.fWindow.wLeft + 1;
If fWidth < 0 then
   Raise Exception.Create(WIDTH_OUT_OF_RANGE);

// Calculate height
fHeight := fPCXHeader.fWindow.wBottom - fPCXHeader.fWindow.wTop + 1;
If fHeight < 0 then
   Raise Exception.Create(HEIGHT_OUT_OF_RANGE);

// Is it too large?
If fWidth > fMaxImageWidth then
   Raise Exception.Create(IMAGE_WIDTH_TOO_LARGE);

// Calculate pixelformat
fPixelFormat := fPCXHeader.fPlanes * fPCXHeader.fBitsPerPixel;

// Calculate number of colors
fColorDepth := 1 shl fPixelFormat;

// Is this image supported?
If not(fPixelFormat in [1,8,24]) then
   Raise Exception.Create(ERROR_UNSUPPORTED);

// The lines following are NOT tested!!!
(*
If fColorDepth <= 16 then
   For I := 0 to fColorDepth - 1 do
      Begin
      If fPCXHeader.fVersion = 3 then
         Begin
         fPCXPalette.fPalette[I].R := fPCXHeader.fColorMap[I].R shl 2;
         fPCXPalette.fPalette[I].G := fPCXHeader.fColorMap[I].G shl 2;
         fPCXPalette.fPalette[I].B := fPCXHeader.fColorMap[I].B shl 2;
         End
      else
         Begin
         fPCXPalette.fPalette[I].R := fPCXHeader.fColorMap[I].R;
         fPCXPalette.fPalette[I].G := fPCXHeader.fColorMap[I].G;
         fPCXPalette.fPalette[I].B := fPCXHeader.fColorMap[I].B;
         End;
      End;
*)

// Calculate number of data bytes


// If fFileLength > fMaxDataFileLength then
//    Raise Exception.Create(INPUT_FILE_TOO_LARGE);

If fPixelFormat = 24 then
   Begin
   fFileLength := Stream.Size - Stream.Position;
   SetLength(fPCXData.fData,fFileLength);
   // Read the data
   Stream.Read(fPCXData.fData[0],fFileLength);
   fHasPalette := False;
   End;

If fPixelFormat in [1,8] then
   Begin
   fFileLength := Stream.Size - Stream.Position - 769;
   SetLength(fPCXData.fData,fFileLength);
   // Correct number of data bytes
   Stream.Read(fPCXData.fData[0],fFilelength);
   // Read the palette
   Stream.Read(fPCXPalette,SizeOf(fPCXPalette));
   fHasPalette := True;
   // Check palette signature byte
   If fPCXPalette.fSignature <> $0C then
      Raise Exception.Create(PALETTE_ERROR);
   End;

End;
//---------------------------------------------------------------------
Procedure TPCXFile.SaveToStream(Stream : TStream);

Begin
fHasPalette := False;
Stream.Write(fPCXHeader,SizeOf(fPCXHeader));
Stream.Write(fPCXData.fData[0],fCurrentPos);
If fPixelFormat in [1,8] then
   Begin
   Stream.Write(fPCXPalette,SizeOf(fPCXPalette));
   fHasPalette := True;
   End;
End;
//---------------------------------------------------------------------
// Register PCX format
Initialization
   TPicture.RegisterFileFormat('PCX',sPCXImageFile,TPCXImage);
   CF_PCX := RegisterClipBoardFormat('PCX Image');
   TPicture.RegisterClipBoardFormat(CF_PCX,TPCXImage);
//---------------------------------------------------------------------
// Unregister PCX format
Finalization
   TPicture.UnRegisterGraphicClass(TPCXImage);
//---------------------------------------------------------------------
End.
//=====================================================================






Please rate this article!
Skill level:
BeginnerExpert

Useful:
No!Very!

Overall rating:
PoorExcellent



Comments to this article
Write a new comment
tuty
    ghjgh (Jan 26 2004 5:23PM)

tutyutughfhfghgfhfghgfhfghgf
Respond














 
Sign up to consume product discounts for Bronze memberships !

read more


  Visit our Sponsor

 

  Community Ad of
Hans Gulö
 
   














 







     
  Copyright © 2000 - 2007 delphi3000.com - All rights reserved. Terms of use. || Privacy
delphi3000.com is a service by bluestep.com IT-Services GmbH (Vienna)