fpreadxwd.pas 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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 reader 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. { 08/2005 by Giulio Bernardi:
  14. - Added support for 16 and 15 bpp bitmaps.
  15. - If we have bpp <= 8 make an indexed image instead of converting it to RGB
  16. - Support for RLE4 and RLE8 decoding
  17. - Support for top-down bitmaps
  18. }
  19. {$mode objfpc}
  20. {$h+}
  21. unit FPReadXWD;
  22. interface
  23. uses FPImage, classes, sysutils, xwdfile;
  24. type
  25. TXWDColors = array of TXWDColor;
  26. { TFPReaderXWD }
  27. TFPReaderXWD = class (TFPCustomImageReader)
  28. private
  29. continue: boolean; // needed for onprogress event
  30. percent: byte;
  31. percentinterval : longword;
  32. percentacc : longword;
  33. Rect : TRect;
  34. procedure SwapXWDFileHeader(var Header: TXWDFileHeader);
  35. procedure SwapXWDColor(var Color: TXWDColor);
  36. procedure WriteScanLine(Row: Integer; Img: TFPCustomImage);
  37. protected
  38. XWDFileHeader: TXWDFileHeader; // The header, as read from the file
  39. WindowName: array of Char;
  40. XWDColors: TXWDColors;
  41. LineBuf: PByte; // Buffer for 1 line
  42. // required by TFPCustomImageReader
  43. procedure InternalRead (Stream:TStream; Img:TFPCustomImage); override;
  44. function InternalCheck (Stream:TStream) : boolean; override;
  45. public
  46. constructor Create; override;
  47. destructor Destroy; override;
  48. end;
  49. implementation
  50. //==============================================================================
  51. // Endian utils
  52. //
  53. // Copied from LCLProc unit
  54. //==============================================================================
  55. {$push}{$R-}
  56. function BEtoN(const AValue: DWord): DWord;
  57. begin
  58. {$IFDEF ENDIAN_BIG}
  59. Result := AValue;
  60. {$ELSE}
  61. Result := (AValue shl 24)
  62. or ((AValue and $0000FF00) shl 8)
  63. or ((AValue and $00FF0000) shr 8)
  64. or (AValue shr 24);
  65. {$ENDIF}
  66. end;
  67. {$pop}
  68. constructor TFPReaderXWD.create;
  69. begin
  70. inherited create;
  71. end;
  72. destructor TFPReaderXWD.Destroy;
  73. begin
  74. If (LineBuf<>Nil) then
  75. begin
  76. FreeMem(LineBuf);
  77. LineBuf:=Nil;
  78. end;
  79. SetLength(WindowName, 0);
  80. SetLength(XWDColors, 0);
  81. inherited destroy;
  82. end;
  83. procedure TFPReaderXWD.SwapXWDColor(var Color: TXWDColor);
  84. begin
  85. Color.pixel := BEtoN(Color.pixel);
  86. Color.red := swap(Color.red);
  87. Color.green := swap(Color.green);
  88. Color.blue := swap(Color.blue);
  89. end;
  90. procedure TFPReaderXWD.SwapXWDFileHeader(var Header: TXWDFileHeader);
  91. begin
  92. Header.header_size := BEtoN(Header.header_size);
  93. Header.file_version := BEtoN(Header.file_version);
  94. Header.pixmap_format := BEtoN(Header.pixmap_format);
  95. Header.pixmap_depth := BEtoN(Header.pixmap_depth);
  96. Header.pixmap_width := BEtoN(Header.pixmap_width);
  97. Header.pixmap_height := BEtoN(Header.pixmap_height);
  98. Header.xoffset := BEtoN(Header.xoffset);
  99. Header.byte_order := BEtoN(Header.byte_order);
  100. Header.bitmap_unit := BEtoN(Header.bitmap_unit);
  101. Header.bitmap_unit := BEtoN(Header.bitmap_bit_order);
  102. Header.bitmap_pad := BEtoN(Header.bitmap_pad);
  103. Header.bits_per_pixel := BEtoN(Header.bits_per_pixel);
  104. Header.bytes_per_line := BEtoN(Header.bytes_per_line);
  105. Header.visual_class := BEtoN(Header.visual_class);
  106. Header.red_mask := BEtoN(Header.red_mask);
  107. Header.green_mask := BEtoN(Header.green_mask);
  108. Header.blue_mask := BEtoN(Header.blue_mask);
  109. Header.bits_per_rgb := BEtoN(Header.bits_per_rgb);
  110. Header.colormap_entries := BEtoN(Header.colormap_entries);
  111. Header.ncolors := BEtoN(Header.ncolors);
  112. Header.window_width := BEtoN(Header.window_width);
  113. Header.window_height := BEtoN(Header.window_height);
  114. Header.window_x := BEtoN(Header.window_x);
  115. Header.window_y := BEtoN(Header.window_y);
  116. Header.window_bdrwidth := BEtoN(Header.window_bdrwidth);
  117. end;
  118. procedure TFPReaderXWD.WriteScanLine(Row : Integer; Img : TFPCustomImage);
  119. var
  120. Column: Integer;
  121. buffer: Cardinal;
  122. MyColor: TFPColor;
  123. begin
  124. MyColor.alpha := 0;
  125. case XWDFileHeader.bits_per_pixel of
  126. 1 :
  127. for Column:=0 to Img.Width-1 do
  128. if ((LineBuf[Column div 8] shr (7-(Column and 7)) ) and 1) <> 0 then
  129. img.Pixels[Column,Row]:=1
  130. else
  131. img.Pixels[Column,Row]:=0;
  132. 4 :
  133. for Column:=0 to img.Width-1 do
  134. img.Pixels[Column,Row]:=(LineBuf[Column div 2] shr (((Column+1) and 1)*4)) and $0f;
  135. 8 :
  136. for Column:=0 to img.Width-1 do
  137. img.Pixels[Column,Row]:=LineBuf[Column];
  138. 16 :
  139. for Column:=0 to img.Width-1 do
  140. img.Pixels[Column,Row]:=LineBuf[Column];
  141. 24 :
  142. for Column:=0 to img.Width-1 do
  143. img.Pixels[Column,Row]:=LineBuf[Column];
  144. 32 :
  145. for Column:=0 to img.Width-1 do
  146. begin
  147. Move(LineBuf[Column * 4], buffer, 4);
  148. // WriteLn(IntToHex(buffer, 8));
  149. { buffer := buffer mod (256 * 256 * 256);
  150. MyColor.red := Word((buffer div 256 * 256) * 256);
  151. buffer := buffer mod (256 * 256);
  152. MyColor.green := Word((buffer div 256) * 256);
  153. buffer := buffer mod 256;
  154. MyColor.blue := Word((buffer) * 256);}
  155. buffer := buffer mod (256 * 256 * 256);
  156. MyColor.blue := Word((buffer div 256 * 256) * 256);
  157. buffer := buffer mod (256 * 256);
  158. MyColor.green := Word((buffer div 256) * 256);
  159. buffer := buffer mod 256;
  160. MyColor.red := Word((buffer) * 256);
  161. img.Colors[Column,Row] := MyColor;
  162. end;
  163. end;
  164. { inc(percentacc,4);
  165. if percentacc>=percentinterval then
  166. begin
  167. percent:=percent+(percentacc div percentinterval);
  168. percentacc:=percentacc mod percentinterval;
  169. Progress(psRunning,percent,false,Rect,'',continue);
  170. end;}
  171. end;
  172. procedure TFPReaderXWD.InternalRead(Stream: TStream; Img: TFPCustomImage);
  173. var
  174. Color: TFPColor;
  175. Size, Row, i, Index: Integer;
  176. begin
  177. {****************************************************************************
  178. Initialization
  179. ****************************************************************************}
  180. Rect.Left:=0; Rect.Top:=0; Rect.Right:=0; Rect.Bottom:=0;
  181. continue:=true;
  182. Progress(psStarting,0,false,Rect,'',continue);
  183. if not continue then exit;
  184. Img.UsePalette := True;
  185. // Img.Palette.Clear;
  186. Color.alpha := 0;
  187. {****************************************************************************
  188. The file is on big-endian format, so it needs to be swaped on little-endian CPUs
  189. ****************************************************************************}
  190. Stream.Position := 0; //* Causes error if removed, but should be
  191. Stream.Read(XWDFileHeader, SizeOf(TXWDFileHeader));
  192. {$ifdef ENDIAN_LITTLE}
  193. SwapXWDFileHeader(XWDFileHeader);
  194. {$endif}
  195. {****************************************************************************
  196. Now reads the window name
  197. ****************************************************************************}
  198. Size := XWDFileHeader.header_size - SizeOf(TXWDFileHeader);
  199. // Avoids allocating too much space for the string
  200. if Size > 256 then raise Exception.Create('Window name string too big. The file might be corrupted.');
  201. SetLength(WindowName, Size);
  202. Stream.Read(WindowName[0], Size);
  203. {****************************************************************************
  204. Fills the palette
  205. ****************************************************************************}
  206. SetLength(XWDColors, XWDFileHeader.ncolors);
  207. Img.Palette.Count := 256;
  208. for i := 1 to XWDFileHeader.ncolors do
  209. begin
  210. Stream.Read(XWDColors[i - 1], SizeOf(TXWDColor));
  211. {$ifdef ENDIAN_LITTLE}
  212. SwapXWDColor(XWDColors[i - 1]);
  213. {$endif}
  214. Color.red := XWDColors[i - 1].red;
  215. Color.green := XWDColors[i - 1].green;
  216. Color.blue := XWDColors[i - 1].blue;
  217. Index := XWDColors[i - 1].pixel mod 256;
  218. // WriteLn(IntToHex(Index, 8));
  219. Img.Palette.Color[Index] := Color;
  220. end;
  221. {****************************************************************************
  222. Reads the matrix of colors
  223. ****************************************************************************}
  224. Img.SetSize(XWDFileHeader.pixmap_width, XWDFileHeader.pixmap_height);
  225. GetMem(LineBuf, XWDFileHeader.bytes_per_line);
  226. for Row := 0 to Img.Height - 1 do
  227. begin
  228. Stream.Read(LineBuf[0], XWDFileHeader.bytes_per_line);
  229. WriteScanLine(Row, Img);
  230. if not continue then exit;
  231. end;
  232. Progress(psEnding,100,false,Rect,'',continue);
  233. end;
  234. function TFPReaderXWD.InternalCheck (Stream:TStream): boolean;
  235. var
  236. Header: TXWDFileHeader;
  237. begin
  238. stream.Read(Header, SizeOf(Header));
  239. {$IFDEF ENDIAN_LITTLE}
  240. SwapXWDFileHeader(Header);
  241. {$ENDIF}
  242. Result := Header.file_version = XWD_FILE_VERSION; // Just check magic number
  243. end;
  244. initialization
  245. ImageHandlers.RegisterImageReader ('XWD Format', 'xwd', TFPReaderXWD);
  246. end.