Click here to Skip to main content
15,867,453 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
The code below when invoked to get a pixel on multiple screens or one screen with Display zoom on it, e.g. 150%, it doesn't get the right pixel in 3840x2160 pixels, it gets another pixel because of the zoom, how to fix that plz?

What I have tried:

static Color GetPixel(Point p)
{
    using (var bitmap = new Bitmap(1, 1))
    {
        using (var graphics = Graphics.FromImage(bitmap))
        {
            graphics.CopyFromScreen(p, new Point(0, 0), new Size(1, 1));
        }
        return bitmap.GetPixel(0, 0);
    }
}



I do this:
if (formMain.WindowState != FormWindowState.Minimized)
                {
                    if (
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50, formMain.pictureBoxCleanup.Top + 20))) == Color.Gray) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 1, formMain.pictureBoxCleanup.Top + 20))) == Color.DarkGray) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 2, formMain.pictureBoxCleanup.Top + 20))) == Color.Brown) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50, formMain.pictureBoxCleanup.Top + 21))) == Color.RosyBrown) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 1, formMain.pictureBoxCleanup.Top + 21))) == Color.DarkSlateGray) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 2, formMain.pictureBoxCleanup.Top + 21))) == Color.DarkGray) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50, formMain.pictureBoxCleanup.Top + 22))) == Color.SlateGray) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 1, formMain.pictureBoxCleanup.Top + 22))) == Color.LightSlateGray) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 2, formMain.pictureBoxCleanup.Top + 22))) == Color.LightGray))
                    {
                        Program.DoMouseClick(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 1, formMain.pictureBoxCleanup.Top + 21)));
                    }
                }


And this:



private void FormMain_Paint(object sender, PaintEventArgs e)
{
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50, 20, Color.Gray);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50 + 1,20, Color.DarkGray);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50 + 2, 20, Color.Brown);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50, 21, Color.RosyBrown);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50 + 1, 21, Color.White);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50 + 2, 21, Color.DarkGray);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50, 22, Color.SlateGray);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50 + 1, 22, Color.LightSlateGray);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50 + 2, 22, Color.LightGray);
}
Posted
Updated 28-Mar-20 11:35am
v2

1 solution

When I was developing the Known Color Pallette Tool (reported in The Known Colors Palette Tool - Final Revision - Hopefully[^], I ran across the same problem (only in the production environment). I revised my code to read as follows and it appears to work.

C#
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace Known_Colors_Palette
    {

    // ************************************************ class Win32API

    /// <summary>
    /// makes available various Win32 API entry points
    /// </summary>
    public class Win32API
        {

        // **************************************************** BitBlt
        
        [ DllImport ( "gdi32.dll", 
                      EntryPoint = "BitBlt" ) ]
        public static extern bool BitBlt ( IntPtr hdcDest, 
                                           int    nXDest,
                                           int    nYDest, 
                                           int    nWidth, 
                                           int    nHeight, 
                                           IntPtr hdcSrc,
                                           int    nXSrc, 
                                           int    nYSrc, 
                                           int    dwRop );

        // ************************************************* get_pixel

        /// <summary>
        /// obtain the GDI+ Color of the pixel at the specified 
        /// location on the monitor
        /// </summary>
        /// <param name="location">
        /// Point containing the location of the pixel on the monitor 
        /// whose Color is to be obtained
        /// </param>
        /// <returns>
        /// the GDI+ Color of the pixel at the location on the screen
        /// </returns>
        /// <remarks>
        /// The method does not use GetPixel, resulting in four 
        /// benefits: 
        /// 1.  the method will not raise an exception when used 
        ///     in a multi-monitor environment; 
        /// 2.  it is faster than GetPixel; 
        /// 3.  the Bitmap used is only one pixel high and wide;
        /// 4.  the Bitmap is local to this method.
        /// </remarks>
        /// <see>
        /// http://stackoverflow.com/questions/1483928/
        ///     how-to-read-the-color-of-a-screen-pixel
        /// </see>
        public static Color get_pixel ( Point location )
            {
            Bitmap  screen_pixel = new Bitmap (
                                        1,
                                        1,
                                        PixelFormat.Format32bppArgb );

            using ( Graphics destination = Graphics.FromImage ( 
                                                    screen_pixel ) )
                {
                using ( Graphics source = Graphics.FromHwnd ( 
                                                   IntPtr.Zero ) )
                    {
                    IntPtr source_DC = source.GetHdc ( );
                    IntPtr destination_DC = destination.GetHdc ( );

                    BitBlt ( destination_DC,
                             0,
                             0,
                             1,
                             1,
                             source_DC,
                             location.X,
                             location.Y,
                             ( int ) CopyPixelOperation.SourceCopy );
                    }
                }

            return ( screen_pixel.GetPixel ( 0, 0 ) );
            }

        } // class Win32API

    } // namespace Known_Colors_Palette

This is a small part of the Win32API.cs code but it includes that portion that may be helpful to you. Good Luck.
 
Share this answer
 
Comments
john1990_1 28-Mar-20 17:12pm    
Thx, didn't work for me:
I edited my question with 2 new blocks of code, plz see them.
gggustafson 28-Mar-20 23:56pm    
You are making me as confused as you are. Why the one pixel offset in the test?
john1990_1 29-Mar-20 8:34am    
I want to make sure formMain is actually shown on the display and there's no lag preventing it from being shown on the display, so I made 3x3 square of colors and this way there's a tiny chance that the pixel colors aren't from my form, because I want my program to order Windows to fake a mouse click on my program (form) in order to select the form in my Google Translate page in my web browser control in my form! I tried everything to select the form like formMain.webBrowser.Document.GetElementByID("source").Focus(); and stuff like that and none of them is always successful so I make a mouse click that always works but I dont want it to click something else I want to make sure the click is on my program (my form).
gggustafson 29-Mar-20 12:27pm    
I think you are getting wrapped around the axel. You need to stop and restart by successfully doing one thing. It appear that the first thing you should do is to write a method that will determine the properties of a form supposedly displayed on a monitor. See https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-findwindowa?redirectedfrom=MSDN. Then we can discuss the next step.
john1990_1 29-Mar-20 13:03pm    
The window is *my program's window*, my program wants to order a mouse click on MY OWN WINDOW THE SAME PROGRAM THAT ORDERS THE CLICK IS THE SAME PROGRAM THAT RECEIVES THE CLICK, this is because wb.Document.GetElementById("source").Focus() is not working, I want to order a mouse click on my program's window to select focus of input on it, this is used when F1 is pressed and my program opens its window for the user to start typing in the source textbox is the "web browser control" in my program's window, my program is to translate, I want to make sure the window is open because when my Winfors.Net app orders Windows to simulate a mouse click on the same app's window I don't want this mouse simulated click to go somewhere other than my program's window. I think it's pretty much clear!!!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900