
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 Visit Windows Forms Tips and Tricks Copyright © Ramuseco Limited 2004-2005 All Rights Reserved.
|