Reputation: 10635
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.
Upvotes: 5
Views: 2191
Reputation: 256711
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:
Upvotes: 2
Reputation: 700322
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;
Upvotes: 5