Changing an Image's hue and saturation in JUCE?

As the title says, I’m looking to adjust the hue of an image as a slider changes. It’s a custom graphic so just making a JUCE shape is not an option, however it could be a vector if that would help. Is this something I would need like openGL for? (I’m not familiar with openGL). If someone could just point me in the right direction that would be very helpful. Thanks!

The JUCE Image class is probably where you want to start: https://docs.juce.com/master/classImage.html… I’m not sure it has the direct API’s for adjust hue, but it will allow for manipulation of the underlying data. I’m sure there are people who have done something similar who can give you more detailed advice. You can use the Pixel class (https://docs.juce.com/master/classPixelARGB.html) to directly manipulate the pixels, and there are a variety of functions in there, but I am not sure how efficient it is to use that across a whole image…

Alright that got me a little closer. Googling a little more from there I think the easiest solution would be to set the PixelFormat to HSV (hue,saturation,value) rather than RGB, however I’m not sure JUCE has an HSV option

Update incase anyone uses this for future reference. Figured it out. Essentially made a function that creates a mask (vector of all Image points with alpha value >0). Called that in the constructor. Then on sliderValueChanged, called a function that iterates through the mask vector, gets the color of that pixel using getPixelAt(x,y), and finally setPixelAt(x,y, Colour (hue,saturation,brightness));

If anyone has a more efficient way of doing this let me know!

I wouldn’t use getPixel() and setPixelAt()…way too slow.

I’ve done it by making a copy of the original Image and manipulating the underlying RGB values, then redraw the entire image. WAY faster. WAY.

Could you elaborate how thats done? I implemented a new method based off what you said, and instead of using the setPixel, I’m now creating a Bitmap, still iterating through, and then using a Bitmap method setPixelColour(x,y,Colour). This in it self is faster than the older method and I assume it’s what you were suggesting to do. If not let me know

That’s basically the idea. Here’s some code for creating a new Image with different gamma that I use:

Image gammaImage(Image inImage, float gamma)
{
	uint8 gammaTable[256];
	
	float ogamma = 1.0f / gamma;
	for(auto i = 0; i < 256; ++i) 
	{
		auto v = std::powf( (float)i / 255.0f, ogamma) * 255.0f;
		gammaTable[i] = (uint8)v;
	}
	
	Image::PixelFormat format = inImage.getFormat();
	jassert (format == Image::ARGB);
	
	auto width = inImage.getWidth();
	auto height = inImage.getHeight();
	jassert(width > 0 && height > 0);
	
	Image outImage = inImage.createCopy();
	if(outImage.isNull() || outImage.isValid() == false)
	{
		jassertfalse;
	}
	
	Image::BitmapData inPic(inImage, Image::BitmapData::readOnly);
	Image::BitmapData outPic(outImage, Image::BitmapData::writeOnly);
	
	if(format == Image::ARGB)
	{
		auto width4 = width * 4;
		for(auto y = 0; y < height; ++y)
		{
			auto inPtr = inPic.getLinePointer(y);
			auto outPtr = outPic.getLinePointer(y);
			for(auto x = 0; x < width4; x += 4)
			{
				outPtr[x + 0] = gammaTable[inPtr[x + 0]];
				outPtr[x + 1] = gammaTable[inPtr[x + 1]];
				outPtr[x + 2] = gammaTable[inPtr[x + 2]];
				outPtr[x + 3] = inPtr[x + 3];
			}
		}
	}
	else if(format == Image::RGB)
	{
		auto width3 = width * 3;
		for(auto y = 0; y < height; ++y)
		{
			auto inPtr = inPic.getLinePointer(y);
			auto outPtr = outPic.getLinePointer(y);
			for(auto x = 0; x < width3; x += 3)
			{
				outPtr[x + 0] = gammaTable[inPtr[x + 0]];
				outPtr[x + 1] = gammaTable[inPtr[x + 1]];
				outPtr[x + 2] = gammaTable[inPtr[x + 2]];
			}
		}
	}
	else
	{
		jassertfalse;
		return Image();
	}
	
	return outImage;
}

You could do something similar to adjust the hue of an image, although hue math is a bit slower than changing the gamma, but this would still be very efficient. Hope that helps.

PS - my handling of the alpha channel isn’t correct here, but it’s not noticeable.

2 Likes