Spring – Rev 1

Subversion Repositories:
Rev:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Spring.Utilities
{
    public static class Helpers
    {
#region Public Methods

        /// <summary>
        ///     Enable double buffering for an arbitrary control.
        /// </summary>
        /// <param name="control">the control to enable double buffering for</param>
        /// <returns>true on success</returns>
        /// <remarks>Do not enable double buffering on RDP: https://devblogs.microsoft.com/oldnewthing/20060103-12/?p=32793</remarks>
        public static bool SetDoubleBuffered(this Control control)
        {
            if (SystemInformation.TerminalServerSession)
            {
                return false;
            }

            var dgvType = control.GetType();

            var pi = dgvType.GetProperty("DoubleBuffered",
                BindingFlags.Instance | BindingFlags.NonPublic);

            if (pi == null)
            {
                return false;
            }

            pi.SetValue(control, true, null);

            return true;
        }

        /// <summary>
        ///     Crop whitespace around a bitmap.
        /// </summary>
        /// <param name="bmp">the bitmap to process</param>
        /// <returns>a cropped bitmap</returns>
        /// <remarks>https://stackoverflow.com/users/329367/darren</remarks>
        public static Bitmap Crop(Bitmap bmp)
        {
            var w = bmp.Width;
            var h = bmp.Height;

            bool AllWhiteRow(int row)
            {
                for (var i = 0; i < w; ++i)
                {
                    if (bmp.GetPixel(i, row)
                           .R !=
                        255)
                    {
                        return false;
                    }
                }

                return true;
            }

            bool AllWhiteColumn(int col)
            {
                for (var i = 0; i < h; ++i)
                {
                    if (bmp.GetPixel(col, i)
                           .R !=
                        255)
                    {
                        return false;
                    }
                }

                return true;
            }

            var topmost = 0;

            for (var row = 0; row < h; ++row)
            {
                if (AllWhiteRow(row))
                {
                    topmost = row;
                }
                else
                {
                    break;
                }
            }

            var bottommost = 0;

            for (var row = h - 1; row >= 0; --row)
            {
                if (AllWhiteRow(row))
                {
                    bottommost = row;
                }
                else
                {
                    break;
                }
            }

            int leftmost = 0, rightmost = 0;

            for (var col = 0; col < w; ++col)
            {
                if (AllWhiteColumn(col))
                {
                    leftmost = col;
                }
                else
                {
                    break;
                }
            }

            for (var col = w - 1; col >= 0; --col)
            {
                if (AllWhiteColumn(col))
                {
                    rightmost = col;
                }
                else
                {
                    break;
                }
            }

            if (rightmost == 0)
            {
                rightmost = w; // As reached left
            }

            if (bottommost == 0)
            {
                bottommost = h; // As reached top.
            }

            var croppedWidth = rightmost - leftmost;
            var croppedHeight = bottommost - topmost;

            if (croppedWidth == 0) // No border on left or right
            {
                leftmost = 0;
                croppedWidth = w;
            }

            if (croppedHeight == 0) // No border on top or bottom
            {
                topmost = 0;
                croppedHeight = h;
            }

            try
            {
                var target = new Bitmap(croppedWidth, croppedHeight);

                using (var g = Graphics.FromImage(target))
                {
                    g.DrawImage(bmp,
                        new RectangleF(0, 0, croppedWidth, croppedHeight),
                        new RectangleF(leftmost, topmost, croppedWidth, croppedHeight),
                        GraphicsUnit.Pixel);
                }

                return target;
            }
            catch (Exception ex)
            {
                throw new Exception(
                    $"Values are topmost={topmost} btm={bottommost} left={leftmost} right={rightmost} croppedWidth={croppedWidth} croppedHeight={croppedHeight}",
                    ex);
            }
        }

        public static string Md5Hash(string input)
        {
            // Use input string to calculate MD5 hash
            using (var md5 = MD5.Create())
            {
                var inputBytes = Encoding.ASCII.GetBytes(input);
                var hashBytes = md5.ComputeHash(inputBytes);

                // Convert the byte array to hexadecimal string
                var sb = new StringBuilder();

                foreach (var hashByte in hashBytes)
                {
                    sb.Append(hashByte.ToString("X2"));
                }

                return sb.ToString();
            }
        }

        public static string Sha1Hash(string input)
        {
            using (var sha1 = new SHA1Managed())
            {
                var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(input));
                var sb = new StringBuilder(hash.Length * 2);

                foreach (var b in hash)
                {
                    // can be "x2" if you want lowercase
                    sb.Append(b.ToString("X2"));
                }

                return sb.ToString();
            }
        }

        public static async Task<byte[]> LoadResource(string resource)
        {
            var assembly = Assembly.GetExecutingAssembly();

            using (var manifestResourceStream = assembly.GetManifestResourceStream(resource))
            {
                if (manifestResourceStream == null)
                {
                    return null;
                }

                var memoryStream = new MemoryStream();

                await manifestResourceStream.CopyToAsync(memoryStream);

                memoryStream.Position = 0L;

                return memoryStream.ToArray();
            }
        }

        public static void InvokeIfRequired<T>(this T control, Action<T> action) where T : Control
        {
            if (control.InvokeRequired)
            {
                control.BeginInvoke((MethodInvoker) delegate { action(control); });

                return;
            }

            action(control);
        }

        public static T MapValueToRange<T>(this T value, T xMin, T xMax, T yMin, T yMax)
            where T : struct, IComparable<T>, IConvertible =>
            (dynamic) yMin +
            ((dynamic) yMax - (dynamic) yMin) * ((dynamic) value - (dynamic) xMin) / ((dynamic) xMax - (dynamic) xMin);

        public static IEnumerable<TU> SequenceSubtract<TU, TV>(this IEnumerable<TU> a,
                                                               IEnumerable<TV> b,
                                                               Func<TU, TV, bool> cmp)
        {
            var eb = new List<TV>(b);

            using (var ea = a.GetEnumerator())
            {
                while (ea.MoveNext())
                {
                    if (ea.Current == null)
                    {
                        continue;
                    }

                    foreach (var ib in eb)
                    {
                        if (cmp.Invoke(ea.Current, ib))
                        {
                            continue;
                        }

                        yield return ea.Current;

                        break;
                    }
                }
            }
        }

#endregion
    }
}