public bool ProcessIconSingle(XmlNode Element, ref _Icon Icon)
        {
            bool Result = true;

            try
            {
                SetString(Element, "Filename", ref Icon.OutputFilename, true);
                SetInt(Element, "Level", ref Icon.Level, false);
                foreach (XmlNode Node in Element.ChildNodes)
                    ProcessIcon(Node, ref Icon, true);
            }
            catch (Exception e)
            {
                Console.WriteLine("");
                Console.WriteLine(e.Message);
                Result = false;
            }

            return Result;
        }
        public bool ProcessIconRange(XmlNode Element, ref _Icon Icon, bool Required)
        {
            bool Result = true;

            try
            {
                SetInt(Element, "Max", ref Icon.Level, true);
                foreach (XmlNode Node in Element.ChildNodes)
                    ProcessIcon(Node, ref Icon, Required);
            }
            catch (Exception e)
            {
                Console.WriteLine("");
                Console.WriteLine(e.Message);
                Result = false;
            }

            return Result;
        }
        public bool LoadConfigFile(string ConfigFileName)
        {
            bool Result = true;

            try
            {
                int i;
                _Icon Item = new _Icon();
                XmlDocument Document = new XmlDocument();
                Document.Load(ConfigFileName);

                SingleIcons = new List<_Icon>();
                PercentIcons.Initialize();
                ChargeIcons.Initialize();

                XmlNode Node = Document.GetElementsByTagName("Output")[0];
                SetString(Node, "Folder", ref OutputFolder, true);
                SetString(Node, "Preview", ref PreviewFile, false);

                Node = Document.GetElementsByTagName("SingleIcons")[0];
                if (Node != null)
                {
                    foreach (XmlNode Single in Node.ChildNodes)
                    {
                        if (Single.Name == "Icon")
                        {
                            Item.Initialize();
                            ProcessIconSingle(Single, ref Item);
                            SingleIcons.Add(Item);
                        }
                    }
                }

                Node = Document.GetElementsByTagName("PercentIcons")[0];
                if (Node != null)
                {
                    SetString(Node, "Filename", ref PercentIcons.OutputFilename, true);
                    SetInt(Node, "StartLevel", ref PercentIcons.StartLevel, false);
                    SetInt(Node, "Step", ref PercentIcons.Step, false);

                    Item.Initialize();
                    i = 0;
                    foreach (XmlNode Percent in Node.ChildNodes)
                    {
                        if (Percent.Name == "Level")
                        {
                            if (ProcessIconRange(Percent, ref Item, (i == 0)))
                                PercentIcons.Icons.Add(Item);
                            ++i;
                        }
                    }
                }

                Node = Document.GetElementsByTagName("ChargeIcons")[0];
                if (Node != null)
                {
                    SetString(Node, "Filename", ref ChargeIcons.OutputFilename, true);
                    SetInt(Node, "StartLevel", ref ChargeIcons.StartLevel, false);
                    SetInt(Node, "Step", ref ChargeIcons.Step, false);

                    Item.Initialize();
                    i = 0;
                    foreach (XmlNode Charge in Node.ChildNodes)
                    {
                        if (Charge.Name == "Level")
                        {
                            if (ProcessIconRange(Charge, ref Item, (i == 0)))
                                ChargeIcons.Icons.Add(Item);
                            ++i;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("");
                Console.WriteLine(e.Message);
                Result = false;
            }

            return Result;
        }
        public void ProcessIcon(XmlNode Node, ref _Icon Icon, bool Required)
        {
            switch (Node.Name.ToLower())
            {
                case "background":
                    SetString(Node, "Filename", ref Icon.TemplateFilename, Required);
                    break;

                case "overlay":
                    SetString(Node, "Filename", ref Icon.OverlayFilename, false);
                    SetBool(Node, "OverlayUnderText", ref Icon.OverlayUnderText, false);
                    break;

                case "bar":
                    SetInt(Node, "StartX", ref Icon.StartX, false);
                    SetInt(Node, "StartY", ref Icon.StartY, false);
                    SetInt(Node, "EndX", ref Icon.EndX, false);
                    SetInt(Node, "EndY", ref Icon.EndY, false);
                    SetString(Node, "Filename", ref Icon.BarFilename, Required);
                    SetInt(Node, "StartRotate", ref Icon.StartRotate, false);
                    SetInt(Node, "EndRotate", ref Icon.EndRotate, false);
                    SetInt(Node, "DrawCount", ref Icon.DrawCount, false);
                    SetInt(Node, "SkipCount", ref Icon.SkipCount, false);
                    break;

                case "text":
                    SetString(Node, "Color", ref Icon.FontColor, Required);
                    SetString(Node, "Font", ref Icon.FontFamily, Required);
                    SetFloat(Node, "Size", ref Icon.FontSize, Required);
                    SetBool(Node, "Italic", ref Icon.Italic, Required);
                    SetBool(Node, "Bold", ref Icon.Bold, Required);
                    SetString(Node, "FormatString", ref Icon.FormatString, Required);
                    SetBool(Node, "CenterX", ref Icon.CenterX, Required);
                    SetBool(Node, "CenterY", ref Icon.CenterY, Required);
                    SetInt(Node, "OffsetX", ref Icon.OffsetX, Required);
                    SetInt(Node, "OffsetY", ref Icon.OffsetY, Required);
                    break;

                default:
                    break;
            }
        }
        static void CreateIcon(_Icon Icon, string OutputFolder, string OutputFilename,
            int Level, ref Size MaxSize)
        {
            //  Make sure that the template file exists.

            if (!File.Exists(Icon.TemplateFilename))
                throw new Exception("Template file '" + Icon.TemplateFilename + "' does not exist");

            //  If a graphic bar file is specified, make sure that it exists.

            if (!String.IsNullOrEmpty(Icon.BarFilename))
            {
                if (!File.Exists(Icon.BarFilename))
                    throw new Exception("Bar file '" + Icon.BarFilename + "' does not exist");
            }

            //  If an overlay file is specified, make sure that it exists.

            if (!String.IsNullOrEmpty(Icon.OverlayFilename))
            {
                if (!File.Exists(Icon.OverlayFilename))
                    throw new Exception("Overlay file '" + Icon.OverlayFilename + "' does not exist");
            }

            //  Create a bitmap object from the template file.

            System.Drawing.Bitmap b = (Bitmap) System.Drawing.Bitmap.FromFile(Icon.TemplateFilename);

            //  Adjust the maximum width and height to the dimensions of the bitmap.

            if (b.Width > MaxSize.Width)
                MaxSize.Width = b.Width;
            if (b.Height > MaxSize.Height)
                MaxSize.Height = b.Height;

            //  Create a graphics object out of the bitmap.

            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(b);
            Image bar = null;

            //  If an overlay file is specified, make sure that it exists.  If it does,
            //  create an image object from it (to be used later).

            Image o = null;
            if (!String.IsNullOrEmpty(Icon.OverlayFilename))
                o = Image.FromFile(Icon.OverlayFilename);

            //  If a graphics bar file was specified, use it to fill the dimensions
            //  specified in the config file. The fill action is based on both the icon
            //  type (circular or horizontal/vertical) and the percentage level.

            if (!String.IsNullOrEmpty(Icon.BarFilename))
            {
                int count = Icon.DrawCount;
                bool draw = true;

                if ((Icon.StartRotate != 0) || (Icon.EndRotate != 0))
                {
                    //  Fill a rotating circular icon.

                    for (float tmp = 0; tmp <= Level; tmp++)
                    {
                        if (--count <= 0)
                        {
                            draw = !draw;
                            count = (draw ? Icon.DrawCount : Icon.SkipCount);
                        }
                        if (draw)
                        {
                            bar = Image.FromFile(Icon.BarFilename);
                            float angle = Icon.StartRotate + ((Icon.EndRotate - Icon.StartRotate) * (tmp / 100f));
                            Graphics g2 = Graphics.FromImage(bar);
                            g2.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                            g2.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;

                            g2.TranslateTransform((float)bar.Width / 2, (float)bar.Height / 2);
                            //rotate
                            g2.RotateTransform(angle);
                            //move image back
                            g2.TranslateTransform(-(float)bar.Width / 2, -(float)bar.Height / 2);
                            g2.DrawImage(bar, 0, 0);
                            g.DrawImage(bar, Icon.StartX, Icon.StartY);
                        }
                    }
                }
                else
                {
                    //  Fill a horizontal/vertical icon.

                    int TempX = (Icon.EndX - Icon.StartX);
                    int TempY = (Icon.EndY - Icon.StartY);
                    //if (Icon.EndX != Icon.StartX)
                    //    ++TempX;
                    //if (Icon.EndY != Icon.StartY)
                    //    ++TempY;
                    float x_incr = TempX / 100f;
                    float y_incr = TempY / 100f;
                    bar = Image.FromFile(Icon.BarFilename);

                    //g.PageUnit = GraphicsUnit.Pixel;
                    for (float tmp = 0; tmp <= Level; tmp++)
                    {
                        if (--count <= 0)
                        {
                            draw = !draw;
                            count = (draw ? Icon.DrawCount : Icon.SkipCount);
                        }
                        if (draw)
                        {
                            PointF BarPos = new PointF(x_incr * tmp + Icon.StartX,
                                                       y_incr * tmp + Icon.StartY);
                            g.DrawImage(bar, new RectangleF(BarPos, bar.Size),
                                             new RectangleF(new PointF(), bar.Size),
                                             GraphicsUnit.Pixel);
                        }
                    }
                }

                bar.Dispose();
            }

            //  If an overlay file was specified, draw it onto the bitmap before drawing
            //  the text (if OverlayUnderText is TRUE).

            if ((o != null) && Icon.OverlayUnderText)
            {
                Image inp = (Image) b;
                Image outp = MergeTwoImages(inp, o);
                b = (Bitmap) outp;
                g = System.Drawing.Graphics.FromImage(b);
            }

            //  If a font was specified, draw the specified text onto the bitmap using
            //  the font, size, style, and coordinates specified. The FormatString will
            //  be used to create a string with the percentage value, but if there is
            //  no C# formatting information in it, only the text of the string itself
            //  will be drawn (i.e. "{0:0}%" will show "100%" but "FULL" will show "FULL").

            if (!String.IsNullOrEmpty(Icon.FontFamily))
            {
                float X, Y;

                //  Create a brush object based on the specified color.

                SolidBrush brush = new SolidBrush(System.Drawing.ColorTranslator.FromHtml("#" + Icon.FontColor));

                //  Create a style based on the bold/italic specifiers.

                FontStyle fs = FontStyle.Regular;
                if (Icon.Bold)
                    fs |= FontStyle.Bold;
                if (Icon.Italic)
                    fs |= FontStyle.Italic;

                //  Create a font object based on the specified font family, size, and style.

                Font font = new Font(Icon.FontFamily, Icon.FontSize, fs);

                //  Create the string to be drawn based on the FormatString and percentage
                //  level, as described above.

                string pct_text = String.Format(Icon.FormatString, Level);
                SizeF sz = g.MeasureString(pct_text, font);

                //  Draw the string onto the graphics object.

                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                if (Icon.CenterX)
                    X = ((b.Width - sz.Width) / 2) + Icon.OffsetX;
                else
                    X = Icon.OffsetX;
                if (Icon.CenterY)
                    Y = ((b.Height - sz.Height) / 2) + Icon.OffsetY;
                else
                    Y = Icon.OffsetY;
                g.DrawString(pct_text, font, brush, new PointF(X, Y));
            }

            //  Save all current changes to the graphics object.

            g.Save();

            //  If an overlay file was specified, draw it onto the bitmap after drawing
            //  the text (if OverlayUnderText is FALSE or not specified).

            if ((o != null) && !Icon.OverlayUnderText)
            {
                Image inp = (Image) b;
                Image outp = MergeTwoImages(inp, o);
                b = (Bitmap) outp;
            }

            //  Write the bitmap object to disk as a PNG file.

            b.Save(Path.Combine(OutputFolder, String.Format(OutputFilename, Level)));

            //  Dispose of the graphics and bitmap objects.

            g.Dispose();
            b.Dispose();
        }