unit KOLTGA;

/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
////      KOL TARGA translated for KOL by MrBrdo     ////
////  I don't know who orignaly made this, but the   ////
////  component was to be registered under A-Team.   ////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////

interface

uses
  Windows, KOL, Messages;

{$I KOLDEF.INC}
{$WARNINGS OFF}

var
  Color16to24: array[0..31] of Byte = (0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112,
                                       120, 128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208,
                                       216, 224, 232, 240, 248);
const

NO_COLORMAP_INCLUDED = 0;
COLORMAP_IS_INCLUDED = 1;

NO_IMAGEDATA_INCLUDED = 0;
COLORMAPPED_IMAGE = 1;
TRUECOLOR_IMAGE = 2;
BLACKANDWHITE_IMAGE = 3;
RLE_COLORMAPPED_IMAGE = 9;
RLE_TRUECOLOR_IMAGE = 10;
RLE_BLACKANDWHITE_IMAGE = 11;

CF_TARGA = 20;

type
PByteArray = ^TByteArray;
TByteArray = array[0..32767] of Byte;

TTargaID = packed record
  Length: Byte;
  Text: PChar;
  end;

TTargaColorMapSpec = packed record
  FirstEntryIndex: Word;
  ColorMapLength: Word;
  ColorMapEntrySize: Byte;
  end;

TTargaImageDescriptor = packed record
  AlphaChannelBits: Byte;
  Top: Boolean;
  Left: Boolean;
  end;

TTargaImageSpec = packed record
  X: Word;
  Y: Word;
  Width: Word;
  Height: Word;
  PixelDepth: Byte;
  ImageDescriptor: TTargaImageDescriptor;
  end;

TRGBA = packed record
  Red: Byte;
  Green: Byte;
  Blue: Byte;
  Alpha: Byte;
  end;

TColorMap = packed array[0..999] of TRGBA;

TTargaType = (ttNoImageData, ttColorMapedImage, ttTrueColorImage, ttBlackAndWhiteImage, ttRLEColorMapedImage,
              ttRLETrueColorImage, ttRLEBlackAndWhiteImage);

TTargaViewType = (tvBitmap, tvAlphaChannel, tvUseAlphaChannel);

TTargaColorDepthType = (cd8bit, cd16bit, cd24bit, cd32bit);

TTargaClipboardType = (ctTarga, ctBitmap, ctAlphaChannel);

type
   PTarga = ^TTarga;
   TTarga = object(TObj)
   private
    FColorDepth: TTargaColorDepthType;
    FColorMapType: Byte;
    FColorMap: TColorMap;
    FColorMapSpec: TTargaColorMapSpec;
    FID: TTargaID;
    FImageType: Byte;
    FImageSpec: TTargaImageSpec;
    FIncludeAlphaChannel: Boolean;
    FTargaType: TTargaType;
    FBitmap: PBitmap;
    FAlphaChannel: PBitmap;
    procedure SetBitmap(Value: PBitmap);
    procedure SetAlphaChannel(Value: PBitmap);
    function RLEDecompress(DataLength: Integer; var RLEBuffer: PChar; var Buffer: PChar): Integer;
    function RLECompress(DataLength: Integer; var RLEBuffer: PChar; var Buffer: PChar): Integer;
   protected
//    function Equals(Graphic: TGraphic): Boolean; virtual;
    function GetEmpty: Boolean; virtual;
    function GetHeight: Integer; virtual;
//    function GetPalette: HPALETTE; virtual;
//    function GetTransparent: Boolean; virtual;
    function GetWidth: Integer; virtual;
//    procedure Progress(Sender: TObject; Stage: TProgressStage; PercentDone: Byte;  RedrawNow: Boolean; const R: TRect; const Msg: string); dynamic;
    procedure SetHeight(Value: Integer); virtual;
//    procedure SetPalette(Value: HPALETTE); virtual;
//    procedure SetTransparent(Value: Boolean); virtual;
    procedure SetWidth(Value: Integer); virtual;
   public
//    constructor Create; virtual;
    procedure Draw(ACanvas: PCanvas; const Rect: TRect); virtual;
    destructor Destroy; virtual;
    procedure LoadFromResourceName(Instance: THandle; const ResName: String);
    procedure LoadFromResourceID(Instance: THandle; ResID: Integer);
    procedure LoadFromFile(const FileName: string); virtual;
    procedure LoadFromStream(Stream: PStream); virtual;
    procedure SaveToFile(const FileName: string); virtual;
    procedure SaveToStream(Stream: PStream); virtual;
    procedure Assign(Source: PTarga); virtual;
    property Bitmap: PBitmap read FBitmap write SetBitmap;
    property AlphaChannel: PBitmap read FAlphaChannel write SetAlphaChannel;
    property Empty: Boolean read GetEmpty;
   end;

function NewTarga: PTarga;

implementation

function NewTarga: PTarga;
begin
  New(Result,Create);
  with Result^ do
  begin
    FBitmap := NewBitmap(0,0);
    FBitmap.PixelFormat:=pf32bit;
    FAlphaChannel:=NewBitmap(0,0);
    FAlphaChannel.PixelFormat:=pf32bit;
  end;
end;

destructor TTarga.Destroy;
begin
  if Assigned(FBitmap) then
    FBitmap.Free;
  if Assigned(FAlphaChannel) then
    FAlphaChannel.Free;
  inherited Destroy;
end;

procedure TTarga.LoadFromFile(const FileName: string);
var fsOpen: PStream;
begin
  fsOpen:=NewReadFileStream(FileName);
  try
    LoadFromStream(fsOpen);
  finally
    fsOpen.Free;
    end;
