| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163 | using System;using System.Drawing;using System.Drawing.Drawing2D;using System.ComponentModel;using FastReport.Utils;using System.Drawing.Design;using System.IO;using System.Drawing.Imaging;namespace FastReport{  /// <summary>  /// Base class for all fills.  /// </summary>  [TypeConverter(typeof(FastReport.TypeConverters.FillConverter))]  public abstract class FillBase  {    internal string Name    {      get { return GetType().Name.Replace("Fill", ""); }    }    /// <summary>    /// Returned true if Color = Transparent    /// </summary>    public abstract bool IsTransparent    {        get;    }    internal bool FloatDiff(float f1, float f2)    {      return Math.Abs(f1 - f2) > 1e-4;    }    /// <summary>    /// Creates exact copy of this fill.    /// </summary>    /// <returns>Copy of this object.</returns>    public abstract FillBase Clone();    /// <summary>    /// Creates the GDI+ Brush object.    /// </summary>    /// <param name="rect">Drawing rectangle.</param>    /// <returns>Brush object.</returns>    public abstract Brush CreateBrush(RectangleF rect);    /// <summary>    /// Creates the GDI+ Brush object with scaling.    /// </summary>    /// <param name="rect">Drawing rectangle.</param>    /// <param name="scaleX">X scaling coefficient.</param>    /// <param name="scaleY">Y scaling coefficient.</param>    /// <returns>Brush object.</returns>    public virtual Brush CreateBrush(RectangleF rect, float scaleX, float scaleY)    {        return CreateBrush(rect);    }    /// <summary>    /// Serializes the fill.    /// </summary>    /// <param name="writer">Writer object.</param>    /// <param name="prefix">Name of the fill property.</param>    /// <param name="fill">Fill object to compare with.</param>    /// <remarks>    /// This method is for internal use only.    /// </remarks>    public virtual void Serialize(FRWriter writer, string prefix, FillBase fill)    {      if (fill.GetType() != GetType())        writer.WriteStr(prefix, Name);    }    public virtual void Deserialize(FRReader reader, string prefix)    {    }    public virtual void FinalizeComponent()    {    }    public virtual void InitializeComponent()    {    }    /// <summary>    /// Fills the specified rectangle.    /// </summary>    /// <param name="e">Draw event arguments.</param>    /// <param name="rect">Drawing rectangle.</param>    public virtual void Draw(FRPaintEventArgs e, RectangleF rect)    {      rect = new RectangleF(rect.Left * e.ScaleX, rect.Top * e.ScaleY, rect.Width * e.ScaleX, rect.Height * e.ScaleY);      using (Brush brush = CreateBrush(rect, e.ScaleX, e.ScaleY))      {        e.Graphics.FillRectangle(brush, rect.Left, rect.Top, rect.Width, rect.Height);      }    }  }    /// <summary>  /// Class represents the solid fill.  /// </summary>  public class SolidFill : FillBase  {    private Color color;    /// <summary>    /// Gets or sets the fill color.    /// </summary>    [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]    public Color Color    {      get { return color; }      set { color = value; }    }    public override bool IsTransparent     {        get { return color.A == 0; }    }    /// <inheritdoc/>    public override FillBase Clone()    {      return new SolidFill(Color);    }    /// <inheritdoc/>    public override int GetHashCode()    {      return Color.GetHashCode();    }    /// <inheritdoc/>    public override bool Equals(object obj)    {      SolidFill f = obj as SolidFill;      return f != null && Color == f.Color;    }    /// <inheritdoc/>    public override Brush CreateBrush(RectangleF rect)    {      return new SolidBrush(Color);    }    /// <inheritdoc/>    public override void Serialize(FRWriter writer, string prefix, FillBase fill)    {      base.Serialize(writer, prefix, fill);      SolidFill c = fill as SolidFill;            if (c == null || c.Color != Color)        writer.WriteValue(prefix + ".Color", Color);    }    /// <inheritdoc/>    public override void Draw(FRPaintEventArgs e, RectangleF rect)    {      if (Color == Color.Transparent)        return;      Brush brush = e.Cache.GetBrush(Color);      e.Graphics.FillRectangle(brush, rect.Left * e.ScaleX, rect.Top * e.ScaleY, rect.Width * e.ScaleX, rect.Height * e.ScaleY);    }        /// <summary>    /// Initializes the <see cref="SolidFill"/> class with Transparent color.    /// </summary>    public SolidFill() : this(Color.Transparent)    {    }        /// <summary>    /// Initializes the <see cref="SolidFill"/> class with specified color.    /// </summary>    /// <param name="color"></param>    public SolidFill(Color color)    {      Color = color;    }  }    /// <summary>  /// Class represents the linear gradient fill.  /// </summary>  public class LinearGradientFill : FillBase  {    private Color startColor;    private Color endColor;    private int angle;    private float focus;    private float contrast;    /// <summary>    /// Gets or sets the start color of the gradient.     /// </summary>    [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]    public Color StartColor    {      get { return startColor; }      set { startColor = value; }    }    /// <summary>    /// Gets or sets the end color of the gradient.     /// </summary>    [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]    public Color EndColor    {      get { return endColor; }      set { endColor = value; }    }    public override bool IsTransparent     {        get { return startColor.A == 0 && endColor.A == 0; }    }    /// <summary>    /// Gets or sets the angle of the gradient.    /// </summary>    [Editor("FastReport.TypeEditors.AngleEditor, FastReport", typeof(UITypeEditor))]    public int Angle    {      get { return angle; }      set { angle = value % 360; }    }        /// <summary>    /// Gets or sets the focus point of the gradient.    /// </summary>    /// <remarks>    /// Value is a floating point value from 0 to 1.    /// </remarks>    public float Focus    {      get { return focus; }      set       {         if (value < 0)          value = 0;        if (value > 1)          value = 1;        focus = value;       }    }        /// <summary>    /// Gets or sets the gradient contrast.    /// </summary>    /// <remarks>    /// Value is a floating point value from 0 to 1.    /// </remarks>    public float Contrast    {      get { return contrast; }      set       {        if (value < 0)          value = 0;        if (value > 1)          value = 1;        contrast = value;       }    }    /// <inheritdoc/>    public override FillBase Clone()    {      return new LinearGradientFill(StartColor, EndColor, Angle, Focus, Contrast);    }    /// <inheritdoc/>    public override int GetHashCode()    {      return StartColor.GetHashCode() ^ (EndColor.GetHashCode() << 1) ^         ((Angle.GetHashCode() + 1) << 2) ^ ((Focus.GetHashCode() + 1) << 10) ^ ((Contrast.GetHashCode() + 1) << 20);    }    /// <inheritdoc/>    public override bool Equals(object obj)    {      LinearGradientFill f = obj as LinearGradientFill;      return f != null && StartColor == f.StartColor && EndColor == f.EndColor && Angle == f.Angle &&         !FloatDiff(Focus, f.Focus) && !FloatDiff(Contrast, f.Contrast);    }    /// <inheritdoc/>    public override Brush CreateBrush(RectangleF rect)    {      // workaround the gradient bug      rect.Inflate(1, 1);            LinearGradientBrush result = new LinearGradientBrush(rect, StartColor, EndColor, Angle);      result.SetSigmaBellShape(Focus, Contrast);      return result;    }    /// <inheritdoc/>    public override void Serialize(FRWriter writer, string prefix, FillBase fill)    {      base.Serialize(writer, prefix, fill);      LinearGradientFill c = fill as LinearGradientFill;      if (c == null || c.StartColor != StartColor)        writer.WriteValue(prefix + ".StartColor", StartColor);      if (c == null || c.EndColor != EndColor)        writer.WriteValue(prefix + ".EndColor", EndColor);      if (c == null || c.Angle != Angle)        writer.WriteInt(prefix + ".Angle", Angle);      if (c == null || FloatDiff(c.Focus, Focus))        writer.WriteFloat(prefix + ".Focus", Focus);      if (c == null || FloatDiff(c.Contrast, Contrast))        writer.WriteFloat(prefix + ".Contrast", Contrast);    }    /// <summary>    /// Initializes the <see cref="LinearGradientFill"/> class with default settings.    /// </summary>    public LinearGradientFill() : this(Color.Black, Color.White, 0, 100, 100)    {    }    /// <summary>    /// Initializes the <see cref="LinearGradientFill"/> class with start and end colors.    /// </summary>    /// <param name="startColor">Start color.</param>    /// <param name="endColor">End color.</param>    public LinearGradientFill(Color startColor, Color endColor) : this(startColor, endColor, 0)    {    }    /// <summary>    /// Initializes the <see cref="LinearGradientFill"/> class with start, end colors and angle.    /// </summary>    /// <param name="startColor">Start color.</param>    /// <param name="endColor">End color.</param>    /// <param name="angle">Angle.</param>    public LinearGradientFill(Color startColor, Color endColor, int angle) : this(startColor, endColor, angle, 0, 100)    {    }    /// <summary>    /// Initializes the <see cref="LinearGradientFill"/> class with start and end colors, angle, focus and contrast.    /// </summary>    /// <param name="startColor">Start color.</param>    /// <param name="endColor">End color.</param>    /// <param name="angle">Angle.</param>    /// <param name="focus">Focus.</param>    /// <param name="contrast">Contrast.</param>    public LinearGradientFill(Color startColor, Color endColor, int angle, float focus, float contrast)    {      StartColor = startColor;      EndColor = endColor;      Angle = angle;      Focus = focus;      Contrast = contrast;    }      }    /// <summary>  /// The style of the path gradient.  /// </summary>  public enum PathGradientStyle   {     /// <summary>    /// Elliptic gradient.    /// </summary>    Elliptic,         /// <summary>    /// Rectangular gradient.    /// </summary>    Rectangular  }  /// <summary>  /// Class represents the path gradient fill.  /// </summary>  public class PathGradientFill : FillBase  {    private Color centerColor;    private Color edgeColor;    private PathGradientStyle style;    /// <summary>    /// Gets or sets the center color of the gradient.    /// </summary>    [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]    public Color CenterColor    {      get { return centerColor; }      set { centerColor = value; }    }    /// <summary>    /// Gets or sets the edge color of the gradient.    /// </summary>    [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]    public Color EdgeColor    {      get { return edgeColor; }      set { edgeColor = value; }    }    /// <summary>    /// Gets or sets the style of the gradient.    /// </summary>    public PathGradientStyle Style    {      get { return style; }      set { style = value; }    }    public override bool IsTransparent     {        get { return centerColor.A == 0 && edgeColor.A == 0; }    }    /// <inheritdoc/>    public override FillBase Clone()    {      return new PathGradientFill(CenterColor, EdgeColor, Style);    }    /// <inheritdoc/>    public override int GetHashCode()    {      return CenterColor.GetHashCode() ^ (EdgeColor.GetHashCode() << 1) ^ ((Style.GetHashCode() + 1) << 2);    }    /// <inheritdoc/>    public override bool Equals(object obj)    {      PathGradientFill f = obj as PathGradientFill;      return f != null && CenterColor == f.CenterColor && EdgeColor == f.EdgeColor && Style == f.Style;    }    /// <inheritdoc/>    public override Brush CreateBrush(RectangleF rect)    {      GraphicsPath path = new GraphicsPath();      if (Style == PathGradientStyle.Rectangular)        path.AddRectangle(rect);      else      {        float radius = (float)Math.Sqrt(rect.Width * rect.Width + rect.Height * rect.Height) / 2 + 1;        PointF center = new PointF(rect.Left + rect.Width / 2 - 1, rect.Top + rect.Height / 2 - 1);        RectangleF r = new RectangleF(center.X - radius, center.Y - radius, radius * 2, radius * 2);        path.AddEllipse(r);      }      PathGradientBrush result = new PathGradientBrush(path);      path.Dispose();      result.CenterColor = CenterColor;      result.SurroundColors = new Color[] { EdgeColor };      return result;    }    /// <inheritdoc/>    public override void Serialize(FRWriter writer, string prefix, FillBase fill)    {      base.Serialize(writer, prefix, fill);      PathGradientFill c = fill as PathGradientFill;      if (c == null || c.CenterColor != CenterColor)        writer.WriteValue(prefix + ".CenterColor", CenterColor);      if (c == null || c.EdgeColor != EdgeColor)        writer.WriteValue(prefix + ".EdgeColor", EdgeColor);      if (c == null || c.Style != Style)        writer.WriteValue(prefix + ".Style", Style);    }    /// <summary>    /// Initializes the <see cref="PathGradientFill"/> class with default settings.    /// </summary>    public PathGradientFill() : this(Color.Black, Color.White, PathGradientStyle.Elliptic)    {    }    /// <summary>    /// Initializes the <see cref="PathGradientFill"/> class with center, edge colors and style.    /// </summary>    /// <param name="centerColor">Center color.</param>    /// <param name="edgeColor">Edge color.</param>    /// <param name="style">Gradient style.</param>    public PathGradientFill(Color centerColor, Color edgeColor, PathGradientStyle style)    {      CenterColor = centerColor;      EdgeColor = edgeColor;      Style = style;    }  }  /// <summary>  /// Class represents the hatch fill.  /// </summary>  public class HatchFill : FillBase  {    private Color foreColor;    private Color backColor;    private HatchStyle style;    /// <summary>    /// Gets or sets the foreground color.    /// </summary>    [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]    public Color ForeColor    {      get { return foreColor; }      set { foreColor = value; }    }    /// <summary>    /// Gets or sets the background color.    /// </summary>    [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]    public Color BackColor    {      get { return backColor; }      set { backColor = value; }    }    /// <summary>    /// Gets or sets the hatch style.    /// </summary>    public HatchStyle Style    {      get { return style; }      set { style = value; }    }    public override bool IsTransparent     {        get { return foreColor.A == 0 && backColor.A == 0; }    }    /// <inheritdoc/>    public override FillBase Clone()    {      return new HatchFill(ForeColor, BackColor, Style);    }    /// <inheritdoc/>    public override int GetHashCode()    {      return ForeColor.GetHashCode() ^ (BackColor.GetHashCode() << 1) ^ ((Style.GetHashCode() + 1) << 2);    }    /// <inheritdoc/>    public override bool Equals(object obj)    {      HatchFill f = obj as HatchFill;      return f != null && ForeColor == f.ForeColor && BackColor == f.BackColor && Style == f.Style;    }    /// <inheritdoc/>    public override Brush CreateBrush(RectangleF rect)    {      return new HatchBrush(Style, ForeColor, BackColor);    }    /// <inheritdoc/>    public override void Serialize(FRWriter writer, string prefix, FillBase fill)    {      base.Serialize(writer, prefix, fill);      HatchFill c = fill as HatchFill;      if (c == null || c.ForeColor != ForeColor)        writer.WriteValue(prefix + ".ForeColor", ForeColor);      if (c == null || c.BackColor != BackColor)        writer.WriteValue(prefix + ".BackColor", BackColor);      if (c == null || c.Style != Style)        writer.WriteValue(prefix + ".Style", Style);    }        /// <summary>    /// Initializes the <see cref="HatchFill"/> class with default settings.    /// </summary>    public HatchFill() : this(Color.Black, Color.White, HatchStyle.BackwardDiagonal)    {    }        /// <summary>    /// Initializes the <see cref="HatchFill"/> class with foreground, background colors and hatch style.    /// </summary>    /// <param name="foreColor">Foreground color.</param>    /// <param name="backColor">Background color.</param>    /// <param name="style">Hatch style.</param>    public HatchFill(Color foreColor, Color backColor, HatchStyle style)    {      ForeColor = foreColor;      BackColor = backColor;      Style = style;    }  }  /// <summary>  /// Class represents the glass fill.  /// </summary>  public class GlassFill : FillBase  {    private Color color;    private float blend;    private bool hatch;    /// <summary>    /// Gets or sets the fill color.    /// </summary>        [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]    public Color Color    {      get { return color; }      set { color = value; }    }        /// <summary>    /// Gets or sets the blend value.    /// </summary>    /// <remarks>Value must be between 0 and 1.    /// </remarks>    [DefaultValue(0.2f)]    public float Blend    {      get { return blend; }      set { blend = value < 0 ? 0 : value > 1 ? 1 : value; }    }        /// <summary>    /// Gets or sets a value determines whether to draw a hatch or not.    /// </summary>    [DefaultValue(true)]    public bool Hatch    {      get { return hatch; }      set { hatch = value; }    }    public override bool IsTransparent     {        get { return color.A == 0; }    }    /// <inheritdoc/>    public override FillBase Clone()    {      return new GlassFill(Color, Blend, Hatch);    }    /// <inheritdoc/>    public override int GetHashCode()    {      return Color.GetHashCode() ^ (Blend.GetHashCode() + 1) ^ ((Hatch.GetHashCode() + 1) << 2);    }    /// <inheritdoc/>    public override bool Equals(object obj)    {      GlassFill f = obj as GlassFill;      return f != null && Color == f.Color && Blend == f.Blend && Hatch == f.Hatch;    }    /// <inheritdoc/>    public override void Draw(FRPaintEventArgs e, RectangleF rect)    {      rect = new RectangleF(rect.Left * e.ScaleX, rect.Top * e.ScaleY, rect.Width * e.ScaleX, rect.Height * e.ScaleY);      // draw fill      using (SolidBrush b = new SolidBrush(Color))      {        e.Graphics.FillRectangle(b, rect.Left, rect.Top, rect.Width, rect.Height);      }            // draw hatch      if (Hatch)      {        using (HatchBrush b = new HatchBrush(HatchStyle.DarkUpwardDiagonal,          Color.FromArgb(40, Color.White), Color.Transparent))        {          e.Graphics.FillRectangle(b, rect.Left, rect.Top, rect.Width, rect.Height);        }      }      // draw blend      using (SolidBrush b = new SolidBrush(Color.FromArgb((int)(Blend * 255), Color.White)))      {        e.Graphics.FillRectangle(b, rect.Left, rect.Top, rect.Width, rect.Height / 2);      }    }    /// <inheritdoc/>    public override Brush CreateBrush(RectangleF rect)    {      return new SolidBrush(Color);    }    /// <inheritdoc/>    public override void Serialize(FRWriter writer, string prefix, FillBase fill)    {      base.Serialize(writer, prefix, fill);      GlassFill c = fill as GlassFill;      if (c == null || c.Color != Color)        writer.WriteValue(prefix + ".Color", Color);      if (c == null || c.Blend != Blend)        writer.WriteFloat(prefix + ".Blend", Blend);      if (c == null || c.Hatch != Hatch)        writer.WriteBool(prefix + ".Hatch", Hatch);    }    /// <summary>    /// Initializes the <see cref="GlassFill"/> class with default settings.    /// </summary>    public GlassFill() : this(Color.White, 0.2f, true)    {    }    /// <summary>    /// Initializes the <see cref="GlassFill"/> class with given color, blend ratio and hatch style.    /// </summary>    /// <param name="color">Color.</param>    /// <param name="blend">Blend ratio (0..1).</param>    /// <param name="hatch">Display the hatch.</param>    public GlassFill(Color color, float blend, bool hatch)    {      Color = color;      Blend = blend;      Hatch = hatch;    }  }    /// <summary>    /// Class represents the Texture fill.    /// </summary>    public class TextureFill : FillBase    {        #region Fields        private Image image;        private int imageWidth;        private int imageHeight;        private bool preserveAspectRatio;        private WrapMode wrapMode;        private int imageIndex;        private byte[] imageData;        private int imageOffsetX;        private int imageOffsetY;        private static string dummyImageHash;        #endregion // Fields        #region  Properties        /// <summary>        /// Gets or sets value, indicating that image should preserve aspect ratio        /// </summary>        public bool PreserveAspectRatio        {            get { return preserveAspectRatio; }            set { preserveAspectRatio = value; }        }        /// <summary>        /// Gets or sets the image width        /// </summary>        public int ImageWidth        {            get            {                if (imageWidth <= 0)                    ForceLoadImage();                return imageWidth;            }            set            {                if (value != imageWidth && value > 0)                {                    if (PreserveAspectRatio && imageHeight > 0 && imageWidth > 0)                    {                        imageHeight = (int)(imageHeight * (float)value / imageWidth);                    }                    imageWidth = value;                    ResizeImage(imageWidth, ImageHeight);                }            }        }        /// <summary>        /// Gets or sets the image height        /// </summary>        public int ImageHeight        {            get            {                if (imageHeight <= 0)                    ForceLoadImage();                return imageHeight;            }            set            {                if (value != imageHeight && value > 0)                {                    if (PreserveAspectRatio && imageWidth > 0 && imageHeight > 0)                    {                        imageWidth = (int)(imageWidth * (float)value / imageHeight);                    }                    imageHeight = value;                    ResizeImage(imageWidth, ImageHeight);                }            }        }        /// <summary>        /// Gets or sets the texture wrap mode        /// </summary>        public WrapMode WrapMode        {            get { return wrapMode; }            set { wrapMode = value; }        }        /// <summary>        /// Gets or sets the image index        /// </summary>        public int ImageIndex        {            get { return imageIndex; }            set { imageIndex = value; }        }        /// <summary>        /// Gets or sets the image data        /// </summary>        public byte[] ImageData        {            get { return imageData; }            set            {                SetImageData(value);            }        }        /// <summary>        /// Image left offset        /// </summary>        public int ImageOffsetX        {            get { return imageOffsetX; }            set { imageOffsetX = value; }        }        /// <summary>        /// Image top offset        /// </summary>        public int ImageOffsetY        {            get { return imageOffsetY; }            set { imageOffsetY = value; }        }        public override bool IsTransparent         {            get { return false; }        }        #endregion // Properties        #region Private Methods        private void Clear()        {            if (image != null)                image.Dispose();            image = null;            imageData = null;        }        private void ResizeImage(int width, int height)        {            if (imageData == null || width <= 0 || height <= 0)                return;            else            {                image = ImageHelper.Load(imageData);                image = new Bitmap(image, width, height);            }                        }        private void ResetImageIndex()        {            imageIndex = -1;        }        private void ForceLoadImage()        {            byte[] data = imageData;            if (data == null)                return;            byte[] saveImageData = data;            // imageData will be reset after this line, keep it            image = ImageHelper.Load(data);            if (imageWidth <= 0 && imageHeight <= 0)            {                imageWidth = image.Width;                imageHeight = image.Height;            }            else if (imageWidth != image.Width || imageHeight != image.Height)            {                ResizeImage(imageWidth, imageHeight);            }            data = saveImageData;        }        #endregion // Private Methods        #region Public Methods        /// <summary>        /// Sets image data to imageData        /// </summary>        /// <param name="data">input image data</param>        public void SetImageData(byte[] data)        {            ResetImageIndex();            image = null;            imageData = data;            ResizeImage(imageWidth, imageHeight);        }        /// <summary>        /// Set image        /// </summary>        /// <param name="image">input image</param>        public void SetImage(Image image)        {            using (MemoryStream ms = new MemoryStream())            {                image.Save(ms, image.RawFormat);                SetImageData(ms.ToArray());            }        }        /// <inheritdoc/>        public override FillBase Clone()        {                        TextureFill f = new TextureFill(imageData.Clone() as byte[], ImageWidth, ImageHeight, PreserveAspectRatio, WrapMode, ImageOffsetX, ImageOffsetY);            //f.ImageIndex = ImageIndex;            return f;        }        /// <inheritdoc/>        public override int GetHashCode()        {            return ImageData.GetHashCode() ^ (ImageWidth.GetHashCode() << 1) ^                ((ImageHeight.GetHashCode() + 1) << 2) ^                ((PreserveAspectRatio.GetHashCode() + 1) << 10) ^                ((WrapMode.GetHashCode() + 1) << 20) ^                ((ImageOffsetX.GetHashCode() + 1) << 40) ^                ((ImageOffsetY.GetHashCode() + 1) << 60);        }        /// <inheritdoc/>        public override bool Equals(object obj)        {            TextureFill f = obj as TextureFill;            return f != null && ImageData == f.ImageData &&                 ImageWidth == f.ImageWidth &&                 ImageHeight == f.ImageHeight &&                PreserveAspectRatio == f.PreserveAspectRatio &&                WrapMode == f.WrapMode &&                ImageOffsetX == f.ImageOffsetX &&                ImageOffsetY == f.ImageOffsetY;        }        /// <inheritdoc/>        public override Brush CreateBrush(RectangleF rect)        {            if (image == null)                ForceLoadImage();                      TextureBrush brush = new TextureBrush(image, WrapMode);            brush.TranslateTransform(rect.Left + ImageOffsetX, rect.Top + ImageOffsetY);            return brush;        }        /// <inheritdoc/>        public override Brush CreateBrush(RectangleF rect, float scaleX, float scaleY)        {            if (image == null)                ForceLoadImage();            TextureBrush brush = new TextureBrush(image, WrapMode);            brush.TranslateTransform(rect.Left + ImageOffsetX * scaleX, rect.Top + ImageOffsetY * scaleY);            brush.ScaleTransform(scaleX, scaleY);            return brush;        }        /// <inheritdoc/>        public override void Serialize(FRWriter writer, string prefix, FillBase fill)        {            base.Serialize(writer, prefix, fill);            TextureFill c = fill as TextureFill;            if (c == null || c.ImageWidth != ImageWidth)                writer.WriteValue(prefix + ".ImageWidth", ImageWidth);            if (c == null || c.ImageHeight != ImageHeight)                writer.WriteValue(prefix + ".ImageHeight", ImageHeight);            if (c == null || c.PreserveAspectRatio != PreserveAspectRatio)                writer.WriteBool(prefix + ".PreserveAspectRatio", PreserveAspectRatio);            if (c == null || c.WrapMode != WrapMode)                writer.WriteValue(prefix + ".WrapMode", WrapMode);            if (c == null || c.ImageOffsetX != ImageOffsetX)                writer.WriteValue(prefix + ".ImageOffsetX", ImageOffsetX);            if (c == null || c.ImageOffsetY != ImageOffsetY)                writer.WriteValue(prefix + ".ImageOffsetY", ImageOffsetY);            // store image data            if (writer.SerializeTo != SerializeTo.SourcePages)            {                if (writer.BlobStore != null)                {                    // check FImageIndex >= writer.BlobStore.Count is needed when we close the designer                    // and run it again, the BlobStore is empty, but FImageIndex is pointing to                    // previous BlobStore item and is not -1.                    if (imageIndex == -1 || imageIndex >= writer.BlobStore.Count)                    {                        byte[] bytes = imageData;                        if (bytes == null)                        {                            using (MemoryStream stream = new MemoryStream())                            {                                ImageHelper.Save(image, stream, ImageFormat.Png);                                bytes = stream.ToArray();                            }                        }                        if (bytes != null)                        {                            string imgHash = BitConverter.ToString(new Murmur3().ComputeHash(bytes));                            if (imgHash != dummyImageHash)                                imageIndex = writer.BlobStore.AddOrUpdate(bytes, imgHash.Replace("-", String.Empty));                        }                    }                }                else                {                    if (imageData != null)                    {                        string hash = BitConverter.ToString(new Murmur3().ComputeHash(imageData));                        if (hash != dummyImageHash)                        {                            if (c == null || !writer.AreEqual(ImageData, c.ImageData))                                writer.WriteStr(prefix + ".ImageData", Convert.ToBase64String(ImageData));                        }                    }                }                if (writer.BlobStore != null || writer.SerializeTo == SerializeTo.Undo)                    writer.WriteInt(prefix + ".ImageIndex", imageIndex);            }        }        /// <inheritdoc/>        public override void Deserialize(FRReader reader, string prefix)        {            base.Deserialize(reader, prefix);            if (reader.HasProperty(prefix + ".ImageIndex"))            {                imageIndex = reader.ReadInt(prefix + ".ImageIndex");            }            if (reader.BlobStore != null && imageIndex != -1)            {                SetImageData(reader.BlobStore.Get(imageIndex));            }        }        /// <inheritdoc/>        public override void FinalizeComponent()        {            base.FinalizeComponent();            Clear();            ResetImageIndex();                    }        /// <inheritdoc/>        public override void InitializeComponent()        {            base.InitializeComponent();            ResetImageIndex();        }        /// <inheritdoc/>        public override void Draw(FRPaintEventArgs e, RectangleF rect)        {            if (image == null)                ForceLoadImage();            if (image == null)                return;            else                base.Draw(e, rect);        }        #endregion //Public Methods        #region Constructors        /// <summary>        /// Initializes the <see cref="TextureFill"/> class with default texture.        /// </summary>        public TextureFill()        {            ResetImageIndex();            SetImageData(null);            Stream dummy = ResourceLoader.GetStream("FastReport", "icon16.ico");            using (MemoryStream ms = new MemoryStream())            {                const int BUFFER_SIZE = 4 * 1024;                dummy.CopyTo(ms, BUFFER_SIZE);                SetImageData(ms.ToArray());            }            WrapMode = WrapMode.Tile;            PreserveAspectRatio = true;        }        /// <summary>        /// Initializes the <see cref="TextureFill"/> class with specified image.        /// </summary>        /// <param name="imageBytes"></param>        public TextureFill(byte[] imageBytes)        {            ResetImageIndex();            SetImageData(imageBytes);            WrapMode = WrapMode.Tile;            PreserveAspectRatio = true;        }        /// <summary>        /// Initializes the <see cref="TextureFill"/> class with specified image.        /// </summary>        /// <param name="image"></param>        public TextureFill(byte[] imageBytes, int width, int height, bool preserveAspectRatio, WrapMode wrapMode, int imageOffsetX, int imageOffsetY) : this(imageBytes)        {            PreserveAspectRatio = preserveAspectRatio;            WrapMode = wrapMode;            imageWidth = width;            imageHeight = height;            ImageOffsetX = imageOffsetX;            ImageOffsetY = imageOffsetY;        }        static TextureFill()        {            dummyImageHash = "62-57-78-BF-92-9F-81-12-C0-43-6B-5D-B1-D8-04-DD";        }        #endregion //Constructors    }}
 |