Creating an image "eyedropper"

Under Win32 the process of capturing the colour of a pixel was relatively simple. The screen DC had a bitmap selected into it, the display memory itself, and it was possible to simply get the pixel at the desired position with a few lines of code.

GDI+ makes this process a little more complex because the GDI+ device context works in a slightly different way and provides no GetPixel or SetPixel functionality. This means that to obtain the colour of an arbitrary point we need to resort to a little bit of interop.

To obtain the correct Win32 functions to call, the DllImport attribute is used. In this example we'll be importing the GetPixel function from GDI32.DLL and the GetDC and ReleaseDC methods from User32.DLL.

Once the functions are imported the GDI DC of any window or the desktop can be used to call the GetPixel method and the resulting colour obtained using the ColorTranslator class.

So that any pixel on screen can be obtained, the application uses a timer to fire 10 times a second. When the timer fires the Control.MousePosition property is used to obtain the position of the mouse in screen-coordinates. To display the colour obtained, a panel background is set each time the colour is sampled.

The listing shown below details the process. Choose C# or VB code using the buttons at the top of this page.

using System;

using System.Runtime.InteropServices;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

 

namespace pixelcolor

{

  /// <summary>

  /// Summary description for Form1.

  /// </summary>

  public class Form1 : System.Windows.Forms.Form

  {

 

 

    [DllImport("Gdi32.dll")]

    public static extern int GetPixel(

    System.IntPtr hdc,    // handle to DC

    int nXPos,  // x-coordinate of pixel

    int nYPos   // y-coordinate of pixel

    );

 

    [DllImport("User32.dll")]

    public static extern IntPtr GetDC(IntPtr wnd);

 

    [DllImport("User32.dll")]

    public static extern void ReleaseDC(IntPtr dc);

 

 

    private System.Windows.Forms.Panel panel1;

    private System.Timers.Timer timer1;

 

    /// <summary>

    /// Required designer variable.

    /// </summary>

    private System.ComponentModel.Container components = null;

 

    public Form1()

    {

      //

      // Required for Windows Form Designer support

      //

      InitializeComponent();

      this.SetStyle(ControlStyles.ResizeRedraw,true);

    }

 

    /// <summary>

    /// Clean up any resources being used.

    /// </summary>

    protected override void Dispose( bool disposing )

    {

      if( disposing )

      {

        if (components != null)

        {

          components.Dispose();

        }

      }

      base.Dispose( disposing );

    }

 

    #region Windows Form Designer generated code

    /// <summary>

    /// Required method for Designer support - do not modify

    /// the contents of this method with the code editor.

    /// </summary>

    private void InitializeComponent()

    {

      this.panel1 = new System.Windows.Forms.Panel();

      this.timer1 = new System.Timers.Timer();

      ((System.ComponentModel.ISupportInitialize)(this.timer1)).BeginInit();

      this.SuspendLayout();

      //

      // panel1

      //

      this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;

      this.panel1.Location = new System.Drawing.Point(216, 8);

      this.panel1.Name = "panel1";

      this.panel1.Size = new System.Drawing.Size(64, 56);

      this.panel1.TabIndex = 0;

      //

      // timer1

      //

      this.timer1.Enabled = true;

      this.timer1.SynchronizingObject = this;

      this.timer1.Elapsed += new System.Timers.ElapsedEventHandler(this.timer1_Elapsed);

      //

      // Form1

      //

      this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

      this.BackColor = System.Drawing.Color.White;

      this.ClientSize = new System.Drawing.Size(292, 273);

      this.Controls.Add(this.panel1);

      this.Name = "Form1";

      this.Text = "Form1";

      this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);

      ((System.ComponentModel.ISupportInitialize)(this.timer1)).EndInit();

      this.ResumeLayout(false);

 

    }

    #endregion

 

    /// <summary>

    /// The main entry point for the application.

    /// </summary>

    [STAThread]

    static void Main()

    {

      Application.Run(new Form1());

    }

 

    private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

    {

      Random r=new Random(1);

 

      for(int x=0;x<100;x++)

      {

        SolidBrush b=new SolidBrush(Color.FromArgb(r.Next(255),r.Next(255),r.Next(255)));

        e.Graphics.FillRectangle(b,r.Next(this.ClientSize.Width),r.Next(this.ClientSize.Height),r.Next(100),r.Next(100));

      }

    }

 

    private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)

    {

      Point p=Control.MousePosition;

      IntPtr dc=GetDC(IntPtr.Zero);

      this.panel1.BackColor=ColorTranslator.FromWin32(GetPixel(dc,p.X,p.Y));

      ReleaseDC(dc);

    }

  }

}

 

 

Imports System

Imports System.Runtime.InteropServices

Imports System.Drawing

Imports System.Collections

Imports System.ComponentModel

Imports System.Windows.Forms

Imports System.Data

 

 

