Images Aren't Being Painted at their Correct Size

gui

#1

I can’t seem to figure out what I’m doing incorrectly. I have an app that loads images and displays them in a new window. Sometimes, the images show up the correct size, other times they are larger. I’ve been through a ton of debugging, and have checked that that image dimensions, after being loaded into an Image object in JUCE, are the same as their actual dimensions, and they are always the same, but the image doesn’t display correctly, almost as if I have a resolution or scaling option enabled somewhere. I’ve already checked to make sure the getDesktopScalingFactor() and it returns 1 every time.

Here’s my loading code:

Here’s the class for the new window, which was almost a direct copy and paste of the JUCE Plugin new window code:

class BasicWindow : public DocumentWindow
{
private:
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BasicWindow)
    
public:
    BasicWindow (const String& name, Colour backgroundColour, int buttonsNeeded)
    : DocumentWindow (name, backgroundColour, buttonsNeeded)
    {
    }
    
    void closeButtonPressed() override
    {
        delete this;
    }
};

Here’s my “display image” code:

void TrackNotesAudioProcessorEditor::createImageWindow(SafePointer<BasicWindow> &basicWindowPtr, Image &image, File &imagePath)
{
    // Don't allow multiple copies of this window to be made
    if(basicWindowPtr == NULL)
    {
        basicWindowPtr = new BasicWindow(imagePath.getFileNameWithoutExtension(), Colours::grey, DocumentWindow::allButtons);
        
        basicWindowPtr->setUsingNativeTitleBar(true);
        basicWindowPtr->setContentOwned(new ImageWindow(image), true);
        basicWindowPtr->setAlwaysOnTop(true);
        basicWindowPtr->centreWithSize(basicWindowPtr->getWidth(), basicWindowPtr->getHeight());
        basicWindowPtr->setVisible(true);
}

And here’s my paint code in the new window that pops up:

void ImageWindow::paint (Graphics& g)
{
    //[UserPrePaint] Add your own custom painting code here..
    //[/UserPrePaint]

    g.fillAll (Colour (0xff373737));

    g.setColour (Colours::white);
    g.setFont (Font (15.00f, Font::plain).withTypefaceStyle ("Regular"));
    g.drawText (TRANS("Please Load an Image"),
                0, 0, 200, 200,
                Justification::centred, true);

    //[UserPaint] Add your own custom painting code here..

    g.drawImageAt(image, 0, 0, false);
    //[/UserPaint]
}

This may be way too much code to post, but I’m not sure how else to make the problem, or code, any shorter to explain. If an image isn’t loaded into the application, the window just opens up at 200x200 and displays the message “Please Load an Image.” Otherwise, the window is loaded and it fills the window… only sometimes the images are larger than normal. I cannot figure out why.


#2

Still am having issues with this. I changed how I’m loading the image in the new window now. Instead of painting it to the GUI, I’m loading it into an ImageComponent and just setting the image component to display in the new window:

imageComponent.setImage(imageSource);
imageComponent.setBounds(0, 0, imageSource.getWidth(), imageSource.getHeight());
addAndMakeVisible(imageComponent);

The bug still occurs though, most images are the correct size, while others (maybe 10 percent), load MUCH larger than the original. Could be maybe 110 percent bigger, could be 200 or 300 percent bigger.

To give you an idea, the first capture is of the image being displayed in Mac Preview, while the second one is in my plugin. I’ve debugged it so many times I’m losing my mind. All the dimensions of the image that is loaded into the plugin match those of the actual one. Would anyone have any clue or has anyone experienced this themselves?


#3

If you use setImage, you end up with the default placement, which is “centred”.
You can set the placement together with the image using setImage like this:

imageComponent.setImage (imageSource, doNotResize);

HTH


#4

I’m not finding a doNotResize outside of juce::RectanglePlacement::doNotResize. At any rate, I’m setting the size of the window based on the size of the image too, so even if this can control the ImageComponent size, the window will still be as massive I think. I honestly have no clue what’s causing this. I put off fixing it for my v1.0.0 release because I spent too many hours trying to solve it. Some cases aren’t so bad and can be ignored, but other cases like this, where on a 15 inch laptop screen, only 1/4th of the image shows, is not so dismissible.


#5

I think maybe you’re confused about what you mean by the image’s “real” size.

Nothing in the Image class takes into account the original DPI or scale, it’s simply a bitmap of pixels. It’ll draw that many pixels to the screen. If you loaded it from a JPEG with some kind of physical size in inches, that info was lost long ago when it was loaded.

Why not just use Graphics::drawImageWithin()?


#6

I suppose you are correct. I am lacking a bit of knowledge related to different image formats…

Also, the ImageComponent seems to scale images correctly to me, when choosing a specific size. I am using ImageComponent elsewhere in my program as image “previews” and if I choose a specific size (ex. 200 x 200), it scales perfectly. That works for that situation. But I would prefer to find a way where I didn’t have to pick a size when showing the “non-preview” images. I don’t want to use any hard values and be scaling them up or down, I’d like to show them as somewhere close to what they would expect to see.

I think the best workaround I have is writing some custom code, that if an image is either taller or wider than the user’s screen’s size, then scale the image down far enough to fit.


#7

That’s exactly what drawImageWithin does!


#8

…also
https://www.juce.com/doc/classRectanglePlacement


#9

Right, I read the documentation, and am fine with it, but I get the impression it would also scale up very tiny pictures to fit within that frame as well… which would pixelate the heck out of some photos, correct?

“If the image is too big or too small for the space, it will be rescaled to fit as nicely as it can do without affecting its aspect ratio. It will then be placed within the target rectangle according to the justification flags specified.”


#10

RectanglePlacement::onlyReduceInSize


#11

Bingo! I missed your last post while typing up my last one. Looks like this will be a good fix! Thanks!