pixtools.pp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  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. Pixel drawing routines.
  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. {$mode objfpc}{$h+}
  14. unit PixTools;
  15. interface
  16. uses classes, FPCanvas, FPimage;
  17. procedure DrawSolidLine (Canv : TFPCustomCanvas; x1,y1, x2,y2:integer; const color:TFPColor);
  18. procedure DrawPatternLine (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; Pattern:TPenPattern; const color:TFPColor);
  19. procedure FillRectangleColor (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const color:TFPColor);
  20. procedure FillRectanglePattern (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const pattern:TBrushPattern; const color:TFPColor);
  21. procedure FillRectangleHashHorizontal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  22. procedure FillRectangleHashVertical (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  23. procedure FillRectangleHashDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  24. procedure FillRectangleHashBackDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  25. procedure DrawSolidLine (Canv : TFPCustomCanvas; x1,y1, x2,y2:integer);
  26. procedure DrawPatternLine (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; Pattern:TPenPattern);
  27. procedure FillRectanglePattern (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const pattern:TBrushPattern);
  28. procedure FillRectangleColor (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer);
  29. procedure FillRectangleHashHorizontal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  30. procedure FillRectangleHashVertical (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  31. procedure FillRectangleHashDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  32. procedure FillRectangleHashBackDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  33. procedure FillRectangleImage (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const Image:TFPCustomImage);
  34. procedure FillRectangleImageRel (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const Image:TFPCustomImage);
  35. implementation
  36. uses clipping;
  37. procedure FillRectangleColor (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer);
  38. begin
  39. FillRectangleColor (Canv, x1,y1, x2,y2, canv.brush.color);
  40. end;
  41. procedure FillRectangleColor (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const color:TFPColor);
  42. var x,y : integer;
  43. begin
  44. SortRect (x1,y1, x2,y2);
  45. with Canv do
  46. begin
  47. for x := x1 to x2 do
  48. for y := y1 to y2 do
  49. colors[x,y] := color;
  50. end;
  51. end;
  52. {procedure DrawSolidPolyLine (Canv : TFPCustomCanvas; points:array of TPoint; close:boolean);
  53. var i,a, r : integer;
  54. p : TPoint;
  55. begin
  56. i := low(points);
  57. a := high(points);
  58. p := points[i];
  59. with Canv do
  60. begin
  61. for r := i+1 to a do
  62. begin
  63. Line (p.x, p.y, points[r].x, points[r].y);
  64. p := points[r];
  65. end;
  66. if close then
  67. Line (p.x,p.y, points[i].x,points[i].y);
  68. end;
  69. end;
  70. }
  71. type
  72. TPutPixelProc = procedure (Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
  73. procedure PutPixelCopy(Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
  74. begin
  75. with Canv do
  76. Colors[x,y] := color;
  77. end;
  78. procedure PutPixelXor(Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
  79. begin
  80. with Canv do
  81. Colors[x,y] := Colors[x,y] xor color;
  82. end;
  83. procedure PutPixelOr(Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
  84. begin
  85. with Canv do
  86. Colors[x,y] := Colors[x,y] or color;
  87. end;
  88. procedure PutPixelAnd(Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
  89. begin
  90. with Canv do
  91. Colors[x,y] := Colors[x,y] and color;
  92. end;
  93. procedure DrawSolidLine (Canv : TFPCustomCanvas; x1,y1, x2,y2:integer);
  94. begin
  95. DrawSolidLine (Canv, x1,y1, x2,y2, Canv.pen.color);
  96. end;
  97. procedure DrawSolidLine (Canv : TFPCustomCanvas; x1,y1, x2,y2:integer; const color:TFPColor);
  98. var PutPixelProc : TPutPixelProc;
  99. procedure HorizontalLine (x1,x2,y:integer);
  100. var x : integer;
  101. begin
  102. for x := x1 to x2 do
  103. PutPixelProc (Canv, x,y, color);
  104. end;
  105. procedure VerticalLine (x,y1,y2:integer);
  106. var y : integer;
  107. begin
  108. for y := y1 to y2 do
  109. PutPixelProc (Canv, x,y, color);
  110. end;
  111. procedure SlopedLine;
  112. var npixels,xinc1,yinc1,xinc2,yinc2,dx,dy,d,dinc1,dinc2 : integer;
  113. procedure initialize;
  114. begin // precalculations
  115. dx := abs(x2-x1);
  116. dy := abs(y2-y1);
  117. if dx > dy then // determining independent variable
  118. begin // x is independent
  119. npixels := dx + 1;
  120. d := (2 * dy) - dx;
  121. dinc1 := dy * 2;
  122. dinc2:= (dy - dx) * 2;
  123. xinc1 := 1;
  124. xinc2 := 1;
  125. yinc1 := 0;
  126. yinc2 := 1;
  127. end
  128. else
  129. begin // y is independent
  130. npixels := dy + 1;
  131. d := (2 * dx) - dy;
  132. dinc1 := dx * 2;
  133. dinc2:= (dx - dy) * 2;
  134. xinc1 := 0;
  135. xinc2 := 1;
  136. yinc1 := 1;
  137. yinc2 := 1;
  138. end;
  139. // going into the correct direction
  140. if x1 > x2 then
  141. begin
  142. xinc1 := - xinc1;
  143. xinc2 := - xinc2;
  144. end;
  145. if y1 > y2 then
  146. begin
  147. yinc1 := - yinc1;
  148. yinc2 := - yinc2;
  149. end;
  150. end;
  151. var r,x,y : integer;
  152. begin
  153. initialize;
  154. x := x1;
  155. y := y1;
  156. for r := 1 to nPixels do
  157. begin
  158. PutPixelProc (Canv, x,y, color);
  159. if d < 0 then
  160. begin
  161. d := d + dinc1;
  162. x := x + xinc1;
  163. y := y + yinc1;
  164. end
  165. else
  166. begin
  167. d := d + dinc2;
  168. x := x + xinc2;
  169. y := y + yinc2;
  170. end;
  171. end;
  172. end;
  173. begin
  174. with canv.pen do
  175. case mode of
  176. pmAnd : PutPixelProc := @PutPixelAnd;
  177. pmOr : PutPixelProc := @PutPixelOr;
  178. pmXor : PutPixelProc := @PutPixelXor;
  179. else PutPixelProc := @PutPixelCopy;
  180. end;
  181. if x1 = x2 then // vertical line
  182. if y1 < y2 then
  183. VerticalLine (x1, y1, y2)
  184. else
  185. VerticalLine (x1, y2, y1)
  186. else if y1 = y2 then
  187. if x1 < x2 then
  188. HorizontalLine (x1, x2, y1)
  189. else
  190. HorizontalLine (x2, x1, y1)
  191. else // sloped line
  192. SlopedLine;
  193. end;
  194. type
  195. TLinePoints = array[0..PatternBitCount] of boolean;
  196. PLinePoints = ^TLinePoints;
  197. procedure PatternToPoints (const APattern:TPenPattern; LinePoints:PLinePoints);
  198. var r : integer;
  199. i : longword;
  200. begin
  201. i := 1;
  202. for r := PatternBitCount-1 downto 1 do
  203. begin
  204. LinePoints^[r] := (APattern and i) <> 0;
  205. i := i shl 1;
  206. end;
  207. LinePoints^[0] := (APattern and i) <> 0;
  208. end;
  209. procedure DrawPatternLine (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; Pattern:TPenPattern);
  210. begin
  211. DrawPatternLine (Canv, x1,y1, x2,y2, pattern, canv.pen.color);
  212. end;
  213. procedure DrawPatternLine (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; Pattern:TPenPattern; const color:TFPColor);
  214. // Is copy of DrawSolidLine with paterns added. Not the same procedure for faster solid lines
  215. var LinePoints : TLinePoints;
  216. PutPixelProc : TPutPixelProc;
  217. procedure HorizontalLine (x1,x2,y:integer);
  218. var x : integer;
  219. begin
  220. for x := x1 to x2 do
  221. if LinePoints[x mod PatternBitCount] then
  222. PutPixelProc (Canv, x,y, color);
  223. end;
  224. procedure VerticalLine (x,y1,y2:integer);
  225. var y : integer;
  226. begin
  227. for y := y1 to y2 do
  228. if LinePoints[y mod PatternBitCount] then
  229. PutPixelProc (Canv, x,y, color);
  230. end;
  231. procedure SlopedLine;
  232. var npixels,xinc1,yinc1,xinc2,yinc2,dx,dy,d,dinc1,dinc2 : integer;
  233. procedure initialize;
  234. begin // precalculations
  235. dx := abs(x2-x1);
  236. dy := abs(y2-y1);
  237. if dx > dy then // determining independent variable
  238. begin // x is independent
  239. npixels := dx + 1;
  240. d := (2 * dy) - dx;
  241. dinc1 := dy * 2;
  242. dinc2:= (dy - dx) * 2;
  243. xinc1 := 1;
  244. xinc2 := 1;
  245. yinc1 := 0;
  246. yinc2 := 1;
  247. end
  248. else
  249. begin // y is independent
  250. npixels := dy + 1;
  251. d := (2 * dx) - dy;
  252. dinc1 := dx * 2;
  253. dinc2:= (dx - dy) * 2;
  254. xinc1 := 0;
  255. xinc2 := 1;
  256. yinc1 := 1;
  257. yinc2 := 1;
  258. end;
  259. // going into the correct direction
  260. if x1 > x2 then
  261. begin
  262. xinc1 := - xinc1;
  263. xinc2 := - xinc2;
  264. end;
  265. if y1 > y2 then
  266. begin
  267. yinc1 := - yinc1;
  268. yinc2 := - yinc2;
  269. end;
  270. end;
  271. var r,x,y : integer;
  272. begin
  273. initialize;
  274. x := x1;
  275. y := y1;
  276. for r := 1 to nPixels do
  277. begin
  278. if LinePoints[r mod PatternBitCount] then
  279. PutPixelProc (Canv, x,y, color);
  280. if d < 0 then
  281. begin
  282. d := d + dinc1;
  283. x := x + xinc1;
  284. y := y + yinc1;
  285. end
  286. else
  287. begin
  288. d := d + dinc2;
  289. x := x + xinc2;
  290. y := y + yinc2;
  291. end;
  292. end;
  293. end;
  294. var r : integer;
  295. begin
  296. PatternToPoints (pattern, @LinePoints);
  297. with canv.pen do
  298. case mode of
  299. pmAnd : PutPixelProc := @PutPixelAnd;
  300. pmOr : PutPixelProc := @PutPixelOr;
  301. pmXor : PutPixelProc := @PutPixelXor;
  302. else PutPixelProc := @PutPixelCopy;
  303. end;
  304. if x1 = x2 then // vertical line
  305. if y1 < y2 then
  306. VerticalLine (x1, y1, y2)
  307. else
  308. VerticalLine (x1, y2, y1)
  309. else if y1 = y2 then
  310. if x1 < x2 then
  311. HorizontalLine (x1, x2, y1)
  312. else
  313. HorizontalLine (x2, x1, y1)
  314. else // sloped line
  315. SlopedLine;
  316. end;
  317. procedure FillRectangleHashHorizontal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  318. begin
  319. FillRectangleHashHorizontal (Canv, rect, width, canv.brush.color);
  320. end;
  321. procedure FillRectangleHashHorizontal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  322. var y : integer;
  323. begin
  324. with rect do
  325. begin
  326. y := Width + top;
  327. while y <= bottom do
  328. begin
  329. DrawSolidLine (Canv, left,y, right,y, c);
  330. inc (y,Width);
  331. end
  332. end;
  333. end;
  334. procedure FillRectangleHashVertical (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  335. begin
  336. FillRectangleHashVertical (Canv, rect, width, canv.brush.color);
  337. end;
  338. procedure FillRectangleHashVertical (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  339. var x : integer;
  340. begin
  341. with rect do
  342. begin
  343. x := Width + left;
  344. while x <= right do
  345. begin
  346. DrawSolidLine (Canv, x,top, x,bottom, c);
  347. inc (x, Width);
  348. end;
  349. end;
  350. end;
  351. procedure FillRectangleHashDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  352. begin
  353. FillRectangleHashDiagonal (Canv, rect, width, canv.brush.color);
  354. end;
  355. procedure FillRectangleHashDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  356. function CheckCorner (Current, max, start : integer) : integer;
  357. begin
  358. if Current > max then
  359. result := Start + current - max
  360. else
  361. result := Start;
  362. end;
  363. var r, rx, ry : integer;
  364. begin
  365. with rect do
  366. begin
  367. // draw from bottom-left corner away
  368. ry := top + Width;
  369. rx := left + Width;
  370. while (rx < right) and (ry < bottom) do
  371. begin
  372. DrawSolidLine (Canv, left,ry, rx,top, c);
  373. inc (rx, Width);
  374. inc (ry, Width);
  375. end;
  376. // check which turn need to be taken: left-bottom, right-top, or both
  377. if (rx >= right) then
  378. begin
  379. if (ry >= bottom) then
  380. begin // Both corners reached
  381. r := CheckCorner (rx, right, top);
  382. rx := CheckCorner (ry, bottom, left);
  383. ry := r;
  384. end
  385. else
  386. begin // fill vertical
  387. r := CheckCorner (rx, right, top);
  388. while (ry < bottom) do
  389. begin
  390. DrawSolidLine (Canv, left,ry, right,r, c);
  391. inc (r, Width);
  392. inc (ry, Width);
  393. end;
  394. rx := CheckCorner (ry, bottom, left);
  395. ry := r;
  396. end
  397. end
  398. else
  399. if (ry >= bottom) then
  400. begin // fill horizontal
  401. r := checkCorner (ry, bottom, left);
  402. while (rx <= right) do
  403. begin
  404. DrawSolidLine (Canv, r,bottom, rx,top, c);
  405. inc (r, Width);
  406. inc (rx, Width);
  407. end;
  408. ry := CheckCorner (rx, right, top);
  409. rx := r;
  410. end;
  411. while (rx < right) do // fill lower right corner
  412. begin
  413. DrawSolidLine (Canv, rx,bottom, right,ry, c);
  414. inc (rx, Width);
  415. inc (ry, Width);
  416. end;
  417. end;
  418. end;
  419. procedure FillRectangleHashBackDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  420. begin
  421. FillRectangleHashBackDiagonal (Canv, rect, width, canv.brush.color);
  422. end;
  423. procedure FillRectangleHashBackDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  424. function CheckInversCorner (Current, min, start : integer) : integer;
  425. begin
  426. if Current < min then
  427. result := Start - current + min
  428. else
  429. result := Start;
  430. end;
  431. function CheckCorner (Current, max, start : integer) : integer;
  432. begin
  433. if Current > max then
  434. result := Start - current + max
  435. else
  436. result := Start;
  437. end;
  438. var r, rx, ry : integer;
  439. begin
  440. with rect do
  441. begin
  442. // draw from bottom-left corner away
  443. ry := bottom - Width;
  444. rx := left + Width;
  445. while (rx < right) and (ry > top) do
  446. begin
  447. DrawSolidLine (Canv, left,ry, rx,bottom, c);
  448. inc (rx, Width);
  449. dec (ry, Width);
  450. end;
  451. // check which turn need to be taken: left-top, right-bottom, or both
  452. if (rx >= right) then
  453. begin
  454. if (ry <= top) then
  455. begin // Both corners reached
  456. r := CheckCorner (rx, right, bottom);
  457. rx := CheckInversCorner (ry, top, left);
  458. ry := r;
  459. end
  460. else
  461. begin // fill vertical
  462. r := CheckCorner (rx, right, bottom);
  463. while (ry > top) do
  464. begin
  465. DrawSolidLine (Canv, left,ry, right,r, c);
  466. dec (r, Width);
  467. dec (ry, Width);
  468. end;
  469. rx := CheckInversCorner (ry, top, left);
  470. ry := r;
  471. end
  472. end
  473. else
  474. if (ry <= top) then
  475. begin // fill horizontal
  476. r := checkInversCorner (ry, top, left);
  477. while (rx < right) do
  478. begin
  479. DrawSolidLine (Canv, r,top, rx,bottom, c);
  480. inc (r, Width);
  481. inc (rx, Width);
  482. end;
  483. ry := CheckCorner (rx, right, bottom);
  484. rx := r;
  485. end;
  486. while (rx < right) do // fill upper right corner
  487. begin
  488. DrawSolidLine (Canv, rx,top, right,ry, c);
  489. inc (rx, Width);
  490. dec (ry, Width);
  491. end;
  492. end;
  493. end;
  494. procedure FillRectanglePattern (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const pattern:TBrushPattern);
  495. begin
  496. FillRectanglePattern (Canv, x1,y1, x2,y2, pattern, canv.brush.color);
  497. end;
  498. procedure FillRectanglePattern (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const pattern:TBrushPattern; const color:TFPColor);
  499. var r : integer;
  500. begin
  501. for r := y1 to y2 do
  502. DrawPatternLine (Canv, x1,r, x2,r, pattern[r mod PatternBitCount], color);
  503. end;
  504. procedure FillRectangleImage (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const Image:TFPCustomImage);
  505. var x,y : integer;
  506. begin
  507. with image do
  508. for x := x1 to x2 do
  509. for y := y1 to y2 do
  510. Canv.colors[x,y] := colors[x mod width, y mod height];
  511. end;
  512. procedure FillRectangleImageRel (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const Image:TFPCustomImage);
  513. var x,y : integer;
  514. begin
  515. with image do
  516. for x := x1 to x2 do
  517. for y := y1 to y2 do
  518. Canv.colors[x,y] := colors[(x-x1) mod width, (y-y1) mod height];
  519. end;
  520. end.