CBitmap inheritance question

Hi all,

I’d like to create a specific class from CBitmap in order to load a bitmap with a specific scalefactor.
My purpose is to easily provide various sizes for the UI, but only from a big one.

Firstly I hope that when the scale factor is set before loading the bitmap, the memory and the drawing would be done from a resized picture, not the full size one.

But I have a problem with IPlatformBitmap, I don’t know how to create it from the ressourceDescription. Just copy/past the original cbitmap code doesn’t work (incomplete type ‘VSTGUI::IPlatformBitmap’ named in nested name specifier)
Any idea ?

Thanks in advance
Best regards
Xavier

I forgot to say that I’m using VSTGUI 4. 3 (will go to 4.9 but I wanted to sort out this problem first)

I would not go this route. Painting sub images on macOS is slow. Why don’t you want to use it as is? You can just add all the different scale factors to it with CBitmap:: addBitmap().

Hi Arne,
Thanks for your answer. Firstly, I found the compiling error, I forgot to include iplatformbitmap.h in the .cpp file. This solution seems to work so far, but I can’t tell anything yet about how it’s slow or not. Here the code I added to CBitmap
XBitmap::XBitmap (const CResourceDescription& desc, double Scalefactor)
{
resourceDesc = desc;
SharedPointer platformBitmap = owned (IPlatformBitmap::create ());
if (platformBitmap)
{
platformBitmap->setScaleFactor(Scalefactor);
if (platformBitmap->load (desc))
{
bitmaps.push_back (platformBitmap);
}
}
}

About adding bitmap for each factor, that’s a solution if I can work on the graphic element with only the biggest GUI and not to have to scale down manually each image.
So if that’s the case, I just don’t see the difference. The added image would be loaded with an other scalefactor, but still full size in the memory (if I correctly understood) and then downsized when redrawn.

Best regards
Xavier

OK, it looks like I misunderstood what you want to achieve.
Your implementation will force the CPU to rescale the image every time when it is drawn and the scale factor of the target is different than of the image.

So far, the code is working as I expected, the GUI size can be easily changed to any value by simply changing the scale factor, but obviously wasting CPU is not what I want !
Is there a way to downscale the image when loading and not when drawing ?

It seems that there is other users who want to do so (like in the thread slighty-blurry-gui-witch-certain-zoom-factors)

But maybe I misunderstood something with the scale factor

Best regards
Xavier

Best way is to pre render the bitmaps. If you have a UI designer than you should order bitmaps for the different scale factor where you want your plug-in to be looking good at. This should always be preferred than to downscale a bitmap.

Thanks for this answer Arne.
So it seems that what I want to do it is not possible right now.
Having bitmaps for several scale factors is what I did for years, but it’s quite annoying and asking more work when a new size is needed or a simple change in the GUI is done. That’s why I wanted to simplifying this workflow using the scale factor (especially for offering the user to choose freely it’s GUI size)

I was thinking about something that I don’t know if this is possible
When the GUI is loaded:
1- Loading a full size bitmap (A) with a specific scale factor (f)
2- create a bitmap (B) with a size corresponding to the downscale image
3- Drawing the downscale bitmap (A) to that created new sized bitmap (B)
4- returning the bitmap B (with a scale factor of 1.0) instead of (f)

This way, after loading the GUI will always work with an adapted bitmap without needing to downscale when drawing. All the CPU would be need at launch.
So the question is if the point 3- is possible to do

Is createMemoryPNGRepresentation could do that ?

Best regards
Xavier

You can do this of course. You have two options:

  • use the ‘Bilinear Scale’, or ‘Linear Scale’ bitmap filter, see cbitmapfilter.h
  • or use an offscreen context and a transform matrix to draw your bitmap into another bitmap

Thanks Arne
I’ll try that seems really interesting

sorry for bothering you!
I’m scratching my head trying to implement a bilinear Scale filter on an CBitmap, but I can’t sort this out.
Do you have any simple sample code ?
Thanks in advance

I think the only code where the filters are used is here :

This should give you a start.

Thanks Arne

Hi Arne,

I’m almost done, but I can’t find how to get the scaled bitmap after running the filter.

The ScaleBase filter is creating an output bitmap (line 698), but there is no getOutputBitmap as there is a getInputBitmap.
I try to create my own CBitmap and pass it through the setProperty, but it’s not taken into account.
I’m sure I miss something with the getProperty function, but can sort it out;

How do I get a CBitmap from getProperty(BitmapFilter::Standard::Property::kOutputBitmap) ?

Thanks in advance

Best regards
Xavier

