Quality difference when drawing to image vs drawing to screen

Hello all, I’m making an image viewer where it would be useful for me to have in memory an image buffer of what is being displayed on the screen. So, my pipeline right now is:

  • Create an image that is the size of the Component
  • Draw directly into the image
  • Draw this new image in the Component

This looks lower quality than drawing my image directly to the screen. Perceptually blurry. I’m wondering if that is to be expected, or am I missing something. Thanks!

If you’re using a high resolution screen, then the logical size of the component reported by getLocalBounds() will be different to the size of the component in physical pixels. When saving the component to an image, you would need to draw the component at a larger scale, so that the stored image has the correct size in physical pixels.

Is there a way to find out the physical pixel size of a component, based on the current high-resolution screen?

Hello

Perhaps you can use the Display struct (JUCE: Displays::Display Struct Reference). You can find the DPI of the display and the scale factor.

If you’re inside a paint call, you can find the current scale by calling g.getInternalContext().getPhysicalPixelScaleFactor(). If you use this value, then you’re guaranteed to draw at the same scale as the rest of the JUCE window. Querying the current Displays is another option, but this can get tricky in some cases. When the window spans two displays, we want the OS to pick the best scale factor to use, rather than trying to work this out manually.

2 Likes

Is there a way to reliably get this on Windows when running as a plugin?

It always seems to come back with 1.0 in that scenario.

1 Like

Are you testing on JUCE 8? I just tested this on JUCE 7.0.12, using my plugin in the AudioPluginHost. It is being accurately reported.

@reuk - thanks, so would an approach like this be the best? (it seems to work)


void paint (Graphics& g)
{
    auto scaleFactor = g.getInternalContext().getPhysicalPixelScaleFactor();
    auto imageBounds = getLocalBounds().toFloat() * scaleFactor;

    g.saveState();  // save the current Graphics state

    // create an image to draw into with the specifed dimensions
    myImage = Image(Image::ARGB, (int) imageBounds.getWidth(), (int) imageBounds.getHeight(), true);

    // create a new Graphics that will draw into myImage
    Graphics tmp (myImage);

    // add a transform so everything will be drawn at the size corresponding to the scaleFactor
    tmp.addTransform(AffineTransform::scale(scaleFactor));

    //***** do the drawing here ******//

    g.restoreState();   // restore graphics state

    // copy the image to the screen at the normal size
    g.drawImage(myImage, getLocalBounds().toFloat());
}

Testing in Studio One on Windows with JUCE 7.0.10, I always get 1.0 returned. I bodged it by always setting it to 2.0 if 1.0 is returned on Windows.