How to Read the Color of a Screen Pixel

How to read the Color of other Monitor Pixel

So the problem is different scales in each monitor

First, I detect index of which monitor the input point is in with this answer :

    private int ConvertMousePointToScreenIndex(Point mousePoint)
{
//first get all the screens
System.Drawing.Rectangle ret;

for (int i = 1; i <= Screen.AllScreens.Count(); i++)
{
ret = Screen.AllScreens[i - 1].Bounds;
if (ret.Contains(mousePoint))
return i - 1;
}
return 0;
}

Second, I just need to get real width / virtual width of that indexed monitor based on this answer

        const int ENUM_CURRENT_SETTINGS = -1;

public double GetScale(Point point)
{
Screen screen = Screen.AllScreens[ConvertMousePointToScreenIndex(point)];
DEVMODE dm = new DEVMODE();
dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
EnumDisplaySettings(screen.DeviceName, ENUM_CURRENT_SETTINGS, ref dm);

double RealWidth = dm.dmPelsWidth;
double VirtualWidth = screen.Bounds.Width;
return RealWidth / VirtualWidth;
}

[DllImport("user32.dll")]
public static extern bool EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);

[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
private const int CCHDEVICENAME = 0x20;
private const int CCHFORMNAME = 0x20;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public int dmPositionX;
public int dmPositionY;
public ScreenOrientation dmDisplayOrientation;
public int dmDisplayFixedOutput;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
public string dmFormName;
public short dmLogPixels;
public int dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
public int dmICMMethod;
public int dmICMIntent;
public int dmMediaType;
public int dmDitherType;
public int dmReserved1;
public int dmReserved2;
public int dmPanningWidth;
public int dmPanningHeight;
}

And finally, apply it to GetColorAt :

        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern int BitBlt(IntPtr hDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);

Bitmap screenPixel = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
public Color GetColorAt(Point location)
{
double scale = GetScale(location);
using (Graphics gdest = Graphics.FromImage(screenPixel))
{
using (Graphics gsrc = Graphics.FromHwnd(IntPtr.Zero))
{
IntPtr hSrcDC = gsrc.GetHdc();
IntPtr hDC = gdest.GetHdc();
int retval = BitBlt(hDC, 0, 0, 1, 1, hSrcDC, (int)Math.Round(point.X * scale), (int)Math.Round(point.Y * scale), (int)CopyPixelOperation.SourceCopy);
gdest.ReleaseHdc();
gsrc.ReleaseHdc();
}
}

return screenPixel.GetPixel(0, 0);
}

Quickly getting the color of some pixels on the screen in Python on Windows 7

I had this same exact problem, and solved it (in Java, in C#). The main idea behind the solution is GetPixel from screen is slow, and you can't fix that. But as you need some pixels, you can get a bunch of them all at once.

The time that it took to get 64 pixels was 98 times faster.

glReadPixels with screen pixels

As mentioned in the other answer and comments You can use glReadPixels only for pixels inside your OpenGL context window that are actually rendered at that time ... As you mentioned you have used GetPixel it hints you are using GDI. In that case you are trying to read GDI Canvas pixel from OpenGL which is not possible (the other way around is possible however but slow). So I advice to read this:

  • How can I access a graphics card's output directly?

Where you can find example of both methods. If you are trying to obtain pixel from your own app then you can use different api then GetPixel.

If you're in VCL environment use Graphics::TBitmap::ScanLine property which can be used for direct pixel access without restrictions or performance hits if used properly.

On MSVC++ of GCC environment use WinAPI BitBlt but that is a bit slower and not as elegant (at least from my point of view).

How to get the colour of a pixel at X,Y using c#?

To get a pixel color from the Screen here's code from Pinvoke.net:

  using System;
using System.Drawing;
using System.Runtime.InteropServices;

sealed class Win32
{
[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;
}
}

C# How to get pixel color/data from the screen?

To capture specific rectangle form the screen use the following code

    public Bitmap CaptureFromScreen(Rectangle rect)
{
Bitmap bmpScreenCapture = null;

if (rect == Rectangle.Empty)//capture the whole screen
{
rect = Screen.PrimaryScreen.Bounds;
}

bmpScreenCapture = new Bitmap(rect.Width,rect.Height);

Graphics p = Graphics.FromImage(bmpScreenCapture);


p.CopyFromScreen(rect.X,
rect.Y,
0, 0,
rect.Size,
CopyPixelOperation.SourceCopy);


p.Dispose();

return bmpScreenCapture;
}

To Get The color form a specific location use the function

    public Color GetColorFromScreen(Point p)
{
Rectangle rect = new Rectangle(p, new Size(2, 2));

Bitmap map = CaptureFromScreen(rect);

Color c = map.GetPixel(0, 0);

map.Dispose();

return c;
}

How can I get the color of a screen pixel THROUGH ADB

I will post an answer to my own question. The answer maybe device-specified (nexus7 2013), and you can adjust it to your own devices.

1.Firstly, I find out that the command screencap screen.png is quite slow because it take most of its time converting to png file type. So, to save time, the first step is dump screen to a raw data file.

adb shell
screencap screen.dump

2.Check the file size. My screen resolution is 1920*1200, and the file size is 9216012 byte. Noticing that 9216012=1920*1200*4+12, I guess the data file use 4 byte to store every pixel information, and use another 12 byte to do some mystery staff. Just do some more screencaps and I find the 12 byte at the head of each file are the same. So, the additional 12 byte is at the head of the data file.

3.Now, things are simple by using dd and hd. Assuming that I want to get the color at (x,y):

let offset=1200*$y+$x+3
dd if='screen.dump' bs=4 count=1 skip=$offset 2>/dev/null | hd

I get output like

00000000: 4b 73 61 ff s 21e
sum 21e

The 4b 73 61 ff is my answer.



Related Topics



Leave a reply



Submit