auto prop = filter->getProperty (kOutputBitmap);
if (auto bitmap = dynamic_cast<CBitmap*> (prop->getObject ())
{
   // bitmap variable now contains a bitmap
}

Thanks Arne,
All’s working fine now (the rendering is not as good as when the downscale is done during the drawing though)

I can share this class if someone is interested in.

I’ll check the solution with the COffscreenContext, maybe the rendering would be better

Anyway thanks again

Best regards
Xavier

It’s working far better with OffscreenContext than with a bitmap filter

Below is the code for those who are interested in.

Best regards
Xavier

#define USE_FILTER 0
#define USE_OFFSCREEN 1
#define USE_DOWNSCALE_AT_LAUNCH (USE_FILTER||USE_OFFSCREEN)

XBitmap::XBitmap (const CResourceDescription& desc, double Scalefactor, CFrame *Frame, int NbrSubImage)
{

resourceDesc = desc;


SharedPointer<IPlatformBitmap> platformBitmap = owned (IPlatformBitmap::create ());
if (platformBitmap)
{
    platformBitmap->setScaleFactor(Scalefactor);

    if (platformBitmap->load (desc))
    {
        bitmaps.push_back (platformBitmap);

        
        if (Scalefactor != 1.0)
        {
            int Height;
            int Width;
            double DownscaleHeight;
            double DownscaleWidth;
            int NewHeight;
            int NewWidth;
            double NewScalefactor;

            Height = platformBitmap->getSize ().y ;
            Width = platformBitmap->getSize ().x ;

            DownscaleHeight = (double)Height/ Scalefactor;
            DownscaleWidth = (double)Width/ Scalefactor;
            
            NewHeight = (int)DownscaleHeight;
            NewWidth = (int)DownscaleWidth;
            
            NewScalefactor = Scalefactor;

            if (NbrSubImage > 1)
            {
                double HeightSubImageDouble;
                int HeightSubImage;
                
                HeightSubImageDouble = DownscaleHeight/(double)NbrSubImage;
                HeightSubImage = (int)HeightSubImageDouble;
                NewHeight = HeightSubImage * NbrSubImage;
                
                NewScalefactor = (double)Height/(double)NewHeight;
                DownscaleWidth = (double)Width/ NewScalefactor;
                NewWidth = (int)DownscaleWidth;
                
            }// fin if

#if (USE_DOWNSCALE_AT_LAUNCH == 1)

#if (USE_FILTER == 1)

            SharedPointer<VSTGUI::BitmapFilter::IFilter> DownscaleFilter = owned (BitmapFilter::Factory::getInstance ().createFilter (BitmapFilter::Standard::kScaleBilinear));
            if (DownscaleFilter)
            {
                CRect Rect;
                Rect.top=0;
                Rect.left=0;
                Rect.bottom=NewHeight;
                Rect.right=NewWidth;
                
                DownscaleFilter->setProperty(BitmapFilter::Standard::Property::kInputBitmap, this);
                DownscaleFilter->setProperty(BitmapFilter::Standard::Property::kOutputRect, Rect);
                if (DownscaleFilter->run (false))
                {
                    
                    auto prop = DownscaleFilter->getProperty (BitmapFilter::Standard::Property::kOutputBitmap);
                    if (auto bitmap = dynamic_cast<CBitmap*> (prop.getObject ()))
                    {
                        // bitmap variable now contains a bitmap
                        IPlatformBitmap* DownscalePlateformbitmap = bitmap->getPlatformBitmap();
                        DownscalePlateformbitmap->setScaleFactor(1.0);
                        
                        setPlatformBitmap(DownscalePlateformbitmap);
                        
                    }//fin if
                }// fin if
                
            }// fin if

#endif //USE_FILTER

#if (USE_OFFSCREEN == 1)

            SharedPointer<COffscreenContext> offscreenContext = owned (COffscreenContext::create (Frame, NewWidth, NewHeight, 1.0));
            if (offscreenContext)
            {
                
                CRect Rect;
                Rect.top=0;
                Rect.left=0;
                Rect.bottom=NewHeight;
                Rect.right=NewWidth;

                offscreenContext->beginDraw ();
                platformBitmap->setScaleFactor(NewScalefactor);
                this->draw(offscreenContext,Rect);
                
                offscreenContext->endDraw ();
                CBitmap* bitmap = offscreenContext->getBitmap ();
                if (bitmap)
                {
                    // bitmap variable now contains a bitmap
                    IPlatformBitmap* DownscalePlateformbitmap = bitmap->getPlatformBitmap();
                    DownscalePlateformbitmap->setScaleFactor(1.0);
                    
                    setPlatformBitmap(DownscalePlateformbitmap);

                }// fin if bitmap

            
            }// fin if offscreenContext

#endif // USE_OFFSCREEN

#else // USE_DOWNSCALE_AT_LAUNCH
platformBitmap->setScaleFactor(NewScalefactor);
#endif // USE_DOWNSCALE_AT_LAUNCH

        }// fin if scalefactor != 1.0
        
        
    }// fin if load ok
    
}// fin if

}