DrawableButton Image Quality

I have a DrawableButton whose style is DrawableButton::ImageRaw

Its Image is from an image in cache. I noticed it looked quite blurry compared to the original so I ran a little test

On the left I just drew into the component the same image in the paint() method of the contentComponent. On the right is the DrawableButton… You can see its quite blurry in comparison

g.drawImageAt(ImageCache::getFromMemory(toolbargraphics::lock_png,toolbargraphics::lock_pngSize), 250, 0);

In DrawableImage I made the following little test

[code]
void DrawableImage::draw (Graphics& g, const AffineTransform& transform) const
{
if (image != 0)
{
const Colour oldColour (g.getCurrentColour()); // save this so we can restore it later

    if (opacity > 0.0f && ! overlayColour.isOpaque())
    {
        g.setColour (oldColour.withMultipliedAlpha (opacity));

#if 1
g.drawImageAt(image, 0, 0);
#else
g.drawImageTransformed (image,
0, 0, image->getWidth(), image->getHeight(),
transform, false);
#endif
}[/code]

The result now looks like

Quite the differerence

I am getting called this from DrawableButton::paintButton()

if (style == ImageRaw)
{
imageToDraw->draw (g);
}

In my debugger I see the transform parameters are…
mat00 (1.0f)
mat01 (0)
mat02 (0)
mat10 (0)
mat11 (1.0f)
mat12 (0)

I’m hoping some optimization to drawImageTransformed can be made to make this look better!

Tnx

Oh I should also note that since this little hack to avoid drawImageTransformed the button’s image is no longer dropping 2 pixels on mousedown which was happening occasionally(and fixing itself on the next mouse over)

Interesting… I guess the optimisation would be in juce_Graphics.cpp, 908:

void Graphics::drawImageTransformed (const Image* const imageToDraw, int sourceClipX, int sourceClipY, int sourceClipWidth, int sourceClipHeight, const AffineTransform& transform, const bool fillAlphaChannelWithCurrentBrush) const throw() { if (imageToDraw != 0 && (! context->isClipEmpty()) && ! transform.isSingularity()) { if (transform.isIdentity()) { drawImage (imageToDraw, sourceClipX, sourceClipY, sourceClipWidth, sourceClipHeight, sourceClipX, sourceClipY, sourceClipWidth, sourceClipHeight, fillAlphaChannelWithCurrentBrush); } else if (fillAlphaChannelWithCurrentBrush)

…I haven’t tried it, but I guess that’d work?

A beautiful thing indeed! Thanks Julian

I have not tested, but isn’t that going to change the behaviour of drawImageTransformed to an inconsistent one ?

as of now, one has to use an AffineTransform::translation(-.5f, -5f) to achieve “identity” rendering (that is render an image without smoothing it).

Hi jpo, if the translation isn’t ::identity won’t it just call the same code as before?

True, but if I do an animation with translation(-0.1f, -0.1f) at first step, and then translation(0, 0) at second step, and then (0.1, 0.1) at third step, etc, then there will be a “jump” because of the special treatment of identity, that’s what I meant by “inconsistent”

Hang on - this reminds me of something that valley posted a while back, adding 0.5 to the code that did the transformed rendering… ??

don’t be breaking my nicely aligned screen co-ordinates… :shock:

…but if the co-ords were nicely aligned, surely this bug wouldn’t exist? It looks to me like the image at (0, 0) was blurred because of the 0.5 offset (?)

note that there is the same behaviour for Path :

You stroke a path with a lineWidth = 1.0f. If the path coordinates are integers, it will be rendered across pixels boundaries (the one pixel line will appear as a semi-transparent two pixels width line).

One need to set the coordinates to int+0.5f to have it rendered exactely in a single pixel width.

http://www.rawmaterialsoftware.com/juceforum/viewtopic.php?t=3314&highlight=image+offset

The co-ordinates on a resized image are correct with the offset. Take the offset out, and test the positions of pixels that have a known x/y co-ordinate.

Try the same resample with nearest neighbour. Your pixels should line up.

As for blurring, isn’t that to be expected with bilinear? Take a single pixel, and apply a four pixel kernel to it, you have to change the pixel’s value, since it is being interpolated with respect to the entire kernel, not just the part of the kernel that it occupies.

[quote=“jpo”]note that there is the same behaviour for Path :

You stroke a path with a lineWidth = 1.0f. If the path coordinates are integers, it will be rendered across pixels boundaries (the one pixel line will appear as a semi-transparent two pixels width line).

One need to set the coordinates to int+0.5f to have it rendered exactely in a single pixel width.[/quote]

That’s correct though, surely?

The co-ordinate of the top left pixel is 0.5, 0.5 not 0, 0 if you’re working in float space. Discrete and floating point are not interchangable in the way you are trying to do here.

Yes, indeed I’m fine with the way it works, this is consistent with the current behaviour of drawImageTransformed

But maybe these details should be stated more explicitely in the documentation as it can be a source of confusion (at least it has been for me)

on a side note: am I right saying that there currently no implementation of bicubic interpolation in Juce despite the existence of the highResamplingQuality enum ?