end;

procedure TTarga.SaveToFile(const FileName: string);
var fsOpen: PStream;
begin
  if not Assigned(FBitmap) then Exit;
  if UpperCase(CopyTail(FileName,3))='.BMP' then
    begin
    FBitmap.SaveToFile(FileName);
    end
  else
    begin
    fsOpen:=NewWriteFileStream(FileName);
    try
      SaveToStream(fsOpen);
    finally
      fsOpen.Free;
      end;
    end;
end;

procedure TTarga.Draw(ACanvas: PCanvas; const Rect: TRect);
begin
  StretchBlt(ACanvas.Handle, Rect.Left, Rect.Top, Rect.Right - Rect.Left,
             Rect.Bottom - Rect.Top, FBitmap.Canvas.Handle, 0, 0, FBitmap.Width, FBitmap.Height, ACanvas.ModeCopy);
end;

procedure TTarga.SetBitmap(Value: PBitmap);
begin
  if FBitmap <> Value then
  begin
    FBitmap.Assign(Value);
  end;
end;

procedure TTarga.SetAlphaChannel(Value: PBitmap);
begin
  if FAlphaChannel <> Value then
  begin
    FAlphaChannel.Assign(Value);
  end;
end;

function TTarga.GetEmpty: Boolean;
begin
  Result := (FBitmap = nil) or FBitmap.Empty;
end;

function TTarga.GetHeight: Integer;
begin
  Result:=FImageSpec.Height;
end;

function TTarga.GetWidth: Integer;
begin
  Result:=FImageSpec.Width;
end;

procedure TTarga.SetHeight(Value: Integer);
begin
end;

procedure TTarga.SetWidth(Value: Integer);
begin
end;

procedure TTarga.Assign(Source: PTarga);
begin
  FBitmap.Assign(Source^.FBitmap);
  FAlphaChannel.Assign(Source^.FAlphaChannel);
end;

procedure TTarga.LoadFromResourceName(Instance: THandle; const ResName: String);
var
  Stream: PStream;
begin
  Stream := NewMemoryStream;
  Resource2Stream(Stream, Instance, PChar(ResName), RT_RCDATA);
  Stream.Seek(0, spBegin);
  try
    LoadFromStream(Stream);
  finally
    Stream.Free;
  end;
end;

procedure TTarga.LoadFromResourceID(Instance: THandle; ResID: Integer);
var
  Stream: PStream;
begin
  Stream := NewMemoryStream;
  Resource2Stream(Stream, Instance, MAKEINTRESOURCE( ResID ), RT_RCDATA);
  try
    LoadFromStream(Stream);
  finally
    Stream.Free;
  end;
end;

procedure TTarga.LoadFromStream(Stream: PStream);
var Buffer: PChar;
    RLEBuffer: PChar;
    i, j: Integer;
    Color16: Word;
    LineSize: Integer;
    LineBuffer, AlphaBuffer: PByteArray;
    tmp16: Word;
    ReadLength: Integer;

  procedure GetBAWImageType(IsRLE: Boolean);
    var i, j: Integer;
    begin
    FColorDepth:=cd8bit;
    FIncludeAlphaChannel:=False;
    if IsRLE then FTargaType:=ttRLEBlackAndWhiteImage else FTargaType:=ttBlackAndWhiteImage;
    if IsRLE then RLEBuffer:=AllocMem(LineSize*2);
    for i:=0 to FImageSpec.Height-1 do
      begin
      if not FImageSpec.ImageDescriptor.Top and not FImageSpec.ImageDescriptor.Left then
        LineBuffer:=FBitmap.ScanLine[FImageSpec.Height-(i+1)]
      else LineBuffer:=FBitmap.ScanLine[i];
      if IsRLE then
        begin
        ReadLength:=Stream.Read(RLEBuffer^,LineSize*2);
        Stream.Position:=Stream.Position-ReadLength+RLEDecompress(FImageSpec.Width,RLEBuffer, Buffer);
        end
      else Stream.Read(Buffer^,LineSize);
      for j:=0 to FImageSpec.Width-1 do
        begin
        LineBuffer[(j*4)]:=Ord(Buffer[j]);
        LineBuffer[(j*4)+1]:=Ord(Buffer[j]);
        LineBuffer[(j*4)+2]:=Ord(Buffer[j]);
        end;
      end;
    end;

