I’d like to add an option in my plugin to brighten/darken the entire interface. My UI is a combination of images and drawing code, but the background is mostly a big Image.
I thought about looking into ImageEffectFilter on the top level Component, but that just gives me an image and the context to draw it into, but I don’t see any blending modes or any kind of brightness, contrast or gamma functions in JUCE. Of course, I could be missing something.
There may be a better way, but you could create a second copy of your background which is brighter and/or has more contrast and render it with variable alpha over the top of your existing image.
Both of those methods are reasonable, but not ideal.
Another way would be for me to make a copy of each image on the fly and run a gamma function on each pixel. Is there a faster way than using getPixelAt()/setPixelAt() for each pixel?
Has anyone tried something like this as an ImageFilterEffect on the top level Component? If there was a way for fast pixel access that could be interesting.
Ok, so I put the following ImageEffectFilter on my plugin’s top most component, which obviously affects every component down the line. My UI is 1024 x 680.
It looks good and seemed fast on my Mac, but on Windows (in Parallels), the UI lags a bit. Not sure how much of that is due to the emulation.
So, my question is…Is this crazy to run on my entire UI? @jules ?
class GammaFilter : public ImageEffectFilter
{
public:
GammaFilter()
{
setGamma(1.0f);
}
~GammaFilter(){}
void setGamma(float gamma)
{
const float ogamma = 1.0f / gamma;
for (int i = 0; i < 256; i++) {
const float v = std::powf( (float)i / 255.0f, ogamma) * 255.0f;
gammaTable[i] = (uint8)v;
}
}
void applyEffect(Image& sourceImage, Graphics& destContext,
float scaleFactor, float alpha) override
{
Rectangle<float>r(0.0f, 0.0f, (float)sourceImage.getWidth(), (float)sourceImage.getHeight());
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
Image::PixelFormat format = sourceImage.getFormat();
jassert (format == Image::ARGB);
Image::BitmapData inPic(sourceImage, Image::BitmapData::readOnly);
int width4 = width * 4;
for(int y = 0; y < height; y++)
{
uint8* ptr = inPic.getLinePointer(y);
for(int x = 0; x < width4; x += 4)
{
ptr[x + 0] = gammaTable[ptr[x + 0]];
ptr[x + 1] = gammaTable[ptr[x + 1]];
ptr[x + 2] = gammaTable[ptr[x + 2]];
// this is an opaque image so leave alpha alone
}
}
destContext.drawImage(sourceImage, r);
}
private:
uint8 gammaTable[256];
};
And in my Editor:
GammaFilter gammaEffect;
// at the end of the the constructor
setComponentEffect(&gammaEffect);
// called from a menu
gammaEffect.setGamma(newGamma); // 0.8 - 1.2
container.repaint();
Yeah, that’s really going to put an unsustainable load on the CPU! Really not something you’d attempt to do with a live UI, the only way you could do live gamma correction would be using the GPU, but we don’t have any mechanism for that.
Can’t you just gamma-correct the images that you’re using? All your other vector graphics shouldn’t need its gamma to be changed, right?
I had a feeling it wouldn’t be the right thing to do. It would be great if there was a GPU way to do it.
Sure, I can gamma correct each image I use (which is definitely more than a few), but I’ll also have to modify the look and feel for the vector stuff, as I’m basically trying to brighten or darken the entire UI.
I was just looking for a clever/fast way to get this done.