C# GetPixel doesn't give exact color when Valorant is open

116 Views Asked by At

When I use getpixel to grab the current color of a pixel from my screen, it has a slight variation from the actual, true value.

For example, the background color of vs studio is 31, 31, 31 but it will give me anything ranging from 28 - 34.

This happens only when Valorant is open on my PC, even if it minimized and not in fullscreen.

Code:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using static System.Windows.Forms.LinkLabel;

namespace nameherecool
{
    sealed class Win32
    {
        [DllImport("user32.dll")]
        static public extern bool SetProcessDPIAware();

        [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 public System.Drawing.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;
        }
    }
    class Program
    {
        static void Main(string[] argfs)
        {
            while (true)
            {
                Console.SetCursorPosition(0, 0);
                Console.WriteLine(Win32.GetPixelColor(0, 0) + "      ");
                Thread.Sleep(500);
            }
        }
    }
}
1

There are 1 best solutions below

2
Johan Donne On

The problem with your code is that your system is using DPI-scaling (typical for High Resolution displays to keep things readable). By default the GetPixel function in GDI32 does not take DPI-scaling into account whereas the cursor-position does. This means you are not reading the pixel that is actually under the cursor.

The solution is simple: Let Windows know your app is DPI-aware (and GetPixel should use DPI-scaling as well) by calling SetProcessDPIAware:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace greenbox
{
    sealed class Win32
    {
        [DllImport("user32.dll")]
        static public extern bool SetProcessDPIAware();

        [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 public System.Drawing.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;
        }
    }    

    class Program
    {
        static void Main(string[] argfs)
        {
            Win32.SetProcessDPIAware();

            Color newNew;

            while (true)
            {
                newNew = Win32.GetPixelColor(Cursor.Position.X, Cursor.Position.Y);

                Console.SetCursorPosition(0, 0);
                Console.WriteLine(Cursor.Position);
                Console.WriteLine(newNew);
                Thread.Sleep(100);
            }
        }
    }
}