Fills.cs 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162
  1. using System;
  2. using System.Drawing;
  3. using System.Drawing.Drawing2D;
  4. using System.ComponentModel;
  5. using FastReport.Utils;
  6. using System.Drawing.Design;
  7. using System.IO;
  8. using System.Drawing.Imaging;
  9. namespace FastReport
  10. {
  11. /// <summary>
  12. /// Base class for all fills.
  13. /// </summary>
  14. [TypeConverter(typeof(FastReport.TypeConverters.FillConverter))]
  15. public abstract class FillBase
  16. {
  17. internal string Name
  18. {
  19. get { return GetType().Name.Replace("Fill", ""); }
  20. }
  21. /// <summary>
  22. /// Returned true if Color = Transparent
  23. /// </summary>
  24. public abstract bool IsTransparent
  25. {
  26. get;
  27. }
  28. internal bool FloatDiff(float f1, float f2)
  29. {
  30. return Math.Abs(f1 - f2) > 1e-4;
  31. }
  32. /// <summary>
  33. /// Creates exact copy of this fill.
  34. /// </summary>
  35. /// <returns>Copy of this object.</returns>
  36. public abstract FillBase Clone();
  37. /// <summary>
  38. /// Creates the GDI+ Brush object.
  39. /// </summary>
  40. /// <param name="rect">Drawing rectangle.</param>
  41. /// <returns>Brush object.</returns>
  42. public abstract Brush CreateBrush(RectangleF rect);
  43. /// <summary>
  44. /// Creates the GDI+ Brush object with scaling.
  45. /// </summary>
  46. /// <param name="rect">Drawing rectangle.</param>
  47. /// <param name="scaleX">X scaling coefficient.</param>
  48. /// <param name="scaleY">Y scaling coefficient.</param>
  49. /// <returns>Brush object.</returns>
  50. public virtual Brush CreateBrush(RectangleF rect, float scaleX, float scaleY)
  51. {
  52. return CreateBrush(rect);
  53. }
  54. /// <summary>
  55. /// Serializes the fill.
  56. /// </summary>
  57. /// <param name="writer">Writer object.</param>
  58. /// <param name="prefix">Name of the fill property.</param>
  59. /// <param name="fill">Fill object to compare with.</param>
  60. /// <remarks>
  61. /// This method is for internal use only.
  62. /// </remarks>
  63. public virtual void Serialize(FRWriter writer, string prefix, FillBase fill)
  64. {
  65. if (fill.GetType() != GetType())
  66. writer.WriteStr(prefix, Name);
  67. }
  68. public virtual void Deserialize(FRReader reader, string prefix)
  69. {
  70. }
  71. public virtual void FinalizeComponent()
  72. {
  73. }
  74. public virtual void InitializeComponent()
  75. {
  76. }
  77. /// <summary>
  78. /// Fills the specified rectangle.
  79. /// </summary>
  80. /// <param name="e">Draw event arguments.</param>
  81. /// <param name="rect">Drawing rectangle.</param>
  82. public virtual void Draw(FRPaintEventArgs e, RectangleF rect)
  83. {
  84. rect = new RectangleF(rect.Left * e.ScaleX, rect.Top * e.ScaleY, rect.Width * e.ScaleX, rect.Height * e.ScaleY);
  85. using (Brush brush = CreateBrush(rect, e.ScaleX, e.ScaleY))
  86. {
  87. e.Graphics.FillRectangle(brush, rect.Left, rect.Top, rect.Width, rect.Height);
  88. }
  89. }
  90. }
  91. /// <summary>
  92. /// Class represents the solid fill.
  93. /// </summary>
  94. public class SolidFill : FillBase
  95. {
  96. private Color color;
  97. /// <summary>
  98. /// Gets or sets the fill color.
  99. /// </summary>
  100. [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]
  101. public Color Color
  102. {
  103. get { return color; }
  104. set { color = value; }
  105. }
  106. public override bool IsTransparent
  107. {
  108. get { return color.A == 0; }
  109. }
  110. /// <inheritdoc/>
  111. public override FillBase Clone()
  112. {
  113. return new SolidFill(Color);
  114. }
  115. /// <inheritdoc/>
  116. public override int GetHashCode()
  117. {
  118. return Color.GetHashCode();
  119. }
  120. /// <inheritdoc/>
  121. public override bool Equals(object obj)
  122. {
  123. SolidFill f = obj as SolidFill;
  124. return f != null && Color == f.Color;
  125. }
  126. /// <inheritdoc/>
  127. public override Brush CreateBrush(RectangleF rect)
  128. {
  129. return new SolidBrush(Color);
  130. }
  131. /// <inheritdoc/>
  132. public override void Serialize(FRWriter writer, string prefix, FillBase fill)
  133. {
  134. base.Serialize(writer, prefix, fill);
  135. SolidFill c = fill as SolidFill;
  136. if (c == null || c.Color != Color)
  137. writer.WriteValue(prefix + ".Color", Color);
  138. }
  139. /// <inheritdoc/>
  140. public override void Draw(FRPaintEventArgs e, RectangleF rect)
  141. {
  142. if (Color == Color.Transparent)
  143. return;
  144. Brush brush = e.Cache.GetBrush(Color);
  145. e.Graphics.FillRectangle(brush, rect.Left * e.ScaleX, rect.Top * e.ScaleY, rect.Width * e.ScaleX, rect.Height * e.ScaleY);
  146. }
  147. /// <summary>
  148. /// Initializes the <see cref="SolidFill"/> class with Transparent color.
  149. /// </summary>
  150. public SolidFill() : this(Color.Transparent)
  151. {
  152. }
  153. /// <summary>
  154. /// Initializes the <see cref="SolidFill"/> class with specified color.
  155. /// </summary>
  156. /// <param name="color"></param>
  157. public SolidFill(Color color)
  158. {
  159. Color = color;
  160. }
  161. }
  162. /// <summary>
  163. /// Class represents the linear gradient fill.
  164. /// </summary>
  165. public class LinearGradientFill : FillBase
  166. {
  167. private Color startColor;
  168. private Color endColor;
  169. private int angle;
  170. private float focus;
  171. private float contrast;
  172. /// <summary>
  173. /// Gets or sets the start color of the gradient.
  174. /// </summary>
  175. [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]
  176. public Color StartColor
  177. {
  178. get { return startColor; }
  179. set { startColor = value; }
  180. }
  181. /// <summary>
  182. /// Gets or sets the end color of the gradient.
  183. /// </summary>
  184. [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]
  185. public Color EndColor
  186. {
  187. get { return endColor; }
  188. set { endColor = value; }
  189. }
  190. public override bool IsTransparent
  191. {
  192. get { return startColor.A == 0 && endColor.A == 0; }
  193. }
  194. /// <summary>
  195. /// Gets or sets the angle of the gradient.
  196. /// </summary>
  197. [Editor("FastReport.TypeEditors.AngleEditor, FastReport", typeof(UITypeEditor))]
  198. public int Angle
  199. {
  200. get { return angle; }
  201. set { angle = value % 360; }
  202. }
  203. /// <summary>
  204. /// Gets or sets the focus point of the gradient.
  205. /// </summary>
  206. /// <remarks>
  207. /// Value is a floating point value from 0 to 1.
  208. /// </remarks>
  209. public float Focus
  210. {
  211. get { return focus; }
  212. set
  213. {
  214. if (value < 0)
  215. value = 0;
  216. if (value > 1)
  217. value = 1;
  218. focus = value;
  219. }
  220. }
  221. /// <summary>
  222. /// Gets or sets the gradient contrast.
  223. /// </summary>
  224. /// <remarks>
  225. /// Value is a floating point value from 0 to 1.
  226. /// </remarks>
  227. public float Contrast
  228. {
  229. get { return contrast; }
  230. set
  231. {
  232. if (value < 0)
  233. value = 0;
  234. if (value > 1)
  235. value = 1;
  236. contrast = value;
  237. }
  238. }
  239. /// <inheritdoc/>
  240. public override FillBase Clone()
  241. {
  242. return new LinearGradientFill(StartColor, EndColor, Angle, Focus, Contrast);
  243. }
  244. /// <inheritdoc/>
  245. public override int GetHashCode()
  246. {
  247. return StartColor.GetHashCode() ^ (EndColor.GetHashCode() << 1) ^
  248. ((Angle.GetHashCode() + 1) << 2) ^ ((Focus.GetHashCode() + 1) << 10) ^ ((Contrast.GetHashCode() + 1) << 20);
  249. }
  250. /// <inheritdoc/>
  251. public override bool Equals(object obj)
  252. {
  253. LinearGradientFill f = obj as LinearGradientFill;
  254. return f != null && StartColor == f.StartColor && EndColor == f.EndColor && Angle == f.Angle &&
  255. !FloatDiff(Focus, f.Focus) && !FloatDiff(Contrast, f.Contrast);
  256. }
  257. /// <inheritdoc/>
  258. public override Brush CreateBrush(RectangleF rect)
  259. {
  260. // workaround the gradient bug
  261. rect.Inflate(1, 1);
  262. LinearGradientBrush result = new LinearGradientBrush(rect, StartColor, EndColor, Angle);
  263. result.SetSigmaBellShape(Focus, Contrast);
  264. return result;
  265. }
  266. /// <inheritdoc/>
  267. public override void Serialize(FRWriter writer, string prefix, FillBase fill)
  268. {
  269. base.Serialize(writer, prefix, fill);
  270. LinearGradientFill c = fill as LinearGradientFill;
  271. if (c == null || c.StartColor != StartColor)
  272. writer.WriteValue(prefix + ".StartColor", StartColor);
  273. if (c == null || c.EndColor != EndColor)
  274. writer.WriteValue(prefix + ".EndColor", EndColor);
  275. if (c == null || c.Angle != Angle)
  276. writer.WriteInt(prefix + ".Angle", Angle);
  277. if (c == null || FloatDiff(c.Focus, Focus))
  278. writer.WriteFloat(prefix + ".Focus", Focus);
  279. if (c == null || FloatDiff(c.Contrast, Contrast))
  280. writer.WriteFloat(prefix + ".Contrast", Contrast);
  281. }
  282. /// <summary>
  283. /// Initializes the <see cref="LinearGradientFill"/> class with default settings.
  284. /// </summary>
  285. public LinearGradientFill() : this(Color.Black, Color.White, 0, 100, 100)
  286. {
  287. }
  288. /// <summary>
  289. /// Initializes the <see cref="LinearGradientFill"/> class with start and end colors.
  290. /// </summary>
  291. /// <param name="startColor">Start color.</param>
  292. /// <param name="endColor">End color.</param>
  293. public LinearGradientFill(Color startColor, Color endColor) : this(startColor, endColor, 0)
  294. {
  295. }
  296. /// <summary>
  297. /// Initializes the <see cref="LinearGradientFill"/> class with start, end colors and angle.
  298. /// </summary>
  299. /// <param name="startColor">Start color.</param>
  300. /// <param name="endColor">End color.</param>
  301. /// <param name="angle">Angle.</param>
  302. public LinearGradientFill(Color startColor, Color endColor, int angle) : this(startColor, endColor, angle, 0, 100)
  303. {
  304. }
  305. /// <summary>
  306. /// Initializes the <see cref="LinearGradientFill"/> class with start and end colors, angle, focus and contrast.
  307. /// </summary>
  308. /// <param name="startColor">Start color.</param>
  309. /// <param name="endColor">End color.</param>
  310. /// <param name="angle">Angle.</param>
  311. /// <param name="focus">Focus.</param>
  312. /// <param name="contrast">Contrast.</param>
  313. public LinearGradientFill(Color startColor, Color endColor, int angle, float focus, float contrast)
  314. {
  315. StartColor = startColor;
  316. EndColor = endColor;
  317. Angle = angle;
  318. Focus = focus;
  319. Contrast = contrast;
  320. }
  321. }
  322. /// <summary>
  323. /// The style of the path gradient.
  324. /// </summary>
  325. public enum PathGradientStyle
  326. {
  327. /// <summary>
  328. /// Elliptic gradient.
  329. /// </summary>
  330. Elliptic,
  331. /// <summary>
  332. /// Rectangular gradient.
  333. /// </summary>
  334. Rectangular
  335. }
  336. /// <summary>
  337. /// Class represents the path gradient fill.
  338. /// </summary>
  339. public class PathGradientFill : FillBase
  340. {
  341. private Color centerColor;
  342. private Color edgeColor;
  343. private PathGradientStyle style;
  344. /// <summary>
  345. /// Gets or sets the center color of the gradient.
  346. /// </summary>
  347. [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]
  348. public Color CenterColor
  349. {
  350. get { return centerColor; }
  351. set { centerColor = value; }
  352. }
  353. /// <summary>
  354. /// Gets or sets the edge color of the gradient.
  355. /// </summary>
  356. [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]
  357. public Color EdgeColor
  358. {
  359. get { return edgeColor; }
  360. set { edgeColor = value; }
  361. }
  362. /// <summary>
  363. /// Gets or sets the style of the gradient.
  364. /// </summary>
  365. public PathGradientStyle Style
  366. {
  367. get { return style; }
  368. set { style = value; }
  369. }
  370. public override bool IsTransparent
  371. {
  372. get { return centerColor.A == 0 && edgeColor.A == 0; }
  373. }
  374. /// <inheritdoc/>
  375. public override FillBase Clone()
  376. {
  377. return new PathGradientFill(CenterColor, EdgeColor, Style);
  378. }
  379. /// <inheritdoc/>
  380. public override int GetHashCode()
  381. {
  382. return CenterColor.GetHashCode() ^ (EdgeColor.GetHashCode() << 1) ^ ((Style.GetHashCode() + 1) << 2);
  383. }
  384. /// <inheritdoc/>
  385. public override bool Equals(object obj)
  386. {
  387. PathGradientFill f = obj as PathGradientFill;
  388. return f != null && CenterColor == f.CenterColor && EdgeColor == f.EdgeColor && Style == f.Style;
  389. }
  390. /// <inheritdoc/>
  391. public override Brush CreateBrush(RectangleF rect)
  392. {
  393. GraphicsPath path = new GraphicsPath();
  394. if (Style == PathGradientStyle.Rectangular)
  395. path.AddRectangle(rect);
  396. else
  397. {
  398. float radius = (float)Math.Sqrt(rect.Width * rect.Width + rect.Height * rect.Height) / 2 + 1;
  399. PointF center = new PointF(rect.Left + rect.Width / 2 - 1, rect.Top + rect.Height / 2 - 1);
  400. RectangleF r = new RectangleF(center.X - radius, center.Y - radius, radius * 2, radius * 2);
  401. path.AddEllipse(r);
  402. }
  403. PathGradientBrush result = new PathGradientBrush(path);
  404. path.Dispose();
  405. result.CenterColor = CenterColor;
  406. result.SurroundColors = new Color[] { EdgeColor };
  407. return result;
  408. }
  409. /// <inheritdoc/>
  410. public override void Serialize(FRWriter writer, string prefix, FillBase fill)
  411. {
  412. base.Serialize(writer, prefix, fill);
  413. PathGradientFill c = fill as PathGradientFill;
  414. if (c == null || c.CenterColor != CenterColor)
  415. writer.WriteValue(prefix + ".CenterColor", CenterColor);
  416. if (c == null || c.EdgeColor != EdgeColor)
  417. writer.WriteValue(prefix + ".EdgeColor", EdgeColor);
  418. if (c == null || c.Style != Style)
  419. writer.WriteValue(prefix + ".Style", Style);
  420. }
  421. /// <summary>
  422. /// Initializes the <see cref="PathGradientFill"/> class with default settings.
  423. /// </summary>
  424. public PathGradientFill() : this(Color.Black, Color.White, PathGradientStyle.Elliptic)
  425. {
  426. }
  427. /// <summary>
  428. /// Initializes the <see cref="PathGradientFill"/> class with center, edge colors and style.
  429. /// </summary>
  430. /// <param name="centerColor">Center color.</param>
  431. /// <param name="edgeColor">Edge color.</param>
  432. /// <param name="style">Gradient style.</param>
  433. public PathGradientFill(Color centerColor, Color edgeColor, PathGradientStyle style)
  434. {
  435. CenterColor = centerColor;
  436. EdgeColor = edgeColor;
  437. Style = style;
  438. }
  439. }
  440. /// <summary>
  441. /// Class represents the hatch fill.
  442. /// </summary>
  443. public class HatchFill : FillBase
  444. {
  445. private Color foreColor;
  446. private Color backColor;
  447. private HatchStyle style;
  448. /// <summary>
  449. /// Gets or sets the foreground color.
  450. /// </summary>
  451. [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]
  452. public Color ForeColor
  453. {
  454. get { return foreColor; }
  455. set { foreColor = value; }
  456. }
  457. /// <summary>
  458. /// Gets or sets the background color.
  459. /// </summary>
  460. [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]
  461. public Color BackColor
  462. {
  463. get { return backColor; }
  464. set { backColor = value; }
  465. }
  466. /// <summary>
  467. /// Gets or sets the hatch style.
  468. /// </summary>
  469. public HatchStyle Style
  470. {
  471. get { return style; }
  472. set { style = value; }
  473. }
  474. public override bool IsTransparent
  475. {
  476. get { return foreColor.A == 0 && backColor.A == 0; }
  477. }
  478. /// <inheritdoc/>
  479. public override FillBase Clone()
  480. {
  481. return new HatchFill(ForeColor, BackColor, Style);
  482. }
  483. /// <inheritdoc/>
  484. public override int GetHashCode()
  485. {
  486. return ForeColor.GetHashCode() ^ (BackColor.GetHashCode() << 1) ^ ((Style.GetHashCode() + 1) << 2);
  487. }
  488. /// <inheritdoc/>
  489. public override bool Equals(object obj)
  490. {
  491. HatchFill f = obj as HatchFill;
  492. return f != null && ForeColor == f.ForeColor && BackColor == f.BackColor && Style == f.Style;
  493. }
  494. /// <inheritdoc/>
  495. public override Brush CreateBrush(RectangleF rect)
  496. {
  497. return new HatchBrush(Style, ForeColor, BackColor);
  498. }
  499. /// <inheritdoc/>
  500. public override void Serialize(FRWriter writer, string prefix, FillBase fill)
  501. {
  502. base.Serialize(writer, prefix, fill);
  503. HatchFill c = fill as HatchFill;
  504. if (c == null || c.ForeColor != ForeColor)
  505. writer.WriteValue(prefix + ".ForeColor", ForeColor);
  506. if (c == null || c.BackColor != BackColor)
  507. writer.WriteValue(prefix + ".BackColor", BackColor);
  508. if (c == null || c.Style != Style)
  509. writer.WriteValue(prefix + ".Style", Style);
  510. }
  511. /// <summary>
  512. /// Initializes the <see cref="HatchFill"/> class with default settings.
  513. /// </summary>
  514. public HatchFill() : this(Color.Black, Color.White, HatchStyle.BackwardDiagonal)
  515. {
  516. }
  517. /// <summary>
  518. /// Initializes the <see cref="HatchFill"/> class with foreground, background colors and hatch style.
  519. /// </summary>
  520. /// <param name="foreColor">Foreground color.</param>
  521. /// <param name="backColor">Background color.</param>
  522. /// <param name="style">Hatch style.</param>
  523. public HatchFill(Color foreColor, Color backColor, HatchStyle style)
  524. {
  525. ForeColor = foreColor;
  526. BackColor = backColor;
  527. Style = style;
  528. }
  529. }
  530. /// <summary>
  531. /// Class represents the glass fill.
  532. /// </summary>
  533. public class GlassFill : FillBase
  534. {
  535. private Color color;
  536. private float blend;
  537. private bool hatch;
  538. /// <summary>
  539. /// Gets or sets the fill color.
  540. /// </summary>
  541. [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]
  542. public Color Color
  543. {
  544. get { return color; }
  545. set { color = value; }
  546. }
  547. /// <summary>
  548. /// Gets or sets the blend value.
  549. /// </summary>
  550. /// <remarks>Value must be between 0 and 1.
  551. /// </remarks>
  552. [DefaultValue(0.2f)]
  553. public float Blend
  554. {
  555. get { return blend; }
  556. set { blend = value < 0 ? 0 : value > 1 ? 1 : value; }
  557. }
  558. /// <summary>
  559. /// Gets or sets a value determines whether to draw a hatch or not.
  560. /// </summary>
  561. [DefaultValue(true)]
  562. public bool Hatch
  563. {
  564. get { return hatch; }
  565. set { hatch = value; }
  566. }
  567. public override bool IsTransparent
  568. {
  569. get { return color.A == 0; }
  570. }
  571. /// <inheritdoc/>
  572. public override FillBase Clone()
  573. {
  574. return new GlassFill(Color, Blend, Hatch);
  575. }
  576. /// <inheritdoc/>
  577. public override int GetHashCode()
  578. {
  579. return Color.GetHashCode() ^ (Blend.GetHashCode() + 1) ^ ((Hatch.GetHashCode() + 1) << 2);
  580. }
  581. /// <inheritdoc/>
  582. public override bool Equals(object obj)
  583. {
  584. GlassFill f = obj as GlassFill;
  585. return f != null && Color == f.Color && Blend == f.Blend && Hatch == f.Hatch;
  586. }
  587. /// <inheritdoc/>
  588. public override void Draw(FRPaintEventArgs e, RectangleF rect)
  589. {
  590. rect = new RectangleF(rect.Left * e.ScaleX, rect.Top * e.ScaleY, rect.Width * e.ScaleX, rect.Height * e.ScaleY);
  591. // draw fill
  592. using (SolidBrush b = new SolidBrush(Color))
  593. {
  594. e.Graphics.FillRectangle(b, rect.Left, rect.Top, rect.Width, rect.Height);
  595. }
  596. // draw hatch
  597. if (Hatch)
  598. {
  599. using (HatchBrush b = new HatchBrush(HatchStyle.DarkUpwardDiagonal,
  600. Color.FromArgb(40, Color.White), Color.Transparent))
  601. {
  602. e.Graphics.FillRectangle(b, rect.Left, rect.Top, rect.Width, rect.Height);
  603. }
  604. }
  605. // draw blend
  606. using (SolidBrush b = new SolidBrush(Color.FromArgb((int)(Blend * 255), Color.White)))
  607. {
  608. e.Graphics.FillRectangle(b, rect.Left, rect.Top, rect.Width, rect.Height / 2);
  609. }
  610. }
  611. /// <inheritdoc/>
  612. public override Brush CreateBrush(RectangleF rect)
  613. {
  614. return new SolidBrush(Color);
  615. }
  616. /// <inheritdoc/>
  617. public override void Serialize(FRWriter writer, string prefix, FillBase fill)
  618. {
  619. base.Serialize(writer, prefix, fill);
  620. GlassFill c = fill as GlassFill;
  621. if (c == null || c.Color != Color)
  622. writer.WriteValue(prefix + ".Color", Color);
  623. if (c == null || c.Blend != Blend)
  624. writer.WriteFloat(prefix + ".Blend", Blend);
  625. if (c == null || c.Hatch != Hatch)
  626. writer.WriteBool(prefix + ".Hatch", Hatch);
  627. }
  628. /// <summary>
  629. /// Initializes the <see cref="GlassFill"/> class with default settings.
  630. /// </summary>
  631. public GlassFill() : this(Color.White, 0.2f, true)
  632. {
  633. }
  634. /// <summary>
  635. /// Initializes the <see cref="GlassFill"/> class with given color, blend ratio and hatch style.
  636. /// </summary>
  637. /// <param name="color">Color.</param>
  638. /// <param name="blend">Blend ratio (0..1).</param>
  639. /// <param name="hatch">Display the hatch.</param>
  640. public GlassFill(Color color, float blend, bool hatch)
  641. {
  642. Color = color;
  643. Blend = blend;
  644. Hatch = hatch;
  645. }
  646. }
  647. /// <summary>
  648. /// Class represents the Texture fill.
  649. /// </summary>
  650. public class TextureFill : FillBase
  651. {
  652. #region Fields
  653. private Image image;
  654. private int imageWidth;
  655. private int imageHeight;
  656. private bool preserveAspectRatio;
  657. private WrapMode wrapMode;
  658. private int imageIndex;
  659. private byte[] imageData;
  660. private int imageOffsetX;
  661. private int imageOffsetY;
  662. private static string dummyImageHash;
  663. #endregion // Fields
  664. #region Properties
  665. /// <summary>
  666. /// Gets or sets value, indicating that image should preserve aspect ratio
  667. /// </summary>
  668. public bool PreserveAspectRatio
  669. {
  670. get { return preserveAspectRatio; }
  671. set { preserveAspectRatio = value; }
  672. }
  673. /// <summary>
  674. /// Gets or sets the image width
  675. /// </summary>
  676. public int ImageWidth
  677. {
  678. get
  679. {
  680. if (imageWidth <= 0)
  681. ForceLoadImage();
  682. return imageWidth;
  683. }
  684. set
  685. {
  686. if (value != imageWidth && value > 0)
  687. {
  688. if (PreserveAspectRatio && imageHeight > 0 && imageWidth > 0)
  689. {
  690. imageHeight = (int)(imageHeight * (float)value / imageWidth);
  691. }
  692. imageWidth = value;
  693. ResizeImage(imageWidth, ImageHeight);
  694. }
  695. }
  696. }
  697. /// <summary>
  698. /// Gets or sets the image height
  699. /// </summary>
  700. public int ImageHeight
  701. {
  702. get
  703. {
  704. if (imageHeight <= 0)
  705. ForceLoadImage();
  706. return imageHeight;
  707. }
  708. set
  709. {
  710. if (value != imageHeight && value > 0)
  711. {
  712. if (PreserveAspectRatio && imageWidth > 0 && imageHeight > 0)
  713. {
  714. imageWidth = (int)(imageWidth * (float)value / imageHeight);
  715. }
  716. imageHeight = value;
  717. ResizeImage(imageWidth, ImageHeight);
  718. }
  719. }
  720. }
  721. /// <summary>
  722. /// Gets or sets the texture wrap mode
  723. /// </summary>
  724. public WrapMode WrapMode
  725. {
  726. get { return wrapMode; }
  727. set { wrapMode = value; }
  728. }
  729. /// <summary>
  730. /// Gets or sets the image index
  731. /// </summary>
  732. public int ImageIndex
  733. {
  734. get { return imageIndex; }
  735. set { imageIndex = value; }
  736. }
  737. /// <summary>
  738. /// Gets or sets the image data
  739. /// </summary>
  740. public byte[] ImageData
  741. {
  742. get { return imageData; }
  743. set
  744. {
  745. SetImageData(value);
  746. }
  747. }
  748. /// <summary>
  749. /// Image left offset
  750. /// </summary>
  751. public int ImageOffsetX
  752. {
  753. get { return imageOffsetX; }
  754. set { imageOffsetX = value; }
  755. }
  756. /// <summary>
  757. /// Image top offset
  758. /// </summary>
  759. public int ImageOffsetY
  760. {
  761. get { return imageOffsetY; }
  762. set { imageOffsetY = value; }
  763. }
  764. public override bool IsTransparent
  765. {
  766. get { return false; }
  767. }
  768. #endregion // Properties
  769. #region Private Methods
  770. private void Clear()
  771. {
  772. if (image != null)
  773. image.Dispose();
  774. image = null;
  775. imageData = null;
  776. }
  777. private void ResizeImage(int width, int height)
  778. {
  779. if (imageData == null || width <= 0 || height <= 0)
  780. return;
  781. else
  782. {
  783. image = ImageHelper.Load(imageData);
  784. image = new Bitmap(image, width, height);
  785. }
  786. }
  787. private void ResetImageIndex()
  788. {
  789. imageIndex = -1;
  790. }
  791. private void ForceLoadImage()
  792. {
  793. byte[] data = imageData;
  794. if (data == null)
  795. return;
  796. byte[] saveImageData = data;
  797. // imageData will be reset after this line, keep it
  798. image = ImageHelper.Load(data);
  799. if (imageWidth <= 0 && imageHeight <= 0)
  800. {
  801. imageWidth = image.Width;
  802. imageHeight = image.Height;
  803. }
  804. else if (imageWidth != image.Width || imageHeight != image.Height)
  805. {
  806. ResizeImage(imageWidth, imageHeight);
  807. }
  808. data = saveImageData;
  809. }
  810. #endregion // Private Methods
  811. #region Public Methods
  812. /// <summary>
  813. /// Sets image data to imageData
  814. /// </summary>
  815. /// <param name="data">input image data</param>
  816. public void SetImageData(byte[] data)
  817. {
  818. ResetImageIndex();
  819. image = null;
  820. imageData = data;
  821. ResizeImage(imageWidth, imageHeight);
  822. }
  823. /// <summary>
  824. /// Set image
  825. /// </summary>
  826. /// <param name="image">input image</param>
  827. public void SetImage(Image image)
  828. {
  829. using (MemoryStream ms = new MemoryStream())
  830. {
  831. image.Save(ms, image.RawFormat);
  832. SetImageData(ms.ToArray());
  833. }
  834. }
  835. /// <inheritdoc/>
  836. public override FillBase Clone()
  837. {
  838. TextureFill f = new TextureFill(imageData.Clone() as byte[], ImageWidth, ImageHeight, PreserveAspectRatio, WrapMode, ImageOffsetX, ImageOffsetY);
  839. //f.ImageIndex = ImageIndex;
  840. return f;
  841. }
  842. /// <inheritdoc/>
  843. public override int GetHashCode()
  844. {
  845. return ImageData.GetHashCode() ^ (ImageWidth.GetHashCode() << 1) ^
  846. ((ImageHeight.GetHashCode() + 1) << 2) ^
  847. ((PreserveAspectRatio.GetHashCode() + 1) << 10) ^
  848. ((WrapMode.GetHashCode() + 1) << 20) ^
  849. ((ImageOffsetX.GetHashCode() + 1) << 40) ^
  850. ((ImageOffsetY.GetHashCode() + 1) << 60);
  851. }
  852. /// <inheritdoc/>
  853. public override bool Equals(object obj)
  854. {
  855. TextureFill f = obj as TextureFill;
  856. return f != null && ImageData == f.ImageData &&
  857. ImageWidth == f.ImageWidth &&
  858. ImageHeight == f.ImageHeight &&
  859. PreserveAspectRatio == f.PreserveAspectRatio &&
  860. WrapMode == f.WrapMode &&
  861. ImageOffsetX == f.ImageOffsetX &&
  862. ImageOffsetY == f.ImageOffsetY;
  863. }
  864. /// <inheritdoc/>
  865. public override Brush CreateBrush(RectangleF rect)
  866. {
  867. if (image == null)
  868. ForceLoadImage();
  869. TextureBrush brush = new TextureBrush(image, WrapMode);
  870. brush.TranslateTransform(rect.Left + ImageOffsetX, rect.Top + ImageOffsetY);
  871. return brush;
  872. }
  873. /// <inheritdoc/>
  874. public override Brush CreateBrush(RectangleF rect, float scaleX, float scaleY)
  875. {
  876. if (image == null)
  877. ForceLoadImage();
  878. TextureBrush brush = new TextureBrush(image, WrapMode);
  879. brush.TranslateTransform(rect.Left + ImageOffsetX * scaleX, rect.Top + ImageOffsetY * scaleY);
  880. brush.ScaleTransform(scaleX, scaleY);
  881. return brush;
  882. }
  883. /// <inheritdoc/>
  884. public override void Serialize(FRWriter writer, string prefix, FillBase fill)
  885. {
  886. base.Serialize(writer, prefix, fill);
  887. TextureFill c = fill as TextureFill;
  888. if (c == null || c.ImageWidth != ImageWidth)
  889. writer.WriteValue(prefix + ".ImageWidth", ImageWidth);
  890. if (c == null || c.ImageHeight != ImageHeight)
  891. writer.WriteValue(prefix + ".ImageHeight", ImageHeight);
  892. if (c == null || c.PreserveAspectRatio != PreserveAspectRatio)
  893. writer.WriteBool(prefix + ".PreserveAspectRatio", PreserveAspectRatio);
  894. if (c == null || c.WrapMode != WrapMode)
  895. writer.WriteValue(prefix + ".WrapMode", WrapMode);
  896. if (c == null || c.ImageOffsetX != ImageOffsetX)
  897. writer.WriteValue(prefix + ".ImageOffsetX", ImageOffsetX);
  898. if (c == null || c.ImageOffsetY != ImageOffsetY)
  899. writer.WriteValue(prefix + ".ImageOffsetY", ImageOffsetY);
  900. // store image data
  901. if (writer.SerializeTo != SerializeTo.SourcePages)
  902. {
  903. if (writer.BlobStore != null)
  904. {
  905. // check FImageIndex >= writer.BlobStore.Count is needed when we close the designer
  906. // and run it again, the BlobStore is empty, but FImageIndex is pointing to
  907. // previous BlobStore item and is not -1.
  908. if (imageIndex == -1 || imageIndex >= writer.BlobStore.Count)
  909. {
  910. byte[] bytes = imageData;
  911. if (bytes == null)
  912. {
  913. using (MemoryStream stream = new MemoryStream())
  914. {
  915. ImageHelper.Save(image, stream, ImageFormat.Png);
  916. bytes = stream.ToArray();
  917. }
  918. }
  919. if (bytes != null)
  920. {
  921. string imgHash = BitConverter.ToString(new Murmur3().ComputeHash(bytes));
  922. if (imgHash != dummyImageHash)
  923. imageIndex = writer.BlobStore.AddOrUpdate(bytes, imgHash.Replace("-", String.Empty));
  924. }
  925. }
  926. }
  927. else
  928. {
  929. if (imageData != null)
  930. {
  931. string hash = BitConverter.ToString(new Murmur3().ComputeHash(imageData));
  932. if (hash != dummyImageHash)
  933. {
  934. if (c == null || !writer.AreEqual(ImageData, c.ImageData))
  935. writer.WriteStr(prefix + ".ImageData", Convert.ToBase64String(ImageData));
  936. }
  937. }
  938. }
  939. if (writer.BlobStore != null || writer.SerializeTo == SerializeTo.Undo)
  940. writer.WriteInt(prefix + ".ImageIndex", imageIndex);
  941. }
  942. }
  943. /// <inheritdoc/>
  944. public override void Deserialize(FRReader reader, string prefix)
  945. {
  946. base.Deserialize(reader, prefix);
  947. if (reader.HasProperty(prefix + ".ImageIndex"))
  948. {
  949. imageIndex = reader.ReadInt(prefix + ".ImageIndex");
  950. }
  951. if (reader.BlobStore != null && imageIndex != -1)
  952. {
  953. SetImageData(reader.BlobStore.Get(imageIndex));
  954. }
  955. }
  956. /// <inheritdoc/>
  957. public override void FinalizeComponent()
  958. {
  959. base.FinalizeComponent();
  960. Clear();
  961. ResetImageIndex();
  962. }
  963. /// <inheritdoc/>
  964. public override void InitializeComponent()
  965. {
  966. base.InitializeComponent();
  967. ResetImageIndex();
  968. }
  969. /// <inheritdoc/>
  970. public override void Draw(FRPaintEventArgs e, RectangleF rect)
  971. {
  972. if (image == null)
  973. ForceLoadImage();
  974. if (image == null)
  975. return;
  976. else
  977. base.Draw(e, rect);
  978. }
  979. #endregion //Public Methods
  980. #region Constructors
  981. /// <summary>
  982. /// Initializes the <see cref="TextureFill"/> class with default texture.
  983. /// </summary>
  984. public TextureFill()
  985. {
  986. ResetImageIndex();
  987. SetImageData(null);
  988. Stream dummy = ResourceLoader.GetStream("FastReport", "icon16.ico");
  989. using (MemoryStream ms = new MemoryStream())
  990. {
  991. const int BUFFER_SIZE = 4 * 1024;
  992. dummy.CopyTo(ms, BUFFER_SIZE);
  993. SetImageData(ms.ToArray());
  994. }
  995. WrapMode = WrapMode.Tile;
  996. PreserveAspectRatio = true;
  997. }
  998. /// <summary>
  999. /// Initializes the <see cref="TextureFill"/> class with specified image.
  1000. /// </summary>
  1001. /// <param name="imageBytes"></param>
  1002. public TextureFill(byte[] imageBytes)
  1003. {
  1004. ResetImageIndex();
  1005. SetImageData(imageBytes);
  1006. WrapMode = WrapMode.Tile;
  1007. PreserveAspectRatio = true;
  1008. }
  1009. /// <summary>
  1010. /// Initializes the <see cref="TextureFill"/> class with specified image.
  1011. /// </summary>
  1012. public TextureFill(byte[] imageBytes, int width, int height, bool preserveAspectRatio, WrapMode wrapMode, int imageOffsetX, int imageOffsetY) : this(imageBytes)
  1013. {
  1014. PreserveAspectRatio = preserveAspectRatio;
  1015. WrapMode = wrapMode;
  1016. imageWidth = width;
  1017. imageHeight = height;
  1018. ImageOffsetX = imageOffsetX;
  1019. ImageOffsetY = imageOffsetY;
  1020. }
  1021. static TextureFill()
  1022. {
  1023. dummyImageHash = "62-57-78-BF-92-9F-81-12-C0-43-6B-5D-B1-D8-04-DD";
  1024. }
  1025. #endregion //Constructors
  1026. }
  1027. }