Click here to Skip to main content
15,881,881 members
Articles / Containers / Docker

SVG Artiste - An SVG Editor

Rate me:
Please Sign up or sign in to vote.
4.69/5 (23 votes)
3 Aug 2010CPOL14 min read 95.8K   15.4K   93  
A Vector based tool to create and edit SVG images
// --------------------------------------------------------------------------------
// Name:     SvgElement
//
// Author:   Maurizio Bigoloni <big71@fastwebnet.it>
//           See the ReleaseNote.txt file for copyright and license information.
//
// Remarks:
//
// --------------------------------------------------------------------------------

using System;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
using System.Drawing;

namespace SVGLib
{
	/// <summary>
	/// This is the base class of any Svg element.
	/// </summary>
	[DefaultProperty("Id")]
	public class SvgElement
	{
		/// <summary>
		/// List all SVG element types. For each element a specific class is defined in the library.
		/// </summary>
		public enum _SvgElementType
		{
			typeUnsupported,
			typeSvg,
			typeDesc,
			typeText,
			typeGroup,
			typeRect,
			typeCircle,
			typeEllipse,
			typeLine,
			typePath,
			typePolygon,
			typeImage,
			typePolyline
		};

		// ---------- PUBLIC PROPERTIES

		/// <summary>
		/// Standard XML attribute for assigning a unique name to an element.
		/// </summary>
		/// <remarks></remarks>
		[Category("(Core)")]
		[Description("Standard XML attribute for assigning a unique name to an element.")]
		public string Id
		{
			get	
			{
				return GetAttributeStringValue(SvgAttribute._SvgAttribute.attrCore_Id);	
			}

			set	
			{
				SetAttributeValue(SvgAttribute._SvgAttribute.attrCore_Id, value);
			}
		}

		// ---------- PUBLIC PROPERTIES END

		// ---------- PRIVATE PROPERTIES

		private class CEleComparer : IComparer  
		{
			int IComparer.Compare( Object x, Object y )  
			{
				SvgAttribute ax = (SvgAttribute) x;
				SvgAttribute ay = (SvgAttribute) y;

				if ( ax.AttributeGroup == ay.AttributeGroup )
				{
					if ( ax.AttributeType < ay.AttributeType )
					{
						return -1;
					}
					else
					{
						return 1;
					}
				}
				else if ( ax.AttributeGroup < ay.AttributeGroup )
				{
					return -1;
				}
				else
				{
					return 1;
				}
			}
		}


		// navigation
		protected SvgElement m_Parent;
		protected SvgElement m_Child;
		protected SvgElement m_Next; 
		protected SvgElement m_Previous;

		// document
		protected SvgDoc m_doc;
		
		// internal stuff
		protected int m_nInternalId;
		protected string m_sElementName;
		protected string m_sElementValue;
		protected bool m_bHasValue;
		protected _SvgElementType m_ElementType;

		// attributes
		private ArrayList m_attributes;
		
		// ---------- PRIVATE PROPERTIES END

		// ---------- PUBLIC METHODS

		// constructor is protected!

		/// <summary>
		/// It returns the parent element.
		/// </summary>
		/// <returns></returns>
		public SvgElement getParent()
		{
			return m_Parent;
		}

		/// <summary>
		/// It sets the parent element.
		/// </summary>
		/// <param name="ele">New parent element</param>
		public void setParent(SvgElement ele)
		{
			m_Parent = ele;
		}

		/// <summary>
		/// It gest the first child element.
		/// </summary>
		/// <returns>First child element.</returns>
		public SvgElement getChild()
		{
			return m_Child;
		}

		/// <summary>
		/// It sets the first child element.
		/// </summary>
		/// <param name="ele">New child.</param>
		public void setChild(SvgElement ele)
		{
			m_Child = ele;
		}

		/// <summary>
		/// It gets the next sibling element.
		/// </summary>
		/// <returns>Next element.</returns>
		public SvgElement getNext()
		{
			return m_Next;
		}

