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.