Utility.cs :  » GUI » Paint.net » PaintDotNet » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » GUI » Paint.net 
Paint.net » PaintDotNet » Utility.cs
/////////////////////////////////////////////////////////////////////////////////
// Paint.NET                                                                   //
// Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors.     //
// Portions Copyright (C) Microsoft Corporation. All Rights Reserved.          //
// See src/Resources/Files/License.txt for full licensing and attribution      //
// details.                                                                    //
// .                                                                           //
/////////////////////////////////////////////////////////////////////////////////

using Microsoft.Win32;
using PaintDotNet.Threading;
using PaintDotNet.SystemLayer;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace PaintDotNet{
    /// <summary>
    /// Defines miscellaneous constants and static functions.
    /// </summary>
    /// // TODO: refactor into mini static classes
    public sealed class Utility
    {
        private Utility()
        {
        }

        internal static bool IsNumber(float x)
        {
            return x >= float.MinValue && x <= float.MaxValue;
        }

        internal static bool IsNumber(double x)
        {
            return x >= double.MinValue && x <= double.MaxValue;
        }

        internal static int Min(int val0, params int[] vals)
        {
            int min = val0;

            for (int i = 0; i < vals.Length; ++i)
            {
                if (vals[i] < min)
                {
                    min = vals[i];
                }
            }

            return min;
        }

        internal static int Max(int val0, params int[] vals)
        {
            int max = val0;

            for (int i = 0; i < vals.Length; ++i)
            {
                if (vals[i] > max)
                {
                    max = vals[i];
                }
            }

            return max;
        }

        public static PointF[] GetRgssOffsets(int quality)
        {
            unsafe
            {
                int sampleCount = quality * quality;
                PointF[] samplesArray = new PointF[sampleCount];

                fixed (PointF* pSamplesArray = samplesArray)
                {
                    GetRgssOffsets(pSamplesArray, sampleCount, quality);
                }

                return samplesArray;
            }
        }

        public static unsafe void GetRgssOffsets(PointF* samplesArray, int sampleCount, int quality)
        {
            if (sampleCount < 1)
            {
                throw new ArgumentOutOfRangeException("sampleCount", "sampleCount must be [0, int.MaxValue]");
            }

            if (sampleCount != quality * quality)
            {
                throw new ArgumentOutOfRangeException("sampleCount != (quality * quality)");
            }

            if (sampleCount == 1)
            {
                samplesArray[0] = new PointF(0.0f, 0.0f);
            }
            else
            {
                for (int i = 0; i < sampleCount; ++i)
                {
                    double y = (i + 1d) / (sampleCount + 1d);
                    double x = y * quality;

                    x -= (int)x;

                    samplesArray[i] = new PointF((float)(x - 0.5d), (float)(y - 0.5d));
                }
            }
        }

        public static bool IsObsolete(Type type, bool inherit)
        {
            object[] attrs = type.GetCustomAttributes(typeof(ObsoleteAttribute), inherit);
            return (attrs.Length != 0);
        }

        public static void DrawDropShadow1px(Graphics g, Rectangle rect)
        {
            Brush b0 = new SolidBrush(Color.FromArgb(15, Color.Black));
            Brush b1 = new SolidBrush(Color.FromArgb(47, Color.Black));
            Pen p2 = new Pen(Color.FromArgb(63, Color.Black));

            g.FillRectangle(b0, rect.Left, rect.Top, 1, 1);
            g.FillRectangle(b1, rect.Left + 1, rect.Top, 1, 1);
            g.FillRectangle(b1, rect.Left, rect.Top + 1, 1, 1);

            g.FillRectangle(b0, rect.Right - 1, rect.Top, 1, 1);
            g.FillRectangle(b1, rect.Right - 2, rect.Top, 1, 1);
            g.FillRectangle(b1, rect.Right - 1, rect.Top + 1, 1, 1);

            g.FillRectangle(b0, rect.Left, rect.Bottom - 1, 1, 1);
            g.FillRectangle(b1, rect.Left + 1, rect.Bottom - 1, 1, 1);
            g.FillRectangle(b1, rect.Left, rect.Bottom - 2, 1, 1);

            g.FillRectangle(b0, rect.Right - 1, rect.Bottom - 1, 1, 1);
            g.FillRectangle(b1, rect.Right - 2, rect.Bottom - 1, 1, 1);
            g.FillRectangle(b1, rect.Right - 1, rect.Bottom - 2, 1, 1);

            g.DrawLine(p2, rect.Left + 2, rect.Top, rect.Right - 3, rect.Top);
            g.DrawLine(p2, rect.Left, rect.Top + 2, rect.Left, rect.Bottom - 3);
            g.DrawLine(p2, rect.Left + 2, rect.Bottom - 1, rect.Right - 3, rect.Bottom - 1);
            g.DrawLine(p2, rect.Right - 1, rect.Top + 2, rect.Right - 1, rect.Bottom - 3);

            b0.Dispose();
            b0 = null;
            b1.Dispose();
            b1 = null;
            p2.Dispose();
            p2 = null;
        }

        public static Keys LetterOrDigitCharToKeys(char c)
        {
            if (c >= 'a' && c <= 'z')
            {
                return (Keys)((int)(c - 'a') + (int)Keys.A);
            }
            else if (c >= 'A' && c <= 'Z')
            {
                return (Keys)((int)(c - 'A') + (int)Keys.A);
            }
            else if (c >= '0' && c <= '9')
            {
                return (Keys)((int)(c - '0') + (int)Keys.D0);
            }
            else
            {
                return Keys.None;
            }
        }

        public static Control FindFocus()
        {
            foreach (Form form in Application.OpenForms)
            {
                Control focused = FindFocus(form);

                if (focused != null)
                {
                    return focused;
                }
            }

            return null;
        }

        private static Control FindFocus(Control c)
        {
            if (c.Focused)
            {
                return c;
            }

            foreach (Control child in c.Controls)
            {
                Control f = FindFocus(child);

                if (f != null)
                {
                    return f;
                }
            }

            return null;
        }

        public static void DrawColorRectangle(Graphics g, Rectangle rect, Color color, bool drawBorder)
        {
            int inflateAmt = drawBorder ? -2 : 0;
            Rectangle colorRectangle = Rectangle.Inflate(rect, inflateAmt, inflateAmt);
            Brush colorBrush = new LinearGradientBrush(colorRectangle, Color.FromArgb(255, color), color, 90.0f, false);
            HatchBrush backgroundBrush = new HatchBrush(HatchStyle.LargeCheckerBoard, Color.FromArgb(191, 191, 191), Color.FromArgb(255, 255, 255));

            if (drawBorder)
            {
                g.DrawRectangle(Pens.Black, rect.Left, rect.Top, rect.Width - 1, rect.Height - 1);
                g.DrawRectangle(Pens.White, rect.Left + 1, rect.Top + 1, rect.Width - 3, rect.Height - 3);
            }

            PixelOffsetMode oldPOM = g.PixelOffsetMode;
            g.PixelOffsetMode = PixelOffsetMode.Half;
            g.FillRectangle(backgroundBrush, colorRectangle);
            g.FillRectangle(colorBrush, colorRectangle);
            g.PixelOffsetMode = oldPOM;

            backgroundBrush.Dispose();
            colorBrush.Dispose();
        }

        public static Size ComputeThumbnailSize(Size originalSize, int maxEdgeLength)
        {
            Size thumbSize;

            if (originalSize.Width > originalSize.Height)
            {
                int longSide = Math.Min(originalSize.Width, maxEdgeLength);
                thumbSize = new Size(longSide, Math.Max(1, (originalSize.Height * longSide) / originalSize.Width));
            }
            else if (originalSize.Height > originalSize.Width)
            {
                int longSide = Math.Min(originalSize.Height, maxEdgeLength);
                thumbSize = new Size(Math.Max(1, (originalSize.Width * longSide) / originalSize.Height), longSide);
            }
            else // if (docSize.Width == docSize.Height)
            {
                int longSide = Math.Min(originalSize.Width, maxEdgeLength);
                thumbSize = new Size(longSide, longSide);
            }

            return thumbSize;
        }

        public static bool IsClipboardImageAvailable()
        {
            try
            {
                return System.Windows.Forms.Clipboard.ContainsImage() || 
                    System.Windows.Forms.Clipboard.ContainsData(DataFormats.EnhancedMetafile);
            }

            catch (ExternalException)
            {
                return false;
            }
        }

        public static Font CreateFont(string name, float size, FontStyle style)
        {
            Font returnFont;

            try
            {
                returnFont = new Font(name, size, style);
            }

            catch (Exception)
            {
                returnFont = new Font(FontFamily.GenericSansSerif, size);
            }

            return returnFont;
        }

        public static Font CreateFont(string name, float size, string backupName, float backupSize, FontStyle style)
        {
            Font returnFont;

            try
            {
                returnFont = new Font(name, size, style);
            }

            catch (Exception)
            {
                returnFont = CreateFont(backupName, backupSize, style);
            }

            return returnFont;
        }
        
        public static readonly Color TransparentKey = Color.FromArgb(192, 192, 192);

        public static string WebExceptionToErrorMessage(WebException wex)
        {
            string errorMessage;

            switch (wex.Status)
            {
                case WebExceptionStatus.ProtocolError:
                    string format = PdnResources.GetString("WebExceptionStatus.ProtocolError.Format");
                    HttpStatusCode statusCode = ((HttpWebResponse)wex.Response).StatusCode;
                    errorMessage = string.Format(format, statusCode.ToString(), (int)statusCode);
                    break;

                default:
                    string stringName = "WebExceptionStatus." + wex.Status.ToString();
                    errorMessage = PdnResources.GetString(stringName);
                    break;
            }

            return errorMessage;
        }

        private static bool allowGCFullCollect = true;
        public static bool AllowGCFullCollect
        {
            get
            {
                return allowGCFullCollect;
            }

            set
            {
                allowGCFullCollect = value;
            }
        }

        public static void GCFullCollect()
        {
            if (AllowGCFullCollect)
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }
        }

        private static int defaultSimplificationFactor = 50;
        public static int DefaultSimplificationFactor
        {
            get
            {
                return defaultSimplificationFactor;
            }

            set
            {
                defaultSimplificationFactor = value;
            }
        }

        public static bool IsArrowKey(Keys keyData)
        {
            Keys key = keyData & Keys.KeyCode;

            if (key == Keys.Up || key == Keys.Down || key == Keys.Left || key == Keys.Right)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public static bool DoesControlHaveMouseCaptured(Control control)
        {
            bool result = false;

            result |= control.Capture;

            foreach (Control c in control.Controls)
            {
                result |= DoesControlHaveMouseCaptured(c);
            }

            return result;
        }

        public static void SplitRectangle(Rectangle rect, Rectangle[] rects)
        {
            int height = rect.Height;

            for (int i = 0; i < rects.Length; ++i)
            {
                Rectangle newRect = Rectangle.FromLTRB(rect.Left,
                                                       rect.Top + ((height * i) / rects.Length),
                                                       rect.Right,
                                                       rect.Top + ((height * (i + 1)) / rects.Length));

                rects[i] = newRect;
            }
        }

        public static long TicksToMs(long ticks)
        {
            return ticks / 10000;
        }

        public static string GetStaticName(Type type)
        {
            PropertyInfo pi = type.GetProperty("StaticName", BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty);
            return (string)pi.GetValue(null, null);
        }

        public static readonly float[][] Identity5x5F = new float[][] {
                                                                          new float[] { 1, 0, 0, 0, 0 },
                                                                          new float[] { 0, 1, 0, 0, 0 },
                                                                          new float[] { 0, 0, 1, 0, 0 },
                                                                          new float[] { 0, 0, 0, 1, 0 },
                                                                          new float[] { 0, 0, 0, 0, 1 } 
                                                                      };

        public static readonly ColorMatrix IdentityColorMatrix = new ColorMatrix(Identity5x5F);

        [ThreadStatic]
        private static Matrix identityMatrix = null;
        public static Matrix IdentityMatrix
        {
            get
            {
                if (identityMatrix == null)
                {
                    identityMatrix = new Matrix();
                    identityMatrix.Reset();
                }

                return identityMatrix;
            }
        }

        /// <summary>
        /// Rounds an integer to the smallest power of 2 that is greater
        /// than or equal to it.
        /// </summary>
        public static int Log2RoundUp(int x)
        {
            if (x == 0)
            {
                return 1;
            }

            if (x == 1)
            {
                return 1;
            }

            return 1 << (1 + HighestBit(x - 1));
        }

        private static int HighestBit(int x)
        {
            if (x == 0)
            {
                return 0;
            }

            int b = 0;
            int hi = 0;

            while (b <= 30)
            {
                if ((x & (1 << b)) != 0)
                {
                    hi = b;
                }

                ++b;
            }

            return hi;
        }

        private int CountBits(int x)
        {
            uint y = (uint)x;
            int count = 0;

            for (int bit = 0; bit < 32; ++bit)
            {
                if ((y & ((uint)1 << bit)) != 0)
                {
                    ++count;
                }
            }

            return count;
        }

        public static string RemoveSpaces(string s)
        {
            StringBuilder sb = new StringBuilder();

            foreach (char c in s)
            {
                if (!char.IsWhiteSpace(c))
                {
                    sb.Append(c);
                }
            }

            return sb.ToString();
        }
        
        public static int Max(int[,] array)
        {
            int max = int.MinValue;

            for (int i = array.GetLowerBound(0); i <= array.GetUpperBound(0); ++i)
            {
                for (int j = array.GetLowerBound(1); j <= array.GetUpperBound(1); ++j)
                {
                    if (array[i,j] > max)
                    {
                        max = array[i,j];
                    }
                }
            }

            return max;
        }

        public static int Sum(int[][] array)
        {
            int sum = 0;

            for (int i = 0; i < array.Length; ++i)
            {
                int[] row = array[i];

                for (int j = 0; j < row.Length; ++j)
                {
                    sum += row[j];
                }
            }

            return sum;
        }

        // TODO: obsolete these NUD funcitons, move them into PdnNumericUpDown
        public static void ClipNumericUpDown(NumericUpDown upDown)
        {
            if (upDown.Value < upDown.Minimum)
            {
                upDown.Value = upDown.Minimum;
            }
            else if (upDown.Value > upDown.Maximum)
            {
                upDown.Value = upDown.Maximum;
            }
        }

        public static bool GetUpDownValueFromText(NumericUpDown nud, out double val)
        {
            if (nud.Text == string.Empty)
            {
                val = 0;
                return false;
            }
            else
            {
                try
                {
                    if (nud.DecimalPlaces == 0)
                    {
                        val = (double)int.Parse(nud.Text);
                    }
                    else
                    {
                        val = double.Parse(nud.Text);
                    }
                }

                catch
                {
                    val = 0;
                    return false;
                }

                return true;
            }
        }

        public static bool CheckNumericUpDown(NumericUpDown upDown)
        {
            int a;
            bool result = int.TryParse(upDown.Text, out a);

            if (result && (a <= (int)upDown.Maximum) && (a >= (int)upDown.Minimum))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public static void SetNumericUpDownValue(NumericUpDown upDown, decimal newValue)
        {
            if (upDown.Value != newValue)
            {
                upDown.Value = newValue;
            }
        }

        public static void SetNumericUpDownValue(NumericUpDown upDown, int newValue)
        {
            SetNumericUpDownValue(upDown, (decimal)newValue);
        }

        public static string SizeStringFromBytes(long bytes)
        {
            double bytesDouble = (double)bytes;
            string toStringFormat;
            string formatString;

            if (bytesDouble > (1024 * 1024 * 1024))
            {
                // Gigs
                bytesDouble /= 1024 * 1024 * 1024;
                toStringFormat = "F1";
                formatString = PdnResources.GetString("Utility.SizeStringFromBytes.GBFormat");
            }
            else if (bytesDouble > (1024 * 1024))
            {
                // Megs
                bytesDouble /= 1024 * 1024;
                toStringFormat = "F1";
                formatString = PdnResources.GetString("Utility.SizeStringFromBytes.MBFormat");
            }
            else if (bytesDouble > (1024))
            {
                // K
                bytesDouble /= 1024;
                toStringFormat = "F1";
                formatString = PdnResources.GetString("Utility.SizeStringFromBytes.KBFormat");
            }
            else
            {
                // Bytes
                toStringFormat = "F0";
                formatString = PdnResources.GetString("Utility.SizeStringFromBytes.BytesFormat");
            }

            string bytesString = bytesDouble.ToString(toStringFormat);
            string sizeString = string.Format(formatString, bytesString);

            return sizeString;
        }

        public static void ShowWiaError(IWin32Window owner)
        {
            // WIA requires Windows XP SP1 or later, or Windows Server 2003
            // So if we know they're on WS2k3, we tell them to enable WIA.
            // If they're on XP or later, tell them that WIA isn't available.
            // Otherwise we tell them they need XP SP1 (for the Win2K folks).
            if (OS.Type == OSType.Server)
            {
                Utility.ErrorBox(owner, PdnResources.GetString("WIA.Error.EnableMe"));
            }
            else
            {
                Utility.ErrorBox(owner, PdnResources.GetString("WIA.Error.UnableToLoad"));
            }
        }

        public static void ShowNonAdminErrorBox(IWin32Window parent)
        {
            ErrorBox(parent, PdnResources.GetString("NonAdminErrorBox.Message"));
        }

        public static void ErrorBox(IWin32Window parent, string message)
        {
            MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        public static DialogResult ErrorBoxOKCancel(IWin32Window parent, string message)
        {
            return MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
        }

        public static void InfoBox(IWin32Window parent, string message)
        {
            MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        public static DialogResult InfoBoxOKCancel(IWin32Window parent, string message)
        {
            return MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
        }

        public static DialogResult AskOKCancel(IWin32Window parent, string question)
        {
            return MessageBox.Show(parent, question, PdnInfo.GetBareProductName(), MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
        }

        public static DialogResult AskYesNo(IWin32Window parent, string question)
        {
            return MessageBox.Show(parent, question, PdnInfo.GetBareProductName(), MessageBoxButtons.YesNo, MessageBoxIcon.Question);
        }

        public static DialogResult AskYesNoCancel(IWin32Window parent, string question)
        {
            return MessageBox.Show(parent, question, PdnInfo.GetBareProductName(), MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
        }

        public static Icon ImageToIcon(Image image)
        {
            return ImageToIcon(image, Utility.TransparentKey);
        }

        public static Icon ImageToIcon(Image image, bool disposeImage)
        {
            return ImageToIcon(image, Utility.TransparentKey, disposeImage);
        }

        public static Icon ImageToIcon(Image image, Color seeThru)
        {
            return ImageToIcon(image, seeThru, false);
        }

        /// <summary>
        /// Converts an Image to an Icon.
        /// </summary>
        /// <param name="image">The Image to convert to an icon. Must be an appropriate icon size (32x32, 16x16, etc).</param>
        /// <param name="seeThru">The color that will be treated as transparent in the icon.</param>
        /// <param name="disposeImage">Whether or not to dispose the passed-in Image.</param>
        /// <returns>An Icon representation of the Image.</returns>
        public static Icon ImageToIcon(Image image, Color seeThru, bool disposeImage)
        {
            Bitmap bitmap = new Bitmap(image);

            for (int y = 0; y < bitmap.Height; ++y)
            {
                for (int x = 0; x < bitmap.Width; ++x)
                {
                    if (bitmap.GetPixel(x, y) == seeThru)
                    {
                        bitmap.SetPixel(x, y, Color.FromArgb(0));
                    }
                }
            }

            Icon icon = Icon.FromHandle(bitmap.GetHicon());
            bitmap.Dispose();

            if (disposeImage)
            {
                image.Dispose();
            }

            return icon;
        }

        public static Icon BitmapToIcon(Bitmap bitmap, bool disposeBitmap)
        {
            Icon icon = Icon.FromHandle(bitmap.GetHicon());

            if (disposeBitmap)
            {
                bitmap.Dispose();
            }

            return icon;
        }

        public static Icon SurfaceToIcon(Surface surface, bool disposeSurface)
        {
            Bitmap bitmap = surface.CreateAliasedBitmap();
            Icon icon = Icon.FromHandle(bitmap.GetHicon());

            bitmap.Dispose();

            if (disposeSurface)
            {
                surface.Dispose();
            }

            return icon;
        }

        public static Point GetRectangleCenter(Rectangle rect)
        {
            return new Point((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2);
        }

        public static PointF GetRectangleCenter(RectangleF rect)
        {
            return new PointF((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2);
        }

        public static Scanline[] GetRectangleScans(Rectangle rect)
        {
            Scanline[] scans = new Scanline[rect.Height];

            for (int y = 0; y < rect.Height; ++y)
            {
                scans[y] = new Scanline(rect.X, rect.Y + y, rect.Width);
            }

            return scans;
        }

        public static Scanline[] GetRegionScans(Rectangle[] region)
        {
            int scanCount = 0;

            for (int i = 0; i < region.Length; ++i)
            {
                scanCount += region[i].Height;
            }

            Scanline[] scans = new Scanline[scanCount];
            int scanIndex = 0;

            foreach (Rectangle rect in region)
            {
                for (int y = 0; y < rect.Height; ++y)
                {
                    scans[scanIndex] = new Scanline(rect.X, rect.Y + y, rect.Width);
                    ++scanIndex;
                }
            }

            return scans;
        }

        public static Rectangle[] ScanlinesToRectangles(Scanline[] scans)
        {
            return ScanlinesToRectangles(scans, 0, scans.Length);
        }

        public static Rectangle[] ScanlinesToRectangles(Scanline[] scans, int startIndex, int length)
        {
            Rectangle[] rects = new Rectangle[length];

            for (int i = 0; i < length; ++i)
            {
                Scanline scan = scans[i + startIndex];
                rects[i] = new Rectangle(scan.X, scan.Y, scan.Length, 1);
            }

            return rects;
        }

        /// <summary>
        /// Found on Google Groups when searching for "Region.Union" while looking
        /// for bugs:
        /// ---
        /// Hello,
        /// 
        /// I did not run your code, but I know Region.Union is flawed in both 1.0 and
        /// 1.1, so I assume it is in the gdi+ unmanged code dll.  The best workaround,
        /// in terms of speed, is to use a PdnGraphicsPath, but it must be a path with
        /// FillMode = FillMode.Winding. You add the rectangles to the path, then you do
        /// union onto an empty region with the path. The important point is to do only
        /// one union call on a given empty region. We created a "super region" object
        /// to hide all these bugs and optimize clipping operations. In fact, it is much
        /// faster to use the path than to call Region.Union for each rectangle.
        /// 
        /// Too bad about Region.Union. A lot of people will hit this bug, as it is
        /// essential in high-performance animation.
        /// 
        /// Regards,
        /// Frank Hileman
        /// Prodige Software Corporation
        /// ---
        /// </summary>
        /// <param name="rectsF"></param>
        /// <param name="startIndex"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static PdnRegion RectanglesToRegion(RectangleF[] rectsF, int startIndex, int length)
        {
            PdnRegion region;

            if (rectsF == null || rectsF.Length == 0 || length == 0)
            {
                region = PdnRegion.CreateEmpty();
            }
            else
            {
                using (PdnGraphicsPath path = new PdnGraphicsPath())
                {
                    path.FillMode = FillMode.Winding;

                    if (startIndex == 0 && length == rectsF.Length)
                    {
                        path.AddRectangles(rectsF);
                    }
                    else
                    {
                        for (int i = startIndex; i < startIndex + length; ++i)
                        {
                            path.AddRectangle(rectsF[i]);
                        }
                    }

                    region = new PdnRegion(path);
                }
            }

            return region;
        }

        public static PdnRegion RectanglesToRegion(RectangleF[] rectsF)
        {
            return RectanglesToRegion(rectsF, 0, rectsF != null ? rectsF.Length : 0);
        }

        public static PdnRegion RectanglesToRegion(RectangleF[] rectsF1, RectangleF[] rectsF2, params RectangleF[][] rectsFA)
        {
            using (PdnGraphicsPath path = new PdnGraphicsPath())
            {
                path.FillMode = FillMode.Winding;

                if (rectsF1 != null && rectsF1.Length > 0)
                {
                    path.AddRectangles(rectsF1);
                }

                if (rectsF2 != null && rectsF2.Length > 0)
                {
                    path.AddRectangles(rectsF2);
                }
               
                foreach (RectangleF[] rectsF in rectsFA)
                {
                    if (rectsF != null && rectsF.Length > 0)
                    {
                        path.AddRectangles(rectsF);
                    }
                }

                return new PdnRegion(path);
            }
        }

        public static PdnRegion RectanglesToRegion(Rectangle[] rects, int startIndex, int length)
        {
            PdnRegion region;

            if (length == 0)
            {
                region = PdnRegion.CreateEmpty();
            }
            else
            {
                using (PdnGraphicsPath path = new PdnGraphicsPath())
                {
                    path.FillMode = FillMode.Winding;
                    if (startIndex == 0 && length == rects.Length)
                    {
                        path.AddRectangles(rects);
                    }
                    else
                    {
                        for (int i = startIndex; i < startIndex + length; ++i)
                        {
                            path.AddRectangle(rects[i]);
                        }
                    }

                    region = new PdnRegion(path);
                    path.Dispose();
                }
            }

            return region;
        }

        public static PdnRegion RectanglesToRegion(Rectangle[] rects)
        {
            return RectanglesToRegion(rects, 0, rects.Length);
        }

        public static int GetRegionArea(RectangleF[] rectsF)
        {
            int area = 0;

            foreach (RectangleF rectF in rectsF)
            {
                Rectangle rect = Rectangle.Truncate(rectF);
                area += rect.Width * rect.Height;
            }

            return area;
        }

        public static RectangleF RectangleFromCenter(PointF center, float halfSize) 
        {
            RectangleF ret = new RectangleF(center.X, center.Y, 0, 0);
            ret.Inflate(halfSize, halfSize);
            return ret;
        }

        public static List<PointF> PointListToPointFList(List<Point> ptList)
        {
            List<PointF> ret = new List<PointF>(ptList.Count);

            for (int i = 0; i < ptList.Count; ++i)
            {
                ret.Add((PointF)ptList[i]);
            }

            return ret;
        }

        public static PointF[] PointArrayToPointFArray(Point[] ptArray)
        {
            PointF[] ret = new PointF[ptArray.Length];

            for (int i = 0; i < ret.Length; ++i)
            {
                ret[i] = (PointF)ptArray[i];
            }

            return ret;
        }

        public static Rectangle[] InflateRectangles(Rectangle[] rects, int amount)
        {
            Rectangle[] inflated = new Rectangle[rects.Length];

            for (int i = 0; i < rects.Length; ++i)
            {
                inflated[i] = Rectangle.Inflate(rects[i], amount, amount);
            }

            return inflated;
        }

        public static void InflateRectanglesInPlace(Rectangle[] rects, int amount)
        {
            for (int i = 0; i < rects.Length; ++i)
            {
                rects[i].Inflate(amount, amount);
            }
        }

        public static RectangleF[] InflateRectangles(RectangleF[] rectsF, int amount)
        {
            RectangleF[] inflated = new RectangleF[rectsF.Length];

            for (int i = 0; i < rectsF.Length; ++i)
            {
                inflated[i] = RectangleF.Inflate(rectsF[i], amount, amount);
            }

            return inflated;
        }

        public static void InflateRectanglesInPlace(RectangleF[] rectsF, float amount)
        {
            for (int i = 0; i < rectsF.Length; ++i)
            {
                rectsF[i].Inflate(amount, amount);
            }
        }

        public static Rectangle PointsToConstrainedRectangle(Point a, Point b)
        {
            Rectangle rect = Utility.PointsToRectangle(a, b);
            int minWH = Math.Min(rect.Width, rect.Height);

            rect.Width = minWH;
            rect.Height = minWH;

            if (rect.Y != a.Y)
            {
                rect.Location = new Point(rect.X, a.Y - minWH);
            }

            if (rect.X != a.X)
            {
                rect.Location = new Point(a.X - minWH, rect.Y);
            }

            return rect;
        }

        public static RectangleF PointsToConstrainedRectangle(PointF a, PointF b)
        {
            RectangleF rect = Utility.PointsToRectangle(a, b);
            float minWH = Math.Min(rect.Width, rect.Height);

            rect.Width = minWH;
            rect.Height = minWH;

            if (rect.Y != a.Y)
            {
                rect.Location = new PointF(rect.X, a.Y - minWH);
            }

            if (rect.X != a.X)
            {
                rect.Location = new PointF(a.X - minWH, rect.Y);
            }

            return rect;
        }

        /// <summary>
        /// Takes two points and creates a bounding rectangle from them.
        /// </summary>
        /// <param name="a">One corner of the rectangle.</param>
        /// <param name="b">The other corner of the rectangle.</param>
        /// <returns>A Rectangle instance that bounds the two points.</returns>
        public static Rectangle PointsToRectangle(Point a, Point b)
        {
            int x = Math.Min(a.X, b.X);
            int y = Math.Min(a.Y, b.Y);
            int width = Math.Abs(a.X - b.X) + 1;
            int height = Math.Abs(a.Y - b.Y) + 1;
 
            return new Rectangle(x, y, width, height);
        }

        public static RectangleF PointsToRectangle(PointF a, PointF b)
        {
            float x = Math.Min(a.X, b.X);
            float y = Math.Min(a.Y, b.Y);
            float width = Math.Abs(a.X - b.X) + 1;
            float height = Math.Abs(a.Y - b.Y) + 1;
 
            return new RectangleF(x, y, width, height);
        }

        public static Rectangle PointsToRectangleExclusive(Point a, Point b)
        {
            int x = Math.Min(a.X, b.X);
            int y = Math.Min(a.Y, b.Y);
            int width = Math.Abs(a.X - b.X);
            int height = Math.Abs(a.Y - b.Y);
 
            return new Rectangle(x, y, width, height);
        }

        public static RectangleF PointsToRectangleExclusive(PointF a, PointF b)
        {
            float x = Math.Min(a.X, b.X);
            float y = Math.Min(a.Y, b.Y);
            float width = Math.Abs(a.X - b.X);
            float height = Math.Abs(a.Y - b.Y);
 
            return new RectangleF(x, y, width, height);
        }

        public static RectangleF[] PointsToRectangles(PointF[] pointsF)
        {
            if (pointsF.Length == 0)
            {
                return new RectangleF[] { };
            }

            if (pointsF.Length == 1)
            {
                return new RectangleF[] { new RectangleF(pointsF[0].X, pointsF[0].Y, 1, 1) };
            }

            RectangleF[] rectsF = new RectangleF[pointsF.Length - 1];

            for (int i = 0; i < pointsF.Length - 1; ++i)
            {
                rectsF[i] = PointsToRectangle(pointsF[i], pointsF[i + 1]);
            }

            return rectsF;
        }

        public static Rectangle[] PointsToRectangles(Point[] points)
        {
            if (points.Length == 0)
            {
                return new Rectangle[] { };
            }

            if (points.Length == 1)
            {
                return new Rectangle[] { new Rectangle(points[0].X, points[0].Y, 1, 1) };
            }

            Rectangle[] rects = new Rectangle[points.Length - 1];

            for (int i = 0; i < points.Length - 1; ++i)
            {
                rects[i] = PointsToRectangle(points[i], points[i + 1]);
            }

            return rects;
        }

        /// <summary>
        /// Converts a RectangleF to RectangleF by rounding down the Location and rounding
        /// up the Size.
        /// </summary>
        public static Rectangle RoundRectangle(RectangleF rectF)
        {
            float left = (float)Math.Floor(rectF.Left);
            float top = (float)Math.Floor(rectF.Top);
            float right = (float)Math.Ceiling(rectF.Right);
            float bottom = (float)Math.Ceiling(rectF.Bottom);
            
            return Rectangle.Truncate(RectangleF.FromLTRB(left, top, right, bottom));
        }

        public static Stack Reverse(Stack reverseMe)
        {
            Stack reversed = new Stack();

            foreach (object o in reverseMe)
            {
                reversed.Push(o);
            }

            return reversed;
        }

        public static void SerializeObjectToStream(object graph, Stream stream) 
        {
            new BinaryFormatter().Serialize(stream, graph);
        }

        public static object DeserializeObjectFromStream(Stream stream)
        {
            return new BinaryFormatter().Deserialize(stream);
        }

        [Obsolete("Use rect.Contains() instead", true)]
        public static bool IsPointInRectangle(Point pt, Rectangle rect)
        {
            return rect.Contains(pt);
        }
        
        [Obsolete("Use rect.Contains() instead", true)]
        public static bool IsPointInRectangle(int x, int y, Rectangle rect)
        {
            return rect.Contains(x, y);
        }

        public static Bitmap FullCloneBitmap(Bitmap cloneMe)
        {
            Bitmap bitmap = new Bitmap(cloneMe.Width, cloneMe.Height, cloneMe.PixelFormat);

            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.DrawImage(cloneMe, 0, 0, cloneMe.Width, cloneMe.Height);
            }            

            return bitmap;
        }

        /// <summary>
        /// Allows you to find the bounding box for a Region object without requiring
        /// the presence of a Graphics object.
        /// (Region.GetBounds takes a Graphics instance as its only parameter.)
        /// </summary>
        /// <param name="region">The region you want to find a bounding box for.</param>
        /// <returns>A RectangleF structure that surrounds the Region.</returns>
        public static Rectangle GetRegionBounds(PdnRegion region)
        {
            Rectangle[] rects = region.GetRegionScansReadOnlyInt();
            return GetRegionBounds(rects, 0, rects.Length);
        }

        /// <summary>
        /// Allows you to find the bounding box for a "region" that is described as an
        /// array of bounding boxes.
        /// </summary>
        /// <param name="rectsF">The "region" you want to find a bounding box for.</param>
        /// <returns>A RectangleF structure that surrounds the Region.</returns>
        public static RectangleF GetRegionBounds(RectangleF[] rectsF, int startIndex, int length)
        {
            if (rectsF.Length == 0)
            {
                return RectangleF.Empty;
            }

            float left = rectsF[startIndex].Left;
            float top = rectsF[startIndex].Top;
            float right = rectsF[startIndex].Right;
            float bottom = rectsF[startIndex].Bottom;

            for (int i = startIndex + 1; i < startIndex + length; ++i)
            {
                RectangleF rectF = rectsF[i];

                if (rectF.Left < left)
                {
                    left = rectF.Left;
                }

                if (rectF.Top < top)
                {
                    top = rectF.Top;
                }

                if (rectF.Right > right)
                {
                    right = rectF.Right;
                }

                if (rectF.Bottom > bottom)
                {
                    bottom = rectF.Bottom;
                }
            }

            return RectangleF.FromLTRB(left, top, right, bottom);
        }

        public static RectangleF GetTraceBounds(PointF[] pointsF, int startIndex, int length)
        {
            if (pointsF.Length == 0)
            {
                return RectangleF.Empty;
            }

            float left = pointsF[startIndex].X;
            float top = pointsF[startIndex].Y;
            float right = 1 + pointsF[startIndex].X;
            float bottom = 1 + pointsF[startIndex].Y;

            for (int i = startIndex + 1; i < startIndex + length; ++i)
            {
                PointF pointF = pointsF[i];

                if (pointF.X < left)
                {
                    left = pointF.X;
                }

                if (pointF.Y < top)
                {
                    top = pointF.Y;
                }

                if (pointF.X > right)
                {
                    right = pointF.X;
                }

                if (pointF.Y > bottom)
                {
                    bottom = pointF.Y;
                }
            }

            return RectangleF.FromLTRB(left, top, right, bottom);
        }

        public static Rectangle GetTraceBounds(Point[] points, int startIndex, int length)
        {
            if (points.Length == 0)
            {
                return Rectangle.Empty;
            }

            int left = points[startIndex].X;
            int top = points[startIndex].Y;
            int right = 1 + points[startIndex].X;
            int bottom = 1 + points[startIndex].Y;

            for (int i = startIndex + 1; i < startIndex + length; ++i)
            {
                Point point = points[i];

                if (point.X < left)
                {
                    left = point.X;
                }

                if (point.Y < top)
                {
                    top = point.Y;
                }

                if (point.X > right)
                {
                    right = point.X;
                }

                if (point.Y > bottom)
                {
                    bottom = point.Y;
                }
            }

            return Rectangle.FromLTRB(left, top, right, bottom);
        }

        /// <summary>
        /// Allows you to find the bounding box for a "region" that is described as an
        /// array of bounding boxes.
        /// </summary>
        /// <param name="rectsF">The "region" you want to find a bounding box for.</param>
        /// <returns>A RectangleF structure that surrounds the Region.</returns>
        public static Rectangle GetRegionBounds(Rectangle[] rects, int startIndex, int length)
        {
            if (rects.Length == 0)
            {
                return Rectangle.Empty;
            }

            int left = rects[startIndex].Left;
            int top = rects[startIndex].Top;
            int right = rects[startIndex].Right;
            int bottom = rects[startIndex].Bottom;

            for (int i = startIndex + 1; i < startIndex + length; ++i)
            {
                Rectangle rect = rects[i];

                if (rect.Left < left)
                {
                    left = rect.Left;
                }

                if (rect.Top < top)
                {
                    top = rect.Top;
                }

                if (rect.Right > right)
                {
                    right = rect.Right;
                }

                if (rect.Bottom > bottom)
                {
                    bottom = rect.Bottom;
                }
            }

            return Rectangle.FromLTRB(left, top, right, bottom);
        }

        public static RectangleF GetRegionBounds(RectangleF[] rectsF)
        {
            return GetRegionBounds(rectsF, 0, rectsF.Length);
        }

        public static Rectangle GetRegionBounds(Rectangle[] rects)
        {
            return GetRegionBounds(rects, 0, rects.Length);
        }

        private static float DistanceSquared(RectangleF[] rectsF, int indexA, int indexB)
        {
            PointF centerA = new PointF(rectsF[indexA].Left + (rectsF[indexA].Width / 2), rectsF[indexA].Top + (rectsF[indexA].Height / 2));
            PointF centerB = new PointF(rectsF[indexB].Left + (rectsF[indexB].Width / 2), rectsF[indexB].Top + (rectsF[indexB].Height / 2));
            
            return ((centerA.X - centerB.X) * (centerA.X - centerB.X)) + 
                ((centerA.Y - centerB.Y) * (centerA.Y - centerB.Y));
        }
       
        /// <summary>
        /// Simplifies a Region into N number of bounding boxes.
        /// </summary>
        /// <param name="region">The Region to simplify.</param>
        /// <param name="complexity">The maximum number of bounding boxes to return, or 0 for however many are necessary (equivalent to using Region.GetRegionScans).</param>
        /// <returns></returns>
        public static Rectangle[] SimplifyRegion(PdnRegion region, int complexity)
        {
            Rectangle[] rects = region.GetRegionScansReadOnlyInt();
            return SimplifyRegion(rects, complexity);
        }

        public static Rectangle[] SimplifyRegion(Rectangle[] rects, int complexity)
        {
            if (complexity == 0 || rects.Length < complexity)
            {
                return (Rectangle[])rects.Clone();
            }

            Rectangle[] boxes = new Rectangle[complexity];

            for (int i = 0; i < complexity; ++i)
            {
                int startIndex = (i * rects.Length) / complexity;
                int length = Math.Min(rects.Length, ((i + 1) * rects.Length) / complexity) - startIndex;
                boxes[i] = GetRegionBounds(rects, startIndex, length);
            }

            return boxes;
        }


        public static RectangleF[] SimplifyTrace(PointF[] pointsF, int complexity)
        {
            if (complexity == 0 || 
                (pointsF.Length - 1) < complexity)
            {
                return PointsToRectangles(pointsF);
            }

            RectangleF[] boxes = new RectangleF[complexity];
            int parLength = pointsF.Length - 1; // "(points as Rectangles).Length"
            
            for (int i = 0; i < complexity; ++i)
            {
                int startIndex = (i * parLength) / complexity;
                int length = Math.Min(parLength, ((i + 1) * parLength) / complexity) - startIndex;
                boxes[i] = GetTraceBounds(pointsF, startIndex, length + 1);
            }

            return boxes;
        }

        public static Rectangle[] SimplifyTrace(PdnGraphicsPath trace, int complexity)
        {
            return SimplifyRegion(TraceToRectangles(trace), complexity);
        }

        public static Rectangle[] SimplifyTrace(PdnGraphicsPath trace)
        {
            return SimplifyTrace(trace, DefaultSimplificationFactor);
        }

        public static Rectangle[] TraceToRectangles(PdnGraphicsPath trace, int complexity)
        {
            int pointCount = trace.PointCount;

            if (pointCount == 0)
            {
                return new Rectangle[0];
            }

            PointF[] pathPoints = trace.PathPoints;
            byte[] pathTypes = trace.PathTypes;
            int figureStart = 0;

            // first get count of rectangles we'll need
            Rectangle[] rects = new Rectangle[pointCount];

            for (int i = 0; i < pointCount; ++i)
            {
                byte type = pathTypes[i];

                Point a = Point.Truncate(pathPoints[i]);
                Point b;
            
                if ((type & (byte)PathPointType.CloseSubpath) != 0)
                {
                    b = Point.Truncate(pathPoints[figureStart]);
                    figureStart = i + 1;
                }
                else
                {
                    b = Point.Truncate(pathPoints[i + 1]);
                }

                rects[i] = Utility.PointsToRectangle(a, b);
            }

            return rects;
        }

        public static Rectangle[] TraceToRectangles(PdnGraphicsPath trace)
        {
            return TraceToRectangles(trace, DefaultSimplificationFactor);
        }

        public static RectangleF[] SimplifyTrace(PointF[] pointsF)
        {
            return SimplifyTrace(pointsF, defaultSimplificationFactor);
        }

        public static Rectangle[] SimplifyAndInflateRegion(Rectangle[] rects, int complexity, int inflationAmount)
        {
            Rectangle[] simplified = SimplifyRegion(rects, complexity);

            for (int i = 0; i < simplified.Length; ++i)
            {
                simplified[i].Inflate(inflationAmount, inflationAmount);
            }

            return simplified;
        }

        public static Rectangle[] SimplifyAndInflateRegion(Rectangle[] rects)
        {
            return SimplifyAndInflateRegion(rects, defaultSimplificationFactor, 1);
        }

        public static PdnRegion SimplifyAndInflateRegion(PdnRegion region, int complexity, int inflationAmount)
        {
            Rectangle[] rectRegion = SimplifyRegion(region, complexity);
            
            for (int i = 0; i < rectRegion.Length; ++i)
            {
                rectRegion[i].Inflate(inflationAmount, inflationAmount);
            }

            return RectanglesToRegion(rectRegion);
        }

        public static PdnRegion SimplifyAndInflateRegion(PdnRegion region)
        {
            return SimplifyAndInflateRegion(region, defaultSimplificationFactor, 1);
        }

        public static RectangleF[] TranslateRectangles(RectangleF[] rectsF, PointF offset)
        {
            RectangleF[] retRectsF = new RectangleF[rectsF.Length];
            int i = 0;

            foreach (RectangleF rectF in rectsF)
            {
                retRectsF[i] = new RectangleF(rectF.X + offset.X, rectF.Y + offset.Y, rectF.Width, rectF.Height);
                ++i;
            }

            return retRectsF;
        }

        public static Rectangle[] TranslateRectangles(Rectangle[] rects, int dx, int dy)
        {
            Rectangle[] retRects = new Rectangle[rects.Length];

            for (int i = 0; i < rects.Length; ++i)
            {
                retRects[i] = new Rectangle(rects[i].X + dx, rects[i].Y + dy, rects[i].Width, rects[i].Height);
            }

            return retRects;
        }

        public static void TranslatePointsInPlace(PointF[] ptsF, float dx, float dy)
        {
            for (int i = 0; i < ptsF.Length; ++i)
            {
                ptsF[i].X += dx;
                ptsF[i].Y += dy;
            }
        }

        public static void TranslatePointsInPlace(Point[] pts, int dx, int dy)
        {
            for (int i = 0; i < pts.Length; ++i)
            {
                pts[i].X += dx;
                pts[i].Y += dy;
            }
        }

        public static Rectangle[] TruncateRectangles(RectangleF[] rectsF)
        {
            Rectangle[] rects = new Rectangle[rectsF.Length];

            for (int i = 0; i < rectsF.Length; ++i)
            {
                rects[i] = Rectangle.Truncate(rectsF[i]);
            }

            return rects;
        }

        public static Point[] TruncatePoints(PointF[] pointsF)
        {
            Point[] points = new Point[pointsF.Length];

            for (int i = 0; i < pointsF.Length; ++i)
            {
                points[i] = Point.Truncate(pointsF[i]);
            }

            return points;
        }

        public static Point[] RoundPoints(PointF[] pointsF)
        {
            Point[] points = new Point[pointsF.Length];

            for (int i = 0; i < pointsF.Length; ++i)
            {
                points[i] = Point.Round(pointsF[i]);
            }

            return points;
        }

        /// <summary>
        /// The Sutherland-Hodgman clipping alrogithm.
        /// http://ezekiel.vancouver.wsu.edu/~cs442/lectures/clip/clip/index.html
        /// 
        /// # Clipping a convex polygon to a convex region (e.g., rectangle) will always produce a convex polygon (or no polygon if completely outside the clipping region).
        /// # Clipping a concave polygon to a rectangle may produce several polygons (see figure above) or, as the following algorithm does, produce a single, possibly degenerate, polygon.
        /// # Divide and conquer: Clip entire polygon against a single edge (i.e., half-plane). Repeat for each edge in the clipping region.
        ///
        /// The input is a sequence of vertices: {v0, v1, ... vn} given as an array of Points
        /// the result is a sequence of vertices, given as an array of Points. This result may have
        /// less than, equal, more than, or 0 vertices.
        /// </summary>
        /// <param name="vertices"></param>
        /// <returns></returns>
        public static List<PointF> SutherlandHodgman(RectangleF bounds, List<PointF> v)
        {
            List<PointF> p1 = SutherlandHodgmanOneAxis(bounds, RectangleEdge.Left, v);
            List<PointF> p2 = SutherlandHodgmanOneAxis(bounds, RectangleEdge.Right, p1);
            List<PointF> p3 = SutherlandHodgmanOneAxis(bounds, RectangleEdge.Top, p2);
            List<PointF> p4 = SutherlandHodgmanOneAxis(bounds, RectangleEdge.Bottom, p3);

            return p4;
        }

        private enum RectangleEdge
        {
            Left,
            Right,
            Top,
            Bottom
        }

        private static List<PointF> SutherlandHodgmanOneAxis(RectangleF bounds, RectangleEdge edge, List<PointF> v)
        {
            if (v.Count == 0)
            {
                return new List<PointF>();
            }

            List<PointF> polygon = new List<PointF>();
            
            PointF s = v[v.Count - 1];

            for (int i = 0; i < v.Count; ++i)
            {
                PointF p = v[i];
                bool pIn = IsInside(bounds, edge, p);
                bool sIn = IsInside(bounds, edge, s);

                if (sIn && pIn)
                {   
                    // case 1: inside -> inside
                    polygon.Add(p);
                }
                else if (sIn && !pIn)
                {   
                    // case 2: inside -> outside
                    polygon.Add(LineIntercept(bounds, edge, s, p));
                }
                else if (!sIn && !pIn)
                {   
                    // case 3: outside -> outside
                    // emit nothing
                }
                else if (!sIn && pIn)
                {   
                    // case 4: outside -> inside
                    polygon.Add(LineIntercept(bounds, edge, s, p));
                    polygon.Add(p);
                }

                s = p;
            }

            return polygon;
        }

        private static bool IsInside(RectangleF bounds, RectangleEdge edge, PointF p)
        {
            switch (edge)
            {
                case RectangleEdge.Left:
                    return !(p.X < bounds.Left);
                        
                case RectangleEdge.Right:
                    return !(p.X >= bounds.Right);

                case RectangleEdge.Top:
                    return !(p.Y < bounds.Top);

                case RectangleEdge.Bottom:
                    return !(p.Y >= bounds.Bottom);

                default:
                    throw new InvalidEnumArgumentException("edge");
            }
        }

        private static Point LineIntercept(Rectangle bounds, RectangleEdge edge, Point a, Point b)
        {
            if (a == b)
            {
                return a;
            }

            switch (edge)
            {
                case RectangleEdge.Bottom:
                    if (b.Y == a.Y)
                    {
                        throw new ArgumentException("no intercept found");
                    }

                    return new Point(a.X + (((b.X - a.X) * (bounds.Bottom - a.Y)) / (b.Y - a.Y)), bounds.Bottom);

                case RectangleEdge.Left:
                    if (b.X == a.X)
                    {
                        throw new ArgumentException("no intercept found");
                    }

                    return new Point(bounds.Left, a.Y + (((b.Y - a.Y) * (bounds.Left - a.X)) / (b.X - a.X)));

                case RectangleEdge.Right:
                    if (b.X == a.X)
                    {
                        throw new ArgumentException("no intercept found");
                    }

                    return new Point(bounds.Right, a.Y + (((b.Y - a.Y) * (bounds.Right - a.X)) / (b.X - a.X)));

                case RectangleEdge.Top:
                    if (b.Y == a.Y)
                    {
                        throw new ArgumentException("no intercept found");
                    }

                    return new Point(a.X + (((b.X - a.X) * (bounds.Top - a.Y)) / (b.Y - a.Y)), bounds.Top);                                    
            }

            throw new ArgumentException("no intercept found");
        }

        private static PointF LineIntercept(RectangleF bounds, RectangleEdge edge, PointF a, PointF b)
        {
            if (a == b)
            {
                return a;
            }

            switch (edge)
            {
                case RectangleEdge.Bottom:
                    if (b.Y == a.Y)
                    {
                        throw new ArgumentException("no intercept found");
                    }

                    return new PointF(a.X + (((b.X - a.X) * (bounds.Bottom - a.Y)) / (b.Y - a.Y)), bounds.Bottom);

                case RectangleEdge.Left:
                    if (b.X == a.X)
                    {
                        throw new ArgumentException("no intercept found");
                    }

                    return new PointF(bounds.Left, a.Y + (((b.Y - a.Y) * (bounds.Left - a.X)) / (b.X - a.X)));

                case RectangleEdge.Right:
                    if (b.X == a.X)
                    {
                        throw new ArgumentException("no intercept found");
                    }

                    return new PointF(bounds.Right, a.Y + (((b.Y - a.Y) * (bounds.Right - a.X)) / (b.X - a.X)));

                case RectangleEdge.Top:
                    if (b.Y == a.Y)
                    {
                        throw new ArgumentException("no intercept found");
                    }

                    return new PointF(a.X + (((b.X - a.X) * (bounds.Top - a.Y)) / (b.Y - a.Y)), bounds.Top);                                    
            }

            throw new ArgumentException("no intercept found");
        }

        public static Point[] GetLinePoints(Point first, Point second)
        {
            Point[] coords = null;

            int x1 = first.X;
            int y1 = first.Y;
            int x2 = second.X;
            int y2 = second.Y;
            int dx = x2 - x1;
            int dy = y2 - y1;
            int dxabs = Math.Abs(dx);
            int dyabs = Math.Abs(dy);
            int px = x1;
            int py = y1;
            int sdx = Math.Sign(dx);
            int sdy = Math.Sign(dy);
            int x = 0;
            int y = 0;

            if (dxabs > dyabs)
            {
                coords = new Point[dxabs + 1];

                for (int i = 0; i <= dxabs; i++)
                {
                    y += dyabs;

                    if (y >= dxabs)
                    {
                        y -= dxabs;
                        py += sdy;
                    }

                    coords[i] = new Point(px, py);
                    px += sdx;
                }
            }
            else 
                // had to add in this cludge for slopes of 1 ... wasn't drawing half the line
                if (dxabs == dyabs)
            {
                coords = new Point[dxabs + 1];

                for (int i = 0; i <= dxabs; i++)
                {
                    coords[i] = new Point(px, py);
                    px += sdx;
                    py += sdy;
                }
            }
            else
            {
                coords = new Point[dyabs + 1];

                for (int i = 0; i <= dyabs; i++)
                {
                    x += dxabs;

                    if (x >= dyabs)
                    {
                        x -= dyabs;
                        px += sdx;
                    }

                    coords[i] = new Point(px, py);
                    py += sdy;
                }
            }

            return coords;
        }

        public static long GetTimeMs()
        {
            return Utility.TicksToMs(DateTime.Now.Ticks);        
        }

        /// <summary>
        /// Returns the Distance between two points
        /// </summary>
        public static float Distance(PointF a, PointF b)
        {
            return Magnitude(new PointF(a.X - b.X, a.Y - b.Y));
        }

        /// <summary>
        /// Returns the Magnitude (distance to origin) of a point
        /// </summary>
        // TODO: In v4.0 codebase, turn this into an extension method
        public static float Magnitude(PointF p)
        {
            return (float)Math.Sqrt(p.X * p.X + p.Y * p.Y);
        }

        // TODO: In v4.0 codebase, turn this into an extension method
        public static double Clamp(double x, double min, double max) 
        {
            if (x < min)
            {
                return min;
            }
            else if (x > max)
            {
                return max;
            }
            else
            {
                return x;
            }
        }

        // TODO: In v4.0 codebase, turn this into an extension method
        public static float Clamp(float x, float min, float max) 
        {
            if (x < min)
            {
                return min;
            }
            else if (x > max)
            {
                return max;
            }
            else
            {
                return x;
            }
        }

        // TODO: In v4.0 codebase, turn this into an extension method
        public static int Clamp(int x, int min, int max)
        {
            if (x < min)
            {
                return min;
            }
            else if (x > max)
            {
                return max;
            }
            else
            {
                return x;
            }
        }
        
        public static byte ClampToByte(double x) 
        {
            if (x > 255)
            {
                return 255;
            }
            else if (x < 0)
            {
                return 0;
            }
            else
            {
                return (byte)x;
            }
        }
        
        public static byte ClampToByte(float x) 
        {
            if (x > 255)
            {
                return 255;
            }
            else if (x < 0)
            {
                return 0;
            }
            else
            {
                return (byte)x;
            }
        }
        
        public static byte ClampToByte(int x) 
        {
            if (x > 255)
            {
                return 255;
            }
            else if (x < 0)
            {
                return 0;
            }
            else
            {
                return (byte)x;
            }
        }

        public static float Lerp(float from, float to, float frac) 
        {
            return (from + frac * (to - from));
        }

        public static double Lerp(double from, double to, double frac) 
        {
            return (from + frac * (to - from));
        }

        public static PointF Lerp(PointF from, PointF to, float frac)
        {
            return new PointF(Lerp(from.X, to.X, frac), Lerp(from.Y, to.Y, frac));
        }

        public static int ColorDifference(ColorBgra a, ColorBgra b) 
        {
            return (int)Math.Ceiling(Math.Sqrt(ColorDifferenceSquared(a, b)));
        }

        public static int ColorDifferenceSquared(ColorBgra a, ColorBgra b) 
        {
            int diffSq = 0, tmp;

            tmp = a.R - b.R;
            diffSq += tmp * tmp;
            tmp = a.G - b.G;
            diffSq += tmp * tmp;
            tmp = a.B - b.B;
            diffSq += tmp * tmp;

            return diffSq / 3;
        }

        public static DialogResult ShowDialog(Form showMe, IWin32Window owner)
        {
            DialogResult dr;

            if (showMe is PdnBaseForm)
            {
                PdnBaseForm showMe2 = (PdnBaseForm)showMe;
                double oldOpacity = showMe2.Opacity;
                showMe2.Opacity = 0.9;
                dr = showMe2.ShowDialog(owner);
                showMe2.Opacity = oldOpacity;
            }
            else
            {
                double oldOpacity = showMe.Opacity;
                showMe.Opacity = 0.9;
                dr = showMe.ShowDialog(owner);
                showMe.Opacity = oldOpacity;
            }

            Control control = owner as Control;
            if (control != null)
            {
                Form form = control.FindForm();

                if (form != null)
                {
                    form.Activate();
                }

                control.Update();
            }
            
            return dr;
        }

        public static void ShowHelp(Control parent)
        {
            string helpFileUrlFormat = PdnResources.GetString("HelpFile.Url.Format");
            string baseSiteUrl = InvariantStrings.WebsiteUrl;
            string helpFileUrl = string.Format(helpFileUrlFormat, baseSiteUrl);
            PdnInfo.OpenUrl(parent, helpFileUrl);
        }

        /// <summary>
        /// Reads a 16-bit unsigned integer from a Stream in little-endian format.
        /// </summary>
        /// <param name="stream"></param>
        /// <returns>-1 on failure, else the 16-bit unsigned integer that was read.</returns>
        public static int ReadUInt16(Stream stream)
        {
            int byte1 = stream.ReadByte();

            if (byte1 == -1)
            {
                return -1;
            }

            int byte2 = stream.ReadByte();

            if (byte2 == -1)
            {
                return -1;
            }

            return byte1 + (byte2 << 8);
        }

        public static void WriteUInt16(Stream stream, UInt16 word)
        {
            stream.WriteByte((byte)(word & 0xff));
            stream.WriteByte((byte)(word >> 8));
        }

        public static void WriteUInt24(Stream stream, int uint24)
        {
            stream.WriteByte((byte)(uint24 & 0xff));
            stream.WriteByte((byte)((uint24 >> 8) & 0xff));
            stream.WriteByte((byte)((uint24 >> 16) & 0xff));
        }

        public static void WriteUInt32(Stream stream, UInt32 uint32)
        {
            stream.WriteByte((byte)(uint32 & 0xff));
            stream.WriteByte((byte)((uint32 >> 8) & 0xff));
            stream.WriteByte((byte)((uint32 >> 16) & 0xff));
            stream.WriteByte((byte)((uint32 >> 24) & 0xff));
        }

        /// <summary>
        /// Reads a 24-bit unsigned integer from a Stream in little-endian format.
        /// </summary>
        /// <param name="stream"></param>
        /// <returns>-1 on failure, else the 24-bit unsigned integer that was read.</returns>
        public static int ReadUInt24(Stream stream)
        {
            int byte1 = stream.ReadByte();

            if (byte1 == -1)
            {
                return -1;
            }

            int byte2 = stream.ReadByte();

            if (byte2 == -1)
            {
                return -1;
            }

            int byte3 = stream.ReadByte();

            if (byte3 == -1)
            {
                return -1;
            }

            return byte1 + (byte2 << 8) + (byte3 << 16);
        }

        /// <summary>
        /// Reads a 32-bit unsigned integer from a Stream in little-endian format.
        /// </summary>
        /// <param name="stream"></param>
        /// <returns>-1 on failure, else the 32-bit unsigned integer that was read.</returns>
        public static long ReadUInt32(Stream stream)
        {
            int byte1 = stream.ReadByte();

            if (byte1 == -1)
            {
                return -1;
            }

            int byte2 = stream.ReadByte();

            if (byte2 == -1)
            {
                return -1;
            }

            int byte3 = stream.ReadByte();

            if (byte3 == -1)
            {
                return -1;
            }

            int byte4 = stream.ReadByte();

            if (byte4 == -1)
            {
                return -1;
            }

            return unchecked((long)((uint)(byte1 + (byte2 << 8) + (byte3 << 16) + (byte4 << 24))));
        }

        public static int ReadFromStream(Stream input, byte[] buffer, int offset, int count)
        {
            int totalBytesRead = 0;

            while (totalBytesRead < count)
            {
                int bytesRead = input.Read(buffer, offset + totalBytesRead, count - totalBytesRead);

                if (bytesRead == 0)
                {
                    throw new IOException("ran out of data");
                }

                totalBytesRead += bytesRead;
            }

            return totalBytesRead;
        }

        public static long CopyStream(Stream input, Stream output, long maxBytes)
        {
            long bytesCopied = 0;
            byte[] buffer = new byte[4096];

            while (true)
            {
                int bytesRead = input.Read(buffer, 0, buffer.Length);

                if (bytesRead == 0)
                {
                    break;
                }
                else
                {
                    int bytesToCopy;

                    if (maxBytes != -1 && (bytesCopied + bytesRead) > maxBytes)
                    {
                        bytesToCopy = (int)(maxBytes - bytesCopied);
                    }
                    else
                    {
                        bytesToCopy = bytesRead;
                    }

                    output.Write(buffer, 0, bytesRead);
                    bytesCopied += bytesToCopy;

                    if (bytesToCopy != bytesRead)
                    {
                        break;
                    }
                }
            }

            return bytesCopied;
        }

        public static long CopyStream(Stream input, Stream output)
        {
            return CopyStream(input, output, -1);
        }

        private struct Edge
        {
            public int miny;   // int
            public int maxy;   // int
            public int x;      // fixed point: 24.8
            public int dxdy;   // fixed point: 24.8

            public Edge(int miny, int maxy, int x, int dxdy)
            {
                this.miny = miny;
                this.maxy = maxy;
                this.x = x;
                this.dxdy = dxdy;
            }
        }

        public static Scanline[] GetScans(Point[] vertices)
        {
            return GetScans(vertices, 0, vertices.Length);
        }

        public static Scanline[] GetScans(Point[] vertices, int startIndex, int length)
        {
            if (length > vertices.Length - startIndex)
            {
                throw new ArgumentException("out of bounds: length > vertices.Length - startIndex");
            }

            int ymax = 0;

            // Build edge table
            Edge[] edgeTable = new Edge[length];
            int edgeCount = 0;

            for (int i = startIndex; i < startIndex + length; ++i)
            {
                Point top = vertices[i];
                Point bottom = vertices[(((i + 1) - startIndex) % length) + startIndex];
                int dy;

                if (top.Y > bottom.Y)
                {
                    Point temp = top;
                    top = bottom;
                    bottom = temp;
                }
                
                dy = bottom.Y - top.Y;

                if (dy != 0)
                {
                    edgeTable[edgeCount] = new Edge(top.Y, bottom.Y, top.X << 8, (((bottom.X - top.X) << 8) / dy));
                    ymax = Math.Max(ymax, bottom.Y);
                    ++edgeCount;
                }
            }

            // Sort edge table by miny
            for (int i = 0; i < edgeCount - 1; ++i)
            {
                int min = i;

                for (int j = i + 1; j < edgeCount; ++j)
                {
                    if (edgeTable[j].miny < edgeTable[min].miny)
                    {
                        min = j;
                    }
                }

                if (min != i)
                {
                    Edge temp = edgeTable[min];
                    edgeTable[min] = edgeTable[i];
                    edgeTable[i] = temp;
                }
            }

            // Compute how many scanlines we will be emitting
            int scanCount = 0;
            int activeLow = 0;
            int activeHigh = 0;
            int yscan1 = edgeTable[0].miny;

            // we assume that edgeTable[0].miny == yscan
            while (activeHigh < edgeCount - 1 && 
                   edgeTable[activeHigh + 1].miny == yscan1)
            {
                ++activeHigh;
            }

            while (yscan1 <= ymax)
            {
                // Find new edges where yscan == miny
                while (activeHigh < edgeCount - 1 &&
                       edgeTable[activeHigh + 1].miny == yscan1)
                {
                    ++activeHigh;
                }

                int count = 0;
                for (int i = activeLow; i <= activeHigh; ++i)
                {
                    if (edgeTable[i].maxy > yscan1)
                    {
                        ++count;
                    }
                }

                scanCount += count / 2;
                ++yscan1;

                // Remove edges where yscan == maxy
                while (activeLow < edgeCount - 1 &&
                       edgeTable[activeLow].maxy <= yscan1)
                {
                    ++activeLow;
                }

                if (activeLow > activeHigh)
                {
                    activeHigh = activeLow;
                }
            }

            // Allocate scanlines that we'll return
            Scanline[] scans = new Scanline[scanCount];

            // Active Edge Table (AET): it is indices into the Edge Table (ET)
            int[] active = new int[edgeCount];
            int activeCount = 0;
            int yscan2 = edgeTable[0].miny;
            int scansIndex = 0;
            
            // Repeat until both the ET and AET are empty
            while (yscan2 <= ymax)
            {
                // Move any edges from the ET to the AET where yscan == miny
                for (int i = 0; i < edgeCount; ++i)
                {
                    if (edgeTable[i].miny == yscan2)
                    {
                        active[activeCount] = i;
                        ++activeCount;
                    }
                }

                // Sort the AET on x
                for (int i = 0; i < activeCount - 1; ++i)
                {
                    int min = i;

                    for (int j = i + 1; j < activeCount; ++j)
                    {
                        if (edgeTable[active[j]].x < edgeTable[active[min]].x)
                        {
                            min = j;
                        }
                    }

                    if (min != i)
                    {
                        int temp = active[min];
                        active[min] = active[i];
                        active[i] = temp;
                    }
                }

                // For each pair of entries in the AET, fill in pixels between their info
                for (int i = 0; i < activeCount; i += 2)
                {
                    Edge el = edgeTable[active[i]];
                    Edge er = edgeTable[active[i + 1]];
                    int startx = (el.x + 0xff) >> 8; // ceil(x)
                    int endx = er.x >> 8;      // floor(x)

                    scans[scansIndex] = new Scanline(startx, yscan2, endx - startx);
                    ++scansIndex;
                }

                ++yscan2;

                // Remove from the AET any edge where yscan == maxy
                int k = 0;
                while (k < activeCount && activeCount > 0)
                {
                    if (edgeTable[active[k]].maxy == yscan2)
                    {
                        // remove by shifting everything down one
                        for (int j =  k + 1; j < activeCount; ++j)
                        {
                            active[j - 1] = active[j];
                        }

                        --activeCount;
                    }
                    else
                    {
                        ++k;
                    }
                }

                // Update x for each entry in AET
                for (int i = 0; i < activeCount; ++i)
                {
                    edgeTable[active[i]].x += edgeTable[active[i]].dxdy;
                }
            }

            return scans;
        }

        public static PointF TransformOnePoint(Matrix matrix, PointF ptF)
        {
            PointF[] ptFs = new PointF[1] { ptF };
            matrix.TransformPoints(ptFs);
            return ptFs[0];
        }

        public static PointF TransformOneVector(Matrix matrix, PointF ptF)
        {
            PointF[] ptFs = new PointF[1] { ptF };
            matrix.TransformVectors(ptFs);
            return ptFs[0];
        }

        public static PointF NormalizeVector(PointF vecF)
        {
            float magnitude = Magnitude(vecF);
            vecF.X /= magnitude;
            vecF.Y /= magnitude;
            return vecF;
        }

        public static PointF NormalizeVector2(PointF vecF)
        {
            float magnitude = Magnitude(vecF);

            if (magnitude == 0)
            {
                vecF.X = 0;
                vecF.Y = 0;
            }
            else
            {
                vecF.X /= magnitude;
                vecF.Y /= magnitude;
            }

            return vecF;
        }

        public static void NormalizeVectors(PointF[] vecsF)
        {
            for (int i = 0; i < vecsF.Length; ++i)
            {
                vecsF[i] = NormalizeVector(vecsF[i]);
            }
        }

        public static PointF RotateVector(PointF vecF, float angleDelta)
        {
            angleDelta *= (float)( Math.PI / 180.0);
            float vecFLen = Magnitude(vecF);
            float vecFAngle = angleDelta + (float)Math.Atan2(vecF.Y, vecF.X);
            vecF.X = (float)Math.Cos(vecFAngle);
            vecF.Y = (float)Math.Sin(vecFAngle);
            return vecF;
        }

        public static void RotateVectors(PointF[] vecFs, float angleDelta)
        {
            for (int i = 0; i < vecFs.Length; ++i)
            {
                vecFs[i] = RotateVector(vecFs[i], angleDelta);
            }
        }

        public static PointF MultiplyVector(PointF vecF, float scalar)
        {
            return new PointF(vecF.X * scalar, vecF.Y * scalar);
        }

        public static PointF AddVectors(PointF a, PointF b)
        {
            return new PointF(a.X + b.X, a.Y + b.Y);
        }

        public static PointF SubtractVectors(PointF lhs, PointF rhs)
        {
            return new PointF(lhs.X - rhs.X, lhs.Y - rhs.Y);
        }

        public static PointF NegateVector(PointF v)
        {
            return new PointF(-v.X, -v.Y);
        }

        public static float GetAngleOfTransform(Matrix matrix)
        {
            PointF[] pts = new PointF[] { new PointF(1.0f, 0.0f) };
            matrix.TransformVectors(pts);
            double atan2 = Math.Atan2(pts[0].Y, pts[0].X);
            double angle = atan2 * (180.0f / Math.PI);

            return (float)angle;
        }

        public static bool IsTransformFlipped(Matrix matrix)
        {
            PointF ptX = new PointF(1.0f, 0.0f);
            PointF ptXT = Utility.TransformOneVector(matrix, ptX);
            double atan2X = Math.Atan2(ptXT.Y, ptXT.X);
            double angleX = atan2X * (180.0 / Math.PI);

            PointF ptY = new PointF(0.0f, 1.0f);
            PointF ptYT = Utility.TransformOneVector(matrix, ptY);
            double atan2Y = Math.Atan2(ptYT.Y, ptYT.X);
            double angleY = (atan2Y * (180.0 / Math.PI)) - 90.0;

            while (angleX < 0)
            {
                angleX += 360;
            }

            while (angleY < 0)
            {
                angleY += 360;
            }

            double angleDelta = Math.Abs(angleX - angleY);

            return angleDelta > 1.0 && angleDelta < 359.0;
        }

        /// <summary>
        /// Calculates the dot product of two vectors.
        /// </summary>
        public static float DotProduct(PointF lhs, PointF rhs)
        {
            return lhs.X * rhs.X + lhs.Y * rhs.Y;
        }

        /// <summary>
        /// Calculates the orthogonal projection of y on to u.
        /// yhat = u * ((y dot u) / (u dot u))
        /// z = y - yhat
        /// Section 6.2 (pg. 381) of Linear Algebra and its Applications, Second Edition, by David C. Lay
        /// </summary>
        /// <param name="y">The vector to decompose</param>
        /// <param name="u">The non-zero vector to project y on to</param>
        /// <param name="yhat">The orthogonal projection of y onto u</param>
        /// <param name="yhatLen">The length of yhat such that yhat = yhatLen * u</param>
        /// <param name="z">The component of y orthogonal to u</param>
        /// <remarks>
        /// As a special case, if u=(0,0) the results are all zero.
        /// </remarks>
        public static void GetProjection(PointF y, PointF u, out PointF yhat, out float yhatLen, out PointF z)
        {
            if (u.X == 0 && u.Y == 0)
            {
                yhat = new PointF(0, 0);
                yhatLen = 0;
                z = new PointF(0, 0);
            }
            else
            {
                float yDotU = DotProduct(y, u);
                float uDotU = DotProduct(u, u);
                yhatLen = yDotU / uDotU;
                yhat = MultiplyVector(u, yhatLen);
                z = SubtractVectors(y, yhat);
            }
        }

        public static int GreatestCommonDivisor(int a, int b)
        {
            int r;

            if (a < b)
            {
                r = a;
                a = b;
                b = r;
            }

            do
            {
                r = a % b;
                a = b;
                b = r;
            } while (r != 0);

            return a;
        }

        public static void Swap(ref int a, ref int b)
        {
            int t;

            t = a;
            a = b;
            b = t;
        }

        public static void Swap<T>(ref T a, ref T b)
        {
            T t;

            t = a;
            a = b;
            b = t;
        }

        private static byte[] DownloadSmallFile(Uri uri, WebProxy proxy)
        {
            WebRequest request = WebRequest.Create(uri);

            if (proxy != null)
            {
                request.Proxy = proxy;
            }

            request.Timeout = 5000;
            WebResponse response = request.GetResponse();
            Stream stream = response.GetResponseStream();

            try
            {
                byte[] buffer = new byte[8192];
                int offset = 0;

                while (offset < buffer.Length)
                {
                    int bytesRead = stream.Read(buffer, offset, buffer.Length - offset);

                    if (bytesRead == 0)
                    {
                        byte[] smallerBuffer = new byte[offset + bytesRead];

                        for (int i = 0; i < offset + bytesRead; ++i)
                        {
                            smallerBuffer[i] = buffer[i];
                        }

                        buffer = smallerBuffer;
                    }

                    offset += bytesRead;
                }

                return buffer;
            }

            finally
            {
                if (stream != null)
                {
                    stream.Close();
                    stream = null;
                }

                if (response != null)
                {
                    response.Close();
                    response = null;
                }
            }
        }

        public static T[] RepeatArray<T>(T[] array, int repeatCount)
        {
            T[] returnArray = new T[repeatCount * array.Length];

            for (int i = 0; i < repeatCount; ++i)
            {
                for (int j = 0; j < array.Length; ++j)
                {
                    int index = (i * array.Length) + j;
                    returnArray[index] = array[j];
                }
            }

            return returnArray;
        }

        /// <summary>
        /// Downloads a small file (max 8192 bytes) and returns it as a byte array.
        /// </summary>
        /// <returns>The contents of the file if downloaded successfully.</returns>
        public static byte[] DownloadSmallFile(Uri uri)
        {
            byte[] bytes = null;
            Exception exception = null;
            WebProxy[] proxiesPre = Network.GetProxyList();
            WebProxy[] proxies = RepeatArray(proxiesPre, 2); // see bug #1942

            foreach (WebProxy proxy in proxies)
            {
                try
                {
                    bytes = DownloadSmallFile(uri, proxy);
                    exception = null;
                }

                catch (Exception ex)
                {
                    exception = ex;
                    bytes = null;
                }

                if (bytes != null)
                {
                    break;
                }
            }

            if (exception != null)
            {
                WebException we = exception as WebException;

                if (we != null)
                {
                    throw new WebException(null, we, we.Status, we.Response);
                }
                else
                {
                    throw new ApplicationException("An exception occurred while trying to download '" + uri.ToString() + "'", exception);
                }
            }

            return bytes;
        }

        private static void DownloadFile(Uri uri, Stream output, WebProxy proxy, ProgressEventHandler progressCallback)
        {
            WebRequest request = WebRequest.Create(uri);

            if (proxy != null)
            {
                request.Proxy = proxy;
            }

            request.Timeout = 5000;
            WebResponse response = request.GetResponse();
            Stream stream = null;
            SiphonStream siphonOutputStream = null;

            try
            {
                stream = response.GetResponseStream();
                siphonOutputStream = new SiphonStream(output, 1024); // monitor the completion of writes to 'output'

                siphonOutputStream.IOFinished +=
                    delegate(object sender, IOEventArgs e)
                    {
                        if (progressCallback != null)
                        {
                            double percent = 100.0 * Utility.Clamp(((double)e.Position / (double)response.ContentLength), 0, 100);
                            progressCallback(uri, new ProgressEventArgs(percent));
                        }
                    };

                Utility.CopyStream(stream, siphonOutputStream, 128 * 1024 * 1024); // cap at 128mb
                siphonOutputStream.Flush();
            }

            finally
            {
                if (siphonOutputStream != null)
                {
                    siphonOutputStream.Close();
                    siphonOutputStream = null;
                }

                if (stream != null)
                {
                    stream.Close();
                    stream = null;
                }

                if (response != null)
                {
                    response.Close();
                    response = null;
                }
            }
        }

        /// <summary>
        /// Download a file (max 128MB) and saves it to the given Stream.
        /// </summary>
        public static void DownloadFile(Uri uri, Stream output, ProgressEventHandler progressCallback)
        {
            long startPosition = output.Position;
            Exception exception = null;
            WebProxy[] proxies = Network.GetProxyList();

            foreach (WebProxy proxy in proxies)
            {
                bool success = false;

                try
                {
                    DownloadFile(uri, output, proxy, progressCallback);
                    exception = null;
                    success = true;
                }

                catch (Exception ex)
                {
                    exception = ex;
                }

                // If the output stream was written to, then we know
                // that we were either successful in downloading the
                // file, or there was an error unrelated to using the
                // proxy (maybe they unplugged the network cable, who
                // knows!)
                if (output.Position != startPosition || success)
                {
                    break;
                }
            }

            if (exception != null)
            {
                WebException we = exception as WebException;

                if (we != null)
                {
                    throw new WebException(null, we, we.Status, we.Response);
                }
                else
                {
                    throw new ApplicationException("An exception occurred while trying to download '" + uri.ToString() + "'", exception);
                }
            }
        }

        public static byte FastScaleByteByByte(byte a, byte b)
        {
            int r1 = a * b + 0x80;
            int r2 = ((r1 >> 8) + r1) >> 8;
            return (byte)r2;
        }

        public static int FastDivideShortByByte(ushort n, byte d)
        {
            int i = d * 3;
            uint m = masTable[i];
            uint a = masTable[i + 1];
            uint s = masTable[i + 2];

            uint nTimesMPlusA = unchecked((n * m) + a);
            uint shifted = nTimesMPlusA >> (int)s;
            int r = (int)shifted;

            return r;
        }

        // i = z * 3;
        // (x / z) = ((x * masTable[i]) + masTable[i + 1]) >> masTable[i + 2)
        private static readonly uint[] masTable = 
        {
            0x00000000, 0x00000000, 0,  // 0
            0x00000001, 0x00000000, 0,  // 1
            0x00000001, 0x00000000, 1,  // 2
            0xAAAAAAAB, 0x00000000, 33, // 3
            0x00000001, 0x00000000, 2,  // 4
            0xCCCCCCCD, 0x00000000, 34, // 5
            0xAAAAAAAB, 0x00000000, 34, // 6
            0x49249249, 0x49249249, 33, // 7
            0x00000001, 0x00000000, 3,  // 8
            0x38E38E39, 0x00000000, 33, // 9
            0xCCCCCCCD, 0x00000000, 35, // 10
            0xBA2E8BA3, 0x00000000, 35, // 11
            0xAAAAAAAB, 0x00000000, 35, // 12
            0x4EC4EC4F, 0x00000000, 34, // 13
            0x49249249, 0x49249249, 34, // 14
            0x88888889, 0x00000000, 35, // 15
            0x00000001, 0x00000000, 4,  // 16
            0xF0F0F0F1, 0x00000000, 36, // 17
            0x38E38E39, 0x00000000, 34, // 18
            0xD79435E5, 0xD79435E5, 36, // 19
            0xCCCCCCCD, 0x00000000, 36, // 20
            0xC30C30C3, 0xC30C30C3, 36, // 21
            0xBA2E8BA3, 0x00000000, 36, // 22
            0xB21642C9, 0x00000000, 36, // 23
            0xAAAAAAAB, 0x00000000, 36, // 24
            0x51EB851F, 0x00000000, 35, // 25
            0x4EC4EC4F, 0x00000000, 35, // 26
            0x97B425ED, 0x97B425ED, 36, // 27
            0x49249249, 0x49249249, 35, // 28
            0x8D3DCB09, 0x00000000, 36, // 29
            0x88888889, 0x00000000, 36, // 30
            0x42108421, 0x42108421, 35, // 31
            0x00000001, 0x00000000, 5,  // 32
            0x3E0F83E1, 0x00000000, 35, // 33
            0xF0F0F0F1, 0x00000000, 37, // 34
            0x75075075, 0x75075075, 36, // 35
            0x38E38E39, 0x00000000, 35, // 36
            0x6EB3E453, 0x6EB3E453, 36, // 37
            0xD79435E5, 0xD79435E5, 37, // 38
            0x69069069, 0x69069069, 36, // 39
            0xCCCCCCCD, 0x00000000, 37, // 40
            0xC7CE0C7D, 0x00000000, 37, // 41
            0xC30C30C3, 0xC30C30C3, 37, // 42
            0x2FA0BE83, 0x00000000, 35, // 43
            0xBA2E8BA3, 0x00000000, 37, // 44
            0x5B05B05B, 0x5B05B05B, 36, // 45
            0xB21642C9, 0x00000000, 37, // 46
            0xAE4C415D, 0x00000000, 37, // 47
            0xAAAAAAAB, 0x00000000, 37, // 48
            0x5397829D, 0x00000000, 36, // 49
            0x51EB851F, 0x00000000, 36, // 50
            0xA0A0A0A1, 0x00000000, 37, // 51
            0x4EC4EC4F, 0x00000000, 36, // 52
            0x9A90E7D9, 0x9A90E7D9, 37, // 53
            0x97B425ED, 0x97B425ED, 37, // 54
            0x94F2094F, 0x94F2094F, 37, // 55
            0x49249249, 0x49249249, 36, // 56
            0x47DC11F7, 0x47DC11F7, 36, // 57
            0x8D3DCB09, 0x00000000, 37, // 58
            0x22B63CBF, 0x00000000, 35, // 59
            0x88888889, 0x00000000, 37, // 60
            0x4325C53F, 0x00000000, 36, // 61
            0x42108421, 0x42108421, 36, // 62
            0x41041041, 0x41041041, 36, // 63
            0x00000001, 0x00000000, 6,  // 64
            0xFC0FC0FD, 0x00000000, 38, // 65
            0x3E0F83E1, 0x00000000, 36, // 66
            0x07A44C6B, 0x00000000, 33, // 67
            0xF0F0F0F1, 0x00000000, 38, // 68
            0x76B981DB, 0x00000000, 37, // 69
            0x75075075, 0x75075075, 37, // 70
            0xE6C2B449, 0x00000000, 38, // 71
            0x38E38E39, 0x00000000, 36, // 72
            0x381C0E07, 0x381C0E07, 36, // 73
            0x6EB3E453, 0x6EB3E453, 37, // 74
            0x1B4E81B5, 0x00000000, 35, // 75
            0xD79435E5, 0xD79435E5, 38, // 76
            0x3531DEC1, 0x00000000, 36, // 77
            0x69069069, 0x69069069, 37, // 78
            0xCF6474A9, 0x00000000, 38, // 79
            0xCCCCCCCD, 0x00000000, 38, // 80
            0xCA4587E7, 0x00000000, 38, // 81
            0xC7CE0C7D, 0x00000000, 38, // 82
            0x3159721F, 0x00000000, 36, // 83
            0xC30C30C3, 0xC30C30C3, 38, // 84
            0xC0C0C0C1, 0x00000000, 38, // 85
            0x2FA0BE83, 0x00000000, 36, // 86
            0x2F149903, 0x00000000, 36, // 87
            0xBA2E8BA3, 0x00000000, 38, // 88
            0xB81702E1, 0x00000000, 38, // 89
            0x5B05B05B, 0x5B05B05B, 37, // 90
            0x2D02D02D, 0x2D02D02D, 36, // 91
            0xB21642C9, 0x00000000, 38, // 92
            0xB02C0B03, 0x00000000, 38, // 93
            0xAE4C415D, 0x00000000, 38, // 94
            0x2B1DA461, 0x2B1DA461, 36, // 95
            0xAAAAAAAB, 0x00000000, 38, // 96
            0xA8E83F57, 0xA8E83F57, 38, // 97
            0x5397829D, 0x00000000, 37, // 98
            0xA57EB503, 0x00000000, 38, // 99
            0x51EB851F, 0x00000000, 37, // 100
            0xA237C32B, 0xA237C32B, 38, // 101
            0xA0A0A0A1, 0x00000000, 38, // 102
            0x9F1165E7, 0x9F1165E7, 38, // 103
            0x4EC4EC4F, 0x00000000, 37, // 104
            0x27027027, 0x27027027, 36, // 105
            0x9A90E7D9, 0x9A90E7D9, 38, // 106
            0x991F1A51, 0x991F1A51, 38, // 107
            0x97B425ED, 0x97B425ED, 38, // 108
            0x2593F69B, 0x2593F69B, 36, // 109
            0x94F2094F, 0x94F2094F, 38, // 110
            0x24E6A171, 0x24E6A171, 36, // 111
            0x49249249, 0x49249249, 37, // 112
            0x90FDBC09, 0x90FDBC09, 38, // 113
            0x47DC11F7, 0x47DC11F7, 37, // 114
            0x8E78356D, 0x8E78356D, 38, // 115
            0x8D3DCB09, 0x00000000, 38, // 116
            0x23023023, 0x23023023, 36, // 117
            0x22B63CBF, 0x00000000, 36, // 118
            0x44D72045, 0x00000000, 37, // 119
            0x88888889, 0x00000000, 38, // 120
            0x8767AB5F, 0x8767AB5F, 38, // 121
            0x4325C53F, 0x00000000, 37, // 122
            0x85340853, 0x85340853, 38, // 123
            0x42108421, 0x42108421, 37, // 124
            0x10624DD3, 0x00000000, 35, // 125
            0x41041041, 0x41041041, 37, // 126
            0x10204081, 0x10204081, 35, // 127
            0x00000001, 0x00000000, 7,  // 128
            0x0FE03F81, 0x00000000, 35, // 129
            0xFC0FC0FD, 0x00000000, 39, // 130
            0xFA232CF3, 0x00000000, 39, // 131
            0x3E0F83E1, 0x00000000, 37, // 132
            0xF6603D99, 0x00000000, 39, // 133
            0x07A44C6B, 0x00000000, 34, // 134
            0xF2B9D649, 0x00000000, 39, // 135
            0xF0F0F0F1, 0x00000000, 39, // 136
            0x077975B9, 0x00000000, 34, // 137
            0x76B981DB, 0x00000000, 38, // 138
            0x75DED953, 0x00000000, 38, // 139
            0x75075075, 0x75075075, 38, // 140
            0x3A196B1F, 0x00000000, 37, // 141
            0xE6C2B449, 0x00000000, 39, // 142
            0xE525982B, 0x00000000, 39, // 143
            0x38E38E39, 0x00000000, 37, // 144
            0xE1FC780F, 0x00000000, 39, // 145
            0x381C0E07, 0x381C0E07, 37, // 146
            0xDEE95C4D, 0x00000000, 39, // 147
            0x6EB3E453, 0x6EB3E453, 38, // 148
            0xDBEB61EF, 0x00000000, 39, // 149
            0x1B4E81B5, 0x00000000, 36, // 150
            0x36406C81, 0x00000000, 37, // 151
            0xD79435E5, 0xD79435E5, 39, // 152
            0xD62B80D7, 0x00000000, 39, // 153
            0x3531DEC1, 0x00000000, 37, // 154
            0xD3680D37, 0x00000000, 39, // 155
            0x69069069, 0x69069069, 38, // 156
            0x342DA7F3, 0x00000000, 37, // 157
            0xCF6474A9, 0x00000000, 39, // 158
            0xCE168A77, 0xCE168A77, 39, // 159
            0xCCCCCCCD, 0x00000000, 39, // 160
            0xCB8727C1, 0x00000000, 39, // 161
            0xCA4587E7, 0x00000000, 39, // 162
            0xC907DA4F, 0x00000000, 39, // 163
            0xC7CE0C7D, 0x00000000, 39, // 164
            0x634C0635, 0x00000000, 38, // 165
            0x3159721F, 0x00000000, 37, // 166
            0x621B97C3, 0x00000000, 38, // 167
            0xC30C30C3, 0xC30C30C3, 39, // 168
            0x60F25DEB, 0x00000000, 38, // 169
            0xC0C0C0C1, 0x00000000, 39, // 170
            0x17F405FD, 0x17F405FD, 36, // 171
            0x2FA0BE83, 0x00000000, 37, // 172
            0xBD691047, 0xBD691047, 39, // 173
            0x2F149903, 0x00000000, 37, // 174
            0x5D9F7391, 0x00000000, 38, // 175
            0xBA2E8BA3, 0x00000000, 39, // 176
            0x5C90A1FD, 0x5C90A1FD, 38, // 177
            0xB81702E1, 0x00000000, 39, // 178
            0x5B87DDAD, 0x5B87DDAD, 38, // 179
            0x5B05B05B, 0x5B05B05B, 38, // 180
            0xB509E68B, 0x00000000, 39, // 181
            0x2D02D02D, 0x2D02D02D, 37, // 182
            0xB30F6353, 0x00000000, 39, // 183
            0xB21642C9, 0x00000000, 39, // 184
            0x1623FA77, 0x1623FA77, 36, // 185
            0xB02C0B03, 0x00000000, 39, // 186
            0xAF3ADDC7, 0x00000000, 39, // 187
            0xAE4C415D, 0x00000000, 39, // 188
            0x15AC056B, 0x15AC056B, 36, // 189
            0x2B1DA461, 0x2B1DA461, 37, // 190
            0xAB8F69E3, 0x00000000, 39, // 191
            0xAAAAAAAB, 0x00000000, 39, // 192
            0x15390949, 0x00000000, 36, // 193
            0xA8E83F57, 0xA8E83F57, 39, // 194
            0x15015015, 0x15015015, 36, // 195
            0x5397829D, 0x00000000, 38, // 196
            0xA655C439, 0xA655C439, 39, // 197
            0xA57EB503, 0x00000000, 39, // 198
            0x5254E78F, 0x00000000, 38, // 199
            0x51EB851F, 0x00000000, 38, // 200
            0x028C1979, 0x00000000, 33, // 201
            0xA237C32B, 0xA237C32B, 39, // 202
            0xA16B312F, 0x00000000, 39, // 203
            0xA0A0A0A1, 0x00000000, 39, // 204
            0x4FEC04FF, 0x00000000, 38, // 205
            0x9F1165E7, 0x9F1165E7, 39, // 206
            0x27932B49, 0x00000000, 37, // 207
            0x4EC4EC4F, 0x00000000, 38, // 208
            0x9CC8E161, 0x00000000, 39, // 209
            0x27027027, 0x27027027, 37, // 210
            0x9B4C6F9F, 0x00000000, 39, // 211
            0x9A90E7D9, 0x9A90E7D9, 39, // 212
            0x99D722DB, 0x00000000, 39, // 213
            0x991F1A51, 0x991F1A51, 39, // 214
            0x4C346405, 0x00000000, 38, // 215
            0x97B425ED, 0x97B425ED, 39, // 216
            0x4B809701, 0x4B809701, 38, // 217
            0x2593F69B, 0x2593F69B, 37, // 218
            0x12B404AD, 0x12B404AD, 36, // 219
            0x94F2094F, 0x94F2094F, 39, // 220
            0x25116025, 0x25116025, 37, // 221
            0x24E6A171, 0x24E6A171, 37, // 222
            0x24BC44E1, 0x24BC44E1, 37, // 223
            0x49249249, 0x49249249, 38, // 224
            0x91A2B3C5, 0x00000000, 39, // 225
            0x90FDBC09, 0x90FDBC09, 39, // 226
            0x905A3863, 0x905A3863, 39, // 227
            0x47DC11F7, 0x47DC11F7, 38, // 228
            0x478BBCED, 0x00000000, 38, // 229
            0x8E78356D, 0x8E78356D, 39, // 230
            0x46ED2901, 0x46ED2901, 38, // 231
            0x8D3DCB09, 0x00000000, 39, // 232
            0x2328A701, 0x2328A701, 37, // 233
            0x23023023, 0x23023023, 37, // 234
            0x45B81A25, 0x45B81A25, 38, // 235
            0x22B63CBF, 0x00000000, 37, // 236
            0x08A42F87, 0x08A42F87, 35, // 237
            0x44D72045, 0x00000000, 38, // 238
            0x891AC73B, 0x00000000, 39, // 239
            0x88888889, 0x00000000, 39, // 240
            0x10FEF011, 0x00000000, 36, // 241
            0x8767AB5F, 0x8767AB5F, 39, // 242
            0x86D90545, 0x00000000, 39, // 243
            0x4325C53F, 0x00000000, 38, // 244
            0x85BF3761, 0x85BF3761, 39, // 245
            0x85340853, 0x85340853, 39, // 246
            0x10953F39, 0x10953F39, 36, // 247
            0x42108421, 0x42108421, 38, // 248
            0x41CC9829, 0x41CC9829, 38, // 249
            0x10624DD3, 0x00000000, 36, // 250
            0x828CBFBF, 0x00000000, 39, // 251
            0x41041041, 0x41041041, 38, // 252
            0x81848DA9, 0x00000000, 39, // 253
            0x10204081, 0x10204081, 36, // 254
            0x80808081, 0x00000000, 39  // 255
        };
    }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.