begin
  Buffer:=AllocMem(18);
  Stream.Read(Buffer^,18);
  FID.Length:=Ord(Buffer[0]);
  FColorMapType:=Ord(Buffer[1]);
  FImageType:=Ord(Buffer[2]);
  FColorMapSpec.FirstEntryIndex:=Ord(Buffer[3])+Ord(Buffer[4])*256;
  FColorMapSpec.ColorMapLength:=Ord(Buffer[5])+Ord(Buffer[6])*256;
  FColorMapSpec.ColorMapEntrySize:=Ord(Buffer[7]);
  FImageSpec.X:=Ord(Buffer[8])+Ord(Buffer[9])*256;
  FImageSpec.Y:=Ord(Buffer[10])+Ord(Buffer[11])*256;
  FImageSpec.Width:=Ord(Buffer[12])+Ord(Buffer[13])*256;
  FImageSpec.Height:=Ord(Buffer[14])+Ord(Buffer[15])*256;
  FImageSpec.PixelDepth:=Ord(Buffer[16]);
  FImageSpec.ImageDescriptor.AlphaChannelBits:=Ord(Buffer[17]) and 15;
  FImageSpec.ImageDescriptor.Top:=(Ord(Buffer[17]) and 32)=32;
  FImageSpec.ImageDescriptor.Left:=(Ord(Buffer[17]) and 16)=16;
  FreeMem(Buffer);
  if FID.Length>0 then
    begin
    GetMem( Buffer, FID.Length+1 );
    Buffer[FID.Length] := #0;
    Stream.Read(Buffer^,FID.Length);
    FID.Text:=Buffer;
    FreeMem(Buffer);
    end
  else FID.Text:='';
  //Buffer := nil;
  Free_And_Nil(FBitmap);
  Free_And_Nil(FAlphaChannel);
  if FColorMapType=1 then
    begin
    case FColorMapSpec.ColorMapEntrySize of
      15: begin
          Buffer:=AllocMem(FColorMapSpec.ColorMapLength*2);
          Stream.Read(Buffer^,FColorMapSpec.ColorMapLength*2);
          for i:=0 to FColorMapSpec.ColorMapLength-1 do
            begin
            Color16:=Ord(Buffer[(i*2)+0])+Ord(Buffer[(i*2)+1])*256;
            FColorMap[i].Blue:=Color16to24[Color16 and 31];
            FColorMap[i].Green:=Color16to24[(Color16 and 992) shr 5];
            FColorMap[i].Red:=Color16to24[(Color16 and 31744) shr 10];
            FColorMap[i].Alpha:=0;
            end;
          end;
      16: begin
          Buffer:=AllocMem(FColorMapSpec.ColorMapLength*2);
          Stream.Read(Buffer^,FColorMapSpec.ColorMapLength*2);
          for i:=0 to FColorMapSpec.ColorMapLength-1 do
            begin
            Color16:=Ord(Buffer[(i*2)+0])+Ord(Buffer[(i*2)+1])*256;
            FColorMap[i].Blue:=Color16to24[Color16 and 31];
            FColorMap[i].Green:=Color16to24[(Color16 and 992) shr 5];
            FColorMap[i].Red:=Color16to24[(Color16 and 31744) shr 10];
            FColorMap[i].Alpha:=0;
            end;
          end;
      24: begin
          Buffer:=AllocMem(FColorMapSpec.ColorMapLength*3);
          Stream.Read(Buffer^,FColorMapSpec.ColorMapLength*3);
          for i:=0 to FColorMapSpec.ColorMapLength-1 do
            begin
            FColorMap[i].Blue:=Ord(Buffer[(i*3)+0]);
            FColorMap[i].Green:=Ord(Buffer[(i*3)+1]);
            FColorMap[i].Red:=Ord(Buffer[(i*3)+2]);
            FColorMap[i].Alpha:=0;
            end;
          end;
      32: begin
          Buffer:=AllocMem(FColorMapSpec.ColorMapLength*4);
          Stream.Read(Buffer^,FColorMapSpec.ColorMapLength*4);
          for i:=0 to FColorMapSpec.ColorMapLength-1 do
            begin
            FColorMap[i].Blue:=Ord(Buffer[(i*4)+0]);
            FColorMap[i].Green:=Ord(Buffer[(i*4)+1]);
            FColorMap[i].Red:=Ord(Buffer[(i*4)+2]);
            FColorMap[i].Alpha:=Ord(Buffer[(i*4)+3]);
            end;
          end;
      else Exit;
      end;
    FreeMem(Buffer);
    end;
  if (FImageSpec.Width = 0) or (FImageSpec.Height = 0) then Exit;
  FBitmap := NewDibBitmap(FImageSpec.Width,FImageSpec.Height, pf32bit);

  FAlphaChannel := NewDibBitmap(FImageSpec.Width,FImageSpec.Height,pf32bit);

  LineSize:=FBitmap.Width*(FImageSpec.PixelDepth div 8);
  Buffer:=AllocMem(LineSize);
  if Buffer = nil then Exit;
  TRY
    case FImageType of
      NO_IMAGEDATA_INCLUDED:
        begin
        FTargaType:=ttNoImageData;
        end;
      COLORMAPPED_IMAGE:
        begin
        FTargaType:=ttColorMapedImage;
        case FImageSpec.PixelDepth of
          8: begin
             FColorDepth:=cd8bit;
             FIncludeAlphaChannel:=False;
             for i:=0 to FImageSpec.Height-1 do
               begin
               if not FImageSpec.ImageDescriptor.Top and not FImageSpec.ImageDescriptor.Left then
                 LineBuffer:=FBitmap.ScanLine[FImageSpec.Height-(i+1)]
               else
                 LineBuffer:=FBitmap.ScanLine[i];
               Stream.Read(Buffer^,LineSize);
               for j:=0 to FImageSpec.Width-1 do
                 begin
                 LineBuffer[(j*4)]:=FColorMap[Ord(Buffer[j])].Blue;
                 LineBuffer[(j*4)+1]:=FColorMap[Ord(Buffer[j])].Green;
                 LineBuffer[(j*4)+2]:=FColorMap[Ord(Buffer[j])].Red;
                 end;
               end;
             end;
          16: begin
              end;
          24: begin
              end;
          32: begin
              end;
          else Free_And_Nil( FBitmap );
               Free_And_Nil( FAlphaChannel );
               Exit;
          end;
        end;
      TRUECOLOR_IMAGE:
        begin
        FTargaType:=ttTrueColorImage;
        case FImageSpec.PixelDepth of
          16: begin
              FColorDepth:=cd16bit;
              FIncludeAlphaChannel:=False;
              for i:=0 to FImageSpec.Height-1 do
                begin
                if not FImageSpec.ImageDescriptor.Top and not FImageSpec.ImageDescriptor.Left then
                  LineBuffer:=FBitmap.ScanLine[FImageSpec.Height-(i+1)]
                else
                  LineBuffer:=FBitmap.ScanLine[i];
                Stream.Read(Buffer^,LineSize);
                for j:=0 to FImageSpec.Width-1 do
                  begin
                  tmp16:=Ord(Buffer[j*2])+Ord(Buffer[j*2+1])*256;
                  LineBuffer[(j*4)]:=Color16to24[(tmp16 and 31)];
                  LineBuffer[(j*4)+1]:=Color16to24[((tmp16 and 992) shr 5)];
                  LineBuffer[(j*4)+2]:=Color16to24[((tmp16 and 31744) shr 10)];
                  end;
                end;
              end;
          24: begin
              FColorDepth:=cd24bit;
              FIncludeAlphaChannel:=False;
              for i:=0 to FImageSpec.Height-1 do
                begin
                if not FImageSpec.ImageDescriptor.Top and not FImageSpec.ImageDescriptor.Left then
                  LineBuffer:=FBitmap.ScanLine[FImageSpec.Height-(i+1)]
                else
                  LineBuffer:=FBitmap.ScanLine[i];
                Stream.Read(Buffer^,LineSize);
                for j:=0 to FImageSpec.Width-1 do
                  begin
                  LineBuffer[(j*4)]:=Ord(Buffer[j*3]);
                  LineBuffer[(j*4)+1]:=Ord(Buffer[j*3+1]);
                  LineBuffer[(j*4)+2]:=Ord(Buffer[j*3+2]);
                  end;
                end;
              end;
          32: begin
              FColorDepth:=cd32bit;
              FIncludeAlphaChannel:=True;
              for i:=0 to FImageSpec.Height-1 do
                begin
                if not FImageSpec.ImageDescriptor.Top and not FImageSpec.ImageDescriptor.Left then
                  begin
                  LineBuffer:=FBitmap.ScanLine[FImageSpec.Height-(i+1)];
                  AlphaBuffer:=FAlphaChannel.ScanLine[FImageSpec.Height-(i+1)];
                  end
                else
                  begin
                  LineBuffer:=FBitmap.ScanLine[i];

                  AlphaBuffer:=FAlphaChannel.ScanLine[i];
                  end;
                Stream.Read(Buffer^,LineSize);
                for j:=0 to FImageSpec.Width-1 do
                  begin
                  LineBuffer[(j*4)]:=Ord(Buffer[j*4]);
                  LineBuffer[(j*4)+1]:=Ord(Buffer[j*4+1]);
                  LineBuffer[(j*4)+2]:=Ord(Buffer[j*4+2]);
                  AlphaBuffer[(j*4)]:=Ord(Buffer[j*4+3]);
                  AlphaBuffer[(j*4)+1]:=Ord(Buffer[j*4+3]);
                  AlphaBuffer[(j*4)+2]:=Ord(Buffer[j*4+3]);
                  end;
                end;
              end;
          end;
        end;
      BLACKANDWHITE_IMAGE: GetBAWImageType(False);
      RLE_COLORMAPPED_IMAGE:
        begin
        FTargaType:=ttRLEColorMapedImage;
        case FImageSpec.PixelDepth of
          8: begin
             FColorDepth:=cd8bit;
             FIncludeAlphaChannel:=False;
             RLEBuffer:=AllocMem(LineSize*2);
             for i:=0 to FImageSpec.Height-1 do
               begin
               if not FImageSpec.ImageDescriptor.Top and not FImageSpec.ImageDescriptor.Left then
                 LineBuffer:=FBitmap.ScanLine[FImageSpec.Height-(i+1)]
               else
                 LineBuffer:=FBitmap.ScanLine[i];
               ReadLength:=Stream.Read(RLEBuffer^,LineSize*2);
               Stream.Position:=Stream.Position-ReadLength+RLEDecompress(FImageSpec.Width,RLEBuffer, Buffer);
               for j:=0 to FImageSpec.Width-1 do
                 begin
                 LineBuffer[(j*4)]:=FColorMap[Ord(Buffer[j])].Blue;
                 LineBuffer[(j*4)+1]:=FColorMap[Ord(Buffer[j])].Green;
                 LineBuffer[(j*4)+2]:=FColorMap[Ord(Buffer[j])].Red;
                 end;
               end;
             end;
          16: begin
              end;
          24: begin
              end;
          32: begin
              end;
          end;
        end;
      RLE_TRUECOLOR_IMAGE:
        begin
        FTargaType:=ttRLETrueColorImage;
        case FImageSpec.PixelDepth of
          16: begin
              FColorDepth:=cd16bit;
              FIncludeAlphaChannel:=False;
              RLEBuffer:=AllocMem(LineSize*2);
              for i:=0 to FImageSpec.Height-1 do
                begin
                if not FImageSpec.ImageDescriptor.Top and not FImageSpec.ImageDescriptor.Left then
                  LineBuffer:=FBitmap.ScanLine[FImageSpec.Height-(i+1)]
                else
                  LineBuffer:=FBitmap.ScanLine[i];
                ReadLength:=Stream.Read(RLEBuffer^,LineSize*2);
                Stream.Position:=Stream.Position-ReadLength+RLEDecompress(FImageSpec.Width*2,RLEBuffer, Buffer);
                for j:=0 to FImageSpec.Width-1 do
                  begin
                  tmp16:=Ord(Buffer[j*2])+Ord(Buffer[j*2+1])*256;
                  LineBuffer[(j*4)]:=Color16to24[(tmp16 and 31)];
                  LineBuffer[(j*4)+1]:=Color16to24[((tmp16 and 992) shr 5)];
                  LineBuffer[(j*4)+2]:=Color16to24[((tmp16 and 31744) shr 10)];
                  end;
                end;
              FreeMem(RLEBuffer);
              end;
          24: begin
              FColorDepth:=cd24bit;
              FIncludeAlphaChannel:=False;
              RLEBuffer:=AllocMem(LineSize*2);
              for i:=0 to FImageSpec.Height-1 do
                begin
                if not FImageSpec.ImageDescriptor.Top and not FImageSpec.ImageDescriptor.Left then
                  LineBuffer:=FBitmap.ScanLine[FImageSpec.Height-(i+1)]
                else
                  LineBuffer:=FBitmap.ScanLine[i];
                ReadLength:=Stream.Read(RLEBuffer^,LineSize*2);
                Stream.Position:=Stream.Position-ReadLength+RLEDecompress(FImageSpec.Width*3,RLEBuffer, Buffer);
                for j:=0 to FImageSpec.Width-1 do
                  begin
                  LineBuffer[(j*4)]:=Ord(Buffer[j*3]);
                  LineBuffer[(j*4)+1]:=Ord(Buffer[j*3+1]);
                  LineBuffer[(j*4)+2]:=Ord(Buffer[j*3+2]);
                  end;
                end;
              FreeMem(RLEBuffer);
              end;
          32: begin
              FColorDepth:=cd32bit;
              FIncludeAlphaChannel:=True;
              RLEBuffer:=AllocMem(LineSize*2);
              for i:=0 to FImageSpec.Height-1 do
                begin
                if not FImageSpec.ImageDescriptor.Top and not FImageSpec.ImageDescriptor.Left then
                  begin
                  LineBuffer:=FBitmap.ScanLine[FImageSpec.Height-(i+1)];
                  AlphaBuffer:=FAlphaChannel.ScanLine[FImageSpec.Height-(i+1)];
                  end
                else
                  begin
                  LineBuffer:=FBitmap.ScanLine[i];
                  AlphaBuffer:=FAlphaChannel.ScanLine[i];
                  end;
                ReadLength:=Stream.Read(RLEBuffer^,LineSize*2);
                Stream.Position:=Stream.Position-ReadLength+RLEDecompress(FImageSpec.Width*4,RLEBuffer, Buffer);
                for j:=0 to FImageSpec.Width-1 do
                  begin
                  LineBuffer[(j*4)]:=Ord(Buffer[j*4]);
                  LineBuffer[(j*4)+1]:=Ord(Buffer[j*4+1]);
                  LineBuffer[(j*4)+2]:=Ord(Buffer[j*4+2]);
                  AlphaBuffer[(j*4)]:=Ord(Buffer[j*4+3]);
                  AlphaBuffer[(j*4)+1]:=Ord(Buffer[j*4+3]);
                  AlphaBuffer[(j*4)+2]:=Ord(Buffer[j*4+3]);
                  end;
                end;
              FreeMem(RLEBuffer);
              end;
          end;
        end;
      RLE_BLACKANDWHITE_IMAGE: GetBAWImageType(True);
      end;
  FINALLY
    FreeMem(Buffer);
  END;
