如何获取椭圆内指定颜色的坐标? [英] How do I get the coordinates of a specified color inside an Ellipse?

查看:84
本文介绍了如何获取椭圆内指定颜色的坐标?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

小的免责声明:这是我第一次搞砸Forms中的Graphics,因此我对这里的概念不太熟悉



好的,因此我一直在尝试制作一个可在整个屏幕上跟踪光标位置并在其周围绘制椭圆的应用程序。我借用的代码来自


Small disclaimer: This is my first time messing with Graphics in Forms, therefore I am not so familiar with the concepts here

Alright, so I have been trying to make an application that tracks the cursor's position in the entire screen and draws an Ellipse around it. The code I borrowed was from this question (I changed the X and Y position of the Ellipse in order to auto-adjust itself around the cursor regardless of its size) everything works perfectly up to this point. Here is the code so far:

        public static float width;
        public static float height;

        public Main(float w, float h)
        {
            InitializeComponent();
            this.DoubleBuffered = true;
            width = w;
            height = h;
            BackColor = Color.White;
            FormBorderStyle = FormBorderStyle.None;
            Bounds = Screen.PrimaryScreen.Bounds;
            TopMost = true;
            TransparencyKey = BackColor;
            this.ShowInTaskbar = false;
            timer1.Tick += timer1_Tick;
        }

        Timer timer1 = new Timer() { Interval = 1, Enabled = true };

        protected override void OnPaint(PaintEventArgs e)
        {
            DrawTest(e.Graphics);
            base.OnPaint(e);
        }

        private void DrawTest(Graphics g)
        {
            var p = PointToClient(Cursor.Position);
            g.DrawEllipse(Pens.DeepSkyBlue, p.X - (width / 2), p.Y - (height / 2), width, height);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Invalidate();
        }

So now I want the application to check whether a preassigned color is present within the area of the Ellipse, and if so, get the position of the nearest pixel to the cursor that has this color. I have searched everywhere and haven't found any method of doing it.

I get that the logic behind it would be to get all the pixels within the Ellipse, check if the color exists and find the one pixel with this color nearest to the cursor but I haven't been able to implement it.

Any help would be very appreciated.

解决方案

This is a simplified method (it doesn't require PInvoking, mouse tracking/hooking or other low level operations).
It can work well enough if you don't need too much control on what happens behind your Window, you don't want to record animated Images, just do what's in the question's description: capture colors of external Windows / Desktop elements currently under the mouse pointer.

A trick is used here: the Form's BackColor and its TransparencyKey are set to a blue-ish color (Color.Navy). This allows to have a transparent but solid Form.
In practice, MouseMove events are raised even if the Form is completely transparent an can be clicked-though.

Another quasi-trick, is to double-buffer the Form, using the standard DoubleBuffer property, not the OptimizedDoubleBuffer which can be enabled calling the SetStyle() method.

The ResizeRedraw property is set to true, so the Form redraws itself if/when resized.

With this setup, to get the Color under the Cursor position, you just have to take an one-Pixel snapshot of the current Screen, using a Bitmap sized as (1, 1) (we need just that one Pixel) and use the (not very fast but functional) GetPixel() method to read the Color from the Bitmap.

When the Mouse right button is clicked, the Color under the Cursor is saved in a List<Color> (which is accessible using the public/read-only SavedColors property) and then drawn in a PictureBox used as canvas for this Palette.

To build this example:

  • Create a new Form
  • Add a PictureBox (here, named picColor) and anchor it Top-Right. This Control is used to show the current Color under the Cursor when the Mouse pointer moves.
  • Add a second PictureBox (here, named picPalette) under the previous one and anchor it Top-Right-Bottom. This is used to draw the current palette of saved colors.
    In the Designer, use the Events Panel to subscribe to the Paint event using the handler method you can find in this code (i.e., don't add another).

using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

public partial class frmColorPicker : Form
{
    Color m_CurrentColor = Color.Empty;
    List<Color> m_SavedColors = new List<Color>();

    public frmColorPicker()
    {
        InitializeComponent();
        this.ResizeRedraw = true;
        this.DoubleBuffered = true;

        this.TopMost = true;
        this.BackColor = Color.Navy;
        this.TransparencyKey = Color.Navy;
    }

    public Color CursorEllipseColor { get; set; } = Color.Orange;

    public List<Color> SavedColors => m_SavedColors;

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        GetColorUnderCursor();
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        var rect = GetCursorEllipse();
        using (var pen = new Pen(CursorEllipseColor, 2)) {
            e.Graphics.DrawEllipse(pen, rect);
        }
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        base.OnMouseDown(e);
        if (e.Button == MouseButtons.Right) {
            m_SavedColors.Add(m_CurrentColor);
            picPalette.Invalidate();
        }
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);
        this.Invalidate();
    }

    private Rectangle GetCursorEllipse()
    {
        var cursorEllipse = new Rectangle(PointToClient(Cursor.Position), Cursor.Size);
        cursorEllipse.Offset(-cursorEllipse.Width / 2, -cursorEllipse.Height / 2);
        return cursorEllipse;
    }

    private void GetColorUnderCursor()
    {
        using (var bmp = new Bitmap(1, 1))
        using (var g = Graphics.FromImage(bmp)) {
            g.CopyFromScreen(Cursor.Position, Point.Empty, new Size(1, 1));
            m_CurrentColor = bmp.GetPixel(0, 0);
            picColor.BackColor = m_CurrentColor;
        }
    }

    private void picPalette_Paint(object sender, PaintEventArgs e)
    {
        int rectsCount = 0;
        int rectsLines = 0;
        int rectsPerLine = picPalette.Width / 20;

        foreach (var color in m_SavedColors) {
            using (var brush = new SolidBrush(color)) {
                var rect = new Rectangle(new Point(rectsCount * 20, rectsLines * 20), new Size(20, 20));
                e.Graphics.FillRectangle(brush, rect);
                e.Graphics.DrawRectangle(Pens.DarkGray, rect);
                rectsCount += 1;
                if (rectsCount == rectsPerLine) {
                    rectsCount = 0;
                    rectsLines += 1;
                }
            }
        }
    }
}


This is how it works:

这篇关于如何获取椭圆内指定颜色的坐标?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