		/// <summary>
		/// It sets the next sibling element.
		/// </summary>
		/// <param name="ele">New next element.</param>
		public void setNext(SvgElement ele)
		{
			m_Next = ele;
		}

		/// <summary>
		/// It gets the previous sibling element.
		/// </summary>
		/// <returns>Previous element.</returns>
		public SvgElement getPrevious()
		{
			return m_Previous;
		}

		/// <summary>
		/// It sets the previous element.
		/// </summary>
		/// <param name="ele">New previous element.</param>
		public void setPrevious(SvgElement ele)
		{
			m_Previous = ele;
		}

		/// <summary>
		/// It gets the internal Id of the element.
		/// </summary>
		/// <returns>Internal Id.</returns>
		/// <remarks>The internal Id is a unique number inside the SVG document.
		/// It is assigned when the element is added to the document.</remarks>
		public int getInternalId()
		{
			return m_nInternalId;
		}

		/// <summary>
		/// It sets the internal Id of the element.
		/// </summary>
		/// <param name="nId">New internal Id.</param>
		public void setInternalId(int nId)
		{
			m_nInternalId = nId;
		}

		/// <summary>
		/// It returns the SVG element name.
		/// </summary>
		/// <returns>SVG name.</returns>
		public string getElementName()
		{
			return m_sElementName;
		}

		/// <summary>
		/// It returns the current element value.
		/// </summary>
		/// <returns>Element value.</returns>
		/// <remarks>Not all SVG elements are supposed to have a value. For instance a rect element or 
		/// a circle do not usually have a value while a desc or a text they normally have it.</remarks>
		public string getElementValue()
		{
			return m_sElementValue;
		}

		/// <summary>
		/// Sets the element value.
		/// </summary>
		/// <param name="sValue">New element value.</param>
		public void setElementValue(string sValue)
		{
			m_sElementValue = sValue;
		}

		/// <summary>
		/// Flag indicating if a value is expected for the SVG element.
		/// </summary>
		/// <returns>true if the SVG element has normally a value.</returns>
		public bool HasValue()
		{
			return m_bHasValue;
		}

		/// <summary>
		/// It returns the SVG element type.
		/// </summary>
		/// <returns></returns>
		public _SvgElementType getElementType()
		{
			return m_ElementType;
		}

		/// <summary>
		/// It returns the XML string of the SVG tree starting from the element.
		/// </summary>
		/// <returns>XML string.</returns>
		/// <remarks>The method is recursive so it creates the SVG string for the current element and for its
		/// sub-tree. If the element is the root of the SVG document the method return the entire SVG XML string.</remarks>
		public string GetXML()
		{
			string sXML;

			sXML = OpenXMLTag();

			if ( m_Child != null )
			{
				sXML += m_Child.GetXML();
			}

			sXML += CloseXMLTag();

			SvgElement ele = m_Next;
			if (ele != null)
			{
				sXML += ele.GetXML();
			}

			ErrH.Log("SvgElement", "GetXML", ElementInfo(), ErrH._LogPriority.Info);
		
			return sXML;
		}

		/// <summary>
		/// It returns the XML string of the SVG element.
		/// </summary>
		/// <returns>XML string.</returns>
		public string GetTagXml()
		{
			string sXML;

			sXML = OpenXMLTag();
			sXML += CloseXMLTag();

			return sXML;
		}

		/// <summary>
		/// It gets all element attributes.
		/// </summary>
		/// <param name="aType">Attribute type array.</param>
		/// <param name="aName">Attribute name array.</param>
		/// <param name="aValue">Attribute value array.</param>
		public void FillAttributeList(ArrayList aType, ArrayList aName, ArrayList aValue)
		{
			IComparer myComparer = new CEleComparer();
			m_attributes.Sort(myComparer);


			for (int i = 0; i < m_attributes.Count; i++ )
			{
				SvgAttribute attr = (SvgAttribute) m_attributes[i];

				aType.Add(attr.AttributeType);
				aName.Add(attr.Name);
				aValue.Add(attr.Value);
			}
		}

