fpreadxpm.pp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2003 by the Free Pascal development team
  5. XPM reader class.
  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. {$mode objfpc}{$h+}
  13. unit FPReadXPM;
  14. interface
  15. uses FPImage, classes, sysutils;
  16. type
  17. TFPReaderXPM = class (TFPCustomImageReader)
  18. private
  19. width, height, ncols, cpp, xhot, yhot : integer;
  20. xpmext : boolean;
  21. palette : TStringList;
  22. function HexToColor(s : string) : TFPColor;
  23. function NameToColor(s : string) : TFPColor;
  24. function DiminishWhiteSpace (s : string) : string;
  25. protected
  26. procedure InternalRead (Str:TStream; Img:TFPCustomImage); override;
  27. function InternalCheck (Str:TStream) : boolean; override;
  28. public
  29. constructor Create; override;
  30. destructor Destroy; override;
  31. end;
  32. implementation
  33. const
  34. WhiteSpace = ' '#8#10#13;
  35. constructor TFPReaderXPM.create;
  36. begin
  37. inherited create;
  38. palette := TStringList.Create;
  39. end;
  40. destructor TFPReaderXPM.Destroy;
  41. begin
  42. Palette.Free;
  43. inherited destroy;
  44. end;
  45. function TFPReaderXPM.HexToColor(s : string) : TFPColor;
  46. var l : integer;
  47. function CharConv (c : char) : longword;
  48. begin
  49. if (c >= 'A') and (c <= 'F') then
  50. result := ord (c) - ord('A') + 10
  51. else if (c >= '0') and (c <= '9') then
  52. result := ord (c) - ord('0')
  53. else
  54. raise exception.CreateFmt ('Wrong character (%s) in hexadecimal number', [c]);
  55. end;
  56. function convert (n : string) : word;
  57. var t,r: integer;
  58. begin
  59. result := 0;
  60. t := length(n);
  61. if t > 4 then
  62. raise exception.CreateFmt ('Too many bytes for color (%s)',[s]);
  63. for r := 1 to length(n) do
  64. result := (result shl 4) or CharConv(n[r]);
  65. // fill missing bits
  66. case t of
  67. 1: result:=result or (result shl 4) or (result shl 8) or (result shl 12);
  68. 2: result:=result or (result shl 8);
  69. 3: result:=result or (result shl 12);
  70. end;
  71. end;
  72. begin
  73. s := uppercase (s);
  74. l := length(s) div 3;
  75. result.red := (Convert(copy(s,1,l)));
  76. result.green := (Convert(copy(s,l+1,l)));
  77. result.blue := Convert(copy(s,l+l+1,l));
  78. result.alpha := AlphaOpaque;
  79. end;
  80. function TFPReaderXPM.NameToColor(s : string) : TFPColor;
  81. begin
  82. s := lowercase (s);
  83. if s = 'transparent' then
  84. result := colTransparent
  85. else if s = 'none' then
  86. result := colTransparent
  87. else if s = 'black' then
  88. result := colBlack
  89. else if s = 'blue' then
  90. result := colBlue
  91. else if s = 'green' then
  92. result := colGreen
  93. else if s = 'cyan' then
  94. result := colCyan
  95. else if s = 'red' then
  96. result := colRed
  97. else if s = 'magenta' then
  98. result := colMagenta
  99. else if s = 'yellow' then
  100. result := colYellow
  101. else if s = 'white' then
  102. result := colWhite
  103. else if s = 'gray' then
  104. result := colGray
  105. else if s = 'ltgray' then
  106. result := colLtGray
  107. else if s = 'dkblue' then
  108. result := colDkBlue
  109. else if s = 'dkgreen' then
  110. result := colDkGreen
  111. else if s = 'dkcyan' then
  112. result := colDkCyan
  113. else if s = 'dkred' then
  114. result := colDkRed
  115. else if s = 'dkmagenta' then
  116. result := colDkMagenta
  117. else if s = 'dkyellow' then
  118. result := colDkYellow
  119. else if s = 'maroon' then
  120. result := colMaroon
  121. else if s = 'ltgreen' then
  122. result := colLtGreen
  123. else if s = 'olive' then
  124. result := colOlive
  125. else if s = 'navy' then
  126. result := colNavy
  127. else if s = 'purple' then
  128. result := colPurple
  129. else if s = 'teal' then
  130. result := colTeal
  131. else if s = 'silver' then
  132. result := colSilver
  133. else if s = 'lime' then
  134. result := colLime
  135. else if s = 'fuchsia' then
  136. result := colFuchsia
  137. else if s = 'aqua' then
  138. result := colAqua
  139. else
  140. result := colTransparent;
  141. end;
  142. function TFPReaderXPM.DiminishWhiteSpace (s : string) : string;
  143. var r : integer;
  144. Doit : boolean;
  145. begin
  146. Doit := true;
  147. result := '';
  148. for r := 1 to length(s) do
  149. if pos(s[r],WhiteSpace)>0 then
  150. begin
  151. if DoIt then
  152. result := result + ' ';
  153. DoIt := false;
  154. end
  155. else
  156. begin
  157. DoIt := True;
  158. result := result + s[r];
  159. end;
  160. end;
  161. procedure TFPReaderXPM.InternalRead (Str:TStream; Img:TFPCustomImage);
  162. var l : TStringList;
  163. procedure TakeInteger (var s : string; var i : integer);
  164. var r : integer;
  165. begin
  166. r := pos (' ', s);
  167. if r = 0 then
  168. begin
  169. i := StrToInt(s);
  170. s := '';
  171. end
  172. else
  173. begin
  174. i := StrToInt(copy(s,1,r-1));
  175. delete (s, 1, r);
  176. end;
  177. end;
  178. procedure ParseFirstLine;
  179. var s : string;
  180. begin
  181. s := l[0];
  182. // diminish all whitespace to 1 blank
  183. s := DiminishWhiteSpace (trim(s));
  184. Takeinteger (s, width);
  185. Takeinteger (s, height);
  186. Takeinteger (s, ncols);
  187. Takeinteger (s, cpp);
  188. if s <> '' then
  189. begin
  190. Takeinteger (s, xhot);
  191. Takeinteger (s, yhot);
  192. xpmext := (comparetext(s, 'XPMEXT') = 0);
  193. if (s <> '') and not xpmext then
  194. Raise Exception.Create ('Wrong word for XPMEXT tag');
  195. end;
  196. end;
  197. procedure AddPalette (const code:string;const Acolor:TFPColor);
  198. var r : integer;
  199. begin
  200. r := Palette.Add(code);
  201. img.palette.Color[r] := Acolor;
  202. end;
  203. procedure AddToPalette(s : string);
  204. var code : string;
  205. c : TFPColor;
  206. p : integer;
  207. begin
  208. code := copy(s,1,cpp);
  209. s := trim(diminishWhiteSpace (copy(s,cpp+1,maxint)));
  210. // Search for c-key in the color values
  211. if s[1] = 'c' then
  212. delete (s, 1, 2)
  213. else
  214. begin
  215. p := pos (' c ',s);
  216. if p = 0 then
  217. s := ''
  218. else
  219. delete (s, 1, p+2);
  220. end;
  221. // c color value is first word, remove the rest of the line
  222. p := pos(' ', s);
  223. if p > 0 then
  224. delete (s, p, maxint);
  225. // check if exists
  226. if s = '' then
  227. raise exception.Create ('Only c-key is used for colors');
  228. // convert #hexadecimal value to integer and place in palette
  229. if s[1] = '#' then
  230. c := HexToColor(copy(s,2,maxint))
  231. else
  232. c := NameToColor(s);
  233. AddPalette(code,c);
  234. end;
  235. procedure ReadPalette;
  236. var r : integer;
  237. begin
  238. Palette.Clear;
  239. Img.Palette.Count := ncols;
  240. for r := 1 to ncols do
  241. AddToPalette (l[r]);
  242. end;
  243. procedure ReadLine (const s : string; imgindex : integer);
  244. var color, r, p : integer;
  245. code : string;
  246. begin
  247. p := 1;
  248. for r := 1 to width do
  249. begin
  250. code := copy(s, p, cpp);
  251. inc(p,cpp);
  252. for color := 0 to Palette.Count-1 do
  253. { Can't use indexof, as compare must be case sensitive }
  254. if code = Palette[color] then begin
  255. img.pixels[r-1,imgindex] := color;
  256. Break;
  257. end;
  258. end;
  259. end;
  260. procedure ReadData;
  261. var r : integer;
  262. begin
  263. for r := 1 to height do
  264. ReadLine (l[ncols+r], r-1);
  265. end;
  266. var p, r : integer;
  267. begin
  268. l := TStringList.Create;
  269. try
  270. l.LoadFromStream (Str);
  271. for r := l.count-1 downto 0 do
  272. begin
  273. p := pos ('"', l[r]);
  274. if p > 0 then
  275. l[r] := copy(l[r], p+1, lastdelimiter('"',l[r])-p-1)
  276. else
  277. l.delete(r);
  278. end;
  279. ParseFirstLine;
  280. Img.SetSize (width, height);
  281. ReadPalette;
  282. ReadData;
  283. finally
  284. l.Free;
  285. end;
  286. end;
  287. function TFPReaderXPM.InternalCheck (Str:TStream) : boolean;
  288. var s : string[9];
  289. l : integer;
  290. begin
  291. try
  292. l := str.Read (s[1],9);
  293. s[0] := char(l);
  294. if l <> 9 then
  295. result := False
  296. else
  297. result := (s = '/* XPM */');
  298. except
  299. result := false;
  300. end;
  301. end;
  302. initialization
  303. ImageHandlers.RegisterImageReader ('XPM Format', 'xpm', TFPReaderXPM);
  304. end.