Search code examples
c#filefile-iostreamreaderstreamwriter

Read the file faster and get the pixel color quickly?


I've got the following code and it works properly, however, it works really slowly and to read the file with the recording and analyze each pixel - it takes way too long. Is there any way I could make it work faster?

[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("user32.dll")]
static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);
[DllImport("gdi32.dll")]
static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);

static void Main(string[] args)
{
    if (isCorrect("test.LOB"))
    {
        Console.WriteLine("Yes");
    }
    else
    {
        Console.WriteLine("Nope...");
    }
    Console.ReadKey();
    //Record("test", 0, 0, 50, 50, 10);
}

public static void Record(string name, int start_x, int start_y, int end_x, int end_y, int max_Difference)
{
    string path = name + ".LOB";
    string result;
    Color pixel_Result;
    for (int x = start_x; x <= end_x; x++)
    {
        for (int y = start_y; y <= end_y; y++)
        {
            pixel_Result = GetPixelColor(x, y);
            result = x + "|" + y + "|" + pixel_Result.R + "|" + pixel_Result.G + "|" + pixel_Result.B + "|" + max_Difference;
            if (!File.Exists(path))
            {
                using (StreamWriter sw = File.CreateText(path))
                {
                    sw.WriteLine(result);
                }
            }
            else
            {
                using (StreamWriter sw = File.AppendText(path))
                {
                    sw.WriteLine(result);
                }
            }
        }
    }
}

public static bool isCorrect(string path)
{
    using (StreamReader sr = File.OpenText(path))
    {
        string result = "";
        string[] correctedResult;
        while ((result = sr.ReadLine()) != null)
        {
            correctedResult = result.Split('|');
            int X = Convert.ToInt32(correctedResult[0]);
            int Y = Convert.ToInt32(correctedResult[1]);
            int R = Convert.ToInt32(correctedResult[2]);
            int G = Convert.ToInt32(correctedResult[3]);
            int B = Convert.ToInt32(correctedResult[4]);
            int maxDifference = Convert.ToInt32(correctedResult[5]);
            Color c;
            c = GetPixelColor(X, Y);
            maxDifference /= 2;
            if (R < c.R - maxDifference || R > c.R + maxDifference)
            {
                return false;
            }
            if (G < c.G - maxDifference || G > c.G + maxDifference)
            {
                return false;
            }
            if (B < c.B - maxDifference || B > c.B + maxDifference)
            {
                return false;
            }
        }
        return true;
    }
}

static public Color GetPixelColor(int x, int y)
{
    IntPtr hdc = GetDC(IntPtr.Zero);
    uint pixel = GetPixel(hdc, x, y);
    ReleaseDC(IntPtr.Zero, hdc);
    Color color = Color.FromArgb((int)(pixel & 0x000000FF),
                 (int)(pixel & 0x0000FF00) >> 8,
                 (int)(pixel & 0x00FF0000) >> 16);
    return color;
}

Thanks in advance!


Solution

  • There are two major issues slowing down your code. First, you open and close your stream writer every pixel, this is going to be very slow. Move the opening to outside of the loop. Also there is a constructor of StreamWriter that lets you specifiy append mode so you don't need your if/else check.

    The 2nd problem is you are opening and closing your IntPtr handle every pixel too, this is going to be very slow, open it once then close it when you are done.

    static public Color GetPixelColor(int x, int y, IntPtr hdc)
    {
        uint pixel = GetPixel(hdc, x, y);
        Color color = Color.FromArgb((int)(pixel & 0x000000FF),
                     (int)(pixel & 0x0000FF00) >> 8,
                     (int)(pixel & 0x00FF0000) >> 16);
        return color;
    }
    
    public static bool isCorrect(string path)
    {
        IntPtr hdc = GetDC(IntPtr.Zero);
        try
        {
            using (StreamReader sr = File.OpenText(path))
            {
                string result = "";
                string[] correctedResult;
                while ((result = sr.ReadLine()) != null)
                {
                    correctedResult = result.Split('|');
                    int X = Convert.ToInt32(correctedResult[0]);
                    int Y = Convert.ToInt32(correctedResult[1]);
                    int R = Convert.ToInt32(correctedResult[2]);
                    int G = Convert.ToInt32(correctedResult[3]);
                    int B = Convert.ToInt32(correctedResult[4]);
                    int maxDifference = Convert.ToInt32(correctedResult[5]);
                    Color c;
                    c = GetPixelColor(X, Y, hdc);
                    maxDifference /= 2;
                    if (R < c.R - maxDifference || R > c.R + maxDifference)
                    {
                        return false;
                    }
                    if (G < c.G - maxDifference || G > c.G + maxDifference)
                    {
                        return false;
                    }
                    if (B < c.B - maxDifference || B > c.B + maxDifference)
                    {
                        return false;
                    }
                }
                return true;
            }
        }
        finally
        {
            ReleaseDC(IntPtr.Zero, hdc);
        }
    }
    
    public static void Record(string name, int start_x, int start_y, int end_x, int end_y, int max_Difference)
    {
        string path = name + ".LOB";
    
        string result;
        Color pixel_Result;
    
        IntPtr hdc = GetDC(IntPtr.Zero);
        try
        {
            using (StreamWriter sw = new StreamWriter(path, append:true))
            {
                for (int x = start_x; x <= end_x; x++)
                {
                    for (int y = start_y; y <= end_y; y++)
                    {
                        pixel_Result = GetPixelColor(x, y, hdc);
                        result = x + "|" + y + "|" + pixel_Result.R + "|" + pixel_Result.G + "|" + pixel_Result.B + "|" + max_Difference;
                        sw.WriteLine(result);
                    }
                }
            }
        finally
        {
            ReleaseDC(IntPtr.Zero, hdc);
        }
    }
    

    If after fixing the slowness in GetPixelColor the code is still too slow I would recommend running a profiler on the code to see which part is the slowness coming from, you may be able to pipeline the work with some tools like TPL DataFlow so the reading of the pixels are single threaded but you use multiple threads to test the read values to see if they are correct or not.