Introduction
This article is about gradients (simple and those not so simple). A simple class is developed in order to help render different gradient types like: horizontal, vertical, diagonal, radial, two-color and multi-color, and as a special case, custom gradients (based on user-created regions). Also, this class has a built-in gamma correction method with adjustable gamma threshold values.
Background
There are many resources available (on the CodeProject and on the Internet) considering gradients, so this article is just another way the problem can be solved.
Using the code
Using this class is as simple as it can be. You should include the class header file Gradient.h, and after that, you will able to create as many instances of the CGradient
class. But they all do the same thing described below:
#include "Gradient.h"
CGradient gradient;
RECT rect = {100, 100, 200, 200};
COLORREF colorStart = RGB(255,0,0);
COLORREF colorEnd = RGB(0,0,255);
gradient.HorizontalGradient(pDC->m_hDC, rect,
colorStart, colorEnd);
And this would be enough to get a horizontal two-color gradient. In the base, all methods of the CGradient
class work in the same manner. The last two params of the methods are BOOL
and double
which turn on/off the gamma correction and set the gamma correction value, respectively. See the "Gradient.h" header file for details.
The following gradients can be drawn:
- Two-color horizontal gradient
- Two-color vertical gradient
- Two-color forward diagonal gradient
- Two-color backward diagonal gradient
- Two-color radial gradient
- Multi-color horizontal gradient
- Multi-color vertical gradient
- Multi-color radial gradient
- Custom two-color horizontal gradient
- Custom two-color vertical gradient
- Custom multi-color horizontal gradient
- Custom multi-color vertical gradient
What about custom gradients?
Well, instead of passing a RECT
variable as an argument for the two-color or multi-color horizontal and vertical gradients, we can pass a HRGN
variable. There are overloaded methods for this (the last four in the list above). In this way, beautiful effects can be achieved with very little effort to create custom regions. I should mention here that if HRGN
is used, the gradients are rendered slower than when RECT
is used. It is primarily because the Win API method PtInRegion()
must be called in this case to check if a pixel belongs to the region or not.
What about gamma correction?
Gamma correction is used to get a smooth gradient scale. It is well known that different monitors apply different intensity of light (based on the input voltage) for different pixel intensity values. This means if a pixel has an intensity of 255 it should be white, with maximum intensity of light. And the one with intensity of 128 (gray color) should have exactly one half of the light intensity than the previous one. Right? No, not at all. Maybe 73% or something, I don't know. But if you apply simple color processing features, you can get very good results and the speed of the algorithm is not degraded. It is a very simple equation:
color = ((color/maximumColor) ^ gamma) * maximumColor;
This is applied to all three channels (red, green, and blue) and you can see the result. The range of the gamma value goes from 0 to 2.5 or more (if necessary), and it depends on the monitor type. In this project, the gamma value of 0.4 is used. If you find this value not good for your case, you can use other values. Smaller values make images lighter, and larger makes them darker.
Conclusion
There are some methods that can be used to make custom gradients render better, and I am still researching.
Points of Interest
I was impressed by the GDI+ brushes (specially LinearGradientBrush
) which can create wonderful gradients and is also able to adjust the gamma value.