Friday, February 21, 2014

Draw Pie Chart

In today's post I want to show how to draw pie charts (also called circle diagrams) "manually", meaning by drawing via the Graphics class, in C#. I got the idea because I wanted to draw one in an Android app, but in the Xamarin Studio there was no Chart control as opposed to in the Visual Studio.
Drawing is done by the class PieChart with the function Draw(). This expects a list of tuples as parameter, where the first value always describes the name of the corresponding category and the second the actual value.
The single pieces of the pie are then drawn by the function FillPie(), to which the starting and ending angle can be passed.
The function DetermineColor() determines the color of the pie arc, depending on the current angle. I tried to picture a complete color circle and for this approximted quadratic functions for the colors red, green and blue with a doman of 240° each. So that adjacent pieces have a high color contrast from each other, in turns to the current angle either 0°, 120° or 240° are added. I have to admit I am not really satisfied with this coloring function. If someone writes an interesting function for this, I would be very happy about a comment.
The first values of the tuples, the names of the categories, are not used in this class, because I thought that a possible labelling will anyway be very individual. For suggestions though I recommend a look at the post about the app linked above, there I print the labels below the chart.
Now the code:

    public class PieChart
    {
        int PosCounter = 0;

        private Color DetermineColor(float angle)
        {
            angle += PosCounter * 120;
            while (angle > 360)
                angle -= 360;

            PosCounter++;
            if (PosCounter > 2)
                PosCounter = 0;

            int Red;
            if (angle >= 270)
                Red = (int)((-0.000069 * Math.Pow((angle - 360), 2) + 1) * 255);
            else
                Red = (int)((-0.000069 * Math.Pow((angle), 2) + 1) * 255);
            Red = (Red > 0) ? Red : 0;
            Red = (Red > 255) ? 255 : Red;

            int Green = (int)((-0.000114 * Math.Pow((angle), 2) + 0.030682 * angle + -1.04545) * 255);
            Green = (Green > 0) ? Green : 0;
            Green = (Green > 255) ? 255 : Green;

            int Blue = (int)((-0.000069 * Math.Pow(((angle)), 2) + 0.033333 * angle - 3) * 255);
            Blue = (Blue > 0) ? Blue : 0;
            Blue = (Blue > 255) ? 255 : Blue;

            return Color.FromArgb(Red, Green, Blue);
        }

        public Bitmap Draw(List<Tuple<string,float>> data)
        {
            int PieSize = 400;
            float PrevStart = 0;

            Bitmap Result = new Bitmap(PieSize, PieSize);
            Graphics G = Graphics.FromImage(Result);

            float TotalValue = 0;
            for (int i = 0; i < data.Count; i++)
            {
                TotalValue += data[i].Item2;
            }

            for (int i = 0; i < data.Count; i++)
            {
                G.FillPie(new SolidBrush(DetermineColor(PrevStart)), new Rectangle(0, 0, PieSize, PieSize), PrevStart, (data[i].Item2 / TotalValue) * 360);
                PrevStart += (data[i].Item2 / TotalValue) * 360;
            }

            return Result;
        }
    }

A sample call could look as follows:
        private void pictureBox1_Click(object sender, EventArgs e)
        {
            PieChart A = new PieChart();
            List<Tuple<string, float>> B = new List<Tuple<string, float>>();

            B.Add(new Tuple<string, float>("A", 3));
            B.Add(new Tuple<string, float>("A", 2));
            B.Add(new Tuple<string, float>("A", 1));
            B.Add(new Tuple<string, float>("A", 2));
            B.Add(new Tuple<string, float>("A", 4));
            B.Add(new Tuple<string, float>("A", 3));

            pictureBox1.Image = A.Draw(B);
        }

The result then looks as follows:


Friday, February 14, 2014

Prevent Standby Mode

If one listens for example to music or watches a movie, the Windows computer does not enter the power saving mode / sleep mode despite the missing user interaction. But with a running C# application it does.
Today I want to show how to prevent this. For that we have to include the function SetThreadExecutionState() via P/Invoke, with which we can tell the system, that the program needs it right now.
Induced states can be amongst others:

  • ES_DISPLAY_REQUIRED: This mode prevents the shutting off of the displays.
  • ES_SYSTEM_REQUIRED: This mode prevents the shutting off of the whole system. 
If you call the function with one of these states alone, just the timer for the respective event is reset, meaning from the time of execution on the system counts as idle again and after the elapse of the set time the display / system is turned off.
To avoid the shutdown completely, the function either has to be called periodically or you combine the state with ES_CONTINOUS, then a single call is sufficient.
The following example program on startup tells the operating system, that it never is supposed to go to sleep:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public enum EXECUTION_STATE : uint
        {
            ES_AWAYMODE_REQUIRED = 0x00000040,
            ES_CONTINUOUS = 0x80000000,
            ES_DISPLAY_REQUIRED = 0x00000002,
            ES_SYSTEM_REQUIRED = 0x00000001
        }

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED);
        }
    }
}

Monday, February 3, 2014

Optical Character Recognition (OCR)

Due to a reader's comment on my German blog I experimented a bit with the very interesting topic of automatic text recognition, usually called "Optical character Recognition (OCR)", and found out that relatively easy relatively good results can be achieved.
OCR is the automatic recognition of texts and characters out of images - of course here I post about OCR in C#.
To write an own OCR class would not be easy - but there are a lot of complete classes, also for C#, which can be used. I used Puma.NET.
First of all this has to be downloaded from the homepage linked above. If you then want to use Puma in a program, first a reference to the library "Puma.Net.dll" has to be added, which is located on my computer under "C:\Program Files (x86)\Puma.NET\Assemblies".
If you then compile the project, the 3 files "puma.interop.dll", "Puma.Net.dll" and "dibapi.dll" have to appear in the Build folder. The last one probably does not exist and therefore has to be copied manually to that folder from the Assembly folder of Puma.
One last thing has to be done before you can work with OCR: Full access has to be given to the current user for the folder "COM Server" of the Puma directory.
Now to the code, with already 4 lines of code a complete text recognition can be realized. For simplicity we include Puma.Net via using.
First we have to create an object of the type PumaPage and hand the path to the image we want to recognize over.
Next we set the format of the characters, here we simply chose  TxtAscii.
Via the property Language we can even set the language of the text we want to sccan.
With RecognizeToString() the program then tries to recognize text from the image.
Here the complete code:

PumaPage P1 = new PumaPage(@"C:\Users\Oliver\Documents\Visual Studio 2013\Projects\COCR\COCR\bin\Debug\Test.bmp");
P1.FileFormat = PumaFileFormat.TxtAscii;
P1.Language = PumaLanguage.German;
string Result = P1.RecognizeToString();

For computer texts the program works pretty well, but as soon as the font gets a little bit more "squiggly", the quality of the result decreases rapidly.