Introduction
Anyone who works with Adobe(R) Photoshop knows about its very versatile color picker dialog, which far exceeds the features built in Windows' out-of-date native color dialog.
Some might say, the Windows one does the job very well. But, especially for creating applications which handle graphics or painting, we might want to have some special capabilities in the picker, such as:
- Different color models to choose from
- Internal exact color model
- Graphical picker control with syncing to text-editable value fields
- Easy and fast conversion
- Off-screen picker
- Copy hexcode to Clipboard
- Reset to previous color
- Add to color table
Whenever you code a graphical application, you should keep in mind that the user might want to keep his colors and color themes regardless of what color model he has entered them. That means, an HSL color has to be stored the same way as a La*b* color.
Therefore, I have written this set of color picking controls and combined them into a picker dialog, inspired by Adobe's. I couldn't reproduce the exact values in the LAB section, because they seem to use another weighting format, which is based on the white-point of the spectrum.
Internal Design
ColorSelectionModule
The main goal of this picker was to support different color models. Therefore, it has to be kept in mind that all selection controls have to support a general interface. This is achieved using the class ColorSelectionModule
. It is an abstract class, and every class inheriting from it offers properties for:
ColorSelectionFader
, which scrolls the selected parameters of the color model
ColorSelectionPlane
, which scrolls the remaining parameters of the color model
XYZ
, which lets you get or set the selected color
The ColorSelectionModule
coordinates the updates of the fader and the plane. For example, if you scroll the fader, the image of the plane has to change, and vice versa. Also, if you change the selected color, both have to change.
Color Spaces
The core of the picker are the color spaces which are the base for the ColorSelectionModule
. XYZ or formerly CIEXYZ is used as the internal format, as it features floating-point intensities, and contains all the other spectrums. LAB is a weighted derivate of the XYZ space, which is basically derived from RGB, just as HSV and CMYK are.
Each color space can only convert to the next in the chain. For detailed specifications and official conversion algorithms, visit EasyRGB.com.
The main goal of this article is to provide a useful color dialog, not explain color models. If you want further information, have a look at this excellent article: Manipulating colors in .NET.
Picking from the Screen
If you write a raster graphics editor, you would certainly want to be able to pick a color off the document. This can be achieved using a tool, and spoken more natively, a delegate which is called for every mouse move on the screen. To be able to pick a color from anywhere in the screen area is, on the one hand, more flexible because you can pick a color from another application as well, and on the other hand, it may be subject to more errors, as you can run onto a grid line in your document or other windows, for example.
The code involves basic Win32 API, which offers a fairly easy way to copy a color from an HDC.
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("user32.dll")]
private static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
[DllImport("gdi32.dll")]
private static extern int GetPixel(IntPtr hdc, int x, int y);
public static Color GetScreenPixel(int x, int y)
{
IntPtr descdc=GetDC(IntPtr.Zero);
Color res=ColorTranslator.FromWin32(GetPixel(descdc,x,y));
ReleaseDC(IntPtr.Zero,descdc);
return res;
}
The ability to do this is encapsulated in the control ColorLabel
, which also manages Hexcode drawing and previous color comparison.
Packing the Tools
Finally, we have the different controls combined on a form, which could be used straight-forward in the code. But, we should also be able to used it same way as the basic .NET / Windows color dialog. Therefore, a class called ColorDialogEx
, which inherits from Component
, is added. If dragged from the Toolbox onto the form of the application, it snaps to the components area and can be accessed from the code through the Color
property, which gets or sets a System.Drawing.Color
.
Advanced functionalities such as picking a color off the screen, copy a color's hexcode to the Clipboard, returning to the previously selected color, or selecting the L*a*b color model is accessed through a context menu on the color label. Furthermore, pressing Shift while dragging on the selection plane/fader will display a grid the selection point will snap to. There maybe ways to display these features more visibly, but I decided to instead add a tooltip help.
Conclusion
Finally, I hope this will be a useful component for anyone dealing with color management in their applications. There are some more tools in the DrawingEx
namespace, such as a color button, a 32 bpp true-color icon encoder with quantizer, and some 3D helper classes. Soon, there will also be a gradient selector tool similar to Adobe illustrator's one, so we will not have to re-learn interacting with the application when switching from Adobe products.