fpreadtga.pp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. {*****************************************************************************}
  2. {
  3. This file is part of the Free Pascal's "Free Components Library".
  4. Copyright (c) 2003 by Mazen NEIFER of the Free Pascal development team
  5. BMP writer implementation.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. }
  12. {*****************************************************************************}
  13. {$mode objfpc}
  14. {$h+}
  15. unit FPReadTGA;
  16. interface
  17. uses FPImage, classes, sysutils, targacmn;
  18. type
  19. TFPReaderTarga = class (TFPCustomImageReader)
  20. Private
  21. Procedure FreeBuffers; // Free (and nil) buffers.
  22. protected
  23. Header : TTargaHeader;
  24. Identification : ShortString;
  25. Compressed,
  26. BottomUp : Boolean;
  27. BytesPerPixel : Byte;
  28. FPalette : PFPColor;
  29. FScanLine : PByte;
  30. FLineSize : Integer;
  31. FPaletteSize : Integer;
  32. FBlockCount : Integer;
  33. FPixelCount : Integer;
  34. FLastPixel : Packed Array[0..3] of byte;
  35. // AnalyzeHeader will allocate the needed buffers.
  36. Procedure AnalyzeHeader(Img : TFPCustomImage);
  37. Procedure ReadPalette(Stream : TStream);
  38. procedure ReadScanLine(Row : Integer; Stream : TStream); virtual;
  39. procedure WriteScanLine(Row : Integer; Img : TFPCustomImage); virtual;
  40. // required by TFPCustomImageReader
  41. procedure InternalRead (Stream:TStream; Img:TFPCustomImage); override;
  42. function InternalCheck (Stream:TStream) : boolean; override;
  43. public
  44. constructor Create; override;
  45. destructor Destroy; override;
  46. end;
  47. Implementation
  48. Constructor TFPReaderTarga.Create;
  49. begin
  50. end;
  51. Destructor TFPReaderTarga.Destroy;
  52. begin
  53. FreeBuffers;
  54. Inherited;
  55. end;
  56. Procedure TFPReaderTarga.FreeBuffers;
  57. begin
  58. If (FScanLine<>Nil) then
  59. begin
  60. FreeMem(FScanLine);
  61. FScanLine:=Nil;
  62. end;
  63. If (FPalette<>Nil) then
  64. begin
  65. FreeMem(FPalette);
  66. FScanLine:=Nil;
  67. end;
  68. end;
  69. Procedure TFPReaderTarga.AnalyzeHeader(Img : TFPCustomImage);
  70. begin
  71. With Header do
  72. begin
  73. If (Flags shl 6)<>0 then
  74. Raise Exception.Create('Interlaced targa images not supported.');
  75. If MapType>1 then
  76. Raise Exception.CreateFmt('Unknown targa colormap type: %d',[MapType]);
  77. if (PixelSize and 7)<>0 then
  78. Raise Exception.Create('Pixelsize must be multiple of 8');
  79. BottomUp:=(Flags and $20) <>0;
  80. BytesPerPixel:=PixelSize shr 3;
  81. Compressed:=ImgType>8;
  82. If Compressed then
  83. ImgType:=ImgType-8;
  84. Case ImgType of
  85. 1: if (BytesPerPixel<>1) or (MapType<>1) then
  86. Raise Exception.Create('Error in targa header: Colormapped image needs 1 byte per pixel and maptype 1');
  87. 2: If not (BytesPerPixel in [2..4]) then
  88. Raise Exception.Create('Error in targa header: RGB image needs bytes per pixel between 2 and 4');
  89. 3: begin
  90. if BytesPerPixel<>1 then
  91. Raise Exception.Create('Error in targa header: Grayscale image needs 1 byte per pixel.');
  92. end;
  93. else
  94. Raise Exception.CreateFmt('Unknown/Unsupported Targa image type : %d',[ImgType]);
  95. end;
  96. if (ToWord(MapLength)>0) and (MapEntrySize<>24) then
  97. Raise Exception.CreateFmt('Only targa BGR colormaps are supported. Got : %d',[MapEntrySize]);
  98. if (ToWord(MapLength)>0) and (MapType<>0) then
  99. Raise Exception.Create('Empty colormap in Targa image file');
  100. FLineSize:=BytesPerPixel*ToWord(Width);
  101. GetMem(FScanLine,FLineSize);
  102. FPaletteSize:=SizeOf(TFPColor)*ToWord(MapLength);
  103. GetMem(FPalette,FPaletteSize);
  104. Img.Width:=ToWord(Width);
  105. Img.Height:=ToWord(Height);
  106. end;
  107. end;
  108. Procedure TFPReaderTarga.ReadPalette(Stream : TStream);
  109. Var
  110. Entry : TBGREntry;
  111. I : Integer;
  112. begin
  113. For I:=0 to ToWord(Header.MapLength)-1 do
  114. begin
  115. Stream.ReadBuffer(Entry,SizeOf(Entry));
  116. With FPalette[i] do
  117. begin
  118. Red:=Entry.Red;
  119. Green:=Entry.Green;
  120. Blue:=Entry.Blue;
  121. Alpha:=AlphaOpaque;
  122. end;
  123. end;
  124. end;
  125. Procedure TFPReaderTarga.InternalRead (Stream:TStream; Img:TFPCustomImage);
  126. var
  127. H,Row : Integer;
  128. begin
  129. Stream.Read(Header,SizeOf(Header));
  130. AnalyzeHeader(Img);
  131. If Header.IdLen>0 then
  132. begin
  133. SetLength(Identification,Header.IDLen);
  134. Stream.Read(Identification[1],Header.Idlen);
  135. If Length(Identification)<>0 then
  136. Img.Extra[KeyIdentification]:=Identification;
  137. end;
  138. If Toword(Header.MapLength)>0 then
  139. ReadPalette(Stream);
  140. H:=Img.height;
  141. If BottomUp then
  142. For Row:=0 to H-1 do
  143. begin
  144. ReadScanLine(Row,Stream);
  145. WriteScanLine(Row,Img);
  146. end
  147. else
  148. For Row:=H-1 downto 0 do
  149. begin
  150. ReadScanLine(Row,Stream);
  151. WriteScanLine(Row,Img);
  152. end;
  153. end;
  154. Procedure TFPReaderTarga.ReadScanLine(Row : Integer; Stream : TStream);
  155. Var
  156. P : PByte;
  157. B : Byte;
  158. I,J : Integer;
  159. begin
  160. If Not Compressed then
  161. Stream.ReadBuffer(FScanLine^,FLineSize)
  162. else
  163. begin
  164. P:=FScanLine;
  165. For I:=0 to ToWord(Header.Width)-1 do
  166. begin
  167. If (FPixelCount>0) then
  168. Dec(FPixelCount)
  169. else
  170. begin
  171. Dec(FBlockCount);
  172. If (FBlockCount<0) then
  173. begin
  174. Stream.ReadBuffer(B,1);
  175. If (B and $80)<>0 then
  176. begin
  177. FPixelCount:=B and $7F;
  178. FblockCount:=0;
  179. end
  180. else
  181. FBlockCount:=B and $7F
  182. end;
  183. Stream.ReadBuffer(FlastPixel,BytesPerPixel);
  184. end;
  185. For J:=0 to BytesPerPixel-1 do
  186. begin
  187. P[0]:=FLastPixel[j];
  188. Inc(P);
  189. end;
  190. end;
  191. end;
  192. end;
  193. const
  194. c5to8bits : array[0..32-1] of Byte =
  195. ( 0, 8, 16, 25, 33, 41, 49, 58,
  196. 66, 74, 82, 90, 99, 107, 115, 123,
  197. 132, 140, 148, 156, 165, 173, 181, 189,
  198. 197, 206, 214, 222, 230, 239, 247, 255);
  199. Procedure TFPReaderTarga.WriteScanLine(Row : Integer; Img : TFPCustomImage);
  200. Var
  201. Col : Integer;
  202. B : Byte;
  203. C : TFPColor;
  204. W : Word;
  205. P : PByte;
  206. begin
  207. C.Alpha:=AlphaOpaque;
  208. P:=FScanLine;
  209. Case Header.ImgType of
  210. 1 : for Col:=0 to Img.width-1 do
  211. Img.Colors[Col,Row]:=FPalette[P[Col]];
  212. 2 : for Col:=0 to Img.Width-1 do
  213. begin
  214. // Fill C depending on number of pixels.
  215. case BytesPerPixel of
  216. 2 : begin
  217. W:=P[0];
  218. inc(P);
  219. W:=W or (P[0] shl 8);
  220. With C do
  221. begin
  222. Blue:=c5to8bits[W and $1F];
  223. W:=W shr 5;
  224. Green:=c5to8bits[W and $1F];
  225. W:=W shr 5;
  226. Red:=c5to8bits[W and $1F];
  227. end;
  228. end;
  229. 3,4 : With C do
  230. begin
  231. Blue:=P[0] or (P[0] shl 8);
  232. Inc(P);
  233. Green:=P[0] or (P[0] shl 8);
  234. Inc(P);
  235. Red:=P[0] or (P[0] shl 8);
  236. If bytesPerPixel=4 then
  237. begin
  238. Inc(P);
  239. // Alpha:=P[0] or (P[0] shl 8); what is TARGA Attribute ??
  240. end;
  241. end;
  242. end; // Case BytesPerPixel;
  243. Img[Col,Row]:=C;
  244. Inc(P);
  245. end;
  246. 3 : For Col:=0 to Img.Width-1 do
  247. begin
  248. B:=FScanLine[Col];
  249. B:=B+(B Shl 8);
  250. With C do
  251. begin
  252. Red:=B;
  253. Green:=B;
  254. Blue:=B;
  255. end;
  256. Img.Colors[Col,Row]:=C;
  257. end;
  258. end;
  259. end;
  260. function TFPReaderTarga.InternalCheck (Stream:TStream) : boolean;
  261. begin
  262. Result:=True;
  263. end;
  264. initialization
  265. ImageHandlers.RegisterImageReader ('TARGA Format', 'tga', TFPReaderTarga);
  266. end.