		/// <summary>
		/// It copies all the attributes of the element eleToClone to the
		/// current element.
		/// </summary>
		/// <param name="eleToClone">Element that has to be cloned.</param>
		public void CloneAttributeList(SvgElement eleToClone)
		{
			ArrayList aType = new ArrayList();
			ArrayList aName = new ArrayList();
			ArrayList aValue = new ArrayList();

			eleToClone.FillAttributeList(aType, aName, aValue);

			m_attributes.Clear();


			// copy the attributes
			for (int i = 0; i < aType.Count; i++ )
			{
				AddAttr((SvgAttribute._SvgAttribute) aType[i], aValue[i]);
			}

			// copy the value
			if ( m_bHasValue )
			{
				m_sElementValue = eleToClone.m_sElementValue;
			}
		}

		/// <summary>
		/// It returns a string containing current element info for logging purposes.
		/// </summary>
		/// <returns></returns>
		public string ElementInfo()
		{
			string sMsg = "InternalId:" + m_nInternalId.ToString();

			if ( m_Parent != null )
			{
				sMsg += " - Parent:" + m_Parent.getInternalId().ToString();
			}

			if ( m_Previous != null )
			{
				sMsg += " - Previous:" + m_Previous.getInternalId().ToString();
			}

			if ( m_Next != null )
			{
				sMsg += " - Next:" + m_Next.getInternalId().ToString();
			}

			if ( m_Child != null )
			{
				sMsg += " - Child:" + m_Child.getInternalId().ToString();
			}

			return sMsg;
		}

		// ---------- PUBLIC METHODS END

		// ---------- PRIVATE METHODS

		protected SvgElement(SvgDoc doc)
		{
			ErrH.Log("SvgElement", "SvgElement", "Element created", ErrH._LogPriority.Info);

			m_doc = doc;

			m_attributes = new ArrayList();

			AddAttr(SvgAttribute._SvgAttribute.attrCore_Id, null);

			m_Parent = null;
			m_Child = null;
			m_Next = null;
			m_Previous = null;

			m_sElementName = "unsupported";
			m_sElementValue = "";
			m_bHasValue = false;
			m_ElementType = _SvgElementType.typeUnsupported;
		}

		~SvgElement()
		{
			ErrH.Log("SvgElement", "SvgElement", "Element destroyed, InternalId:" + m_nInternalId.ToString(), ErrH._LogPriority.Info);

			m_Parent = null;
			m_Child = null;
			m_Next = null;
			m_Previous = null;
		}

		protected string OpenXMLTag()
		{
			string sXML;

			sXML = "<" + m_sElementName;

			for (int i = 0; i < m_attributes.Count; i++ )
			{
				SvgAttribute attr = (SvgAttribute) m_attributes[i];
				sXML += attr.GetXML();
			}

			if ( m_sElementValue == "")
			{
				if (m_Child == null)
				{
					sXML += " />\r\n";
				}
				else
				{
					sXML += ">\r\n";
				}
			}
			else
			{
				sXML += ">";
				sXML += m_sElementValue;
			}
			
			return sXML;
		}

		protected string CloseXMLTag()
		{
			if ( (m_sElementValue == "") && (m_Child == null) )
			{
				return "";
			}
			else
			{
				return "</" + m_sElementName + ">\r\n";
			}
		}

		protected void AddAttr(SvgAttribute._SvgAttribute type, object objValue)
		{
			SvgAttribute attrToAdd = new SvgAttribute(type);
			attrToAdd.Value = objValue;

			m_attributes.Add(attrToAdd);
		}

		internal SvgAttribute GetAttribute(string sName)
		{
			for (int i = 0; i < m_attributes.Count; i++ )
			{
				SvgAttribute attr = (SvgAttribute) m_attributes[i];
				if ( attr.Name == sName )
				{
					return attr;
				}
			}
			
			return null;
		}