end;

procedure TTarga.SaveToStream(Stream: PStream);
type
  TRGBCount = record
    RGBA: TRGBA;
    Count: Integer;
    end;
//  TRGBCountPalete = array[0..MaxInt] of TRGBCount;

var Buffer: PChar;
    RLEBuffer: PChar;
    i, j: Integer;
    Color16: Word;
    LineSize, RLELineSize: Integer;
    LineBuffer, AlphaBuffer: PByteArray;
{    ReadLength: Integer;
    PaletePos: Integer;
    tmpPalete: TRGBA;
    CountPalete: TRGBCountPalete;
    IsInPalete: Boolean;}
    tmpPosition: Integer;
    BytePerPixel: Byte;

begin
  case FTargaType of
    ttRLETrueColorImage:
      begin
      Buffer:=AllocMem(18);
      Buffer[0]:=Chr(0);
      Buffer[1]:=Chr(0);
      Buffer[2]:=Chr(RLE_TRUECOLOR_IMAGE);
      Buffer[3]:=Chr(0);
      Buffer[4]:=Chr(0);
      Buffer[5]:=Chr(0);
      Buffer[6]:=Chr(0);
      Buffer[7]:=Chr(0);
      Buffer[8]:=Chr(0);
      Buffer[9]:=Chr(0);
      Buffer[10]:=Chr(0);
      Buffer[11]:=Chr(0);
      Buffer[12]:=Chr(FBitmap.Width mod 256);
      Buffer[13]:=Chr(FBitmap.Width div 256);
      Buffer[14]:=Chr(FBitmap.Height mod 256);
      Buffer[15]:=Chr(FBitmap.Height div 256);
      Buffer[16]:=Chr(24);
      Buffer[17]:=Chr(0);
      Stream.Write(Buffer^,18);
      FreeMem(Buffer);
      LineSize:=FBitmap.Width*3;
      Buffer:=AllocMem(LineSize);
      RLEBuffer:=AllocMem(LineSize*2);
      for i:=0 to FBitmap.Height-1 do
        begin
        LineBuffer:=FBitmap.ScanLine[FBitmap.Height-(i+1)];
        for j:=0 to FBitmap.Width-1 do
          begin
          Buffer[j*3]:=Chr(LineBuffer[j*4]);
          Buffer[j*3+1]:=Chr(LineBuffer[j*4+1]);
          Buffer[j*3+2]:=Chr(LineBuffer[j*4+2]);
          end;
        RLELineSize:=RLECompress(LineSize,RLEBuffer,Buffer);
        tmpPosition:=Stream.Position;
        Stream.Size:=Stream.Size+RLELineSize;
        Stream.Position:=tmpPosition;
        Stream.Write(RLEBuffer^,RLELineSize);
        end;
      FreeMem(Buffer);
      FreeMem(RLEBuffer);
      end;
    else
      begin
      if (FBitmap.Width<>FAlphaChannel.Width) or (FBitmap.Height<>FAlphaChannel.Height) then
        begin
        FAlphaChannel.Width:=FBitmap.Width;
        FAlphaChannel.Height:=FBitmap.Height;
        end;
      case FColorDepth of
        cd16bit: BytePerPixel:=2;
        cd24bit: BytePerPixel:=3;
        cd32bit: BytePerPixel:=4;
        else BytePerPixel:=3;
        end;
      Buffer:=AllocMem(18);
      Buffer[0]:=Chr(0);
      Buffer[1]:=Chr(0);
      Buffer[2]:=Chr(TRUECOLOR_IMAGE);
      Buffer[3]:=Chr(0);
      Buffer[4]:=Chr(0);
      Buffer[5]:=Chr(0);
      Buffer[6]:=Chr(0);
      Buffer[7]:=Chr(0);
      Buffer[8]:=Chr(0);
      Buffer[9]:=Chr(0);
      Buffer[10]:=Chr(0);
      Buffer[11]:=Chr(0);
      Buffer[12]:=Chr(FBitmap.Width mod 256);
      Buffer[13]:=Chr(FBitmap.Width div 256);
      Buffer[14]:=Chr(FBitmap.Height mod 256);
      Buffer[15]:=Chr(FBitmap.Height div 256);
      Buffer[16]:=Chr(8*BytePerPixel);
      Buffer[17]:=Chr(0);
      Stream.Write(Buffer^,18);
      FreeMem(Buffer);
      LineSize:=FBitmap.Width*BytePerPixel;
      Buffer:=AllocMem(LineSize);
      for i:=0 to FBitmap.Height-1 do
        begin
        LineBuffer:=FBitmap.ScanLine[FBitmap.Height-(i+1)];
        AlphaBuffer:=FAlphaChannel.ScanLine[FBitmap.Height-(i+1)];
        for j:=0 to FBitmap.Width-1 do
          begin
          case FColorDepth of
            cd16bit: begin
                     Color16:=(Word(LineBuffer[j*4]) div 8) or ((Word(LineBuffer[(j*4)+1]) div 8) shl 5) or ((Word(LineBuffer[(j*4)+2]) div 8) shl 10);
                     Buffer[(j*2)]:=Chr(Lo(Color16));
                     Buffer[(j*2)+1]:=Chr(Hi(Color16));
                     end;
            cd24bit: begin
                     Buffer[j*3]:=Chr(LineBuffer[j*4]);
                     Buffer[j*3+1]:=Chr(LineBuffer[j*4+1]);
                     Buffer[j*3+2]:=Chr(LineBuffer[j*4+2]);
                     end;
            cd32bit: begin
                     Buffer[j*4]:=Chr(LineBuffer[j*4]);
                     Buffer[j*4+1]:=Chr(LineBuffer[j*4+1]);
                     Buffer[j*4+2]:=Chr(LineBuffer[j*4+2]);
                     Buffer[j*4+3]:=Chr(AlphaBuffer[j*4]);
                     end;
            end;
          end;
        Stream.Write(Buffer^,LineSize);
        end;
      FreeMem(Buffer);
      end;
{    ttColorMapedImage:
      begin
      PaletePos:=0;
      for i:=0 to Bitmap.Height-1 do
        begin
        LineBuffer:=Bitmap.ScanLine[Bitmap.Height+i];
        for j:=0 to Bitmap.Width-1 do
          begin
          tmpPalete.Red:=Ord(LineBuffer[j*4]);
          tmpPalete.Green:=Ord(LineBuffer[j*4+1]);
          tmpPalete.Blue:=Ord(LineBuffer[j*4+2]);
          tmpPalete.Alpha:=0;
          IsInPalete:=False;
          for k:=0 to PaletePos-1 do if tmpPalete=CountPalete[k].RGBA then
            begin
            IsInPalete:=True;
            Inc(CountPalete[k].Count);
            end;
          if
          end;
        end;
      Buffer:=AllocMem(18);
      Buffer[0]:=Chr(0);
      Buffer[1]:=Chr(0);
      Buffer[2]:=Chr(COLORMAPPED_IMAGE);
      Buffer[3]:=Chr(0);
      Buffer[4]:=Chr(0);
      Buffer[5]:=Chr(0);
      Buffer[6]:=Chr(0);
      Buffer[7]:=Chr(0);
      Buffer[8]:=Chr(0);
      Buffer[9]:=Chr(0);
      Buffer[10]:=Chr(0);
      Buffer[11]:=Chr(0);
      Buffer[12]:=Chr(Bitmap.Width mod 256);
      Buffer[13]:=Chr(Bitmap.Width div 256);
      Buffer[14]:=Chr(Bitmap.Height mod 256);
      Buffer[15]:=Chr(Bitmap.Height div 256);
      Buffer[16]:=Chr(8);
      Buffer[17]:=Chr(0);
      fsOpen.Size:=18+Bitmap.Width*Bitmap.Height*3;
      fsOpen.Position:=0;
      fsOpen.Write(Buffer^,18);
      FreeMem(Buffer);
      LineSize:=Bitmap.Width*3;
      Buffer:=AllocMem(LineSize);
      RLEBuffer:=AllocMem(LineSize*2);
      for i:=0 to Bitmap.Height-1 do
        begin
        LineBuffer:=Bitmap.ScanLine[Bitmap.Height-(i+1)];
        for j:=0 to Bitmap.Width-1 do
          begin
          Buffer[j*3]:=Chr(LineBuffer[j*4]);
          Buffer[j*3+1]:=Chr(LineBuffer[j*4+1]);
          Buffer[j*3+2]:=Chr(LineBuffer[j*4+2]);
          end;
        fsOpen.Write(Buffer^,LineSize);
        end;
      FreeMem(Buffer);
      end;}
  end;
