using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
namespace Svg.FilterEffects
{
///
/// A filter effect consists of a series of graphics operations that are applied to a given source graphic to produce a modified graphical result.
///
[SvgElement("filter")]
public sealed class SvgFilter : SvgElement
{
private Bitmap sourceGraphic;
private Bitmap sourceAlpha;
///
/// Gets or sets the width of the resulting filter graphic.
///
[SvgAttribute("width")]
public SvgUnit Width
{
get { return this.Attributes.GetAttribute("width"); }
set { this.Attributes["width"] = value; }
}
///
/// Gets or sets the height of the resulting filter graphic.
///
[SvgAttribute("height")]
public SvgUnit Height
{
get { return this.Attributes.GetAttribute("height"); }
set { this.Attributes["height"] = value; }
}
internal Dictionary> Buffer { get; private set; }
///
/// Initializes a new instance of the class.
///
public SvgFilter()
{
this.Buffer = new Dictionary>();
}
///
/// Renders the and contents to the specified object.
///
/// The object to render to.
protected override void Render(SvgRenderer renderer)
{
// Do nothing
}
///
/// Creates a new object that is a copy of the current instance.
///
///
/// A new object that is a copy of this instance.
///
public override object Clone()
{
return (SvgFilter)this.MemberwiseClone();
}
public void ApplyFilter(SvgVisualElement element, SvgRenderer renderer)
{
this.Buffer.Clear();
this.PopulateDefaults(element, renderer);
IEnumerable primitives = this.Children.OfType();
if (primitives.Count() > 0)
{
foreach (var primitive in primitives)
{
this.Buffer.Add(primitive.Result, (e, r) => primitive.Process());
}
// Render the final filtered image
renderer.DrawImageUnscaled(this.Buffer.Last().Value(element, renderer), new Point(0, 0));
}
}
private void PopulateDefaults(SvgVisualElement element, SvgRenderer renderer)
{
this.ResetDefaults();
this.Buffer.Add(SvgFilterPrimitive.SourceGraphic, this.CreateSourceGraphic);
this.Buffer.Add(SvgFilterPrimitive.SourceAlpha, this.CreateSourceAlpha);
}
#region Defaults
private void ResetDefaults()
{
if (this.sourceGraphic != null)
{
this.sourceGraphic.Dispose();
this.sourceGraphic = null;
}
if (this.sourceAlpha != null)
{
this.sourceAlpha.Dispose();
this.sourceAlpha = null;
}
}
private Bitmap CreateSourceGraphic(SvgVisualElement element, SvgRenderer renderer)
{
if (this.sourceGraphic == null)
{
RectangleF bounds = element.Path.GetBounds();
this.sourceGraphic = new Bitmap((int)bounds.Width, (int)bounds.Height);
using (var graphics = Graphics.FromImage(this.sourceGraphic))
{
graphics.Clip = renderer.Clip;
graphics.Transform = renderer.Transform;
element.RenderElement(SvgRenderer.FromGraphics(graphics));
graphics.Save();
}
}
return this.sourceGraphic;
}
private Bitmap CreateSourceAlpha(SvgVisualElement element, SvgRenderer renderer)
{
if (this.sourceAlpha == null)
{
Bitmap source = this.Buffer[SvgFilterPrimitive.SourceGraphic](element, renderer);
float[][] colorMatrixElements = {
new float[] {0, 0, 0, 0, 0}, // red
new float[] {0, 0, 0, 0, 0}, // green
new float[] {0, 0, 0, 0, 0}, // blue
new float[] {0, 0, 0, 1, 1}, // alpha
new float[] {0, 0, 0, 0, 0} }; // translations
var matrix = new ColorMatrix(colorMatrixElements);
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(matrix);
this.sourceAlpha = new Bitmap(source.Width, source.Height);
using (var graphics = Graphics.FromImage(this.sourceAlpha))
{
graphics.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height), 0, 0,
source.Width, source.Height, GraphicsUnit.Pixel, attributes);
graphics.Save();
}
}
return this.sourceAlpha;
}
#endregion
}
}