		internal SvgAttribute GetAttribute(SvgAttribute._SvgAttribute type)
		{
			for (int i = 0; i < m_attributes.Count; i++ )
			{
				SvgAttribute attr = (SvgAttribute) m_attributes[i];
				if ( attr.AttributeType == type )
				{
					return attr;
				}
			}
			
			return null;
		}
		internal bool SetAttributeValue(string sName, string sValue)
		{
			bool bReturn = false;

			for (int i = 0; i < m_attributes.Count; i++ )
			{
				SvgAttribute attr = (SvgAttribute) m_attributes[i];
				if ( attr.Name == sName )
				{
					switch (attr.AttributeDataType)
					{
						case SvgAttribute._SvgAttributeDataType.datatypeString:
						case SvgAttribute._SvgAttributeDataType.datatypeHRef:
							attr.Value = sValue;
							if (attr.AttributeType == SvgAttribute._SvgAttribute.attrStyle_Style)
								ParseStyle(sValue);
							break;

						case SvgAttribute._SvgAttributeDataType.datatypeEnum:
							int nValue = 0;
							try
							{
								nValue = Convert.ToInt32(sValue);
							}
							catch
							{
							}

							attr.Value = nValue;
							break;

						case SvgAttribute._SvgAttributeDataType.datatypeColor:

							if (sValue == "")
							{
								attr.Value = Color.Transparent;
							}
							else
							{
								Color c = attr.String2Color(sValue);
								attr.Value = c;
							}
							break;
					}

					bReturn = true;

					break;
				}
			}
			
			return bReturn;
		}

		internal bool SetAttributeValue(SvgAttribute._SvgAttribute type, object objValue)
		{
			bool bReturn = false;

			for (int i = 0; i < m_attributes.Count; i++ )
			{
				SvgAttribute attr = (SvgAttribute) m_attributes[i];
				if ( attr.AttributeType == type )
				{
					bReturn = true;
					attr.Value = objValue;

					break;
				}
			}
			
			return bReturn;
		}

		internal bool GetAttributeValue(SvgAttribute._SvgAttribute type, out object objValue)
		{
			bool bReturn = false;
			objValue = null;

			for (int i = 0; i < m_attributes.Count; i++ )
			{
				SvgAttribute attr = (SvgAttribute) m_attributes[i];
				if ( attr.AttributeType == type )
				{
					bReturn = true;
					objValue = attr.Value;

					break;
				}
			}
			
			return bReturn;
		}

		internal object GetAttributeValue(SvgAttribute._SvgAttribute type)
		{
			object objValue;

			if ( GetAttributeValue(type, out objValue) )
			{
				return objValue;
			}
			else
			{
				return null;
			}
		}

		internal string GetAttributeStringValue(SvgAttribute._SvgAttribute type)
		{
			object objValue = GetAttributeValue(type);

			if ( objValue != null )
			{
				return objValue.ToString();
			}
			else
			{
				return "";
			}
		}

		internal int GetAttributeIntValue(SvgAttribute._SvgAttribute type)
		{
			object objValue = GetAttributeValue(type);

			if ( objValue != null )
			{
				int nValue = 0;
				try
				{
					nValue = Convert.ToInt32(objValue.ToString());
				}
				catch
				{
				}

				return nValue;
			}
			else
			{
				return 0;
			}
		}

		internal Color GetAttributeColorValue(SvgAttribute._SvgAttribute type)
		{
			object objValue = GetAttributeValue(type);

			if ( objValue != null )
			{
				Color cValue = Color.Black;
				try
				{
					cValue = (Color) (objValue);
				}
				catch
				{
				}

				return cValue;
			}
			else
			{
				return Color.Black;
			}
		}

		// ---------- PRIVATE METHODS END
		public virtual void ParseStyle(string sval)
		{
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
Singapore Singapore
He is a Microsoft technology enthusiast, who wish to create applications which others find useful.He loves making small tools and getting involved in architecting bigger systems.

He is currently working as a professional developer in a software development firm in .Net technologies.

He likes reading technical blogs, contributing to opensource and most importantly, enjoying life.

His ambition is to be an impressive software maker.

Comments and Discussions