end;    

function TTarga.RLEDecompress(DataLength: Integer; var RLEBuffer: PChar; var Buffer: PChar): Integer;
var RLEPacketType: Boolean;
    RLEPacketLength: Integer;
    RAWDataPosition: Integer;
    RLEPacketPosition: Integer;
    j: Integer;
begin
  RLEPacketPosition:=0;
  RAWDataPosition:=0;
  case FImageSpec.PixelDepth of
    8: begin
       while True do
         begin
         RLEPacketType:=Ord(RLEBuffer[RLEPacketPosition])>127;
         RLEPacketLength:=1+Ord(RLEBuffer[RLEPacketPosition]) and 127;
         if RLEPacketType then
           begin
           for j:=0 to RLEPacketLength-1 do
             begin
             Buffer[RAWDataPosition]:=RLEBuffer[RLEPacketPosition+1];
             Inc(RAWDataPosition);
             end;
           Inc(RLEPacketPosition,2)
           end
         else
           begin
           for j:=0 to RLEPacketLength-1 do
             begin
             Buffer[RAWDataPosition]:=RLEBuffer[RLEPacketPosition+j+1];
             Inc(RAWDataPosition);
             end;
           Inc(RLEPacketPosition,RLEPacketLength+1)
           end;
         if RAWDataPosition>=DataLength then Break;
         end;
       end;
    16: begin
        while True do
          begin
          RLEPacketType:=Ord(RLEBuffer[RLEPacketPosition])>127;
          RLEPacketLength:=1+Ord(RLEBuffer[RLEPacketPosition]) and 127;
          if RLEPacketType then
            begin
            for j:=0 to RLEPacketLength-1 do
              begin
              Buffer[RAWDataPosition]:=RLEBuffer[RLEPacketPosition+1];
              Buffer[RAWDataPosition+1]:=RLEBuffer[RLEPacketPosition+2];
              Inc(RAWDataPosition,2);
              end;
            Inc(RLEPacketPosition,3)
            end
          else
            begin
            for j:=0 to RLEPacketLength-1 do
              begin
              Buffer[RAWDataPosition]:=RLEBuffer[RLEPacketPosition+j*2+1];
              Buffer[RAWDataPosition+1]:=RLEBuffer[RLEPacketPosition+j*2+2];
              Inc(RAWDataPosition,2);
              end;
            Inc(RLEPacketPosition,RLEPacketLength*2+1)
            end;
          if RAWDataPosition>=DataLength then Break;
          end;
        end;
    24: begin
        while True do
          begin
          RLEPacketType:=Ord(RLEBuffer[RLEPacketPosition])>127;
          RLEPacketLength:=(Ord(RLEBuffer[RLEPacketPosition]) and 127)+1;
          if RLEPacketType then
            begin
            for j:=0 to RLEPacketLength-1 do
              begin
              Buffer[RAWDataPosition]:=RLEBuffer[RLEPacketPosition+1];
              Buffer[RAWDataPosition+1]:=RLEBuffer[RLEPacketPosition+2];
              Buffer[RAWDataPosition+2]:=RLEBuffer[RLEPacketPosition+3];
              Inc(RAWDataPosition,3);
              end;
            Inc(RLEPacketPosition,4)
            end
          else
            begin
            for j:=0 to RLEPacketLength-1 do
              begin
              Buffer[RAWDataPosition]:=RLEBuffer[RLEPacketPosition+j*3+1];
              Buffer[RAWDataPosition+1]:=RLEBuffer[RLEPacketPosition+j*3+2];
              Buffer[RAWDataPosition+2]:=RLEBuffer[RLEPacketPosition+j*3+3];
              Inc(RAWDataPosition,3);
              end;
            Inc(RLEPacketPosition,RLEPacketLength*3+1)
            end;
          if RAWDataPosition>=DataLength then Break;
          end;
        end;
    32: begin
        while True do
          begin
          RLEPacketType:=Ord(RLEBuffer[RLEPacketPosition])>127;
          RLEPacketLength:=1+Ord(RLEBuffer[RLEPacketPosition]) and 127;
          if RLEPacketType then
            begin
            for j:=0 to RLEPacketLength-1 do
              begin
              Buffer[RAWDataPosition]:=RLEBuffer[RLEPacketPosition+1];
              Buffer[RAWDataPosition+1]:=RLEBuffer[RLEPacketPosition+2];
              Buffer[RAWDataPosition+2]:=RLEBuffer[RLEPacketPosition+3];
              Buffer[RAWDataPosition+3]:=RLEBuffer[RLEPacketPosition+4];
              Inc(RAWDataPosition,4);
              end;
            Inc(RLEPacketPosition,5)
            end
          else
            begin
            for j:=0 to RLEPacketLength-1 do
              begin
              Buffer[RAWDataPosition]:=RLEBuffer[RLEPacketPosition+j*4+1];
              Buffer[RAWDataPosition+1]:=RLEBuffer[RLEPacketPosition+j*4+2];
              Buffer[RAWDataPosition+2]:=RLEBuffer[RLEPacketPosition+j*4+3];
              Buffer[RAWDataPosition+3]:=RLEBuffer[RLEPacketPosition+j*4+4];
              Inc(RAWDataPosition,4);
              end;
            Inc(RLEPacketPosition,RLEPacketLength*4+1)
            end;
          if RAWDataPosition>=DataLength then Break;
          end;
        end;
    end;
  Result:=RLEPacketPosition;