Namespace pixelcolor

   '/ <summary>

   '/ Summary description for Form1.

   '/ </summary>

  

   Public Class Form1

    Inherits System.Windows.Forms.Form

    

    

    

    <DllImport("Gdi32.dll")> _

    Public Shared Function GetPixel(ByVal hdc As System.IntPtr, ByVal nXPos As Integer, ByVal nYPos As Integer) As Integer

 

    End Function

 

    ' handle to DC

    ' x-coordinate of pixel

    ' y-coordinate of pixel

 

    <DllImport("User32.dll")> _

    Public Shared Function GetDC(ByVal wnd As IntPtr) As IntPtr

 

    End Function

 

 

    <DllImport("User32.dll")> _

    Public Shared Sub ReleaseDC(ByVal dc As IntPtr)

 

    End Sub

 

 

    Private panel1 As System.Windows.Forms.Panel

    Private WithEvents timer1 As System.Timers.Timer

 

    '/ <summary>

    '/ Required designer variable.

    '/ </summary>

    Private components As System.ComponentModel.Container = Nothing

 

 

    Public Sub New()

      '

      ' Required for Windows Form Designer support

      '

      InitializeComponent()

      Me.SetStyle(ControlStyles.ResizeRedraw, True)

    End Sub 'New

 

 

    '/ <summary>

    '/ Clean up any resources being used.

    '/ </summary>

    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

      If disposing Then

        If Not (components Is Nothing) Then

          components.Dispose()

        End If

      End If

      MyBase.Dispose(disposing)

    End Sub 'Dispose

 

#Region "Windows Form Designer generated code"

 

    '/ <summary>

    '/ Required method for Designer support - do not modify

    '/ the contents of this method with the code editor.

    '/ </summary>

    Private Sub InitializeComponent()

      Me.panel1 = New System.Windows.Forms.Panel

      Me.timer1 = New System.Timers.Timer

      CType(Me.timer1, System.ComponentModel.ISupportInitialize).BeginInit()

      Me.SuspendLayout()

      '

      ' panel1

      '

      Me.panel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D

      Me.panel1.Location = New System.Drawing.Point(216, 8)

      Me.panel1.Name = "panel1"

      Me.panel1.Size = New System.Drawing.Size(64, 56)

      Me.panel1.TabIndex = 0

      '

      ' timer1

      '

      Me.timer1.Enabled = True

      Me.timer1.SynchronizingObject = Me

      '

      ' Form1

      '

      Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)

      Me.BackColor = System.Drawing.Color.White

      Me.ClientSize = New System.Drawing.Size(292, 273)

      Me.Controls.Add(panel1)

      Me.Name = "Form1"

      Me.Text = "Form1"

      CType(Me.timer1, System.ComponentModel.ISupportInitialize).EndInit()

      Me.ResumeLayout(False)

    End Sub 'InitializeComponent

#End Region

 

 

    '/ <summary>

    '/ The main entry point for the application.

    '/ </summary>

    <STAThread()> _

    Shared Sub Main()

      Application.Run(New Form1)

    End Sub 'Main

 

 

    Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

      Dim r As New Random(1)

 

      Dim x As Integer

      For x = 0 To 99

        Dim b As New SolidBrush(Color.FromArgb(r.Next(255), r.Next(255), r.Next(255)))

        e.Graphics.FillRectangle(b, r.Next(Me.ClientSize.Width), r.Next(Me.ClientSize.Height), r.Next(100), r.Next(100))

      Next x

    End Sub 'Form1_Paint

 

 

    Private Sub timer1_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles timer1.Elapsed

      Dim p As Point = Control.MousePosition

      Dim dc As IntPtr = GetDC(IntPtr.Zero)

      Me.panel1.BackColor = ColorTranslator.FromWin32(GetPixel(dc, p.X, p.Y))

      ReleaseDC(dc)

    End Sub 'timer1_Elapsed

  End Class 'Form1

End Namespace 'pixelcolor

If you wanted to sample the colours in a PictureBox or in your own form then you simply need to obtain the DC for that object. This can be accomplished using CreateGraphics, Graphics.GetHdc and Graphics.ReleaseHdc. The listing below shows a MouseMove handler that can be used to obtain the pixel colour from a form.

    protected override void OnMouseMove(MouseEventArgs e)

    {

      Graphics g=this.CreateGraphics();

      IntPtr myDC=g.GetHdc();

      Color c=ColorTranslator.FromWin32(GetPixel(myDC,e.X,e.Y));

      g.ReleaseHdc(myDC);

 

      this.panel1.BackColor=c;

    }

 

    Protected Overrides Sub OnMouseMove(e As MouseEventArgs)

     Dim g As Graphics = Me.CreateGraphics()

     Dim myDC As IntPtr = g.GetHdc()

     Dim c As Color = ColorTranslator.FromWin32(GetPixel(myDC, e.X, e.Y))

     g.ReleaseHdc(myDC)

     

     Me.panel1.BackColor = c

    End Sub 'OnMouseMove

Return to the GDI+ FAQ

Visit Windows Forms Tips and Tricks

Copyright © Ramuseco Limited 2004-2005 All Rights Reserved.