I'm looking to replicate the CSS3 hue rotation behaviour found here
original image
image with hue rotated 180deg
I can already accurately convert an RGB value to a HSL value and back again but I'm not sure what the mathematical function to apply to the hue component to replicate the output is.
Addition.
It's that simple, just add 180 to the hue value, then make sure that it wraps around at 360:
hue = (hue + 180) % 360;
I wanted to point out how to actually do this. This was the exact question, but no good answer.
Given a GDI+ Image
, i want to apply a hue shift and return a new image. In practice it will return a new Bitmap
. I'll use C# style pseudo-code.
First is the basic guts to clone a GDI+ image (but without the hue shift yet):
Bitmap CloneImage(Image sourceImage, Single hueShiftAngleDegrees)
{
Int32 width = sourceImage.GetWidth();
Int32 height = sourceImage.Getheight();
//Create destination bitmap
Bitmap bmpDest = new Bitmap(width, height, PixelFormat32bppARGB);
//Create a Graphics that will draw onto our destination bitmap
Graphics g = new Graphics(destinationBitmap);
//Draw the source image into the destination
g.DrawImage(sourceImage, MakeRect(0, 0, width, height),
0, 0, width, height, UnitPixel);
return bmpDest;
}
Next is the idea that when we use the Graphics.DrawImage method, we can supply an ImageAttributes
class.
ImageAttributes attributes = new ImageAttributes();
g.DrawImage(sourceImage, MakeRect(0, 0, width, height),
0, 0, width, height, UnitPixel, attributes);
One of these attributes can be a 5x5 ColorMatrix
:
ColorMatrix cm = (
( rr, gr, br, ar, 0 ),
( rg, gg, bg, ag, 0 ),
( rb, gb, bb, ab, 0 ),
( ra, ga, ba, aa, 0 ),
( r1, g1, b1, a1, 1 )
);
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(cm);
g.DrawImage(sourceImage, MakeRect(0, 0, width, height),
0, 0, width, height, UnitPixel, attributes);
The magic comes from the color matrix that can perform a hue shift. I create a function that can return the ColorMatrix that performs the desired hue shift:
ColorMatrix GetHueShiftColorMax(Single hueShiftDegrees)
{
/* Return the matrix
A00 A01 A02 0 0
A10 A11 A12 0 0
A20 A21 A22 0 0
0 0 0 1 0
0 0 0 0 1
*/
Single theta = hueShiftDegrees/360 * 2*pi; //Degrees --> Radians
Single c = cos(theta);
Single s = sin(theta);
Single A00 = 0.213 + 0.787*c - 0.213*s;
Single A01 = 0.213 - 0.213*c + 0.413*s;
Single A02 = 0.213 - 0.213*c - 0.787*s;
Single A10 = 0.715 - 0.715*c - 0.715*s;
Single A11 = 0.715 + 0.285*c + 0.140*s;
Single A12 = 0.715 - 0.715*c + 0.715*s;
Single A20 = 0.072 - 0.072*c + 0.928*s;
Single A21 = 0.072 - 0.072*c - 0.283*s;
Single A22 = 0.072 + 0.928*c + 0.072*s;
ColorMatrix cm = new ColorMatrix(
( A00, A01, A02, 0, 0 ),
( A10, A11, A12, 0, 0 ),
( A20, A21, A22, 0, 0 ),
( 0, 0, 0, 0, 0 ),
( 0, 0, 0, 0, 1 )
)
return cm;
}
So i'll create a new kind of function, one that makes a copy of an image and applies a ColorMatrix
to it:
Bitmap Multiply(Image sourceImage, ColorMatrix cm)
{
Int32 width = sourceImage.GetWidth();
Int32 height = sourceImage.Getheight();
//Create destination bitmap
Bitmap bmpDest = new Bitmap(width, height, PixelFormat32bppARGB);
//Create a Graphics that will draw onto our destination bitmap
Graphics g = new Graphics(destinationBitmap);
//Draw the source image into the destination
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(cm);
g.DrawImage(sourceImage, MakeRect(0, 0, width, height),
0, 0, width, height, UnitPixel, attributes);
return bmpDest;
}
And our hue shift algorithm becomes:
Bitmap ApplyHueShift(Image sourceImage, Single hueShiftAngleDegrees)
{
ColorMatrix cm = GetHueShiftColorMatrix(hueShiftAngleDegrees);
return Multiply(sourceImage, cm);
}
I have no idea where the hue shift color matrix comes from. It just exists on MSDN page Hue rotation effect archive:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With