mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-20 06:59:42 +02:00
284 lines
7.4 KiB
ObjectPascal
284 lines
7.4 KiB
ObjectPascal
{*****************************************************************************}
|
|
{
|
|
$Id$
|
|
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 writer 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.
|
|
}
|
|
{*****************************************************************************}
|
|
|
|
{$mode objfpc}
|
|
{$h+}
|
|
|
|
unit FPReadBMP;
|
|
|
|
interface
|
|
|
|
uses FPImage, classes, sysutils, BMPcomn;
|
|
|
|
type
|
|
TFPReaderBMP = class (TFPCustomImageReader)
|
|
Private
|
|
Procedure FreeBufs; // Free (and nil) buffers.
|
|
protected
|
|
ReadSize : Integer; // Size (in bytes) of 1 scanline.
|
|
BFI : TBitMapInfoHeader; // The header as read from the stream.
|
|
FPalette : PFPcolor; // Buffer with Palette entries.
|
|
LineBuf : PByte; // Buffer for 1 scanline. Can be Byte, TColorRGB or TColorRGBA
|
|
|
|
// SetupRead will allocate the needed buffers, and read the colormap if needed.
|
|
procedure SetupRead(nPalette, nRowBits: Integer; Stream : TStream); virtual;
|
|
procedure ReadScanLine(Row : Integer; Stream : TStream); virtual;
|
|
procedure WriteScanLine(Row : Integer; Img : TFPCustomImage); virtual;
|
|
// 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
|
|
|
|
|
|
function RGBAToFPColor(Const RGBA: TColorRGBA) : TFPcolor;
|
|
|
|
begin
|
|
with Result, RGBA do
|
|
begin
|
|
Red :=(R shl 8) or R;
|
|
Green :=(G shl 8) or G;
|
|
Blue :=(B shl 8) or B;
|
|
Alpha :=255-A;
|
|
Alpha :=(Alpha shl 8) or Alpha
|
|
end;
|
|
end;
|
|
|
|
Function RGBToFPColor(Const RGB : TColorRGB) : TFPColor;
|
|
|
|
begin
|
|
with Result,RGB do
|
|
begin {Use only the high byte to convert the color}
|
|
Red := (R shl 8) + R;
|
|
Green := (G shl 8) + G;
|
|
Blue := (B shl 8) + B;
|
|
Alpha := AlphaOpaque;
|
|
end;
|
|
end;
|
|
|
|
Constructor TFPReaderBMP.create;
|
|
|
|
begin
|
|
inherited create;
|
|
end;
|
|
|
|
Destructor TFPReaderBMP.Destroy;
|
|
|
|
begin
|
|
FreeBufs;
|
|
inherited destroy;
|
|
end;
|
|
|
|
Procedure TFPReaderBMP.FreeBufs;
|
|
|
|
begin
|
|
If (LineBuf<>Nil) then
|
|
begin
|
|
FreeMem(LineBuf);
|
|
LineBuf:=Nil;
|
|
end;
|
|
If (FPalette<>Nil) then
|
|
begin
|
|
FreeMem(FPalette);
|
|
FPalette:=Nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TFPReaderBMP.SetupRead(nPalette, nRowBits: Integer; Stream : TStream);
|
|
|
|
{$ifdef VER1_0}
|
|
type
|
|
tcolinfo = ARRAY [0..0] OF TColorRGBA;
|
|
pcolinfo = ^tcolinfo;
|
|
var
|
|
ColInfo: pcolinfo;
|
|
{$else}
|
|
var
|
|
ColInfo: ARRAY OF TColorRGBA;
|
|
{$endif}
|
|
i: Integer;
|
|
|
|
begin
|
|
if nPalette>0 then
|
|
begin
|
|
GetMem(FPalette, nPalette*SizeOf(TFPColor));
|
|
{$ifdef VER1_0}
|
|
GetMem(ColInfo, nPalette*Sizeof(TColorRGBA));
|
|
if BFI.ClrUsed>0 then
|
|
Stream.Read(ColInfo^[0],BFI.ClrUsed*SizeOf(TColorRGBA))
|
|
else // Seems to me that this is dangerous.
|
|
Stream.Read(ColInfo^[0],nPalette*SizeOf(TColorRGBA));
|
|
for i := 0 to nPalette-1 do
|
|
FPalette[i] := RGBAToFPColor(ColInfo^[i]);
|
|
{$else}
|
|
SetLength(ColInfo, nPalette);
|
|
if BFI.ClrUsed>0 then
|
|
Stream.Read(ColInfo[0],BFI.ClrUsed*SizeOf(TColorRGBA))
|
|
else // Seems to me that this is dangerous.
|
|
Stream.Read(ColInfo[0],nPalette*SizeOf(TColorRGBA));
|
|
for i := 0 to High(ColInfo) do
|
|
FPalette[i] := RGBAToFPColor(ColInfo[i]);
|
|
{$endif}
|
|
end
|
|
else if BFI.ClrUsed>0 then { Skip palette }
|
|
Stream.Position := Stream.Position + BFI.ClrUsed*SizeOf(TColorRGBA);
|
|
ReadSize:=((nRowBits + 31) div 32) shl 2;
|
|
GetMem(LineBuf,ReadSize);
|
|
{$ifdef VER1_0}
|
|
FreeMem(ColInfo, nPalette*Sizeof(TColorRGBA));
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TFPReaderBMP.InternalRead(Stream:TStream; Img:TFPCustomImage);
|
|
|
|
Var
|
|
Row : Integer;
|
|
|
|
begin
|
|
Stream.Read(BFI,SizeOf(BFI));
|
|
{ This will move past any junk after the BFI header }
|
|
Stream.Position:=Stream.Position-SizeOf(BFI)+BFI.Size;
|
|
with BFI do
|
|
begin
|
|
if (Compression<>0) then
|
|
Raise FPImageException.Create('Compressed bitmaps not supported');
|
|
Img.Width:=Width;
|
|
Img.Height:=Height;
|
|
end;
|
|
Case BFI.BitCount of
|
|
1 : { Monochrome }
|
|
SetupRead(2,Img.Width,Stream);
|
|
4 :
|
|
SetupRead(16,Img.Width*4,Stream);
|
|
8 :
|
|
SetupRead(256,Img.Width*8,Stream);
|
|
16 :
|
|
Raise FPImageException.Create('16 bpp bitmaps not supported');
|
|
24:
|
|
SetupRead(0,Img.Width*8*3,Stream);
|
|
32:
|
|
SetupRead(0,Img.Width*8*4,Stream);
|
|
end;
|
|
Try
|
|
for Row:=Img.Height-1 downto 0 do
|
|
begin
|
|
ReadScanLine(Row,Stream); // Scanline in LineBuf with Size ReadSize.
|
|
WriteScanLine(Row,Img);
|
|
end;
|
|
finally
|
|
FreeBufs;
|
|
end;
|
|
end;
|
|
|
|
procedure TFPReaderBMP.ReadScanLine(Row : Integer; Stream : TStream);
|
|
|
|
begin
|
|
{
|
|
Add here support for compressed lines. The 'readsize' is the same in the end.
|
|
}
|
|
Stream.Read(LineBuf[0],ReadSize);
|
|
end;
|
|
|
|
procedure TFPReaderBMP.WriteScanLine(Row : Integer; Img : TFPCustomImage);
|
|
|
|
Var
|
|
Column : Integer;
|
|
|
|
begin
|
|
Case BFI.BitCount 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.colors[Column,Row]:=FPalette[1]
|
|
else
|
|
img.colors[Column,Row]:=FPalette[0];
|
|
4 :
|
|
for Column:=0 to img.Width-1 do
|
|
img.colors[Column,Row]:=FPalette[(LineBuf[Column div 2] shr (((Column+1) and 1)*4)) and $0f];
|
|
8 :
|
|
for Column:=0 to img.Width-1 do
|
|
img.colors[Column,Row]:=FPalette[LineBuf[Column]];
|
|
16 :
|
|
Raise FPImageException.Create('16 bpp bitmaps not supported');
|
|
24 :
|
|
for Column:=0 to img.Width-1 do
|
|
img.colors[Column,Row]:=RGBToFPColor(PColorRGB(LineBuf)[Column]);
|
|
32 :
|
|
for Column:=0 to img.Width-1 do
|
|
img.colors[Column,Row]:=RGBAToFPColor(PColorRGBA(LineBuf)[Column]);
|
|
end;
|
|
end;
|
|
|
|
function TFPReaderBMP.InternalCheck (Stream:TStream) : boolean;
|
|
|
|
var
|
|
BFH:TBitMapFileHeader;
|
|
begin
|
|
stream.Read(BFH,SizeOf(BFH));
|
|
With BFH do
|
|
Result:=(bfType=BMmagic); // Just check magic number
|
|
end;
|
|
|
|
initialization
|
|
ImageHandlers.RegisterImageReader ('BMP Format', 'bmp', TFPReaderBMP);
|
|
end.
|
|
{
|
|
$Log$
|
|
Revision 1.12 2004-03-01 23:46:38 michael
|
|
+ Corrected alpha in colormap
|
|
|
|
Revision 1.11 2004/02/25 02:36:51 pierre
|
|
* fix compilation with 1.0 compiler
|
|
|
|
Revision 1.10 2004/02/20 23:12:57 michael
|
|
+ Read/WriteScanline virtual, as intended
|
|
|
|
Revision 1.9 2004/02/20 23:07:44 michael
|
|
+ Small improvements. More cosmetic in nature
|
|
|
|
Revision 1.8 2004/02/20 23:00:35 michael
|
|
+ Small improvements. More cosmetic in nature
|
|
|
|
Revision 1.7 2004/02/20 22:42:44 michael
|
|
+ More modular reading of BMP for easier overriding in descendents
|
|
|
|
Revision 1.6 2004/02/15 20:59:06 michael
|
|
+ Patch from Colin Western
|
|
|
|
Revision 1.5 2003/09/30 14:17:05 luk
|
|
* better color conversion (White didn't stay white)
|
|
|
|
Revision 1.4 2003/09/30 06:17:38 mazen
|
|
- all common defintions are now included into bmpcomn unit
|
|
|
|
Revision 1.3 2003/09/15 11:39:01 mazen
|
|
* fixed InternalRead method to load BMP files.
|
|
But still too long to load images.
|
|
|
|
Revision 1.2 2003/09/09 11:26:59 mazen
|
|
+ setting image attributes when loading images
|
|
* fixing copyright section in the file header
|
|
|
|
Revision 1.1 2003/09/08 14:10:10 mazen
|
|
+ adding support for loading bmp images
|
|
|
|
}
|