123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- {*****************************************************************************}
- {
- This file is part of the Free Pascal's "Free Components Library".
- Copyright (c) 2003 by Mazen NEIFER of the Free Pascal development team
- BMP reader implementation.
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- }
- {*****************************************************************************}
- { 08/2005 by Giulio Bernardi:
- - Added support for 16 and 15 bpp bitmaps.
- - If we have bpp <= 8 make an indexed image instead of converting it to RGB
- - Support for RLE4 and RLE8 decoding
- - Support for top-down bitmaps
- }
- {$mode objfpc}
- {$h+}
- unit FPReadXWD;
- interface
- uses FPImage, classes, sysutils, xwdfile;
- type
- TXWDColors = array of TXWDColor;
- { TFPReaderXWD }
- TFPReaderXWD = class (TFPCustomImageReader)
- private
- continue: boolean; // needed for onprogress event
- percent: byte;
- percentinterval : longword;
- percentacc : longword;
- Rect : TRect;
- procedure SwapXWDFileHeader(var Header: TXWDFileHeader);
- procedure SwapXWDColor(var Color: TXWDColor);
- procedure WriteScanLine(Row: Integer; Img: TFPCustomImage);
- protected
- XWDFileHeader: TXWDFileHeader; // The header, as read from the file
- WindowName: array of Char;
- XWDColors: TXWDColors;
- LineBuf: PByte; // Buffer for 1 line
- // required by TFPCustomImageReader
- procedure InternalRead (Stream:TStream; Img:TFPCustomImage); override;
- function InternalCheck (Stream:TStream) : boolean; override;
- public
- constructor Create; override;
- destructor Destroy; override;
- end;
- implementation
- //==============================================================================
- // Endian utils
- //
- // Copied from LCLProc unit
- //==============================================================================
- {$push}{$R-}
- function BEtoN(const AValue: DWord): DWord;
- begin
- {$IFDEF ENDIAN_BIG}
- Result := AValue;
- {$ELSE}
- Result := (AValue shl 24)
- or ((AValue and $0000FF00) shl 8)
- or ((AValue and $00FF0000) shr 8)
- or (AValue shr 24);
- {$ENDIF}
- end;
- {$pop}
- constructor TFPReaderXWD.create;
- begin
- inherited create;
-
- end;
- destructor TFPReaderXWD.Destroy;
- begin
- If (LineBuf<>Nil) then
- begin
- FreeMem(LineBuf);
- LineBuf:=Nil;
- end;
- SetLength(WindowName, 0);
- SetLength(XWDColors, 0);
- inherited destroy;
- end;
- procedure TFPReaderXWD.SwapXWDColor(var Color: TXWDColor);
- begin
- Color.pixel := BEtoN(Color.pixel);
- Color.red := swap(Color.red);
- Color.green := swap(Color.green);
- Color.blue := swap(Color.blue);
- end;
- procedure TFPReaderXWD.SwapXWDFileHeader(var Header: TXWDFileHeader);
- begin
- Header.header_size := BEtoN(Header.header_size);
- Header.file_version := BEtoN(Header.file_version);
- Header.pixmap_format := BEtoN(Header.pixmap_format);
- Header.pixmap_depth := BEtoN(Header.pixmap_depth);
- Header.pixmap_width := BEtoN(Header.pixmap_width);
- Header.pixmap_height := BEtoN(Header.pixmap_height);
- Header.xoffset := BEtoN(Header.xoffset);
- Header.byte_order := BEtoN(Header.byte_order);
- Header.bitmap_unit := BEtoN(Header.bitmap_unit);
- Header.bitmap_unit := BEtoN(Header.bitmap_bit_order);
- Header.bitmap_pad := BEtoN(Header.bitmap_pad);
- Header.bits_per_pixel := BEtoN(Header.bits_per_pixel);
- Header.bytes_per_line := BEtoN(Header.bytes_per_line);
- Header.visual_class := BEtoN(Header.visual_class);
- Header.red_mask := BEtoN(Header.red_mask);
- Header.green_mask := BEtoN(Header.green_mask);
- Header.blue_mask := BEtoN(Header.blue_mask);
- Header.bits_per_rgb := BEtoN(Header.bits_per_rgb);
- Header.colormap_entries := BEtoN(Header.colormap_entries);
- Header.ncolors := BEtoN(Header.ncolors);
- Header.window_width := BEtoN(Header.window_width);
- Header.window_height := BEtoN(Header.window_height);
- Header.window_x := BEtoN(Header.window_x);
- Header.window_y := BEtoN(Header.window_y);
- Header.window_bdrwidth := BEtoN(Header.window_bdrwidth);
- end;
- procedure TFPReaderXWD.WriteScanLine(Row : Integer; Img : TFPCustomImage);
- var
- Column: Integer;
- buffer: Cardinal;
- MyColor: TFPColor;
- begin
- MyColor.alpha := 0;
-
- case XWDFileHeader.bits_per_pixel of
- 1 :
- for Column:=0 to Img.Width-1 do
- if ((LineBuf[Column div 8] shr (7-(Column and 7)) ) and 1) <> 0 then
- img.Pixels[Column,Row]:=1
- else
- img.Pixels[Column,Row]:=0;
- 4 :
- for Column:=0 to img.Width-1 do
- img.Pixels[Column,Row]:=(LineBuf[Column div 2] shr (((Column+1) and 1)*4)) and $0f;
- 8 :
- for Column:=0 to img.Width-1 do
- img.Pixels[Column,Row]:=LineBuf[Column];
- 16 :
- for Column:=0 to img.Width-1 do
- img.Pixels[Column,Row]:=LineBuf[Column];
- 24 :
- for Column:=0 to img.Width-1 do
- img.Pixels[Column,Row]:=LineBuf[Column];
- 32 :
- for Column:=0 to img.Width-1 do
- begin
- Move(LineBuf[Column * 4], buffer, 4);
- // WriteLn(IntToHex(buffer, 8));
- { buffer := buffer mod (256 * 256 * 256);
- MyColor.red := Word((buffer div 256 * 256) * 256);
- buffer := buffer mod (256 * 256);
- MyColor.green := Word((buffer div 256) * 256);
- buffer := buffer mod 256;
- MyColor.blue := Word((buffer) * 256);}
- buffer := buffer mod (256 * 256 * 256);
- MyColor.blue := Word((buffer div 256 * 256) * 256);
- buffer := buffer mod (256 * 256);
- MyColor.green := Word((buffer div 256) * 256);
- buffer := buffer mod 256;
- MyColor.red := Word((buffer) * 256);
- img.Colors[Column,Row] := MyColor;
- end;
- end;
- { inc(percentacc,4);
- if percentacc>=percentinterval then
- begin
- percent:=percent+(percentacc div percentinterval);
- percentacc:=percentacc mod percentinterval;
- Progress(psRunning,percent,false,Rect,'',continue);
- end;}
- end;
- procedure TFPReaderXWD.InternalRead(Stream: TStream; Img: TFPCustomImage);
- var
- Color: TFPColor;
- Size, Row, i, Index: Integer;
- begin
- {****************************************************************************
- Initialization
- ****************************************************************************}
- Rect.Left:=0; Rect.Top:=0; Rect.Right:=0; Rect.Bottom:=0;
- continue:=true;
- Progress(psStarting,0,false,Rect,'',continue);
- if not continue then exit;
- Img.UsePalette := True;
- // Img.Palette.Clear;
- Color.alpha := 0;
- {****************************************************************************
- The file is on big-endian format, so it needs to be swaped on little-endian CPUs
- ****************************************************************************}
- Stream.Position := 0; //* Causes error if removed, but should be
- Stream.Read(XWDFileHeader, SizeOf(TXWDFileHeader));
- {$ifdef ENDIAN_LITTLE}
- SwapXWDFileHeader(XWDFileHeader);
- {$endif}
- {****************************************************************************
- Now reads the window name
- ****************************************************************************}
- Size := XWDFileHeader.header_size - SizeOf(TXWDFileHeader);
- // Avoids allocating too much space for the string
- if Size > 256 then raise Exception.Create('Window name string too big. The file might be corrupted.');
-
- SetLength(WindowName, Size);
- Stream.Read(WindowName[0], Size);
- {****************************************************************************
- Fills the palette
- ****************************************************************************}
- SetLength(XWDColors, XWDFileHeader.ncolors);
- Img.Palette.Count := 256;
- for i := 1 to XWDFileHeader.ncolors do
- begin
- Stream.Read(XWDColors[i - 1], SizeOf(TXWDColor));
- {$ifdef ENDIAN_LITTLE}
- SwapXWDColor(XWDColors[i - 1]);
- {$endif}
- Color.red := XWDColors[i - 1].red;
- Color.green := XWDColors[i - 1].green;
- Color.blue := XWDColors[i - 1].blue;
- Index := XWDColors[i - 1].pixel mod 256;
- // WriteLn(IntToHex(Index, 8));
- Img.Palette.Color[Index] := Color;
- end;
- {****************************************************************************
- Reads the matrix of colors
- ****************************************************************************}
- Img.SetSize(XWDFileHeader.pixmap_width, XWDFileHeader.pixmap_height);
- GetMem(LineBuf, XWDFileHeader.bytes_per_line);
- for Row := 0 to Img.Height - 1 do
- begin
- Stream.Read(LineBuf[0], XWDFileHeader.bytes_per_line);
- WriteScanLine(Row, Img);
- if not continue then exit;
- end;
- Progress(psEnding,100,false,Rect,'',continue);
- end;
- function TFPReaderXWD.InternalCheck (Stream:TStream): boolean;
- var
- Header: TXWDFileHeader;
- begin
- stream.Read(Header, SizeOf(Header));
- {$IFDEF ENDIAN_LITTLE}
- SwapXWDFileHeader(Header);
- {$ENDIF}
- Result := Header.file_version = XWD_FILE_VERSION; // Just check magic number
- end;
- initialization
- ImageHandlers.RegisterImageReader ('XWD Format', 'xwd', TFPReaderXWD);
-
- end.
|