Is there any way to define multiple image scales for a single image in Juce? Would it be a good idea to make a new multi resolution image group type class for this purpose?
Being able to group multiple resolutions of the same image together in some way and then using this group like a regular image is useful to abstract target display properties away from the logic of drawing images.
Here is a little helper class to get the ball rolling, it's not very efficiently coded but at least works for a non affine transformed component. I'm using this to blit the background image to my scalable user interface
struct ImageWithScale { ImageWithScale () : image () , scale (1.0f) { } ImageWithScale (Image im, float sc) : image (im) , scale (sc) { } ImageWithScale (const ImageWithScale& other) : image (other.image) , scale (other.scale) { } ImageWithScale& operator= (const ImageWithScale& other) { if (this != &other) { image = other.image; scale = other.scale; } return *this; } Image image; float scale; }; struct ImageWithScale { ImageWithScale () : image () , scale (1.0f) { } ImageWithScale (Image im, float sc) : image (im) , scale (sc) { } ImageWithScale (const ImageWithScale& other) : image (other.image) , scale (other.scale) { } ImageWithScale& operator= (const ImageWithScale& other) { if (this != &other) { image = other.image; scale = other.scale; } return *this; } Image image; float scale; }; class ImageMultiRes { public: ImageMultiRes () : width (0.0f) , height (0.0f) {}; ImageMultiRes (float w, float h) : width (w) , height (h) {}; void setSize (float w, float h) { jassert (images.size () == 0); width = w; height = h; } void addImage (Image im) { jassert (width > 0.0f); jassert (height > 0.0f); float scalex = im.getWidth () / width; float scaley = im.getHeight () / height; // all the images need to have the same aspect ratio jassert (fabsf (scalex - scaley) < 1e-6f); images.add (ImageWithScale (im, scalex)); } void drawImage (Graphics& g) { drawImageScaled (g, 1.0f); } void drawImageScaled (Graphics& g, float scale) { #if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7) juce::Point<int> p = getScreenPosition (); float screenscale = Desktop::getInstance().getDisplays().getDisplayContaining (p).scale; #else float screenscale = g.getInternalContext().getTargetScale (); #endif float whichscale = scale*screenscale; ImageWithScale* whichimage; float closest = 1e10f; for (int i=0; i<images.size (); i++) { ImageWithScale& im = images.getReference (i); float distance = whichscale/im.scale; if (distance < closest) { closest = distance; whichimage = &im; if (closest == 1.0f) { // prefer a direct 1:1 blit break; } } } float targetscale = scale / whichimage->scale; g.drawImageTransformed (whichimage->image, AffineTransform::scale (targetscale)); } float width, height; Array <ImageWithScale> images; };
I'm targetting OS 10.5, so I had to hack in this to the low level graphics context to be able to detect the screen scale:
float CoreGraphicsContext::getTargetScale () { const CGAffineTransform t = CGContextGetUserSpaceToDeviceSpaceTransform (context); return (float) (juce_hypot (t.a, t.c) + juce_hypot (t.b, t.d)) / 2.0f; }
You can use it like this:
ImageMultiRes multires (width, height); multires.addImage (im0); multires.addImage (im1); multires.addImage (im2);
The in your paint:
multires.drawImageScaled (graphics, scale);