mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-20 06:59:42 +02:00
301 lines
7.9 KiB
ObjectPascal
301 lines
7.9 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 FPReadTGA;
|
|
|
|
interface
|
|
|
|
uses FPImage, classes, sysutils, targacmn;
|
|
|
|
type
|
|
TFPReaderTarga = class (TFPCustomImageReader)
|
|
Private
|
|
Procedure FreeBuffers; // Free (and nil) buffers.
|
|
protected
|
|
Header : TTargaHeader;
|
|
Identification : ShortString;
|
|
Compressed,
|
|
BottomUp : Boolean;
|
|
BytesPerPixel : Byte;
|
|
FPalette : PFPColor;
|
|
FScanLine : PByte;
|
|
FLineSize : Integer;
|
|
FPaletteSize : Integer;
|
|
FBlockCount : Integer;
|
|
FPixelCount : Integer;
|
|
FLastPixel : Packed Array[0..3] of byte;
|
|
// AnalyzeHeader will allocate the needed buffers.
|
|
Procedure AnalyzeHeader(Img : TFPCustomImage);
|
|
Procedure ReadPalette(Stream : TStream);
|
|
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
|
|
|
|
Constructor TFPReaderTarga.Create;
|
|
|
|
begin
|
|
end;
|
|
|
|
Destructor TFPReaderTarga.Destroy;
|
|
|
|
begin
|
|
FreeBuffers;
|
|
Inherited;
|
|
end;
|
|
|
|
Procedure TFPReaderTarga.FreeBuffers;
|
|
|
|
begin
|
|
If (FScanLine<>Nil) then
|
|
begin
|
|
FreeMem(FScanLine);
|
|
FScanLine:=Nil;
|
|
end;
|
|
If (FPalette<>Nil) then
|
|
begin
|
|
FreeMem(FPalette);
|
|
FScanLine:=Nil;
|
|
end;
|
|
end;
|
|
|
|
Procedure TFPReaderTarga.AnalyzeHeader(Img : TFPCustomImage);
|
|
|
|
begin
|
|
With Header do
|
|
begin
|
|
If (Flags shl 6)<>0 then
|
|
Raise Exception.Create('Interlaced targa images not supported.');
|
|
If MapType>1 then
|
|
Raise Exception.CreateFmt('Unknown targa colormap type: %d',[MapType]);
|
|
if (PixelSize and 7)<>0 then
|
|
Raise Exception.Create('Pixelsize must be multiple of 8');
|
|
BottomUp:=(Flags and $20) <>0;
|
|
BytesPerPixel:=PixelSize shr 3;
|
|
Compressed:=ImgType>8;
|
|
If Compressed then
|
|
ImgType:=ImgType-8;
|
|
Case ImgType of
|
|
1: if (BytesPerPixel<>1) or (MapType<>1) then
|
|
Raise Exception.Create('Error in targa header: Colormapped image needs 1 byte per pixel and maptype 1');
|
|
2: If not (BytesPerPixel in [2..4]) then
|
|
Raise Exception.Create('Error in targa header: RGB image needs bytes per pixel between 2 and 4');
|
|
3: begin
|
|
if BytesPerPixel<>1 then
|
|
Raise Exception.Create('Error in targa header: Grayscale image needs 1 byte per pixel.');
|
|
end;
|
|
else
|
|
Raise Exception.CreateFmt('Unknown/Unsupported Targa image type : %d',[ImgType]);
|
|
end;
|
|
if (ToWord(MapLength)>0) and (MapEntrySize<>24) then
|
|
Raise Exception.CreateFmt('Only targa BGR colormaps are supported. Got : %d',[MapEntrySize]);
|
|
if (ToWord(MapLength)>0) and (MapType<>0) then
|
|
Raise Exception.Create('Empty colormap in Targa image file');
|
|
FLineSize:=BytesPerPixel*ToWord(Width);
|
|
GetMem(FScanLine,FLineSize);
|
|
FPaletteSize:=SizeOf(TFPColor)*ToWord(MapLength);
|
|
GetMem(FPalette,FPaletteSize);
|
|
Img.Width:=ToWord(Width);
|
|
Img.Height:=ToWord(Height);
|
|
end;
|
|
end;
|
|
|
|
Procedure TFPReaderTarga.ReadPalette(Stream : TStream);
|
|
|
|
Var
|
|
Entry : TBGREntry;
|
|
I : Integer;
|
|
|
|
begin
|
|
For I:=0 to ToWord(Header.MapLength)-1 do
|
|
begin
|
|
Stream.ReadBuffer(Entry,SizeOf(Entry));
|
|
With FPalette[i] do
|
|
begin
|
|
Red:=Entry.Red;
|
|
Green:=Entry.Green;
|
|
Blue:=Entry.Blue;
|
|
Alpha:=AlphaOpaque;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Procedure TFPReaderTarga.InternalRead (Stream:TStream; Img:TFPCustomImage);
|
|
|
|
var
|
|
H,Row : Integer;
|
|
|
|
begin
|
|
Stream.Read(Header,SizeOf(Header));
|
|
AnalyzeHeader(Img);
|
|
If Header.IdLen>0 then
|
|
begin
|
|
SetLength(Identification,Header.IDLen);
|
|
Stream.Read(Identification[1],Header.Idlen);
|
|
If Length(Identification)<>0 then
|
|
Img.Extra[KeyIdentification]:=Identification;
|
|
end;
|
|
If Toword(Header.MapLength)>0 then
|
|
ReadPalette(Stream);
|
|
H:=Img.height;
|
|
If BottomUp then
|
|
For Row:=0 to H-1 do
|
|
begin
|
|
ReadScanLine(Row,Stream);
|
|
WriteScanLine(Row,Img);
|
|
end
|
|
else
|
|
For Row:=H-1 downto 0 do
|
|
begin
|
|
ReadScanLine(Row,Stream);
|
|
WriteScanLine(Row,Img);
|
|
end;
|
|
end;
|
|
|
|
Procedure TFPReaderTarga.ReadScanLine(Row : Integer; Stream : TStream);
|
|
|
|
Var
|
|
P : PByte;
|
|
B : Byte;
|
|
I,J : Integer;
|
|
|
|
begin
|
|
If Not Compressed then
|
|
Stream.ReadBuffer(FScanLine^,FLineSize)
|
|
else
|
|
begin
|
|
P:=FScanLine;
|
|
For I:=0 to ToWord(Header.Width)-1 do
|
|
begin
|
|
If (FPixelCount>0) then
|
|
Dec(FPixelCount)
|
|
else
|
|
begin
|
|
Dec(FBlockCount);
|
|
If (FBlockCount<0) then
|
|
begin
|
|
Stream.ReadBuffer(B,1);
|
|
If (B and $80)<>0 then
|
|
begin
|
|
FPixelCount:=B and $7F;
|
|
FblockCount:=0;
|
|
end
|
|
else
|
|
FBlockCount:=B and $7F
|
|
end;
|
|
Stream.ReadBuffer(FlastPixel,BytesPerPixel);
|
|
end;
|
|
For J:=0 to BytesPerPixel-1 do
|
|
begin
|
|
P[0]:=FLastPixel[j];
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
const
|
|
c5to8bits : array[0..32-1] of Byte =
|
|
( 0, 8, 16, 25, 33, 41, 49, 58,
|
|
66, 74, 82, 90, 99, 107, 115, 123,
|
|
132, 140, 148, 156, 165, 173, 181, 189,
|
|
197, 206, 214, 222, 230, 239, 247, 255);
|
|
|
|
|
|
Procedure TFPReaderTarga.WriteScanLine(Row : Integer; Img : TFPCustomImage);
|
|
|
|
Var
|
|
Col : Integer;
|
|
B : Byte;
|
|
C : TFPColor;
|
|
W : Word;
|
|
P : PByte;
|
|
|
|
begin
|
|
C.Alpha:=AlphaOpaque;
|
|
P:=FScanLine;
|
|
Case Header.ImgType of
|
|
1 : for Col:=0 to Img.width-1 do
|
|
Img.Colors[Col,Row]:=FPalette[P[Col]];
|
|
2 : for Col:=0 to Img.Width-1 do
|
|
begin
|
|
// Fill C depending on number of pixels.
|
|
case BytesPerPixel of
|
|
2 : begin
|
|
W:=P[0];
|
|
inc(P);
|
|
W:=W or (P[0] shl 8);
|
|
With C do
|
|
begin
|
|
Blue:=c5to8bits[W and $1F];
|
|
W:=W shr 5;
|
|
Green:=c5to8bits[W and $1F];
|
|
W:=W shr 5;
|
|
Red:=c5to8bits[W and $1F];
|
|
end;
|
|
end;
|
|
3,4 : With C do
|
|
begin
|
|
Blue:=P[0] or (P[0] shl 8);
|
|
Inc(P);
|
|
Green:=P[0] or (P[0] shl 8);
|
|
Inc(P);
|
|
Red:=P[0] or (P[0] shl 8);
|
|
If bytesPerPixel=4 then
|
|
begin
|
|
Inc(P);
|
|
// Alpha:=P[0] or (P[0] shl 8); what is TARGA Attribute ??
|
|
end;
|
|
end;
|
|
end; // Case BytesPerPixel;
|
|
Img[Col,Row]:=C;
|
|
Inc(P);
|
|
end;
|
|
3 : For Col:=0 to Img.Width-1 do
|
|
begin
|
|
B:=FScanLine[Col];
|
|
B:=B+(B Shl 8);
|
|
With C do
|
|
begin
|
|
Red:=B;
|
|
Green:=B;
|
|
Blue:=B;
|
|
end;
|
|
Img.Colors[Col,Row]:=C;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TFPReaderTarga.InternalCheck (Stream:TStream) : boolean;
|
|
|
|
begin
|
|
Result:=True;
|
|
end;
|
|
|
|
initialization
|
|
ImageHandlers.RegisterImageReader ('TARGA Format', 'tga', TFPReaderTarga);
|
|
end. |