end;

function TTarga.RLECompress(DataLength: Integer; var RLEBuffer: PChar; var Buffer: PChar): Integer;
var ByteR, ByteG, ByteB: Byte;
    ByteCount: Integer;
    RAWDataPosition: Integer;
    IsRLEPacket: Boolean;
    RLEDataPosition: Integer;
    RAWPacketHeaderPos: Integer;
begin
  IsRLEPacket:=False;
  RAWDataPosition:=0;
  RLEDataPosition:=0;
  RAWPacketHeaderPos:=0;
  ByteCount:=0;
  ByteR:=Ord(Buffer[RAWDataPosition]);
  ByteG:=Ord(Buffer[RAWDataPosition+1]);
  ByteB:=Ord(Buffer[RAWDataPosition+2]);
  Inc(RAWDataPosition,3);
  while True do
    begin
    if (RAWDataPosition>=DataLength) or (ByteCount=127) then
      begin
      if IsRLEPacket then
        begin
        RLEBuffer[RLEDataPosition]:=Chr(128+ByteCount);
        RLEBuffer[RLEDataPosition+1]:=Chr(ByteR);
        RLEBuffer[RLEDataPosition+2]:=Chr(ByteG);
        RLEBuffer[RLEDataPosition+3]:=Chr(ByteB);
        Inc(RLEDataPosition,4);
        Inc(RAWDataPosition,3);
        ByteCount:=0;
        RAWPacketHeaderPos:=RLEDataPosition;
        IsRLEPacket:=False;
        end
      else
        begin
        RLEBuffer[RAWPacketHeaderPos]:=Chr(ByteCount);
        if ByteCount>0 then
          begin
          RLEBuffer[RLEDataPosition]:=Chr(ByteR);
          RLEBuffer[RLEDataPosition+1]:=Chr(ByteG);
          RLEBuffer[RLEDataPosition+2]:=Chr(ByteB);
          Inc(RLEDataPosition,3)
          end
        else
          begin
          RLEBuffer[RLEDataPosition+1]:=Chr(ByteR);
          RLEBuffer[RLEDataPosition+2]:=Chr(ByteG);
          RLEBuffer[RLEDataPosition+3]:=Chr(ByteB);
          Inc(RLEDataPosition,4);
          end;
        Inc(RAWDataPosition,3);
        ByteR:=Ord(Buffer[RAWDataPosition]);
        ByteG:=Ord(Buffer[RAWDataPosition+1]);
        ByteB:=Ord(Buffer[RAWDataPosition+2]);
        ByteCount:=0;
        RAWPacketHeaderPos:=RLEDataPosition;
        end;
      if (RAWDataPosition>=DataLength) then Break;
      end;
    if (ByteR=Ord(Buffer[RAWDataPosition])) and (ByteG=Ord(Buffer[RAWDataPosition+1])) and (ByteB=Ord(Buffer[RAWDataPosition+2])) then
      begin
      if not IsRLEPacket then ByteCount:=0;
      Inc(ByteCount);
      Inc(RAWDataPosition,3);
      IsRLEPacket:=True;
      end
    else
      begin
      if IsRLEPacket then
        begin
        RLEBuffer[RLEDataPosition]:=Chr(128+ByteCount);
        RLEBuffer[RLEDataPosition+1]:=Chr(ByteR);
        RLEBuffer[RLEDataPosition+2]:=Chr(ByteG);
        RLEBuffer[RLEDataPosition+3]:=Chr(ByteB);
        Inc(RLEDataPosition,4);
        ByteR:=Ord(Buffer[RAWDataPosition]);
        ByteG:=Ord(Buffer[RAWDataPosition+1]);
        ByteB:=Ord(Buffer[RAWDataPosition+2]);
        Inc(RAWDataPosition,3);
        ByteCount:=0;
        RAWPacketHeaderPos:=RLEDataPosition;
        IsRLEPacket:=False;
        end
      else
        begin
        RLEBuffer[RAWPacketHeaderPos]:=Chr(ByteCount);
        if ByteCount>0 then
          begin
          RLEBuffer[RLEDataPosition]:=Chr(ByteR);
          RLEBuffer[RLEDataPosition+1]:=Chr(ByteG);
          RLEBuffer[RLEDataPosition+2]:=Chr(ByteB);
          Inc(RLEDataPosition,3)
          end
        else
          begin
          RLEBuffer[RLEDataPosition+1]:=Chr(ByteR);
          RLEBuffer[RLEDataPosition+2]:=Chr(ByteG);
          RLEBuffer[RLEDataPosition+3]:=Chr(ByteB);
          Inc(RLEDataPosition,4);
          end;
        ByteR:=Ord(Buffer[RAWDataPosition]);
        ByteG:=Ord(Buffer[RAWDataPosition+1]);
        ByteB:=Ord(Buffer[RAWDataPosition+2]);
        Inc(RAWDataPosition,3);
        Inc(ByteCount);
        end;
      end;
    end;
  Result:=RLEDataPosition;
end;

end.
