GXS.FileTGA.pas 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. //
  2. // The graphics engine GXScene https://github.com/glscene
  3. //
  4. unit GXS.FileTGA;
  5. (*
  6. Simple TGA formats supports for Delphi.
  7. Currently supports only 24 and 32 bits RGB formats (uncompressed
  8. and RLE compressed).
  9. *)
  10. interface
  11. {$I Stage.Defines.inc}
  12. uses
  13. System.Classes,
  14. System.SysUtils,
  15. FMX.Graphics,
  16. FMX.Types,
  17. GXS.Graphics;
  18. type
  19. (* TGA image load/save capable class for Delphi.
  20. TGA formats supported : 24 and 32 bits uncompressed or RLE compressed,
  21. saves only to uncompressed TGA. *)
  22. TTGAImage = class(TBitmap)
  23. public
  24. constructor Create; override;
  25. destructor Destroy; override;
  26. procedure LoadFromStream(stream: TStream); // in VCL override;
  27. procedure SaveToStream(stream: TStream); // in VCL override;
  28. end;
  29. ETGAException = class(Exception)
  30. end;
  31. // ------------------------------------------------------------------
  32. implementation
  33. // ------------------------------------------------------------------
  34. type
  35. TTGAHeader = packed record
  36. IDLength: Byte;
  37. ColorMapType: Byte;
  38. ImageType: Byte;
  39. ColorMapOrigin: Word;
  40. ColorMapLength: Word;
  41. ColorMapEntrySize: Byte;
  42. XOrigin: Word;
  43. YOrigin: Word;
  44. Width: Word;
  45. Height: Word;
  46. PixelSize: Byte;
  47. ImageDescriptor: Byte;
  48. end;
  49. procedure ReadAndUnPackRLETGA24(stream: TStream; destBuf: PAnsiChar;
  50. totalSize: Integer);
  51. type
  52. TRGB24 = packed record
  53. r, g, b: Byte;
  54. end;
  55. PRGB24 = ^TRGB24;
  56. var
  57. n: Integer;
  58. color: TRGB24;
  59. bufEnd: PAnsiChar;
  60. b: Byte;
  61. begin
  62. bufEnd := @destBuf[totalSize];
  63. while destBuf < bufEnd do
  64. begin
  65. stream.Read(b, 1);
  66. if b >= 128 then
  67. begin
  68. // repetition packet
  69. stream.Read(color, 3);
  70. b := (b and 127) + 1;
  71. while b > 0 do
  72. begin
  73. PRGB24(destBuf)^ := color;
  74. Inc(destBuf, 3);
  75. Dec(b);
  76. end;
  77. end
  78. else
  79. begin
  80. n := ((b and 127) + 1) * 3;
  81. stream.Read(destBuf^, n);
  82. Inc(destBuf, n);
  83. end;
  84. end;
  85. end;
  86. procedure ReadAndUnPackRLETGA32(stream: TStream; destBuf: PAnsiChar;
  87. totalSize: Integer);
  88. type
  89. TRGB32 = packed record
  90. r, g, b, a: Byte;
  91. end;
  92. PRGB32 = ^TRGB32;
  93. var
  94. n: Integer;
  95. color: TRGB32;
  96. bufEnd: PAnsiChar;
  97. b: Byte;
  98. begin
  99. bufEnd := @destBuf[totalSize];
  100. while destBuf < bufEnd do
  101. begin
  102. stream.Read(b, 1);
  103. if b >= 128 then
  104. begin
  105. // repetition packet
  106. stream.Read(color, 4);
  107. b := (b and 127) + 1;
  108. while b > 0 do
  109. begin
  110. PRGB32(destBuf)^ := color;
  111. Inc(destBuf, 4);
  112. Dec(b);
  113. end;
  114. end
  115. else
  116. begin
  117. n := ((b and 127) + 1) * 4;
  118. stream.Read(destBuf^, n);
  119. Inc(destBuf, n);
  120. end;
  121. end;
  122. end;
  123. // ------------------
  124. // ------------------ TTGAImage ------------------
  125. // ------------------
  126. constructor TTGAImage.Create;
  127. begin
  128. inherited Create;
  129. end;
  130. destructor TTGAImage.Destroy;
  131. begin
  132. inherited Destroy;
  133. end;
  134. procedure TTGAImage.LoadFromStream(stream: TStream);
  135. var
  136. header: TTGAHeader;
  137. y, rowSize, bufSize: Integer;
  138. verticalFlip: Boolean;
  139. unpackBuf: PAnsiChar;
  140. function GetLineAddress(ALine: Integer): PByte;
  141. begin
  142. { TODO : E2003 Undeclared identifier: 'ScanLine' }
  143. (* Result := PByte(ScanLine[ALine]); *)
  144. end;
  145. begin
  146. stream.Read(header, Sizeof(TTGAHeader));
  147. if header.ColorMapType <> 0 then
  148. raise ETGAException.Create('ColorMapped TGA unsupported');
  149. { TODO : E2129 Cannot assign to a read-only property }
  150. (*
  151. case header.PixelSize of
  152. 24 : PixelFormat:=TPixelFormat.RGBA; //in VCL glpf24bit;
  153. 32 : PixelFormat:=TPixelFormat.RGBA32F; //in VCL glpf32bit;
  154. else
  155. raise ETGAException.Create('Unsupported TGA ImageType');
  156. end;
  157. *)
  158. Width := header.Width;
  159. Height := header.Height;
  160. rowSize := (Width * header.PixelSize) div 8;
  161. verticalFlip := ((header.ImageDescriptor and $20) = 0);
  162. if header.IDLength > 0 then
  163. stream.Seek(header.IDLength, soFromCurrent);
  164. try
  165. case header.ImageType of
  166. 0:
  167. begin // empty image, support is useless but easy ;)
  168. Width := 0;
  169. Height := 0;
  170. Abort;
  171. end;
  172. 2:
  173. begin // uncompressed RGB/RGBA
  174. if verticalFlip then
  175. begin
  176. for y := 0 to Height - 1 do
  177. stream.Read(GetLineAddress(Height - y - 1)^, rowSize);
  178. end
  179. else
  180. begin
  181. for y := 0 to Height - 1 do
  182. stream.Read(GetLineAddress(y)^, rowSize);
  183. end;
  184. end;
  185. 10:
  186. begin // RLE encoded RGB/RGBA
  187. bufSize := Height * rowSize;
  188. unpackBuf := GetMemory(bufSize);
  189. try
  190. // read & unpack everything
  191. if header.PixelSize = 24 then
  192. ReadAndUnPackRLETGA24(stream, unpackBuf, bufSize)
  193. else
  194. ReadAndUnPackRLETGA32(stream, unpackBuf, bufSize);
  195. // fillup bitmap
  196. if verticalFlip then
  197. begin
  198. for y := 0 to Height - 1 do
  199. begin
  200. Move(unpackBuf[y * rowSize], GetLineAddress(Height - y - 1)
  201. ^, rowSize);
  202. end;
  203. end
  204. else
  205. begin
  206. for y := 0 to Height - 1 do
  207. Move(unpackBuf[y * rowSize], GetLineAddress(y)^, rowSize);
  208. end;
  209. finally
  210. FreeMemory(unpackBuf);
  211. end;
  212. end;
  213. else
  214. raise ETGAException.Create('Unsupported TGA ImageType ' +
  215. IntToStr(header.ImageType));
  216. end;
  217. finally
  218. //
  219. end;
  220. end;
  221. procedure TTGAImage.SaveToStream(stream: TStream);
  222. var
  223. y, rowSize: Integer;
  224. header: TTGAHeader;
  225. begin
  226. // prepare the header, essentially made up from zeroes
  227. FillChar(header, Sizeof(TTGAHeader), 0);
  228. header.ImageType := 2;
  229. header.Width := Width;
  230. header.Height := Height;
  231. case PixelFormat of
  232. TPixelFormat.RGBA32F:
  233. header.PixelSize := 32;
  234. else
  235. raise ETGAException.Create('Unsupported Bitmap format');
  236. end;
  237. stream.Write(header, Sizeof(TTGAHeader));
  238. rowSize := (Width * header.PixelSize) div 8;
  239. for y := 0 to Height - 1 do
  240. { TODO : E2003 Undeclared identifier: 'ScanLine' }
  241. (* stream.Write(ScanLine[Height-y-1]^, rowSize); *)
  242. end;
  243. // ------------------------------------------------------------------
  244. initialization
  245. // ------------------------------------------------------------------
  246. { TODO : E2003 Undeclared identifier: 'RegisterFileFormat' }
  247. (* TPicture.RegisterFileFormat('tga', 'Targa', TTGAImage); *)
  248. // ? RegisterRasterFormat('tga', 'Targa', TTGAImage);
  249. finalization
  250. { TODO : E2003 Undeclared identifier: 'UNregisterFileFormat' }
  251. (* TPicture.UnregisterGraphicClass(TTGAImage); *)
  252. end.