Program & Design Tips, tricks, tutorials, and tools on programming & web design

10Sep/122

High quality image resize (C#)

You can use this class to resize images proportionally (maintaining aspect ratio), or to resize an image to an exact size and crop off excess (useful for making nice thumbnails):

public static class ImageExt
{
    public static Image Resize(this Image img, int srcX, int srcY, int srcWidth, int srcHeight, int dstWidth, int dstHeight)
    {
        var bmp = new Bitmap(dstWidth, dstHeight);
        using (var graphics = Graphics.FromImage(bmp))
        {
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.CompositingMode = CompositingMode.SourceCopy;
            graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
            using (var wrapMode = new ImageAttributes())
            {
                wrapMode.SetWrapMode(WrapMode.TileFlipXY);
                var destRect = new Rectangle(0, 0, dstWidth, dstHeight);
                graphics.DrawImage(img, destRect, srcX, srcY, srcWidth, srcHeight, GraphicsUnit.Pixel, wrapMode);
            }
        }
        return bmp;
    }

    public static Image ResizeProportional(this Image img, int width, int height, bool enlarge=false)
    {
        double ratio = Math.Max(img.Width / (double)width, img.Height / (double)height);
        if (ratio < 1 && !enlarge) return img;
        return img.Resize(0, 0, img.Width, img.Height, M2.Round(img.Width / ratio), M2.Round(img.Height / ratio));
    }

    public static Image ResizeCropExcess(this Image img, int dstWidth, int dstHeight)
    {
        double srcRatio = img.Width / (double)img.Height;
        double dstRatio = dstWidth / (double)dstHeight;
        int srcX, srcY, cropWidth, cropHeight;

        if (srcRatio < dstRatio) // trim top and bottom
        {
            cropHeight = dstHeight * img.Width / dstWidth;
            srcY = (img.Height - cropHeight) / 2;
            cropWidth = img.Width;
            srcX = 0;
        }
        else // trim left and right
        {
            cropWidth = dstWidth * img.Height / dstHeight;
            srcX = (img.Width - cropWidth) / 2;
            cropHeight = img.Height;
            srcY = 0;
        }

        return Resize(img, srcX, srcY, cropWidth, cropHeight, dstWidth, dstHeight);
    }
}
Filed under: C# 2 Comments
10Sep/120

Convert decimal numbers to any base (C#)

You can use this little function to convert a decimal to any base. I use it for compacting large numbers.

public static class BaseConverter
{
    public static string Encode(BigInteger value, int @base=0, string chars="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
    {
        if (@base <= 0) @base = chars.Length;
        var sb = new StringBuilder();
        do
        {
            int m = (int)(value % @base);
            sb.Insert(0, chars[m]);
            value = (value - m) / @base;
        } while (value > 0);
        return sb.ToString();
    }
}

Or you can use it to make a nice GUID:

private static BigInteger UnsignedBigInt(byte[] bytes)
{
    if ((bytes[bytes.Length - 1] & 0x80) != 0) Array.Resize(ref bytes, bytes.Length + 1);
    return new BigInteger(bytes);
}

private static string GetUniqueFileName(string extension)
{
    return BaseConverter.Encode(UnsignedBigInt(Guid.NewGuid().ToByteArray()), 0, "0123456789abcdefghijklmnopqrstuvwxyz_-") + extension;
}
Filed under: C# No Comments
2Jan/118

JSON Prettifier

This is a simple class I wrote to nicely format a JSON string. Just call it with JsonFormatter.PrettyPrint(yourJsonString)

public static class JsonFormatter
{
    public static string Indent = "    ";

    public static void AppendIndent(StringBuilder sb, int count)
    {
        for (; count > 0; --count) sb.Append(Indent);
    }

    public static bool IsEscaped(StringBuilder sb, int index)
    {
        bool escaped = false;
        while (index > 0 && sb[--index] == '\\') escaped = !escaped;
        return escaped;
    }

    public static string PrettyPrint(string input)
    {
        var output = new StringBuilder(input.Length * 2);
        char? quote = null;
        int depth = 0;

        for(int i=0; i<input.Length; ++i)
        {
            char ch = input[i];

            switch (ch)
            {
                case '{':
                case '[':
                    output.Append(ch);
                    if (!quote.HasValue)
                    {
                        output.AppendLine();
                        AppendIndent(output, ++depth);
                    }
                    break;
                case '}':
                case ']':
                    if (quote.HasValue)  
                        output.Append(ch);
                    else
                    {
                        output.AppendLine();
                        AppendIndent(output, --depth);
                        output.Append(ch);
                    }
                    break;
                case '"':
                case '\'':
                    output.Append(ch);
                    if (quote.HasValue)
                    {
                        if (!IsEscaped(output, i))
                            quote = null;
                    }
                    else quote = ch;
                    break;
                case ',':
                    output.Append(ch);
                    if (!quote.HasValue)
                    {
                        output.AppendLine();
                        AppendIndent(output, depth);
                    }
                    break;
                case ':':
                    if (quote.HasValue) output.Append(ch);
                    else output.Append(" : ");
                    break;
                default:
                    if (quote.HasValue || !char.IsWhiteSpace(ch))
                        output.Append(ch);
                    break;
            }
        }

        return output.ToString();
    }
}
Filed under: C# 8 Comments
30Dec/100

Subtracting Sets

A couple times now I've wanted to subtract one set (`HashSet`) from another. `HashSet` has a method ExceptWith that does just this, except that it modifies the current set in place. What if you don't want that? You need to copy it first.

Or you could use Linq's Except method, except that it returns `IEnumerable` instead of a `HashSet`. What if you don't want that? You need to convert it.

So... which method is faster? Let's find out!

static class Program
{
    public static HashSet<T> ToSet<T>(this IEnumerable<T> collection)
    {
        return new HashSet<T>(collection);
    }

    public static HashSet<T> Subtract<T>(this HashSet<T> set, IEnumerable<T> other)
    {
        var clone = set.ToSet();
        clone.ExceptWith(other);
        return clone;
    }

    static void Main(string[] args)
    {
        var A = new HashSet<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        var B = new HashSet<int> { 2, 4, 6, 8, 10 };
        var sw = new Stopwatch();

        sw.Restart();
        for (int i = 0; i < 1000000; ++i)
        {
            var C = A.Except(B).ToSet();
        }
        sw.Stop();
        Console.WriteLine("Linq: {0} ms", sw.ElapsedMilliseconds);

        sw.Restart();
        for (int i = 0; i < 1000000; ++i)
        {
            var C = A.Subtract(B);
        }
        sw.Stop();
        Console.WriteLine("Native: {0} ms", sw.ElapsedMilliseconds);

        Console.ReadLine();
    }
}

On my computer, this outputs:

Linq: 1291 ms
Native: 756 ms

So, clearly the second method is faster. About 40% for you math types.

I should note that "clone" isn't really a clone, it's a shallow copy. Only the container class itself is "cloned"; the elements still refer their originals.

Filed under: C# No Comments
20Oct/103

String Slice

Here's an extension method to slice strings in C#, similar to Python's slice notation.

public static string Slice(this string str, int? start = null, int? end = null, int step = 1)
{
    if (step == 0) throw new ArgumentException("Step size cannot be zero.", "step");

    if (start == null) start = step > 0 ? 0 : str.Length - 1;
    else if (start < 0) start = start < -str.Length ? 0 : str.Length + start;
    else if (start > str.Length) start = str.Length;

    if (end == null) end = step > 0 ? str.Length : -1;
    else if (end < 0) end = end < -str.Length ? 0 : str.Length + end;
    else if (end > str.Length) end = str.Length;

    if (start == end || start < end && step < 0 || start > end && step > 0) return "";
    if (start < end && step == 1) return str.Substring(start.Value, (end - start).Value);

    var sb = new StringBuilder((int)Math.Ceiling((end - start).Value / (float)step));
    for (int i = start.Value; step > 0 && i < end || step < 0 && i > end; i += step)
        sb.Append(str[i]);
    return sb.ToString();
}

"Hello World".Slice(1, -1); // ello Worl
"Hello World".Slice(null, null, -1); // dlroW olleH
Filed under: C# 3 Comments
5Sep/100

How to deep-copy/clone an object

The easiest way to deep copy an object is to serialize and deserialize it. Here's an example from a project I'm working on:

[Serializable()]
public class Board :ICloneable, ISerializable {

    // ...

    object ICloneable.Clone()
    {
        return this.Clone();
    }

    public Board Clone()
    {
        using (var ms = new MemoryStream())
        {
            var bf = new BinaryFormatter();
            bf.Serialize(ms, this);
            ms.Position = 0;
            return (Board)bf.Deserialize(ms);
        }
    }

You might need to implement the serialization functions too for this to work, however.

Filed under: C# No Comments
7May/102

Thread-Safe Observable List for WPF

I'm probably posting this too early; I haven't had a chance to extensively test it yet but I basically just locked every function down, and made any method that actually modifies the list run on the main thread so that notifications can be sent. It ought to work :)

class ObservableList<T> : IList<T>, INotifyCollectionChanged where T : INotifyPropertyChanged
{
    private Dispatcher dispatcher;
    private List<T> list;
    private object sync;

    public ObservableList(Dispatcher dispatcher = null)
    {
        this.dispatcher = dispatcher ?? Dispatcher.CurrentDispatcher;
        this.list = new List<T>();
        this.sync = new object();
    }

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        lock (sync)
        {
            if (CollectionChanged != null)
            {
                CollectionChanged(this, e);
            }
        }
    }

    public int IndexOf(T item)
    {
        lock (sync)
        {
            return list.IndexOf(item);
        }
    }

    public void Insert(int index, T item)
    {
        if (dispatcher.CheckAccess())
        {
            lock (sync)
            {
                list.Insert(index, item);
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
            }
        }
        else
        {
            dispatcher.Invoke(new Action<int, T>(Insert), DispatcherPriority.Send, index, item);
        }
    }

    public void RemoveAt(int index)
    {
        if (dispatcher.CheckAccess())
        {
            lock (sync)
            {
                var item = list[index];
                list.RemoveAt(index);
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index));
            }
        }
        else
        {
            dispatcher.Invoke(new Action<int>(RemoveAt), DispatcherPriority.Send, index);
        }
    }

    public T this[int index]
    {
        get
        {
            lock (sync) { return list[index]; }
        }
        set
        {
            lock (sync) { list[index] = value; }
        }
    }

    public void Add(T item)
    {
        if (dispatcher.CheckAccess())
        {
            lock (sync)
            {
                list.Add(item);
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
            }
        }
        else
        {
            dispatcher.Invoke(new Action<T>(Add), DispatcherPriority.Send, item);
        }
    }

    public void Clear()
    {
        if (dispatcher.CheckAccess())
        {
            lock (sync)
            {
                list.Clear();
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
        }
        else
        {
            dispatcher.Invoke(new Action(Clear), DispatcherPriority.Send);
        }
    }

    public bool Contains(T item)
    {
        lock (sync) { return list.Contains(item); }
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        lock (sync) { list.CopyTo(array, arrayIndex); }
    }

    public int Count
    {
        get { lock (sync) { return list.Count; } }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public bool Remove(T item)
    {
        if (dispatcher.CheckAccess())
        {
            lock (sync)
            {
                var index = list.IndexOf(item);
                var result = list.Remove(item);
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index));
                return result;
            }
        }
        else
        {
            return (bool)dispatcher.Invoke(new Func<T, bool>(Remove), DispatcherPriority.Send, item);
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        lock (sync)
        {
            return list.GetEnumerator();
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

You can simply delete the "where T : INotifyPropertyChanged" if you don't like that restriction, but I put it there so that you don't forget that your objects should notify your controls that their properties have changed, so that the GUI gets refreshed properly.

Filed under: C# 2 Comments
6May/100

Observable Priority Queue

Just started playing around with WPF in VS 2010. They have this ObservableCollection class which you can bind to your DataGrid or ListControl and then when you add or remove items from it, the control is refreshed automatically. However, I wanted to use my PriorityQueue class that I posted about earlier, so I modified it a bit:

class PriorityQueue<TValue> : PriorityQueue<TValue, int> where TValue : INotifyPropertyChanged { }
class PriorityQueue<TValue, TPriority> : IEnumerable<TValue>, INotifyCollectionChanged
    where TValue : INotifyPropertyChanged
    where TPriority : IComparable
{
    private SortedDictionary<TPriority, Queue<TValue>> dict = new SortedDictionary<TPriority, Queue<TValue>>(new ReverseComparer());
    private int count = 0;

    public int Count { get { return count; } }
    public bool Empty { get { return Count == 0; } }

    private class ReverseComparer : IComparer<TPriority>
    {
        public int Compare(TPriority x, TPriority y) { return y.CompareTo(x); }
    }

    public void Enqueue(TValue val, TPriority pri = default(TPriority))
    {
        ++count;
        if (!dict.ContainsKey(pri)) dict[pri] = new Queue<TValue>();
        dict[pri].Enqueue(val);
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, val));
    }

    public TValue Dequeue()
    {
        --count;
        var pair = dict.First();
        var queue = pair.Value;
        var val = queue.Dequeue();
        if (queue.Count == 0) dict.Remove(pair.Key);
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, val));
        return val;
    }

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (CollectionChanged != null)
        {
            CollectionChanged(this, e);
        }
    }

    public IEnumerator<TValue> GetEnumerator()
    {
        foreach (var queue in dict.Values)
        {
            foreach (var value in queue)
            {
                yield return value;
            }
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Priorities are sorted in descending order (higher value = higher priority).

Also discovered that I could just use "yield return" instead of having to write a custom Enumerator class too! Very nice. Especially since I wouldn't have known how to write it :)

Tagged as: , , , No Comments
2May/100

Human-readable file size in C#

static string ReadableFileSize(double size, int unit = 0)
{
    string[] units = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB" };

    while (size >= 1024)
    {
        size /= 1024;
        ++unit;
    }

    return String.Format("{0:G4} {1}", size, units[unit]);
}

I made "bytes" a double so you could pass in fractions, which you might get when calculating download speeds.

Tagged as: , No Comments
30Apr/101

A Simple Priority Queue in C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace QueueSpace
{
    public class PriorityQueue<TValue> : PriorityQueue<TValue, int> { }

    public class PriorityQueue<TValue, TPriority> where TPriority : IComparable
    {
        private SortedDictionary<TPriority, Queue<TValue>> dict = new SortedDictionary<TPriority, Queue<TValue>>();

        public int Count { get; private set; }
        public bool Empty { get { return Count == 0; } }

        public void Enqueue(TValue val)
        {
            Enqueue(val, default(TPriority));
        }

        public void Enqueue(TValue val, TPriority pri)
        {
            ++Count;
            if (!dict.ContainsKey(pri)) dict[pri] = new Queue<TValue>();
            dict[pri].Enqueue(val);
        }

        public TValue Dequeue()
        {
            --Count;
            var item = dict.Last();
            if (item.Value.Count == 1) dict.Remove(item.Key);
            return item.Value.Dequeue();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var pq = new PriorityQueue<int>();

            for (int i = 0; i < 10; ++i)
            {
                pq.Enqueue(i,i/2);
            }
            while (!pq.Empty)
            {
                Console.Write(pq.Dequeue() + " ");
            }

            Console.ReadKey();
        }
    }
}

Output

8 9 6 7 4 5 2 3 0 1

Items with the same priority are dequeued in the same order that they were inserted.