blog of Guganeshan.T

January 30, 2012

StackOverflow logo using C# and GDI+

Filed under: Programming — Tags: , , , , , — Guganeshan.T @ 12:09 am

StackOverflow logoDiscovered the “Code Golf” in StackExchange from the people I follow in twitter (for the #codechallenge hashtag).

The question to generate the StackOverflow logo in code was particularly interesting to me and naturally I wanted to try generating the logo using C# (GDI+ code). Because nobody had a C# solution listed there, I also put the code there as an answer (Look for the answer titled “C#/GDI+”)

I initially recreated the logo in GDI+ without a for loop (every rectangle had a hardcoded value for its locations and size). Using that approach, its possible to recreate the logo almost identical to the original. But I was not happy with doing it that way.

Also because they say → “The image is not required to be identical to the logo, however it must be recognizable as it” in the description, I used a for loop to minimize the number of lines written and to just generate a logo that looks like the StackOverflow logo, but not identical.

This is no “ingenious” code. I would be really happy to see anyone generating the same logo with GDI+ in a more efficient and accurate manner, using a formula to represent the exact curve that the original logo has (without hard-coding each and every position and size of the overflowing elements)

Here’s the difference between my generated logo and the original StackOverflow logo →

stackoverflow logo generated vs original

Click here to download the code (zip file)

Here’s the code listing:

using System.Drawing;
using System.Drawing.Drawing2D;
 
namespace StackOverflowLogoCodeChallenge
{
    public class SOLogo
    {
        private float _rotateValue;
        private float _xValueForTransformation;
        private float _yValueForTransformation;
 
        int _containerWidth;
        int _containerHeight;
        float _lineThickness;
        int _paddingWithinContainer;
        int _elementStartY;
 
        public SOLogo(
            float rotateValue,
            float xValueForTransformation,
            float yValueForTransformation)
        {
            // Values used to position and rotate the overflowing elements.
            _rotateValue = rotateValue;
            _xValueForTransformation  = xValueForTransformation;
            _yValueForTransformation = yValueForTransformation;
        }
 
        public void DrawLogo(Graphics g, int startX, int startY)
        {
            // Backup the current smoothing mode to apply later.
            var SmoothingMoodBackup = g.SmoothingMode;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
 
            // Values for the container box.
            _containerWidth = 94;
            _containerHeight = 61;
            _lineThickness = 11f;
            _paddingWithinContainer = 15;
 
            // Y value of the position where the 1st overflowing element starts.
            _elementStartY = 0;
 
            // Starting point of the 'container':
            // Top point of the line on the left-> |_|
            Point pointContainerLineStart = new Point(startX, startY);
 
            Point pointContainer1stLineEnd =new Point(
                pointContainerLineStart.X,
                pointContainerLineStart.Y); // Start with the previous
            pointContainer1stLineEnd.Offset(0, _containerHeight); // Offset "Y"
 
            Point pointContainer2ndLineEnd = new Point(
                pointContainer1stLineEnd.X,
                pointContainer1stLineEnd.Y); // Start with the previous
            pointContainer2ndLineEnd.Offset(_containerWidth, 0); // Offset "X"
 
            Point pointContainer3rdLineEnd = new Point(
                pointContainer2ndLineEnd.X,
                pointContainer2ndLineEnd.Y); // Start with the previous
            pointContainer3rdLineEnd.Offset(0, 0 - _containerHeight); // Offset "Y" (negative)
 
            GraphicsPath pathOfBox = new GraphicsPath();
            pathOfBox.AddLine(
                pointContainerLineStart,
                pointContainer1stLineEnd); // Left line. Top to bottom
            pathOfBox.AddLine(
                pointContainer1stLineEnd,
                pointContainer2ndLineEnd); // Bottom line. Left to right
            pathOfBox.AddLine(
                pointContainer2ndLineEnd,
                pointContainer3rdLineEnd); // Right line. Bottom to top
 
            Pen thickPen = new Pen(Brushes.Gray, _lineThickness);
            Color elementColor = Color.FromKnownColor(KnownColor.Gray);
 
            // Draw the 'container'
            g.DrawPath(thickPen, pathOfBox);
 
            // Increase the size of the pen to draw the elements inside the container
            thickPen.Width = _lineThickness += 3;
            // "Y" - position of the 1st element
            _elementStartY = startY + 38;
 
            // The following section draws the overflowing elements
 
            Point pointElement1Left = new Point(
                startX + _paddingWithinContainer,
                _elementStartY);
            Point pointElement1Right = new Point(
                (startX + _containerWidth) - _paddingWithinContainer,
                _elementStartY);
 
            // Six colors of the overflowing elements
            var colors = new Color[] {
                Color.Gray,
                Color.FromArgb(-6911615),
                Color.FromArgb(-4417693),
                Color.FromArgb(-2848227),
                Color.FromArgb(-554957),
                Color.FromArgb(-688847)
            };
 
            for (int x = 0; x < 6; x++)
            {
                thickPen.Color = colors[x];
 
                pointElement1Left = new Point(
                    startX + _paddingWithinContainer,
                    _elementStartY);
                pointElement1Right = new Point(
                    (startX + _containerWidth) - _paddingWithinContainer,
                    _elementStartY);
 
                g.DrawLine(thickPen, pointElement1Left, pointElement1Right);
                g.RotateTransform(_rotateValue);
                g.TranslateTransform(_xValueForTransformation, _yValueForTransformation);
            }
 
            pathOfBox.Dispose();
            thickPen.Dispose();
 
            // Restore the smoothing mood that was backed up before we started this method.
            g.SmoothingMode = SmoothingMoodBackup;
        }
    }
}

Happy coding.
 

3 Comments »

  1. Have you considered adding some type of bookmarking buttons or links to your web page?

    Comment by tv amr — September 15, 2014 @ 12:23 pm

  2. Real Nice.
    The colors are correct.
    I guess you presumed that the bars are equally spaced.
    A simple modification would do the trick
    Keep up the good work

    Comment by SS D — February 17, 2016 @ 11:41 pm

  3. Thanks for the feedback! 🙂

    Comment by Guganeshan.T — February 20, 2016 @ 6:23 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment

CommentLuv badge

Powered by WordPress