Articles   Members Online:
-Article/Tip Search
-News Group Search over 21 Million news group articles.
-Delphi/Pascal
-CBuilder/C++
-C#Builder/C#
-JBuilder/Java
-Kylix
Member Area
-Home
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Login/Logout
-Become a Member
-Why sign up!
-Newsletter
-Chat Online!
-Indexes NEW!!
Employment
-Build your resume
-Find a job
-Post a job
-Resume Search
Contacts
-Contacts
-Feedbacks
-Link to us
-Privacy/Disclaimer
Embarcadero
Visit Embarcadero
Embarcadero Community
JEDI
Links
PCX Image Component Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
22-Oct-02
Category
VCL-General
Language
Delphi 5.x
Views
135
User Rating
No Votes
# Votes
0
Replies
0
Publisher:
DSP, Administrator
Reference URL:
DKB
			Author: Maarten de Haan 

PCX image component. Fully supports reading and writing of: 1, 8 and 24 bit PCX 
images.

Answer:
1   
2   ///////////////////////////////////////////////////////////////////////
3   //                                                                   //
4   //                           TPCXImage                               //
5   //                           =========                               //
6   //                                                                   //
7   // Completed: The 10th of August 2001                                //
8   // Author:    M. de Haan                                             //
9   // Email:     M.deHaan@inn.nl                                        //
10  // Tested:    under W95 SP1, NT4 SP6, WIN2000                        //
11  // Version:   1.0                                                    //
12  //-------------------------------------------------------------------//
13  // Update:    The 14th of August 2001 to version 1.1.                //
14  // Reason:    Added version check.                                   //
15  //            Added comment info on version.                         //
16  //            Changed PCX header ID check.                           //
17  //-------------------------------------------------------------------//
18  // Update:    The 19th of August 2001 to version 2.0.                //
19  // Reason:    Warning from Delphi about using abstract methods,      //
20  //            caused by not implementing ALL TGraphic methods.       //
21  //            (Thanks goes to R.P. Sterkenburg for his diagnostic.)  //
22  // Added:     SaveToClipboardFormat, LoadFromClipboardFormat,        //
23  //            GetEmpty.                                              //
24  //-------------------------------------------------------------------//
25  // Update:    The 13th of October 2001 to version 2.1.               //
26  // Reason:    strange errors, read errors, EExternalException, IDE   //
27  //            hanging, Delphi hanging, Debugger hanging, windows     //
28  //            hanging, keyboard locked, and so on.                   //
29  // Changed:   Assign procedure.                                      //
30  //-------------------------------------------------------------------//
31  // Update:    The 5th of April 2002 to version 2.2.                  //
32  // Changed:   RLE compressor routine.                                //
33  // Reason:    Incompatibility problems with other programs caused    //
34  //            by the RLE compressor.                                 //
35  //            Other programs encode: $C0 as: $C1 $C0.                //
36  //            ($C0 means: repeat the following byte 0 times          //
37  //            $C1 means: repeat the following byte 1 time.)          //
38  // Changed:   File read routine.                                     //
39  // Reason:    Now detects unsupported PCX data formats.              //
40  // Added:     'Unsupported data format' in exception handler.        //
41  // Added:     1 bit PCX support in reading.                          //
42  // Added:     Procedure Convert1BitPCXDataToImage.                   //
43  // Renamed:   Procedure ConvertPCXDataToImage to                     //
44  //            Convert24BitPCXDataToImage.                            //
45  //-------------------------------------------------------------------//
46  // Update:    The 14th of April 2002 to version 2.3.                 //
47  //            Now capable of reading and writing 1 and 24 bit PCX    //
48  //            images.                                                //
49  // Added:     1 bit PCX support in writing.                          //
50  // Added:     Procedure ConvertImageTo1bitPCXData.                   //
51  // Changed:   Procedure CreatePCXHeader.                             //
52  // Changed:   Procedure TPCXImage.SaveToFile.                        //
53  //-------------------------------------------------------------------//
54  // Update:    The 19th of April 2002 to version 2.4.                 //
55  //            Now capable of reading and writing: 1, 8 and 24 bit    //
56  //            PCX images.                                            //
57  // Added:     8 bit PCX support in reading and writing.              //
58  // Renamed:   Procedure ConvertImageTo1And8bitPCXData.               //
59  // Renamed:   Procedure Convert1And8bitPCXDataToImage.               //
60  // Changed:   Procedure fSetPalette, fGetPalette.                    //
61  //-------------------------------------------------------------------//
62  // Update:    The 7th of May 2002 to version 2.5.                    //
63  // Reason:    The palette of 8-bit PCX images couldn't be read in    //
64  //            the calling program.                                   //
65  // Changed:   Procedures Assign, AssignTo, fSetPalette, fGetPalette. //
66  // Tested:    All formats were tested with the following programs:   //
67  //            - import in Word 97,                                   //
68  //            * (Word ignores the palette of 1 bit PCX images!)      //
69  //            - import and export in MigroGrafX.                     //
70  //            * (MicroGrafX also ignores the palette of 1 bit PCX    //
71  //              images.)                                             //
72  //            No problems were detected.                             //
73  //                                                                   //
74  //===================================================================//
75  //                                                                   //
76  //         The PCX image file format is copyrighted by:              //
77  //           ZSoft, PC Paintbrush, PC Paintbrush plus                //
78  //                        Trademarks: N/A                            //
79  //                       Royalty fees: NONE                          //
80  //                                                                   //
81  //===================================================================//
82  //                                                                   //
83  // The author can not be held responsable for using this software    //
84  // in anyway.                                                        //
85  //                                                                   //
86  // The features and restrictions of this component are:              //
87  // ----------------------------------------------------              //
88  //                                                                   //
89  // The reading and writing (import / export) of files / images:      //
90  //     - PCX version 5 definition, PC Paintbrush 3 and higher,       //
91  //     - RLE-compressed,                                             //
92  //     - 1 and 8 bit PCX images WITH palette and                     //
93  //     - 24 bit PCX images without palette,                          //
94  //     are supported by this component.                              //
95  //                                                                   //
96  // Known issues                                                      //
97  // ------------                                                      //
98  //                                                                   //
99  // 1) GetEmpty is NOT tested.                                        //
100 //                                                                   //
101 // 2) SaveToClipboardFormat is NOT tested.                           //
102 //                                                                   //
103 // 3) LoadFromClipboardFormat is NOT tested.                         //
104 //                                                                   //
105 // 4) 4 bit PCX images (with palette) are NOT (yet) implemented.     //
106 //    (I have no 4-bit PCX images to test it on...)                  //
107 //                                                                   //
108 ///////////////////////////////////////////////////////////////////////
109 
110 unit
111   PCXImage;
112 
113 interface
114 
115 uses
116   Windows,
117   SysUtils,
118   Classes,
119   Graphics;
120 
121 const
122   WIDTH_OUT_OF_RANGE = 'Illegal width entry in PCX file header';
123   HEIGHT_OUT_OF_RANGE = 'Illegal height entry in PCX file header';
124   FILE_FORMAT_ERROR = 'Invalid file format';
125   VERSION_ERROR = 'Only PC Paintbrush (plus) V3.0 and ' +
126     'higher are supported';
127   FORMAT_ERROR = 'Illegal identification byte in PCX file' +
128     ' header';
129   PALETTE_ERROR = 'Invalid palette signature found';
130   ASSIGN_ERROR = 'Can only Assign a TBitmap or a TPicture';
131   ASSIGNTO_ERROR = 'Can only AssignTo a TBitmap';
132   PCXIMAGE_EMPTY = 'The PCX image is empty';
133   BITMAP_EMPTY = 'The bitmap is empty';
134   INPUT_FILE_TOO_LARGE = 'The input file is too large to be read';
135   IMAGE_WIDTH_TOO_LARGE = 'Width of PCX image is too large to handle';
136   // added 19/08/2001
137   CLIPBOARD_LOAD_ERROR = 'Loading from clipboard failed';
138   // added 19/08/2001
139   CLIPBOARD_SAVE_ERROR = 'Saving to clipboard failed';
140   // added 14/10/2001
141   PCX_WIDTH_ERROR = 'Unexpected line length in PCX data';
142   PCX_HEIGHT_ERROR = 'More PCX data found than expected';
143   PCXIMAGE_TOO_LARGE = 'PCX image is too large';
144   // added 5/4/2002
145   ERROR_UNSUPPORTED = 'Unsupported PCX format';
146 
147 const
148   sPCXImageFile = 'PCX V3.0+ image';
149 
150   // added 19/08/2001
151 var
152   CF_PCX: WORD;
153 
154   ///////////////////////////////////////////////////////////////////////
155   //                                                                   //
156   //                            PCXHeader                              //
157   //                                                                   //
158   ///////////////////////////////////////////////////////////////////////
159 
160 type
161   QWORD = Cardinal; // Seems more logical to me...
162 
163 type
164   fColorEntry = packed record
165     ceRed: BYTE;
166     ceGreen: BYTE;
167     ceBlue: BYTE;
168   end; // of packed record fColorEntry
169 
170 type
171   TPCXImageHeader = packed record
172     fID: BYTE;
173     fVersion: BYTE;
174     fCompressed: BYTE;
175     fBitsPerPixel: BYTE;
176     fWindow: packed record
177       wLeft,
178         wTop,
179         wRight,
180         wBottom: WORD;
181     end; // of packed record fWindow
182     fHorzResolution: WORD;
183     fVertResolution: WORD;
184     fColorMap: array[0..15] of fColorEntry;
185     fReserved: BYTE;
186     fPlanes: BYTE;
187     fBytesPerLine: WORD;
188     fPaletteInfo: WORD;
189     fFiller: array[0..57] of BYTE;
190   end; // of packed record TPCXImageHeader
191 
192   ///////////////////////////////////////////////////////////////////////
193   //                                                                   //
194   //                             PCXData                               //
195   //                                                                   //
196   ///////////////////////////////////////////////////////////////////////
197 
198 type
199   TPCXData = object
200     fData: array of BYTE;
201   end; // of Type TPCXData
202 
203   ///////////////////////////////////////////////////////////////////////
204   //                                                                   //
205   //                             ScanLine                              //
206   //                                                                   //
207   ///////////////////////////////////////////////////////////////////////
208 
209 const
210   fMaxScanLineLength = $FFF; // Max image width: 4096 pixels
211 
212 type
213   mByteArray = array[0..fMaxScanLineLength] of BYTE;
214   pmByteArray = ^mByteArray;
215 
216   // The "standard" pByteArray from Delphi allocates 32768 bytes,
217   // which is a little bit overdone here, I think...
218 
219 const
220   fMaxImageWidth = $FFF; // Max image width: 4096 pixels
221 
222 type
223   xByteArray = array[0..fMaxImageWidth] of BYTE;
224 
225   ///////////////////////////////////////////////////////////////////////
226   //                                                                   //
227   //                          PCXPalette                               //
228   //                                                                   //
229   ///////////////////////////////////////////////////////////////////////
230 
231 type
232   TPCXPalette = packed record
233     fSignature: BYTE;
234     fPalette: array[0..255] of fColorEntry;
235   end; // of packed record TPCXPalette
236 
237   ///////////////////////////////////////////////////////////////////////
238   //                                                                   //
239   //                             Classes                               //
240   //                                                                   //
241   ///////////////////////////////////////////////////////////////////////
242 
243 type
244   TPCXImage = class;
245   TPCXFile = class;
246 
247   ///////////////////////////////////////////////////////////////////////
248   //                                                                   //
249   //                           PCXFile                                 //
250   //                                                                   //
251   //                         File handler                              //
252   //                                                                   //
253   ///////////////////////////////////////////////////////////////////////
254 
255   TPCXFile = class(TPersistent)
256 
257   private
258     fHeight: Integer;
259     fWidth: Integer;
260     fPCXHeader: TPCXImageHeader;
261     fPCXData: TPCXData;
262     fPCXPalette: TPCXPalette;
263     fColorDepth: QWORD;
264     fPixelFormat: BYTE; // added 5/4/2002
265     fCurrentPos: QWORD;
266     fHasPalette: Boolean; // added 7/5/2002
267 
268   protected
269     // Protected declarations
270 
271   public
272     // Public declarations
273     constructor Create;
274     destructor Destroy; override;
275     procedure LoadFromFile(const Filename: string);
276     procedure LoadFromStream(Stream: TStream);
277     procedure SaveToFile(const Filename: string);
278     procedure SaveToStream(Stream: TStream);
279 
280   published
281     // Published declarations
282     // The publishing is done in the TPCXImage section
283 
284   end;
285 
286   ///////////////////////////////////////////////////////////////////////
287   //                                                                   //
288   //                         TPCXImage                                 //
289   //                                                                   //
290   //                       Image handler                               //
291   //                                                                   //
292   ///////////////////////////////////////////////////////////////////////
293 
294   TPCXImage = class(TGraphic)
295 
296   private
297     // Private declarations
298     fBitmap: TBitmap;
299     fPCXFile: TPCXFile;
300     fRLine: xByteArray;
301     fGLine: xByteArray;
302     fBLine: xByteArray;
303     fP: pmByteArray;
304     fhPAL: HPALETTE;
305 
306     procedure fConvert24BitPCXDataToImage;
307     procedure fConvert1And8BitPCXDataToImage;
308     procedure fConvertImageTo24BitPCXData;
309     procedure fConvertImageTo1And8BitPCXData(ImageWidthInBytes:
310       QWORD);
311     procedure fFillDataLines(const fLine: array of BYTE);
312     procedure fCreatePCXHeader(const byBitsPerPixel: BYTE;
313       const byPlanes: BYTE; const wBytesPerLine: DWORD);
314     procedure fSetPalette(const wNumColors: WORD);
315     procedure fGetPalette(const wNumColors: WORD);
316     function fGetPixelFormat: TPixelFormat; // Added 07/05/2002
317     function fGetBitmap: TBitmap; // Added 07/05/2002
318 
319   protected
320     // Protected declarations
321     procedure Draw(ACanvas: TCanvas; const Rect: TRect); override;
322     function GetHeight: Integer; override;
323     function GetWidth: Integer; override;
324     procedure SetHeight(Value: Integer); override;
325     procedure SetWidth(Value: Integer); override;
326     function GetEmpty: Boolean; override;
327 
328   public
329     // Public declarations
330     constructor Create; override;
331     destructor Destroy; override;
332     procedure Assign(Source: TPersistent); override;
333     procedure AssignTo(Dest: TPersistent); override;
334     procedure LoadFromFile(const Filename: string); override;
335     procedure LoadFromStream(Stream: TStream); override;
336     procedure SaveToFile(const Filename: string); override;
337     procedure SaveToStream(Stream: TStream); override;
338     procedure LoadFromClipboardFormat(AFormat: WORD;
339       AData: THandle; APalette: HPALETTE); override;
340     procedure SaveToClipboardFormat(var AFormat: WORD;
341       var AData: THandle; var APalette: HPALETTE); override;
342 
343   published
344     // Published declarations
345     property Height: Integer
346       read GetHeight write SetHeight;
347     property Width: Integer
348       read GetWidth write SetWidth;
349     property PixelFormat: TPixelFormat
350       read fGetPixelFormat;
351     property Bitmap: TBitmap
352       read fGetBitmap; // Added 7/5/2002
353 
354   end;
355 
356 implementation
357 
358 ///////////////////////////////////////////////////////////////////////
359 //                                                                   //
360 //                           TPCXImage                               //
361 //                                                                   //
362 //                         Image handler                             //
363 //                                                                   //
364 ///////////////////////////////////////////////////////////////////////
365 
366 constructor TPCXImage.Create;
367 
368 begin
369   inherited Create;
370   // Init HPALETTE
371   fhPAL := 0;
372 
373   // Create a private bitmap to hold the image
374   if not Assigned(fBitmap) then
375     fBitmap := TBitmap.Create;
376 
377   // Create the PCXFile
378   if not Assigned(fPCXFile) then
379     fPCXFile := TPCXFile.Create;
380 
381 end;
382 //---------------------------------------------------------------------
383 
384 destructor TPCXImage.Destroy;
385 
386 begin
387   // Reversed order of create
388   // Free fPCXFile
389   fPCXFile.Free;
390   // Free private bitmap
391   fBitmap.Free;
392   // Delete palette
393   if fhPAL <> 0 then
394     DeleteObject(fhPAL);
395   // Distroy all the other things
396   inherited Destroy;
397 end;
398 //---------------------------------------------------------------------
399 
400 procedure TPCXImage.SetHeight(Value: Integer);
401 
402 begin
403   if Value >= 0 then
404     fBitmap.Height := Value;
405 end;
406 //---------------------------------------------------------------------
407 
408 procedure TPCXImage.SetWidth(Value: Integer);
409 
410 begin
411   if Value >= 0 then
412     fBitmap.Width := Value;
413 end;
414 //---------------------------------------------------------------------
415 
416 function TPCXImage.GetHeight: Integer;
417 
418 begin
419   Result := fPCXFile.fHeight;
420 end;
421 //---------------------------------------------------------------------
422 
423 function TPCXImage.GetWidth: Integer;
424 
425 begin
426   Result := fPCXFile.fWidth;
427 end;
428 //---------------------------------------------------------------------
429 
430 function TPCXImage.fGetBitmap: TBitmap;
431 
432 begin
433   Result := fBitmap;
434 end;
435 //-------------------------------------------------------------------//
436 // The credits for this procedure go to his work of TGIFImage by     //
437 // Reinier P. Sterkenburg                                            //
438 // Added 19/08/2001                                                  //
439 //-------------------------------------------------------------------//
440 // NOT TESTED!
441 
442 procedure TPCXImage.LoadFromClipboardFormat(AFormat: WORD;
443   ADAta: THandle; APalette: HPALETTE);
444 
445 var
446   Size: QWORD;
447   Buf: Pointer;
448   Stream: TMemoryStream;
449   BMP: TBitmap;
450 
451 begin
452   if (AData = 0) then
453     AData := GetClipBoardData(AFormat);
454   if (AData <> 0) and (AFormat = CF_PCX) then
455   begin
456     Size := GlobalSize(AData);
457     Buf := GlobalLock(AData);
458     try
459       Stream := TMemoryStream.Create;
460       try
461         Stream.SetSize(Size);
462         Move(Buf^, Stream.Memory^, Size);
463         Self.LoadFromStream(Stream);
464       finally
465         Stream.Free;
466       end;
467     finally
468 
469       GlobalUnlock(AData);
470     end;
471   end
472   else if (AData <> 0) and (AFormat = CF_BITMAP) then
473   begin
474     BMP := TBitmap.Create;
475     try
476       BMP.LoadFromClipboardFormat(AFormat, AData, APalette);
477       Self.Assign(BMP);
478     finally
479       BMP.Free;
480     end;
481   end
482   else
483     raise Exception.Create(CLIPBOARD_LOAD_ERROR);
484 end;
485 //-------------------------------------------------------------------//
486 // The credits for this procedure go to his work of TGIFImage by     //
487 // Reinier P. Sterkenburg                                            //
488 // Added 19/08/2001                                                  //
489 //-------------------------------------------------------------------//
490 // NOT TESTED!
491 
492 procedure TPCXImage.SaveToClipboardFormat(var AFormat: WORD;
493   var AData: THandle; var APalette: HPALETTE);
494 
495 var
496   Stream: TMemoryStream;
497   Data: THandle;
498   Buf: Pointer;
499 
500 begin
501   if Empty then
502     Exit;
503   // First store the bitmap to the clipboard
504   fBitmap.SaveToClipboardFormat(AFormat, AData, APalette);
505   // Then try to save the PCX
506   Stream := TMemoryStream.Create;
507   try
508     SaveToStream(Stream);
509     Stream.Position := 0;
510     Data := GlobalAlloc(HeapAllocFlags, Stream.Size);
511     try
512       if Data <> 0 then
513       begin
514         Buf := GlobalLock(Data);
515         try
516           Move(Stream.Memory^, Buf^, Stream.Size);
517         finally
518           GlobalUnlock(Data);
519         end;
520         if SetClipBoardData(CF_PCX, Data) = 0 then
521           raise Exception.Create(CLIPBOARD_SAVE_ERROR);
522       end;
523     except
524       GlobalFree(Data);
525       raise;
526     end;
527   finally
528     Stream.Free;
529   end;
530 end;
531 //-------------------------------------------------------------------//
532 // NOT TESTED!
533 
534 function TPCXImage.GetEmpty: Boolean; // Added 19/08/2002
535 
536 begin
537   if Assigned(fBitmap) then
538     Result := fBitmap.Empty
539   else
540     Result := (fPCXFile.fHeight = 0) or (fPCXFile.fWidth = 0);
541 end;
542 //---------------------------------------------------------------------
543 
544 procedure TPCXImage.SaveToFile(const Filename: string);
545 
546 var
547   fPCX: TFileStream;
548   W, WW: QWORD;
549 
550 begin
551   if (fBitmap.Width = 0) or (fBitmap.Height = 0) then
552     raise Exception.Create(BITMAP_EMPTY);
553   W := fBitmap.Width;
554   WW := W div 8;
555   if (W mod 8) > 0 then
556     Inc(WW);
557   case fBitmap.PixelFormat of
558     pf1bit:
559       begin
560         // Fully supported by PCX and by this component
561         fCreatePCXHeader(1, 1, WW);
562         fConvertImageTo1And8BitPCXData(WW);
563         fGetPalette(2);
564       end;
565     pf4bit:
566       begin
567         // I don't have 4-bit PCX images to test with
568         // It will be treated as a 24 bit image
569         fCreatePCXHeader(8, 3, W);
570         fConvertImageTo24BitPCXData;
571       end;
572     pf8bit:
573       begin
574         // Fully supported by PCX and by this component
575         fCreatePCXHeader(8, 1, W);
576         fConvertImageTo1And8BitPCXData(W);
577         fGetPalette(256);
578       end;
579     pf15bit:
580       begin
581         // Is this supported in PCX?
582         // It will be treated as a 24 bit image
583         fCreatePCXHeader(8, 3, W);
584         fConvertImageTo24BitPCXData;
585       end;
586     pf16bit:
587       begin
588         // Is this supported in PCX?
589         // It will be treated as a 24 bit image
590         fCreatePCXHeader(8, 3, W);
591         fConvertImageTo24BitPCXData;
592       end;
593     pf24bit:
594       begin
595         // Fully supported by PCX and by this component
596         fCreatePCXHeader(8, 3, W);
597         fConvertImageTo24BitPCXData;
598       end;
599     pf32bit:
600       begin
601         // Not supported by PCX
602         fCreatePCXHeader(8, 3, W);
603         fConvertImageTo24BitPCXData;
604       end;
605   else
606     begin
607       fCreatePCXHeader(8, 3, W);
608       fConvertImageTo24BitPCXData;
609     end; // of else
610   end; // of Case
611   fPCX := TFileStream.Create(Filename, fmCreate);
612   try
613     fPCX.Position := 0;
614     SaveToStream(fPCX);
615   finally
616     fPCX.Free;
617   end; // of finally
618   SetLength(fPCXFile.fPCXData.fData, 0);
619 end; // of Procedure SaveToFile
620 //-------------------------------------------------------------------//
621 
622 procedure TPCXImage.AssignTo(Dest: TPersistent);
623 
624 var
625   bAssignToError: Boolean;
626 
627 begin
628   bAssignToError := True;
629 
630   if Dest is TBitmap then
631   begin
632     // The old AssignTo procedure was like this.
633     // But then the palette was couldn't be accessed in the calling
634     // program for some reason.
635     // --------------------------
636     // (Dest as TBitmap).Assign(fBitmap);
637     // If fBitmap.Palette <> 0 then
638     //    (Dest as TBitmap).Palette := CopyPalette(fBitmap.Palette);
639     // --------------------------
640 
641     // Do the assigning
642     (Dest as TBitmap).Assign(fBitmap);
643 
644     if fPCXFile.fHasPalette then
645       (Dest as TBitmap).Palette := CopyPalette(fhPAL);
646     // Now the calling program can access the palette
647     // (if it has one)!
648     bAssignToError := False;
649   end;
650 
651   if Dest is TPicture then
652   begin
653     (Dest as TPicture).Graphic.Assign(fBitmap);
654     bAssignToError := False;
655   end;
656 
657   if bAssignToError then
658     raise Exception.Create(ASSIGNTO_ERROR);
659 
660   // You can write other assignments here, if you want...
661 
662 end;
663 //-------------------------------------------------------------------//
664 
665 procedure TPCXImage.Assign(Source: TPersistent);
666 
667 var
668   iX, iY: DWORD;
669   bAssignError: Boolean;
670 
671 begin
672   bAssignError := True;
673 
674   if (Source is TBitmap) then
675   begin
676     fBitmap.Assign(Source as TBitmap);
677     if (Source as TBitmap).Palette <> 0 then
678     begin
679       fhPAL := CopyPalette((Source as TBitmap).Palette);
680       fBitmap.Palette := fhPAL;
681     end;
682     bAssignError := False;
683   end;
684 
685   if (Source is TPicture) then
686   begin
687     iX := (Source as TPicture).Width;
688     iY := (Source as TPicture).Height;
689     fBitmap.Width := iX;
690     fBitmap.Height := iY;
691     fBitmap.Canvas.Draw(0, 0, (Source as TPicture).Graphic);
692     bAssignError := False;
693   end;
694 
695   // You can write other assignments here, if you want...
696 
697   if bAssignError then
698     raise Exception.Create(ASSIGN_ERROR);
699 
700 end;
701 //---------------------------------------------------------------------
702 
703 procedure TPCXImage.Draw(ACanvas: TCanvas; const Rect: TRect);
704 
705 begin
706   // Faster
707   // ACanvas.Draw(0,0,fBitmap);
708 
709   // Slower
710   ACanvas.StretchDraw(Rect, fBitmap);
711 end;
712 //---------------------------------------------------------------------
713 
714 procedure TPCXImage.LoadFromFile(const Filename: string);
715 
716 begin
717   fPCXFile.LoadFromFile(Filename);
718   // added 5/4/2002
719   case fPCXFile.fPixelFormat of
720     1: fConvert1And8BitPCXDataToImage;
721     8: fConvert1And8BitPCXDataToImage;
722     24: fConvert24BitPCXDataToImage;
723   end;
724 end;
725 //---------------------------------------------------------------------
726 
727 procedure TPCXImage.SaveToStream(Stream: TStream);
728 
729 begin
730   fPCXFile.SaveToStream(Stream);
731 end;
732 //---------------------------------------------------------------------
733 
734 procedure TPCXImage.LoadFromStream(Stream: TStream);
735 
736 begin
737   fPCXFile.LoadFromStream(Stream);
738 end;
739 ///////////////////////////////////////////////////////////////////////
740 //                                                                   //
741 //                       Called by RLE compressor                    //
742 //                                                                   //
743 ///////////////////////////////////////////////////////////////////////
744 
745 procedure TPCXImage.fFillDataLines(const fLine: array of BYTE);
746 
747 var
748   By: BYTE;
749   Cnt: WORD;
750   I: QWORD;
751   W: QWORD;
752 
753 begin
754   I := 0;
755   By := fLine[0];
756   Cnt := $C1;
757   W := fBitmap.Width;
758 
759   repeat
760 
761     Inc(I);
762 
763     if By = fLine[I] then
764     begin
765       Inc(Cnt);
766       if Cnt = $100 then
767       begin
768         fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] :=
769           BYTE(Pred(Cnt));
770         Inc(fPCXFile.fCurrentPos);
771         fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := By;
772         Inc(fPCXFile.fCurrentPos);
773         Cnt := $C1;
774         By := fLine[I];
775       end;
776     end;
777 
778     if (By <> fLine[I]) then
779     begin
780       if (Cnt = $C1) then
781       begin
782         // If (By < $C1) then
783         if (By < $C0) then // changed 5/4/2002
784         begin
785           fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := By;
786           Inc(fPCXFile.fCurrentPos);
787         end
788         else
789         begin
790           fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := BYTE(Cnt);
791           Inc(fPCXFile.fCurrentPos);
792           fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := By;
793           Inc(fPCXFile.fCurrentPos);
794         end;
795       end
796       else
797       begin
798         fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := BYTE(Cnt);
799         Inc(fPCXFile.fCurrentPos);
800         fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := By;
801         Inc(fPCXFile.fCurrentPos);
802       end;
803 
804       Cnt := $C1;
805       By := fLine[I];
806     end;
807 
808   until I = W - 1;
809 
810   // Write the last byte(s)
811   if (Cnt > $C1) then
812   begin
813     fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := BYTE(Cnt);
814     Inc(fPCXFile.fCurrentPos);
815   end;
816 
817   if (Cnt = $C1) and (By > $C0) then
818   begin
819     fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := BYTE(Cnt);
820     Inc(fPCXFile.fCurrentPos);
821   end;
822 
823   fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := By;
824   Inc(fPCXFile.fCurrentPos);
825 
826 end;
827 //-------------------------------------------------------------------//
828 //                  RLE Compression algorithm                        //
829 //-------------------------------------------------------------------//
830 
831 procedure TPCXImage.fConvertImageTo24BitPCXData; // Renamed 5/4/2002
832 
833 var
834   H, W: QWORD;
835   X, Y: QWORD;
836   I: QWORD;
837 
838 begin
839   H := fBitmap.Height;
840   W := fBitmap.Width;
841   fPCXFile.fCurrentPos := 0;
842   SetLength(fPCXFile.fPCXData.fData, 6 * H * W); // To be sure...
843   fBitmap.PixelFormat := pf24bit; // Always do this if you're using
844   // ScanLine!
845 
846   for Y := 0 to H - 1 do
847   begin
848     fP := fBitmap.ScanLine[Y];
849     I := 0;
850     for X := 0 to W - 1 do
851     begin
852       fRLine[X] := fP[I];
853       Inc(I); // Extract a red line
854       fGLine[X] := fP[I];
855       Inc(I); // Extract a green line
856       fBLine[X] := fP[I];
857       Inc(I); // Extract a blue line
858     end;
859 
860     fFillDataLines(fBLine); // Compress the blue line
861     fFillDataLines(fGLine); // Compress the green line
862     fFillDataLines(fRLine); // Compress the red line
863 
864   end;
865 
866   // Correct the length of fPCXData.fData
867   SetLength(fPCXFile.fPCXData.fData, fPCXFile.fCurrentPos);
868 end;
869 //-------------------------------------------------------------------//
870 
871 procedure TPCXImage.fConvertImageTo1And8BitPCXData(ImageWidthInBytes:
872   QWORD);
873 
874 var
875   H, W, X, Y: QWORD;
876   oldByte, newByte: BYTE;
877   Cnt: BYTE;
878 
879 begin
880   H := fBitmap.Height;
881   W := ImageWidthInBytes;
882   fPCXFile.fCurrentPos := 0;
883   SetLength(fPCXFile.fPCXData.fData, 2 * H * W); // To be sure...
884   oldByte := 0; // Otherwise the compiler issues a warning about
885   // oldByte not being initialized...
886   Cnt := $C1;
887   for Y := 0 to H - 1 do
888   begin
889     fP := fBitmap.ScanLine[Y];
890     for X := 0 to W - 1 do
891     begin
892 
893       newByte := fP[X];
894 
895       if X > 0 then
896       begin
897         if (Cnt = $FF) then
898         begin
899           fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := Cnt;
900           Inc(fPCXFile.fCurrentPos);
901           fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := oldByte;
902           Inc(fPCXFile.fCurrentPos);
903           Cnt := $C1;
904         end
905         else if newByte = oldByte then
906           Inc(Cnt);
907 
908         if newByte <> oldByte then
909         begin
910           if (Cnt > $C1) or (oldByte >= $C0) then
911           begin
912             fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := Cnt;
913             Inc(fPCXFile.fCurrentPos);
914             Cnt := $C1;
915           end;
916           fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := oldByte;
917           Inc(fPCXFile.fCurrentPos);
918         end;
919 
920       end;
921       oldByte := newByte;
922     end;
923     // Write last byte of line
924     if (Cnt > $C1) or (oldByte >= $C0) then
925     begin
926       fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := Cnt;
927       Inc(fPCXFile.fCurrentPos);
928       Cnt := $C1;
929     end;
930 
931     fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := oldByte;
932     Inc(fPCXFile.fCurrentPos);
933   end;
934 
935   // Write last byte of image
936   if (Cnt > $C1) or (oldByte >= $C0) then
937   begin
938     fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := Cnt;
939     Inc(fPCXFile.fCurrentPos);
940     // Cnt := 1;
941   end;
942   fPCXFile.fPCXData.fData[fPCXFile.fCurrentPos] := oldByte;
943   Inc(fPCXFile.fCurrentPos);
944 
945   // Correct the length of fPCXData.fData
946   SetLength(fPCXFile.fPCXData.fData, fPCXFile.fCurrentPos);
947 end;
948 //-------------------------------------------------------------------//
949 //                  RLE Decompression algorithm                      //
950 //-------------------------------------------------------------------//
951 
952 procedure TPCXImage.fConvert24BitPCXDataToImage; // Renamed 5/4/2002
953 
954 var
955 
956   I: QWORD;
957   By: BYTE;
958   Cnt: BYTE;
959   H, W: QWORD;
960   X, Y: QWORD;
961   K, L: QWORD;
962 
963 begin
964   H := fPCXFile.fPCXHeader.fWindow.wBottom -
965     fPCXFile.fPCXHeader.fWindow.wTop + 1;
966   W := fPCXFile.fPCXHeader.fWindow.wRight -
967     fPCXFile.fPCXHeader.fWindow.wLeft + 1;
968   Y := 0; // First line of image
969   fBitmap.Width := W; // Set bitmap width
970   fBitmap.Height := H; // Set bitmap height
971   fBitmap.PixelFormat := pf24bit; // Always do this if you're using
972   // ScanLine!
973   I := 0; // Pointer to data byte of fPXCFile
974   repeat
975 
976     // Process the red line
977     // ProcessLine(fRLine,W);
978 
979     X := 0; // Pointer to position in Red / Green / Blue line
980     repeat
981       By := fPCXFile.fPCXData.fData[I];
982       Inc(I);
983 
984       // one byte
985       if By < $C1 then
986         if X <= W then // added 5/4/2002
987         begin
988           fRLine[X] := By;
989           Inc(X);
990         end;
991 
992       // multiple bytes (RLE)
993       if By > $C0 then
994       begin
995         Cnt := By and $3F;
996 
997         By := fPCXFile.fPCXData.fData[I];
998         Inc(I);
999 
1000        //FillChar(fRLine[J],Cnt,By);
1001        //Inc(J,Cnt);
1002
1003        for K := 1 to Cnt do
1004          if X <= W then // added 5/4/2002
1005          begin
1006            fRLine[X] := By;
1007            Inc(X);
1008          end;
1009
1010      end;
1011
1012    until X >= W;
1013
1014    // Process the green line
1015    // ProcessLine(fGLine,W);
1016
1017    X := 0;
1018    repeat
1019      By := fPCXFile.fPCXData.fData[I];
1020      Inc(I);
1021
1022      // one byte
1023      if By < $C1 then
1024        if X <= W then // added 5/4/2002
1025        begin
1026          fGLine[X] := By;
1027          Inc(X);
1028        end;
1029
1030      // multiple bytes (RLE)
1031      if By > $C0 then
1032      begin
1033        Cnt := By and $3F;
1034
1035        By := fPCXFile.fPCXData.fData[I];
1036        Inc(I);
1037
1038        for K := 1 to Cnt do
1039          if X <= W then // added 5/4/2002
1040          begin
1041            fGLine[X] := By;
1042            Inc(X);
1043          end;
1044
1045      end;
1046
1047    until X >= W;
1048
1049    // Process the blue line
1050    // ProcessLine(fBLine,W);
1051
1052    X := 0;
1053    repeat
1054      By := fPCXFile.fPCXData.fData[I];
1055      Inc(I);
1056
1057      // one byte
1058      if By < $C1 then
1059        if X <= W then // added 5/4/2002
1060        begin
1061          fBLine[X] := By;
1062          Inc(X);
1063        end;
1064
1065      // multiple bytes (RLE)
1066      if By > $C0 then
1067      begin
1068        Cnt := By and $3F;
1069
1070        By := fPCXFile.fPCXData.fData[I];
1071        Inc(I);
1072
1073        for K := 1 to Cnt do
1074          if X <= W then // added 5/4/2002
1075          begin
1076            fBLine[X] := By;
1077            Inc(X);
1078          end;
1079
1080      end;
1081
1082    until X >= W;
1083
1084    // Write the just processed data RGB lines to the bitmap
1085    fP := fBitmap.ScanLine[Y];
1086    L := 0;
1087    for X := 0 to W - 1 do
1088    begin
1089      fP[L] := fBLine[X];
1090      Inc(L);
1091      fP[L] := fGLine[X];
1092      Inc(L);
1093      fP[L] := fRLine[X];
1094      Inc(L);
1095    end;
1096
1097    Inc(Y); // Process the next RGB line
1098
1099  until Y >= H;
1100
1101  SetLength(fPCXFile.fPCXData.fData, 0);
1102end;
1103//-------------------------------------------------------------------//
1104
1105procedure TPCXImage.fConvert1And8BitPCXDataToImage; // added 5/4/2002
1106
1107var
1108  I, J: QWORD;
1109  By: BYTE;
1110  Cnt: BYTE;
1111  H, W, WW: QWORD;
1112  X, Y: QWORD;
1113
1114begin
1115  H := fPCXFile.fPCXHeader.fWindow.wBottom -
1116    fPCXFile.fPCXHeader.fWindow.wTop + 1;
1117  W := fPCXFile.fPCXHeader.fWindow.wRight -
1118    fPCXFile.fPCXHeader.fWindow.wLeft + 1;
1119  fBitmap.Width := W; // Set bitmap width
1120  fBitmap.Height := H; // Set bitmap height
1121  WW := W;
1122
1123  // 1 bit PCX
1124  if fPCXFile.fPixelFormat = 1 then
1125  begin
1126    // All 1 bit images have a palette
1127    fBitmap.PixelFormat := pf1bit; // Always do this if you're using
1128    // ScanLine!
1129    WW := W div 8; // Correct width for pf1bit
1130    if W mod 8 > 0 then
1131    begin
1132      Inc(WW);
1133      fBitMap.Width := WW * 8;
1134    end;
1135    fSetPalette(2);
1136  end;
1137
1138  // 8 bit PCX
1139  if fPCXFile.fPixelFormat = 8 then
1140  begin
1141    // All 8 bit images have a palette!
1142    // This is how to set the palette of a bitmap
1143    // 1. First set the bitmap to pf8bit;
1144    // 2. then set the palette of the bitmap;
1145    // 3. then set the pixels with ScanLine or with Draw.
1146    // If you do it with StretchDraw, it won't work. Don't ask me why.
1147    // If you don't do it in this order, it won't work either! You'll
1148    // get strange colors.
1149    fBitmap.PixelFormat := pf8bit; // Always do this if you're using
1150    // ScanLine!
1151    fSetPalette(256);
1152  end;
1153
1154  I := 0;
1155  Y := 0;
1156  repeat
1157    fP := fBitmap.ScanLine[Y];
1158    X := 0; // Pointer to position in line
1159    repeat
1160      By := fPCXFile.fPCXData.fData[I];
1161      Inc(I);
1162
1163      // one byte
1164      if By < $C1 then
1165        if X <= WW then
1166        begin
1167          fP[X] := By;
1168          Inc(X);
1169        end;
1170
1171      // multiple bytes (RLE)
1172      if By > $C0 then
1173      begin
1174        Cnt := By and $3F;
1175
1176        By := fPCXFile.fPCXData.fData[I];
1177        Inc(I);
1178
1179        for J := 1 to Cnt do
1180          if X <= WW then
1181          begin
1182            fP[X] := By;
1183            Inc(X);
1184          end;
1185
1186      end;
1187
1188    until X >= WW;
1189
1190    Inc(Y); // Next line
1191
1192  until Y >= H;
1193end;
1194//---------------------------------------------------------------------
1195
1196procedure TPCXImage.fCreatePCXHeader(const byBitsPerPixel: BYTE;
1197  const byPlanes: BYTE; const wBytesPerLine: DWORD);
1198
1199var
1200  H, W: WORD;
1201
1202begin
1203  W := fBitmap.Width;
1204  H := fBitmap.Height;
1205
1206  // PCX header
1207  fPCXFile.fPCXHeader.fID := BYTE($0A); // BYTE (1)
1208  fPCXFile.fPCXHeader.fVersion := BYTE(5); // BYTE (2)
1209  fPCXFile.fPCXHeader.fCompressed := BYTE(1); // BYTE (3)
1210  // 0 = uncompressed, 1 = compressed
1211  // Only RLE compressed files are supported by this component
1212  fPCXFile.fPCXHeader.fBitsPerPixel := BYTE(byBitsPerPixel);
1213  // BYTE (4)
1214  fPCXFile.fPCXHeader.fWindow.wLeft := WORD(0); // WORD (5,6)
1215  fPCXFile.fPCXHeader.fWindow.wTop := WORD(0); // WORD (7,8)
1216  fPCXFile.fPCXHeader.fWindow.wRight := WORD(W - 1); // WORD (9,10)
1217  fPCXFile.fPCXHeader.fWindow.wBottom := WORD(H - 1); // WORD (11,12)
1218  fPCXFile.fPCXHeader.fHorzResolution := WORD(72); // WORD (13,14)
1219  fPCXFile.fPCXHeader.fVertResolution := WORD(72); // WORD (15,16)
1220
1221  FillChar(fPCXFile.fPCXHeader.fColorMap, 48, 0); // Array of Byte
1222  // (17..64)
1223
1224  fPCXFile.fPCXHeader.fReserved := BYTE(0); // BYTE (65)
1225  fPCXFile.fPCXHeader.fPlanes := BYTE(byPlanes);
1226  // BYTE (66)
1227  fPCXFile.fPCXHeader.fBytesPerLine := WORD(wBytesPerLine);
1228  // WORD (67,68)
1229  // must be even
1230  // rounded above
1231  fPCXFile.fPCXHeader.fPaletteInfo := WORD(1); // WORD (69,70)
1232
1233  FillChar(fPCXFile.fPCXHeader.fFiller, 58, 0); // Array of Byte
1234  // (71..128)
1235
1236  fPCXFile.fPixelFormat := fPCXFile.fPCXHeader.fPlanes *
1237    fPCXFile.fPCXHeader.fBitsPerPixel;
1238  fPCXFile.fColorDepth := 1 shl fPCXFile.fPixelFormat;
1239end;
1240//---------------------------------------------------------------------
1241(*
1242// From Delphi 5.0, graphics.pas
1243Function CopyPalette(Palette: HPALETTE): HPALETTE;
1244
1245Var
1246   PaletteSize    : Integer;
1247   LogPal         : TMaxLogPalette;
1248
1249Begin
1250Result := 0;
1251If Palette = 0 then
1252   Exit;
1253PaletteSize := 0;
1254If GetObject(Palette,SizeOf(PaletteSize),@PaletteSize) = 0 then
1255   Exit;
1256If PaletteSize = 0 then
1257   Exit;
1258With LogPal do
1259   Begin
1260   palVersion := $0300;
1261   palNumEntries := PaletteSize;
1262   GetPaletteEntries(Palette,0,PaletteSize,palPalEntry);
1263   End;
1264Result := CreatePalette(PLogPalette(@LogPal)^);
1265End;
1266*)
1267//---------------------------------------------------------------------
1268// From Delphi 5.0, graphics.pas
1269(*
1270Procedure TPCXImage.fSetPixelFormat(Value : TPixelFormat);
1271
1272Const
1273  BitCounts : Array [pf1Bit..pf32Bit] of BYTE = (1,4,8,16,16,24,32);
1274
1275Var
1276   DIB     : TDIBSection;
1277   Pal     : HPALETTE;
1278   DC      : hDC;
1279   KillPal : Boolean;
1280
1281Begin
1282If Value = GetPixelFormat then
1283   Exit;
1284Case Value of
1285      pfDevice : Begin
1286                 HandleType := bmDDB;
1287                 Exit;
1288                 End;
1289      pfCustom : InvalidGraphic(@SInvalidPixelFormat);
1290   else
1291      FillChar(DIB,sizeof(DIB), 0);
1292
1293   DIB.dsbm := FImage.FDIB.dsbm;
1294   KillPal := False;
1295   With DIB, dsbm,dsbmih do
1296      Begin
1297      bmBits := nil;
1298      biSize := SizeOf(DIB.dsbmih);
1299      biWidth := bmWidth;
1300      biHeight := bmHeight;
1301      biPlanes := 1;
1302      biBitCount := BitCounts[Value];
1303      Pal := FImage.FPalette;
1304      Case Value of
1305            pf4Bit  : Pal := SystemPalette16;
1306            pf8Bit  : Begin
1307                      DC := GDICheck(GetDC(0));
1308                      Pal := CreateHalftonePalette(DC);
1309                      KillPal := True;
1310                      ReleaseDC(0, DC);
1311                      End;
1312            pf16Bit : Begin
1313                      biCompression := BI_BITFIELDS;
1314                      dsBitFields[0] := $F800;
1315                      dsBitFields[1] := $07E0;
1316                      dsBitFields[2] := $001F;
1317                      End;
1318         End; // of Case
1319      Try
1320      CopyImage(Handle, Pal, DIB);
1321      PaletteModified := (Pal <> 0);
1322      Finally
1323         if KillPal then
1324            DeleteObject(Pal);
1325            End; // of Try
1326      Changed(Self);
1327      End; // of With
1328   End; // of Case
1329End; // of Procedure
1330*)
1331//---------------------------------------------------------------------
1332
1333procedure TPCXImage.fSetPalette(const wNumColors: WORD);
1334
1335(* From Delphi 5.0, graphics.pas
1336
1337Type
1338   TPalEntry = packed record
1339      peRed     : BYTE;
1340      peGreen   : BYTE;
1341      peBlue    : BYTE;
1342      End;
1343
1344Type
1345   tagLOGPALETTE = packed record
1346      palVersion     : WORD;
1347      palNumEntries  : WORD;
1348      palPalEntry    : Array[0..255] of TPalEntry
1349      End;
1350
1351Type
1352   TMAXLogPalette = tagLOGPALETTE;
1353   PMAXLogPalette = ^TMAXLogPalette;
1354
1355Type
1356   PRGBQuadArray = ^TRGBQuadArray;
1357   TRGBQuadArray = Array[BYTE] of TRGBQuad;
1358
1359Type
1360   PRGBQuadArray = ^TRGBQuadArray;
1361   TRGBQuadArray = Array[BYTE] of TRGBQuad;
1362*)
1363
1364var
1365  pal: TMaxLogPalette;
1366  W: WORD;
1367
1368begin
1369  pal.palVersion := $300; // The "Magic" number
1370  pal.palNumEntries := wNumColors;
1371  for W := 0 to 255 do
1372  begin
1373    pal.palPalEntry[W].peRed :=
1374      fPCXFile.fPCXPalette.fPalette[W].ceRed;
1375    pal.palPalEntry[W].peGreen :=
1376      fPCXFile.fPCXPalette.fPalette[W].ceGreen;
1377    pal.palPalEntry[W].peBlue :=
1378      fPCXFile.fPCXPalette.fPalette[W].ceBlue;
1379    pal.palPalEntry[W].peFlags := 0;
1380  end;
1381
1382  (* Must we delete the old palette first here? I don't know.
1383  If fhPAL <> 0 then
1384     DeleteObject(fhPAL);
1385  *)
1386
1387  fhPAL := CreatePalette(PLogPalette(@pal)^);
1388  if fhPAL <> 0 then
1389    fBitmap.Palette := fhPAL;
1390end;
1391//---------------------------------------------------------------------
1392
1393function TPCXImage.fGetPixelFormat: TPixelFormat;
1394
1395// Only pf1bit, pf4bit and pf8bit images have a palette.
1396// pf15bit, pf16bit, pf24bit and pf32bit images have no palette.
1397// You can change the palette of pf1bit images in windows.
1398// The foreground color and the background color of pf1bit images
1399// do not have to be black and white. You can choose any tow colors.
1400// The palette of pf4bit images is fixed.
1401// The palette entries 0..9 and 240..255 of pf8bit images are reserved
1402// in windows.
1403begin
1404  Result := pfDevice;
1405  case fPCXFile.fPixelFormat of
1406    01: Result := pf1bit; // Implemented WITH palette.
1407    // 04 : Result :=  pf4bit; // Not yet implemented in this component,
1408                               // is however implemented in PCX format.
1409    08: Result := pf8bit; // Implemented WITH palette.
1410    // 15 : Result := pf15bit; // Not implemented in PCX format?
1411    // 16 : Result := pf16bit; // Not implemented in PCX format?
1412    24: Result := pf24bit; // Implemented, has no palette.
1413    // 32 : Result := pf32bit; // Not implemented in PCX format.
1414  end;
1415end;
1416//---------------------------------------------------------------------
1417
1418procedure TPCXImage.fGetPalette(const wNumColors: WORD);
1419
1420var
1421  pal: TMaxLogPalette;
1422  W: WORD;
1423
1424begin
1425  fPCXFile.fPCXPalette.fSignature := $0C;
1426
1427  pal.palVersion := $300; // The "Magic" number
1428  pal.palNumEntries := wNumColors;
1429  GetPaletteEntries(CopyPalette(fBitmap.Palette), 0, wNumColors,
1430    pal.palPalEntry);
1431  for W := 0 to 255 do
1432    if W < wNumColors then
1433    begin
1434      fPCXFile.fPCXPalette.fPalette[W].ceRed :=
1435        pal.palPalEntry[W].peRed;
1436      fPCXFile.fPCXPalette.fPalette[W].ceGreen :=
1437        pal.palPalEntry[W].peGreen;
1438      fPCXFile.fPCXPalette.fPalette[W].ceBlue :=
1439        pal.palPalEntry[W].peBlue;
1440    end
1441    else
1442    begin
1443      fPCXFile.fPCXPalette.fPalette[W].ceRed := 0;
1444      fPCXFile.fPCXPalette.fPalette[W].ceGreen := 0;
1445      fPCXFile.fPCXPalette.fPalette[W].ceBlue := 0;
1446    end;
1447end;
1448//=====================================================================
1449
1450///////////////////////////////////////////////////////////////////////
1451//                                                                   //
1452//                         TPCXFile                                  //
1453//                                                                   //
1454///////////////////////////////////////////////////////////////////////
1455
1456constructor TPCXFile.Create;
1457
1458begin
1459  inherited Create;
1460  fHeight := 0;
1461  fWidth := 0;
1462  fCurrentPos := 0;
1463end;
1464//---------------------------------------------------------------------
1465
1466destructor TPCXFile.Destroy;
1467
1468begin
1469  SetLength(fPCXData.fData, 0);
1470  inherited Destroy;
1471end;
1472//---------------------------------------------------------------------
1473
1474procedure TPCXFile.LoadFromFile(const Filename: string);
1475
1476var
1477  fPCXStream: TFileStream;
1478
1479begin
1480  fPCXStream := TFileStream.Create(Filename, fmOpenRead);
1481  try
1482    fPCXStream.Position := 0;
1483    LoadFromStream(fPCXStream);
1484  finally
1485    fPCXStream.Free;
1486  end;
1487end;
1488//---------------------------------------------------------------------
1489
1490procedure TPCXFile.SaveToFile(const Filename: string);
1491
1492var
1493  fPCXStream: TFileStream;
1494
1495begin
1496  fPCXStream := TFileStream.Create(Filename, fmCreate);
1497  try
1498    fPCXStream.Position := 0;
1499    SaveToStream(fPCXStream);
1500  finally
1501    fPCXStream.Free;
1502  end;
1503end;
1504//---------------------------------------------------------------------
1505
1506procedure TPCXFile.LoadFromStream(Stream: TStream);
1507
1508var
1509  fFileLength: Cardinal;
1510
1511begin
1512  // Read the PCX header
1513  Stream.read(fPCXHeader, SizeOf(fPCXHeader));
1514
1515  // Check the ID byte
1516  if fPCXHeader.fID <> $0A then
1517    raise Exception.Create(FORMAT_ERROR);
1518
1519  (*
1520  Check PCX version byte
1521  ======================
1522  Versionbyte = 0 => PC PaintBrush V2.5
1523  Versionbyte = 2 => PC Paintbrush V2.8 with palette information
1524  Versionbyte = 3 => PC Paintbrush V2.8 without palette information
1525  Versionbyte = 4 => PC Paintbrush for Windows
1526  Versionbyte = 5 => PC Paintbrush V3 and up, and PC Paintbrush Plus
1527                     with 24 bit image support
1528  *)
1529  // Check the PCX version
1530  if fPCXHeader.fVersion <> 5 then
1531    raise Exception.Create(VERSION_ERROR);
1532
1533  // Calculate width
1534  fWidth := fPCXHeader.fWindow.wRight - fPCXHeader.fWindow.wLeft + 1;
1535  if fWidth < 0 then
1536    raise Exception.Create(WIDTH_OUT_OF_RANGE);
1537
1538  // Calculate height
1539  fHeight := fPCXHeader.fWindow.wBottom - fPCXHeader.fWindow.wTop + 1;
1540  if fHeight < 0 then
1541    raise Exception.Create(HEIGHT_OUT_OF_RANGE);
1542
1543  // Is it too large?
1544  if fWidth > fMaxImageWidth then
1545    raise Exception.Create(IMAGE_WIDTH_TOO_LARGE);
1546
1547  // Calculate pixelformat
1548  fPixelFormat := fPCXHeader.fPlanes * fPCXHeader.fBitsPerPixel;
1549
1550  // Calculate number of colors
1551  fColorDepth := 1 shl fPixelFormat;
1552
1553  // Is this image supported?
1554  if not (fPixelFormat in [1, 8, 24]) then
1555    raise Exception.Create(ERROR_UNSUPPORTED);
1556
1557  // The lines following are NOT tested!!!
1558  (*
1559  If fColorDepth <= 16 then
1560     For I := 0 to fColorDepth - 1 do
1561        Begin
1562        If fPCXHeader.fVersion = 3 then
1563           Begin
1564           fPCXPalette.fPalette[I].R := fPCXHeader.fColorMap[I].R shl 2;
1565           fPCXPalette.fPalette[I].G := fPCXHeader.fColorMap[I].G shl 2;
1566           fPCXPalette.fPalette[I].B := fPCXHeader.fColorMap[I].B shl 2;
1567           End
1568        else
1569           Begin
1570           fPCXPalette.fPalette[I].R := fPCXHeader.fColorMap[I].R;
1571           fPCXPalette.fPalette[I].G := fPCXHeader.fColorMap[I].G;
1572           fPCXPalette.fPalette[I].B := fPCXHeader.fColorMap[I].B;
1573           End;
1574        End;
1575  *)
1576
1577  // Calculate number of data bytes
1578
1579  // If fFileLength > fMaxDataFileLength then
1580  //    Raise Exception.Create(INPUT_FILE_TOO_LARGE);
1581
1582  if fPixelFormat = 24 then
1583  begin
1584    fFileLength := Stream.Size - Stream.Position;
1585    SetLength(fPCXData.fData, fFileLength);
1586    // Read the data
1587    Stream.read(fPCXData.fData[0], fFileLength);
1588    fHasPalette := False;
1589  end;
1590
1591  if fPixelFormat in [1, 8] then
1592  begin
1593    fFileLength := Stream.Size - Stream.Position - 769;
1594    SetLength(fPCXData.fData, fFileLength);
1595    // Correct number of data bytes
1596    Stream.read(fPCXData.fData[0], fFilelength);
1597    // Read the palette
1598    Stream.read(fPCXPalette, SizeOf(fPCXPalette));
1599    fHasPalette := True;
1600    // Check palette signature byte
1601    if fPCXPalette.fSignature <> $0C then
1602      raise Exception.Create(PALETTE_ERROR);
1603  end;
1604
1605end;
1606//---------------------------------------------------------------------
1607
1608procedure TPCXFile.SaveToStream(Stream: TStream);
1609
1610begin
1611  fHasPalette := False;
1612  Stream.write(fPCXHeader, SizeOf(fPCXHeader));
1613  Stream.write(fPCXData.fData[0], fCurrentPos);
1614  if fPixelFormat in [1, 8] then
1615  begin
1616    Stream.write(fPCXPalette, SizeOf(fPCXPalette));
1617    fHasPalette := True;
1618  end;
1619end;
1620//---------------------------------------------------------------------
1621// Register PCX format
1622initialization
1623  TPicture.RegisterFileFormat('PCX', sPCXImageFile, TPCXImage);
1624  CF_PCX := RegisterClipBoardFormat('PCX Image');
1625  TPicture.RegisterClipBoardFormat(CF_PCX, TPCXImage);
1626  //---------------------------------------------------------------------
1627  // Unregister PCX format
1628finalization
1629  TPicture.UnRegisterGraphicClass(TPCXImage);
1630  //---------------------------------------------------------------------
1631end.
1632//=====================================================================


			
Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10

 

Advertisement
Share this page
Advertisement
Download from Google

Copyright © Mendozi Enterprises LLC