AsphyreTGA.pas
上传用户:ctlcnc
上传日期:2021-12-10
资源大小:4933k
文件大小:14k
源码类别:

2D图形编程

开发平台:

Delphi

  1. unit AsphyreTGA;
  2. //---------------------------------------------------------------------------
  3. // AsphyreTGA.pas                                       Modified: 08-Ago-2005
  4. // Truevision TARGA format support for Asphyre                    Version 1.0
  5. //---------------------------------------------------------------------------
  6. // The contents of this file are subject to the Mozilla Public License
  7. // Version 1.1 (the "License"); you may not use this file except in
  8. // compliance with the License. You may obtain a copy of the License at
  9. // http://www.mozilla.org/MPL/
  10. //
  11. // Software distributed under the License is distributed on an "AS IS"
  12. // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  13. // License for the specific language governing rights and limitations
  14. // under the License.
  15. //---------------------------------------------------------------------------
  16. interface
  17. //---------------------------------------------------------------------------
  18. uses
  19.  Types, Classes, SysUtils, Graphics;
  20. //---------------------------------------------------------------------------
  21. type
  22.  TTGAFlag  = (tfMirrored, tfFlipped, tfCompressed);
  23.  TTGAFlags = set of TTGAFlag;
  24. //---------------------------------------------------------------------------
  25. // LoadTGAtoBMP()
  26. //
  27. // Loads 24-bit or 32-bit Truevision TARGA file from stream and stores all
  28. // information in destination bitmap.
  29. //---------------------------------------------------------------------------
  30. function LoadTGAtoBMP(Stream: TStream; Dest: TBitmap): Boolean; overload;
  31. //---------------------------------------------------------------------------
  32. // SaveBMPtoTGA()
  33. //
  34. // Saves 24-bit or 32-bit bitmap as Truevision TARGA file to stream.
  35. //---------------------------------------------------------------------------
  36. function SaveBMPtoTGA(Stream: TStream; Source: TBitmap;
  37.  Flags: TTGAFlags): Boolean; overload;
  38. //---------------------------------------------------------------------------
  39. // Overloaded functions to save/load TGAs to/from external files.
  40. //---------------------------------------------------------------------------
  41. function LoadTGAtoBMP(const FileName: string; Dest: TBitmap): Boolean; overload;
  42. function SaveBMPtoTGA(const FileName: string; Source: TBitmap;
  43.  Flags: TTGAFlags): Boolean; overload;
  44. //---------------------------------------------------------------------------
  45. implementation
  46. //---------------------------------------------------------------------------
  47. type
  48.  TTGAHeader = packed record
  49.   tfIDLength     : Byte;
  50.   tfColorMapType : Byte;
  51.   tfImageType    : Byte;
  52.   tfColorMapSpec : packed array[0..4] of Byte;
  53.   tfOrigX        : Word;
  54.   tfOrigY        : Word;
  55.   tfWidth        : Word;
  56.   tfHeight       : Word;
  57.   tfBpp          : Byte;
  58.   tfImageDesc    : Byte;
  59.  end;
  60. //---------------------------------------------------------------------------
  61. procedure DecodeTargaRLE(Stream: TStream; Dest: Pointer; DestSize,
  62.  tgaBpp: Integer);
  63. var
  64.  Write: Pointer;
  65.  Count, bSize: Integer;
  66.  RLEHeader,
  67.  BlockLength: Byte;
  68.  RLEBuf: Longword;
  69. begin
  70.  // bytes to write
  71.  Count:= DestSize;
  72.  // pointer to destination
  73.  Write:= Dest;
  74.  // read pixels
  75.  while (Count > 0) do
  76.   begin
  77.    // read the RLE header
  78.    Stream.ReadBuffer(RLEHeader, SizeOf(RLEHeader));
  79.    // RLE Block length
  80.    BlockLength:= (RLEHeader and $7F) + 1;
  81.    if (RLEHeader and $80) = $80 then
  82.     begin
  83.      // if highest bit is set, the read one pixel and repeat it BlockLength times
  84.      Stream.ReadBuffer(RLEBuf, tgaBpp);
  85.      // write BlockLength pixels of RLEBuf
  86.      while (BlockLength > 0) do
  87.       begin
  88.        Move(RLEBuf, Write^, tgaBpp); // repeat the pixel, one at a time
  89.        Inc(Integer(Write), tgaBpp);
  90.        Dec(Count, tgaBpp);
  91.        Dec(BlockLength);
  92.       end;
  93.     end else
  94.     begin
  95.      // size of scanline to read
  96.      bSize:= Integer(BlockLength) * tgaBpp;
  97.      // read BlockLength pixels
  98.      Stream.ReadBuffer(Write^, bSize);
  99.      // increment destination pointer
  100.      Inc(Integer(Write), bSize);
  101.      // decrement the remaining byte count
  102.      Dec(Count, bSize);
  103.     end; // if RLEHeader
  104.   end; // while
  105. end;
  106. //---------------------------------------------------------------------------
  107. procedure Flip(Image: TBitmap);
  108. var
  109.  i, j: Integer;
  110.  ScanBuf: Pointer;
  111.  MyPitch: Integer;
  112. begin
  113.  if (Image.PixelFormat <> pf32bit) then Image.PixelFormat:= pf32bit;
  114.  // determine scanline size
  115.  MyPitch:= Image.Width * 4;
  116.  // proceed only if scanline exists
  117.  if (MyPitch > 0) then
  118.   begin
  119.    // allocate memory for temporary buffer
  120.    GetMem(ScanBuf, MyPitch);
  121.    // flip the image
  122.    for i:= 0 to (Image.Height div 2) - 1 do
  123.     begin
  124.      // calculate the opposite line
  125.      j:= (Image.Height - 1) - i;
  126.      // copy scanline[i] to buffer
  127.      Move(Image.Scanline[i]^, ScanBuf^, MyPitch);
  128.      // copy scanline[j] to scanline[i]
  129.      Move(Image.Scanline[j]^, Image.Scanline[i]^, MyPitch);
  130.      // copy buffer to scanline[j]
  131.      Move(ScanBuf^, Image.Scanline[j]^, MyPitch);
  132.     end;
  133.    // free unused memory
  134.    FreeMem(ScanBuf);
  135.   end; // if
  136. end;
  137. //---------------------------------------------------------------------------
  138. procedure Mirror(Image: TBitmap);
  139. var
  140.  i, j: Integer;
  141.  ScanBuf, Dest, Source: Pointer;
  142.  MyPitch: Integer;
  143. begin
  144.  if (Image.PixelFormat <> pf32bit) then Image.PixelFormat:= pf32bit;
  145.  // determine scanline size
  146.  MyPitch:= Image.Width * 4;
  147.  // proceed only if scanline exists
  148.  if (MyPitch > 0) then
  149.   begin
  150.    // allocate memory for temporary buffer
  151.    GetMem(ScanBuf, MyPitch);
  152.    // mirror the image
  153.    for j:= 0 to Image.Height - 1 do
  154.     begin
  155.      // assume the destination is the same as source
  156.      Move(Image.Scanline[j]^, ScanBuf^, MyPitch);
  157.      // point destination to the first pixel
  158.      Dest:= ScanBuf;
  159.      // point source to last pixel
  160.      Source:= Pointer(Integer(Image.Scanline[j]) + (MyPitch - 4));
  161.      for i:= 0 to Image.Width - 1 do
  162.       begin
  163.        Longword(Dest^):= Longword(Source^);
  164.        Dec(Integer(Source), 4);
  165.        Inc(Integer(Dest), 4);
  166.       end; // for i
  167.      // copy the mirrored scanline back
  168.      Move(ScanBuf^, Image.Scanline[j]^, MyPitch);
  169.     end; // for j
  170.    // free unused memory
  171.    FreeMem(ScanBuf);
  172.   end; // if
  173. end;
  174. //---------------------------------------------------------------------------
  175. function LoadTGAtoBMP(Stream: TStream; Dest: TBitmap): Boolean;
  176. var
  177.  tgaHeader: TTGAHeader;
  178.  tgaBpp, i: Integer;
  179.  BufSize, ScanLength: Integer;
  180.  PixBuffer, Read: Pointer;
  181. begin
  182.  Result:= False;
  183.  PixBuffer:= nil;
  184.  try
  185.   // read TGA header
  186.   Stream.ReadBuffer(tgaHeader, SizeOf(TTGAHeader));
  187.   // check if the image is either True-Color or RLE encoded
  188.   if (tgaHeader.tfImageType <> 2)and(tgaHeader.tfImageType <> 10) then Exit;
  189.   // color-mapping
  190.   if (tgaHeader.tfColorMapType <> 0) then Exit;
  191.   // bit-depth check
  192.   tgaBpp:= tgaHeader.tfBpp;
  193.   if (tgaBpp <> 32)and(tgaBpp <> 24) then Exit;
  194.   // skip Image ID field
  195.   if (tgaHeader.tfIDLength <> 0) then
  196.    Stream.Seek(tgaHeader.tfIDLength, soFromCurrent);
  197.   // create pixel buffer
  198.   BufSize:= Integer(tgaHeader.tfWidth) * tgaHeader.tfHeight * (tgaBpp div 8);
  199.   PixBuffer:= AllocMem(BufSize);
  200.   // read pixels
  201.   if (tgaHeader.tfImageType <> 10) then
  202.    begin
  203.     // read raw pixel data
  204.     Stream.ReadBuffer(pixBuffer^, bufSize);
  205.    end else
  206.    begin
  207.     // read RLE data
  208.     DecodeTargaRLE(Stream, pixBuffer, bufSize, tgaBpp div 8);
  209.    end;
  210.  except
  211.   if (PixBuffer <> nil) then FreeMem(PixBuffer);
  212.   Exit;
  213.  end; 
  214.  // specify file size
  215.  Dest.Width := tgaHeader.tfWidth;
  216.  Dest.Height:= tgaHeader.tfHeight;
  217.  // specify bit-depth
  218.  if (tgaBpp = 32) then Dest.PixelFormat:= pf32bit else Dest.PixelFormat:= pf24bit;
  219.  // source pointer
  220.  Read:= pixBuffer;
  221.  // scanline width
  222.  ScanLength:= Dest.Width * (tgaBpp div 8);
  223.  // set pixel data
  224.  for i:= 0 to Dest.Height - 1 do
  225.   begin
  226.    Move(Read^, Dest.Scanline[i]^, ScanLength);
  227.    Inc(Integer(Read), ScanLength);
  228.   end;
  229.  // check if the image is mirrored
  230.  if (tgaHeader.tfImageDesc and $10 = $10) then Mirror(Dest);
  231.  // check if the image is flipped
  232.  if (tgaHeader.tfImageDesc and $20 <> $20) then Flip(Dest);
  233.  // release the buffer memory and reading stream
  234.  FreeMem(PixBuffer);
  235.  Result:= True;
  236. end;
  237. //---------------------------------------------------------------------------
  238. procedure ScanRLE(Data: Pointer; PixRemain, iBpp: Integer;
  239.  out PixCount: Integer; out DoRepeat: Boolean);
  240. var
  241.  Pixels: array[0..2] of Longword;
  242.  nPixel: Longword;
  243.  i: Integer;
  244. begin
  245.  // case 0: less than 3 pixels to write
  246.  if (PixRemain < 3) then
  247.   begin
  248.    PixCount:= PixRemain;
  249.    DoRepeat:= False;
  250.    Exit;
  251.   end;
  252.  // read next 3 pixels
  253.  for i:= 0 to 2 do
  254.   begin
  255.    Pixels[i]:= 0;
  256.    Move(Pointer(Integer(Data) + (iBpp * i))^, Pixels[i], iBpp);
  257.   end;
  258.  // case 1: repeating pixels
  259.  nPixel:= 0;
  260.  if (Pixels[0] = Pixels[1])and(Pixels[1] = Pixels[2]) then
  261.   begin
  262.    PixCount:= 3;
  263.    nPixel:= Pixels[0];
  264.    while (PixCount < PixRemain)and(PixCount < $80)and(nPixel = Pixels[0]) do
  265.     begin
  266.      // increment repeated pixel count
  267.      Inc(PixCount);
  268.      Move(Pointer(Integer(Data) + (iBpp * PixCount))^, nPixel, iBpp);
  269.     end;
  270.    DoRepeat:= True;
  271.    Exit;
  272.   end;
  273.  // case 2: non-repeating pixels
  274.  PixCount:= 2;
  275.  while (PixCount < PixRemain - 1)and(PixCount < $80) do
  276.   begin
  277.    // read next 3 pixels
  278.    for i:= 0 to 2 do
  279.     begin
  280.      Pixels[i]:= 0;
  281.      Move(Pointer(Integer(Data) + (iBpp * (i + PixCount)))^, Pixels[i], iBpp);
  282.     end;
  283.    // check if the pixels are different
  284.    if (Pixels[0] = Pixels[1])and(Pixels[1] = Pixels[2]) then break
  285.     else Inc(PixCount);
  286.   end;
  287.  DoRepeat:= False;
  288. end;
  289. //---------------------------------------------------------------------------
  290. procedure EncodeTargaRLE(Stream: TStream; Source: Pointer;
  291.  SourceSize, tgaBpp: Integer);
  292. var
  293.  Read: Pointer;
  294.  Count, bSize: Integer;
  295.  RLEHeader: Byte;
  296.  PixCount: Integer;
  297.  DoRepeat: Boolean;
  298. begin
  299.  // bytes to read
  300.  Count:= SourceSize;
  301.  // pointer to source
  302.  Read:= Source;
  303.  // write pixels
  304.  while (Count > 0) do
  305.   begin
  306.    // scan repeating pixels
  307.    ScanRLE(Read, Count div tgaBpp, tgaBpp, PixCount, DoRepeat);
  308.    // calculate scanline size
  309.    bSize:= PixCount * tgaBpp;
  310.    // set # of pixels
  311.    RLEHeader:= (PixCount - 1) and $7F;
  312.    if (DoRepeat) then
  313.     begin
  314.      // update RLE header
  315.      RLEHeader:= RLEHeader or $80; // set RLE bit
  316.      // write updated RLE header
  317.      Stream.WriteBuffer(RLEHeader, SizeOf(RLEHeader));
  318.      // write the repeating pixel data
  319.      Stream.WriteBuffer(Read^, tgaBpp);
  320.     end else
  321.     begin
  322.      // write RLE header
  323.      Stream.WriteBuffer(RLEHeader, SizeOf(RLEHeader));
  324.      // write pixel data
  325.      Stream.WriteBuffer(Read^, bSize);
  326.     end;
  327.    // increment source pointer by number of scanned pixels
  328.    Inc(Integer(Read), bSize);
  329.    // decrement bytes remaining
  330.    Dec(Count, bSize);
  331.   end; // while
  332. end;
  333. //---------------------------------------------------------------------------
  334. function SaveBMPtoTGA(Stream: TStream; Source: TBitmap;
  335.  Flags: TTGAFlags): Boolean;
  336. var
  337.  tgaHeader: TTGAHeader;
  338.  tgaBpp, i: Integer;
  339.  BufSize, ScanLength: Integer;
  340.  PixBuffer, Write: Pointer;
  341. begin
  342.  // check bit-depth
  343.  if (not (Source.PixelFormat in [pf24bit, pf32bit])) then
  344.   begin
  345.    Result:= False;
  346.    Exit;
  347.   end;
  348.  // bit-depth configuration
  349.  tgaBpp:= 24;
  350.  if (Source.PixelFormat = pf32bit) then tgaBpp:= 32;
  351.  // create pixel buffer
  352.  BufSize:= Source.Width * Source.Height * (tgaBpp div 8);
  353.  GetMem(PixBuffer, BufSize);
  354.  // source pointer
  355.  Write:= PixBuffer;
  356.  // scanline width
  357.  ScanLength:= Source.Width * (tgaBpp div 8);
  358.  // apply flip & mirror attributes
  359.  if (tfFlipped in Flags) then Flip(Source);
  360.  if (tfMirrored in Flags) then Mirror(Source);
  361.  // set pixel data
  362.  for i:= 0 to Source.Height - 1 do
  363.   begin
  364.    Move(Source.Scanline[i]^, Write^, ScanLength);
  365.    Inc(Integer(Write), ScanLength);
  366.   end;
  367.  // return image to normal state
  368.  if (tfFlipped in Flags) then Flip(Source);
  369.  if (tfMirrored in Flags) then Mirror(Source);
  370.  // clear TARGA header
  371.  FillChar(tgaHeader, SizeOf(TTGAHeader), 0);
  372.  // create new TARGA header
  373.  tgaHeader.tfImageType:= 2;    // True-color
  374.  if (tfCompressed in Flags) then tgaHeader.tfImageType:= 10;    // RLE-encoded
  375.  // set flip & mirror attributes
  376.  tgaHeader.tfImageDesc:= $00;   // the image is flipped
  377.  // mirrored
  378.  if (tfFlipped in Flags) then
  379.   tgaHeader.tfImageDesc:= tgaHeader.tfImageDesc or $20;
  380.  // flipped
  381.  if (tfMirrored in Flags) then
  382.   tgaHeader.tfImageDesc:= tgaHeader.tfImageDesc or $10;
  383.  tgaHeader.tfColorMapType := 0;     // no colormapping
  384.  tgaHeader.tfWidth        := Source.Width; // image width
  385.  tgaHeader.tfHeight       := Source.Height;// image height
  386.  tgaHeader.tfBpp          := tgaBpp;// image bit-depth
  387.  Result:= True;
  388.  try
  389.   // write new TARGA header
  390.   Stream.WriteBuffer(tgaHeader, SizeOf(TTGAHeader));
  391.   // encode pixel data
  392.   if (tfCompressed in Flags) then
  393.    begin
  394.     EncodeTargaRLE(Stream, pixBuffer, bufSize, tgaBpp div 8);
  395.    end else
  396.    begin
  397.     Stream.WriteBuffer(pixBuffer^, bufSize);
  398.    end;
  399.  except
  400.   Result:= False;
  401.  end; 
  402.  // release the buffer memory and reading stream
  403.  FreeMem(PixBuffer);
  404. end;
  405. //---------------------------------------------------------------------------
  406. function LoadTGAtoBMP(const FileName: string; Dest: TBitmap): Boolean; overload;
  407. var
  408.  Stream: TStream;
  409. begin
  410.  try
  411.   Stream:= TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  412.  except
  413.   Result:= False;
  414.   Exit;
  415.  end;
  416.  try
  417.   Result:= LoadTGAtoBMP(Stream, Dest);
  418.  finally
  419.   Stream.Free();
  420.  end;
  421. end;
  422. //---------------------------------------------------------------------------
  423. function SaveBMPtoTGA(const FileName: string; Source: TBitmap;
  424.  Flags: TTGAFlags): Boolean;
  425. var
  426.  Stream: TStream;
  427. begin
  428.  try
  429.   Stream:= TFileStream.Create(FileName, fmCreate or fmShareExclusive);
  430.  except
  431.   Result:= False;
  432.   Exit;
  433.  end;
  434.  try
  435.   Result:= SaveBMPtoTGA(Stream, Source, Flags);
  436.  finally
  437.   Stream.Free();
  438.  end;
  439. end;
  440. //---------------------------------------------------------------------------
  441. end.