Как читать цвет пикселя экрана
Хорошо, я ищу функцию или что-то, что будет читать цвет определенного пикселя на моем мониторе, и когда этот цвет будет обнаружен, будет включена другая функция. Я использую RGB. Вся помощь была оценена. Спасибо.
- addFontFile из ресурсов
- Правильный способ изменения языка во время выполнения
- Отображение формы Windows на дополнительном мониторе?
- Как предотвратить печать экрана
- Как вы должны диагностировать ошибку? SEHException - Внешний компонент выбрал исключение
- Как визуализировать формулу в WPF или WinForms
- Добавить таймер в приложение Windows Forms
- Как получить список всех принтеров на компьютере
Это наиболее эффективно: он захватывает пиксель в месте расположения курсора и не полагается только на один монитор.
using System; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.Windows.Forms; using System.Diagnostics; namespace FormTest { public partial class Form1 : Form { [DllImport("user32.dll")] static extern bool GetCursorPos(ref Point lpPoint); [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); public Form1() { InitializeComponent(); } private void MouseMoveTimer_Tick(object sender, EventArgs e) { Point cursor = new Point(); GetCursorPos(ref cursor); var c = GetColorAt(cursor); this.BackColor = c; if (cR == cG && cG < 64 && cB > 128) { MessageBox.Show("Blue"); } } Bitmap screenPixel = new Bitmap(1, 1, PixelFormat.Format32bppArgb); public Color GetColorAt(Point 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, location.X, location.Y, (int)CopyPixelOperation.SourceCopy); gdest.ReleaseHdc(); gsrc.ReleaseHdc(); } } return screenPixel.GetPixel(0, 0); } } }
Теперь, очевидно, вам не нужно использовать текущее местоположение курсора, но это общая идея.
РЕДАКТИРОВАТЬ:
Учитывая вышеприведенную функцию GetColorAt
вы можете опросить определенный пиксель на экране безопасным, удобным для производительности способом:
private void PollPixel(Point location, Color color) { while(true) { var c = GetColorAt(location); if (cR == color.R && cG == color.G && cB == color.B) { DoAction(); return; } // By calling Thread.Sleep() without a parameter, we are signaling to the // operating system that we only want to sleep long enough for other // applications. As soon as the other apps yield their CPU time, we will // regain control. Thread.Sleep() } }
вprivate void PollPixel(Point location, Color color) { while(true) { var c = GetColorAt(location); if (cR == color.R && cG == color.G && cB == color.B) { DoAction(); return; } // By calling Thread.Sleep() without a parameter, we are signaling to the // operating system that we only want to sleep long enough for other // applications. As soon as the other apps yield their CPU time, we will // regain control. Thread.Sleep() } }
Вы можете обернуть это в streamе, если хотите, или выполнить его из консольного приложения. «Что бы ни нравилось твоей фантазии», я думаю.
В большинстве ответов здесь используется тот же источник этого пикселя (рабочий стол постоянного тока).
Ключевой функцией является GetPixel
.
[DllImport("user32.dll", SetLastError = true)] public static extern IntPtr GetDesktopWindow(); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr GetWindowDC(IntPtr window); [DllImport("gdi32.dll", SetLastError = true)] public static extern uint GetPixel(IntPtr dc, int x, int y); [DllImport("user32.dll", SetLastError = true)] public static extern int ReleaseDC(IntPtr window, IntPtr dc); public static Color GetColorAt(int x, int y) { IntPtr desk = GetDesktopWindow(); IntPtr dc = GetWindowDC(desk); int a = (int) GetPixel(dc, x, y); ReleaseDC(desk, dc); return Color.FromArgb(255, (a >> 0) & 0xff, (a >> 8) & 0xff, (a >> 16) & 0xff); }
Я думаю, что это самый чистый и быстрый способ.
Примечание .
Если вы изменили размер текста по умолчанию среди параметров экрана в Windows, чтобы повысить читаемость на дисплее с высоким разрешением, параметры координат GetPixel () необходимо отрегулировать одинаково. Например, если местоположение курсора (x, y) с 150% размера текста в Windows 7, вам нужно вызвать GetPixel (x * 1.5, y * 1.5), чтобы получить цвет пикселя под курсором.
Пожалуйста, проверьте две разные функции, которые я использовал в одном из моих предыдущих проектов:
1) Эта функция выполняет моментальный снимок рабочего стола
private void CaptureScreenAndSave(string strSavePath) { //SetTitle("Capturing Screen..."); Bitmap bmpScreenshot; Graphics gfxScreenshot; bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height,System.Drawing.Imaging.PixelFormat.Format32bppArgb); gfxScreenshot = Graphics.FromImage(bmpScreenshot); gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy); MemoryStream msIn = new MemoryStream(); bmpScreenshot.Save(msIn, System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()[0], null); msIn.Close(); byte[] buf = msIn.ToArray(); MemoryStream msOut = new MemoryStream(); msOut.Write(buf, 0, buf.Length); msOut.Position = 0; Bitmap bmpOut = new Bitmap(msOut); try { bmpOut.Save(strSavePath, System.Drawing.Imaging.ImageFormat.Bmp); //SetTitle("Capturing Screen Image Saved..."); } catch (Exception exp) { } finally { msOut.Close(); } }
2) Эта функция принимает изображение во входе и вычисляет RGB среднее значение диапазона пикселей.
double GetRGBAverageForPixelRange( int istartRange, int iEndRange, Bitmap oBitmap ) { double dRetnVal = 0 ; Color oTempColor ; int i, j ; for( int iCounter = istartRange ; iCounter < iEndRange ; iCounter++ ) { i = (iCounter % (oBitmap.Width)); j = ( iCounter / ( oBitmap.Width ) ) ; if (i >= 0 && j >= 0 && i < oBitmap.Width && j < oBitmap.Height ) { oTempColor = oBitmap.GetPixel(i, j); dRetnVal = dRetnVal + oTempColor.ToArgb(); } } return dRetnVal ; }
Эти две функции вместе могут решить вашу проблему. Счастливое кодирование 🙂
EDIT : Обратите внимание, что GetPixel работает очень медленно. Я буду думать дважды, прежде чем использовать его.
Насколько я знаю, самый простой способ сделать это:
- сделать снимок экрана
- посмотрите на bitmap и получите цвет пикселя
редактировать
Вероятно, нет способа «подождать», пока пиксель не изменится на определенный цвет. Ваша программа, вероятно, должна будет просто зацикливаться и проверять ее каждый раз, пока не увидит цвет.
Например:
while(!IsPixelColor(x, y, color)) { //probably best to add a sleep here so your program doesn't use too much CPU } DoAction();
EDIT 2
Вот пример кода, который вы можете изменить. Этот код просто изменяет цвет метки на основе текущего цвета в данном пикселе. Этот код позволяет избежать упомянутой утечки рукоятки.
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.Threading; using System.Runtime.InteropServices; namespace WindowsFormsApplication1 { public partial class Form1 : Form { [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); Thread t; int x, y; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { x = 20; y = 50; t = new Thread(update); t.Start(); } private void update() { Bitmap screenCopy = new Bitmap(1, 1); using (Graphics gdest = Graphics.FromImage(screenCopy)) { while (true) { //g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(256, 256)); using (Graphics gsrc = Graphics.FromHwnd(IntPtr.Zero)) { IntPtr hSrcDC = gsrc.GetHdc(); IntPtr hDC = gdest.GetHdc(); int retval = BitBlt(hDC, 0, 0, 1, 1, hSrcDC, x, y, (int)CopyPixelOperation.SourceCopy); gdest.ReleaseHdc(); gsrc.ReleaseHdc(); } Color c = Color.FromArgb(screenCopy.GetPixel(0, 0).ToArgb()); label1.ForeColor = c; } } } }
}
Эта функция короче и может достичь того же результата, используя System.Drawing
, без Pinvoke.
Bitmap bmp = new Bitmap(1, 1); Color GetColorAt(int x, int y) { Rectangle bounds = new Rectangle(x, y, 1, 1); using (Graphics g = Graphics.FromImage(bmp)) g.CopyFromScreen(bounds.Location, Point.Empty, bounds.Size); return bmp.GetPixel(0, 0); }