setTransform and setBufferedToImage bug


#1

I believe I’ve found an issue with setBufferedToImage, in that it doesn’t seem to work properly when a component’s parent has a transform.

I’ve managed to reproduce this problem in as simple a program as possible. The following is basically a tweaked IntroJucer HelloWorld project. Inside the main component, we have a view that is scaled (via setTransform) so it always fills the window. There are also two labels: one a direct child of the scaled view; the other a child of a container component.

When the container component isn’t cached to an image, the fonts scale beautifully as the window resizes. Great!

However, if you uncomment the ‘container->setBufferedToImage (true);’ line, the font appears to be an upscaled lo-res rendering.

MainComponent.h

#ifndef __JUCE_HEADER_9002020A4DD09B20__
#define __JUCE_HEADER_9002020A4DD09B20__

#include "../JuceLibraryCode/JuceHeader.h"


class MainComponent  : public Component
{
public:
    //==============================================================================
    MainComponent ();
    ~MainComponent();

    //==============================================================================
    void paint (Graphics& g);
    void resized();

private:
    //==============================================================================
	ScopedPointer<Component> scaledView;
    ScopedPointer<Label> helloWorldLabel;
    ScopedPointer<Component> container;
    ScopedPointer<Label> helloWorldLabel2;
	
    ScopedPointer<ResizableCornerComponent> resizer;
    ComponentBoundsConstrainer resizeLimits;

    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};

#endif   // __JUCE_HEADER_9002020A4DD09B20__

MainComponent.cpp


#include "MainComponent.h"

//==============================================================================
MainComponent::MainComponent ()
{
	addAndMakeVisible(scaledView = new Component);
	scaledView->setBounds (0, 0, 600, 300);
	
    scaledView->addAndMakeVisible (helloWorldLabel = new Label (String::empty,
                                                    "Hello World!"));
    helloWorldLabel->setFont (Font (40.00f, Font::bold));
    helloWorldLabel->setBounds (0, 0, 200, 40);
	
	scaledView->addAndMakeVisible (container = new Component);
	container->setBounds (0, 40, 200, 40);
	container->setBufferedToImage (true); // NOTE <-- Scaled font looks fine when this line is commented out
	
    container->addAndMakeVisible (helloWorldLabel2 = new Label (String::empty,
																"Hello World!"));
    helloWorldLabel2->setFont (Font (40.00f, Font::bold));
    helloWorldLabel2->setBounds (0, 0, 200, 40);
	 
    addAndMakeVisible (resizer = new ResizableCornerComponent (this, &resizeLimits));
    resizeLimits.setSizeLimits (150, 150, 2000, 2000);

    setSize (600, 300);
}

MainComponent::~MainComponent()
{
}

//==============================================================================
void MainComponent::paint (Graphics& g)
{
    g.fillAll (Colour (0xffc1d0ff));
}

void MainComponent::resized()
{
	scaledView->setTransform (AffineTransform::scale ((float)getWidth() / 600, (float)getHeight() / 300)); 
	resizer->setBounds (getWidth() - 16, getHeight() - 16, 16, 16);
}

#2

Yes, if you have nested transforms then that’ll certainly stop it knowing what the correct scale is. Improving the buffer-to-temporary-image stuff is high on my to-do-list anyway, to make it work better in GL, so this is part of the same kind of thing.


#3


I see that you implemented this cached image scaling a few days ago; much appreciated, thanks! This is a huge improvement on how it was before.


I did, however, notice that labels rendered within a cached child component are marginally less sharp than ones rendered directly into the scaled view. It's a subtle difference - an eyes a few inches from the monitor type situation - but there is a difference. So whilst I'm very happy with the improvement, I was just wondering whether this visual difference is an indication of a slight rounding or some-such bug somewhere in the scaling code. I'd have expected rendered text to be identical, whether or not it is cached to an image. 


The easiest way for you to see this is with the test class I posted above. When you shrink the window, the bottom "Hello World", which is a label within a child component, has a blurry edge not present in the top label. I've attached a screenshot so you can see this for yourself.
 


#4

Not a bug. When it renders to an intermediate image, the CoreGraphics text renderer won't use ClearType (or whatever it's called on the mac). So I think the only difference you're seeing is just the anti-aliasing.


#5

Ah, that explains it then; cheers!