Providing multiple png files to suit scaling?

I have a GUI with 3 discrete resize options. Let’s call them 100%, 150% and 200%. Now, normally what I would do is wrap the entire GUI inside a child component, and then simply scale that one component with guiWrapperComponent.setTransform(juce::AffineTransform::scale(SCALE, SCALE));

This GUI uses a lot of PNG files for it’s look. When PNG’s are scaled, they look awful.

I can provide variants of the source PNG files so they need not be stretched. However, I don’t see a clear way to handle this in code. I could obtain the scale factor, and swap to a higher res image, but then this higher res image will still be scaled, resulting in a much larger image than intended, that has still been stretched.

Is there a clever way to detect that a component has been scaled, ignore that scale for it’s paint routine and simply sub in a higher res image?

Why you don’t resize your components in the resized() callback dynamically? In the paint () callback you could call getWidth for detecting your scale factor.

Scaling a wrapper component handles things like font sizes and popup menu sizes etc in a very easy way. Scale one thing, and the entire GUI is done. The only downside is the PNG issue, so I’m looking to see if the best of both worlds is possible.

Maybe You could use getParentComponent.getwidth() for detecting your scale?

Edit: but to be honest, I don’t think that a AffineTransform is a good way for scaling a component. Didn’t you mention blurry fonts?

If the font is done via juce the scaling doesn’t make it blurry. Everything in paint calls looks the same as doing it how you are suggesting, only bitmaps/pngs are stretched.

The way I’m handling this is using source images that are at a higher resolution than needed and scaling down. On macOS this works fine, but on Windows have to use the AVIR scaling algorithm in the Gin module by @RolandMR to overcome how completely crap scaled image look in Windows (by design, there are a few topic about this in the forum already).
I use a simple hand-rolled caching system to take care of the fact that AVIR is quite costly.

There’s no built-in mechanism for handling density-variable images. I had the same needs and came up with:

  • a convention for naming my files (e.g. myimg_72dpi.png, myimg_144dpi.png, ...)
  • an assets manager with methods like: setDPI (...) and Image getDensityVariableImage ("myimg.png")

Once you’re able to ask for a given image file and have the right variant returned, scaling, as you mentioned, will do the rest.

1 Like

I’ll try explain my issue with a bit more detail and see if you found this to be the same, and if so, how you solved it.

I have a component that is 500x500. I have a source image that is 500x500. If I scale this component by 2, the image has been stretched to 1000x1000 and looks bad. If I have code that checks for scale factor, and swaps this image out for a 1000x1000 variant, the component still applies its 2x scale, causing this image to become 2000x2000. Still stretched, and only the top left quarter fits into the 1000x1000 bounds.

I’m guessing you’re using drawImageAt, aren’t you? You should use drawing methods that will allow you to specify width and height to constrain your image so it fits in your rectangle and “squeeze” those dense pixels, otherwise the framework will treat your image’s pixels as points and scale it as well.

1 Like

That was the ticket, thank you!

1 Like