Smoothing image scaling Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
raananb
Super wx Problem Solver
Super wx Problem Solver
Posts: 488
Joined: Fri Oct 27, 2006 4:35 pm
Location: Paris, France
Contact:

Smoothing image scaling

Post by raananb »

To display a picture of 4000x3000 (Image) in a 800x600 display area, I use a scaled image which squeezes the picture into the display area:

wxImage* scaledImage = new wxImage(Image->Scale(800, 600));

in OnPaint():
wxBufferedPaintDC dc(this);
dc.DrawBitmap(wxBitmap(*scaledImage), wxPoint(0,0), false);

I implemented a slider so that the central part is enlarged as the slider is moved, which gives a zoom effect.

double ratio = (100.0 + slider->GetValue())/100.0; // ratio >= 1.0
scaledImage = new wxImage(Image->Scale(displayWidth*ratio, displayHeight*ratio));
pictureUpperLeftCorner.x = (displaySize.x - scaledImageSize.x)/2.
pictureUpperLeftCorner.y = (displaySize.y - scaledImageSize.y)/2.

pictureUpperLeftCorner has negative values

The corresponding dc expression is:

dc.DrawBitmap(wxBitmap(*scaledImage), pictureUpperLeftCorner, false);

The displayed image is exactly what I expect, so the geometry is OK.

I wonder what can be done to smooth the transition while the slider is moved.
User avatar
doublemax
Moderator
Moderator
Posts: 19158
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Smoothing image scaling

Post by doublemax »

Scaling down a wxImage is a very slow operation. So is converting a wxImage to a wxBitmap. So both steps should be avoided if possible.

If the image is static (= the content changes rarely or never), the convert it into a wxGraphicsBitmap (only when the content changes) and use wxGraphicsContext to draw it.

Use wxGraphicsContext::Scale() to scale the drawing.
Use wxGraphicsContext::SetInterpolationQuality(wxINTERPOLATION_GOOD) to get better output quality.
Use the source, Luke!
raananb
Super wx Problem Solver
Super wx Problem Solver
Posts: 488
Joined: Fri Oct 27, 2006 4:35 pm
Location: Paris, France
Contact:

Re: Smoothing image scaling

Post by raananb »

Thanks for the tip.

wxWidget documentation is quite slim, and does not include a wxImage.

I scoured the internet for an example of how to use wxGraphicContext to do what my code does, but to no avail.

An example would be welcome.
User avatar
doublemax
Moderator
Moderator
Posts: 19158
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Smoothing image scaling

Post by doublemax »

Code: Select all

#include "wx/dc.h"
#include "wx/dcbuffer.h"
#include "wx/graphics.h"
class wxGraphicsBitmapPanel : public wxWindow
{
public:
  wxGraphicsBitmapPanel( wxWindow *parent, int id = wxID_ANY ) 
     : wxWindow( parent, id, wxDefaultPosition, wxDefaultSize,  wxFULL_REPAINT_ON_RESIZE)
     , m_zoom(1.0f)
     , m_bitmap_width(0)
     , m_bitmap_height(0)
  {
    SetBackgroundStyle( wxBG_STYLE_PAINT );
    Bind(wxEVT_PAINT, &wxGraphicsBitmapPanel::OnPaint, this );
  }

  void SetBitmap( const wxBitmap &bitmap )
  {
    wxGraphicsContext *gc = wxGraphicsContext::Create(this);
    m_bitmap = gc->CreateBitmap( bitmap );

    // wxGraphicsBitmap has no method to retrieve bitmap dimensions,
    // so we have to save them
    m_bitmap_width = bitmap.GetWidth();
    m_bitmap_height = bitmap.GetHeight();
    delete gc;
  }

  void SetZoom( double zoom )
  {
    m_zoom = zoom;
    Refresh();
  }

  void OnPaint( wxPaintEvent &evt )
  {
    wxAutoBufferedPaintDC pdc(this);

    pdc.SetBrush( GetBackgroundColour() );
    pdc.SetPen( GetBackgroundColour() );
    pdc.DrawRectangle( wxRect(GetClientSize()) );

    if( !m_bitmap.IsNull() && m_bitmap_width > 0 && m_bitmap_height > 0 )
    {
      wxGraphicsContext *gc = wxGraphicsContext::Create( pdc );
      gc->DrawBitmap( m_bitmap, 0, 0, m_zoom * m_bitmap_width, m_zoom * m_bitmap_height );
      delete gc;
    }
  }

protected:
  double m_zoom;
  int m_bitmap_width, m_bitmap_height;
  wxGraphicsBitmap m_bitmap;
};
How to use:

Code: Select all

wxGraphicsBitmapPanel *gbp = new wxGraphicsBitmapPanel(this, wxID_ANY);
wxBitmap bmp("d:\\something.jpg", wxBITMAP_TYPE_ANY);
gbp->SetBitmap( bmp );
gbp->SetZoom( 0.3f );
Use the source, Luke!
raananb
Super wx Problem Solver
Super wx Problem Solver
Posts: 488
Joined: Fri Oct 27, 2006 4:35 pm
Location: Paris, France
Contact:

Re: Smoothing image scaling

Post by raananb »

Thanks, this works fine.
Post Reply