- Added wxPersistentSplitter.
- Derive wxAuiNotebook from wxBookCtrlBase (Steven Lamerton).
- Fix tooltips in wxSearchCtrl and other composite controls (Catalin Raceanu).
+- Allow converting to and from wxGraphicsBitmap and wxImage directly.
OSX:
static wxGraphicsContext* Create( wxWindow* window );
+#if wxUSE_IMAGE
+ // Create a context for drawing onto a wxImage. The image life time must be
+ // greater than that of the context itself as when the context is destroyed
+ // it will copy its contents to the specified image.
+ static wxGraphicsContext* Create(wxImage& image);
+#endif // wxUSE_IMAGE
+
// create a context that can be used for measuring texts only, no drawing allowed
static wxGraphicsContext * Create();
// create a native bitmap representation
virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) const;
+#if wxUSE_IMAGE
+ wxGraphicsBitmap CreateBitmapFromImage(const wxImage& image) const;
+#endif // wxUSE_IMAGE
// create a native bitmap representation
virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) const;
virtual wxGraphicsContext * CreateContext( wxWindow* window ) = 0;
+#if wxUSE_IMAGE
+ virtual wxGraphicsContext * CreateContextFromImage(wxImage& image) = 0;
+#endif // wxUSE_IMAGE
+
// create a context that can be used for measuring texts only, no drawing allowed
virtual wxGraphicsContext * CreateMeasuringContext() = 0;
// create a native bitmap representation
virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) = 0;
+#if wxUSE_IMAGE
+ virtual wxGraphicsBitmap CreateBitmapFromImage(const wxImage& image) = 0;
+#endif // wxUSE_IMAGE
// create a graphics bitmap from a native bitmap
virtual wxGraphicsBitmap CreateBitmapFromNativeBitmap( void* bitmap ) = 0;
Represents a bitmap.
The objects of this class are not created directly but only via
- wxGraphicsContext or wxGraphicsRenderer CreateBitmap() and
- CreateSubBitmap() methods. They can subsequently be used with
- wxGraphicsContext::DrawBitmap(). The only other operation is testing for
- the bitmap validity which can be performed using IsNull() method inherited
- from the base class.
+ wxGraphicsContext or wxGraphicsRenderer CreateBitmap(),
+ CreateBitmapFromImage() or CreateSubBitmap() methods. They can subsequently
+ be used with wxGraphicsContext::DrawBitmap(). The only other operation is
+ testing for the bitmap validity which can be performed using IsNull()
+ method inherited from the base class.
*/
class wxGraphicsBitmap : public wxGraphicsObject
{
*/
static wxGraphicsContext* Create(const wxEnhMetaFileDC& dc);
+ /**
+ Creates a wxGraphicsContext associated with a wxImage.
+
+ The image specifies the size of the context as well as whether alpha is
+ supported (if wxImage::HasAlpha()) or not and the initial contents of
+ the context. The @a image object must have a life time greater than
+ that of the new context as the context copies its contents back to the
+ image when it is destroyed.
+
+ @since 2.9.3
+ */
+ static wxGraphicsContext* Create(wxImage& image);
+
/**
Clips drawings to the specified region.
*/
*/
virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) = 0;
+ /**
+ Creates wxGraphicsBitmap from an existing wxImage.
+
+ This method is more efficient than converting wxImage to wxBitmap first
+ and then calling CreateBitmap() but otherwise has the same effect.
+
+ Returns an invalid wxNullGraphicsBitmap on failure.
+
+ @since 2.9.3
+ */
+ virtual wxGraphicsBitmap CreateBitmapFromImage(const wxImage& image);
+
/**
Extracts a sub-bitmap from an existing bitmap.
*/
virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) = 0;
+ /**
+ Creates wxGraphicsBitmap from an existing wxImage.
+
+ This method is more efficient than converting wxImage to wxBitmap first
+ and then calling CreateBitmap() but otherwise has the same effect.
+
+ Returns an invalid wxNullGraphicsBitmap on failure.
+
+ @since 2.9.3
+ */
+ virtual wxGraphicsBitmap CreateBitmapFromImage(const wxImage& image) = 0;
+
/**
Creates wxGraphicsBitmap from a native bitmap handle.
*/
virtual wxGraphicsContext* CreateContext(const wxEnhMetaFileDC& dc) = 0;
+ /**
+ Creates a wxGraphicsContext associated with a wxImage.
+
+ This function is used by wxContext::CreateFromImage() and is not
+ normally called directly.
+
+ @since 2.9.3
+ */
+ static wxGraphicsContext* CreateContextFromImage(wxImage& image);
+
/**
Creates a native brush from a wxBrush.
*/
#include "wx/image.h"
#include "wx/file.h"
#include "wx/filename.h"
+#include "wx/graphics.h"
#include "wx/mstream.h"
#include "wx/wfstream.h"
#include "wx/quantize.h"
+#include "wx/scopedptr.h"
#include "wx/stopwatch.h"
#include "wx/versioninfo.h"
#ifdef wxHAVE_RAW_BITMAP
void OnTestRawBitmap( wxCommandEvent &event );
#endif // wxHAVE_RAW_BITMAP
+#if wxUSE_GRAPHICS_CONTEXT
+ void OnTestGraphics(wxCommandEvent& event);
+#endif // wxUSE_GRAPHICS_CONTEXT
void OnQuit( wxCommandEvent &event );
#if wxUSE_CLIPBOARD
ID_NEW = 100,
ID_INFO,
ID_SHOWRAW,
+ ID_GRAPHICS,
ID_SHOWTHUMBNAIL
};
#ifdef wxHAVE_RAW_BITMAP
EVT_MENU (ID_SHOWRAW, MyFrame::OnTestRawBitmap)
#endif
+#if wxUSE_GRAPHICS_CONTEXT
+ EVT_MENU (ID_GRAPHICS, MyFrame::OnTestGraphics)
+#endif // wxUSE_GRAPHICS_CONTEXT
#if wxUSE_CLIPBOARD
EVT_MENU(wxID_COPY, MyFrame::OnCopy)
EVT_MENU(wxID_PASTE, MyFrame::OnPaste)
menuImage->AppendSeparator();
menuImage->Append( ID_SHOWRAW, wxT("Test &raw bitmap...\tCtrl-R"));
#endif
+#if wxUSE_GRAPHICS_CONTEXT
+ menuImage->AppendSeparator();
+ menuImage->Append(ID_GRAPHICS, "Test &graphics context...\tCtrl-G");
+#endif // wxUSE_GRAPHICS_CONTEXT
menuImage->AppendSeparator();
menuImage->Append( ID_SHOWTHUMBNAIL, wxT("Test &thumbnail...\tCtrl-T"),
"Test scaling the image during load (try with JPEG)");
#endif // wxHAVE_RAW_BITMAP
+#if wxUSE_GRAPHICS_CONTEXT
+
+class MyGraphicsFrame : public wxFrame
+{
+public:
+ enum
+ {
+ WIDTH = 256,
+ HEIGHT = 90
+ };
+
+ MyGraphicsFrame(wxWindow* parent) :
+ wxFrame(parent, wxID_ANY, "Graphics context test"),
+ m_image(WIDTH, HEIGHT, false)
+ {
+ // Create a test image: it has 3 horizontal primary colour bands with
+ // alpha increasing from left to right.
+ m_image.SetAlpha();
+ unsigned char* alpha = m_image.GetAlpha();
+ unsigned char* data = m_image.GetData();
+
+ for ( int y = 0; y < HEIGHT; y++ )
+ {
+ unsigned char r = 0,
+ g = 0,
+ b = 0;
+ if ( y < HEIGHT/3 )
+ r = 0xff;
+ else if ( y < (2*HEIGHT)/3 )
+ g = 0xff;
+ else
+ b = 0xff;
+
+ for ( int x = 0; x < WIDTH; x++ )
+ {
+ *alpha++ = x;
+ *data++ = r;
+ *data++ = g;
+ *data++ = b;
+ }
+ }
+
+ m_bitmap = wxBitmap(m_image);
+
+ Connect(wxEVT_PAINT, wxPaintEventHandler(MyGraphicsFrame::OnPaint));
+
+ Show();
+ }
+
+private:
+ void OnPaint(wxPaintEvent& WXUNUSED(event))
+ {
+ wxPaintDC dc(this);
+ wxScopedPtr<wxGraphicsContext> gc(wxGraphicsContext::Create(dc));
+ wxGraphicsBitmap gb(gc->CreateBitmapFromImage(m_image));
+
+ gc->SetFont(*wxNORMAL_FONT, *wxBLACK);
+
+ gc->DrawText("Bitmap", 0, HEIGHT/2);
+ gc->DrawBitmap(m_bitmap, 0, 0, WIDTH, HEIGHT);
+
+ gc->DrawText("Graphics bitmap", 0, (3*HEIGHT)/2);
+ gc->DrawBitmap(gb, 0, HEIGHT, WIDTH, HEIGHT);
+ }
+
+ wxImage m_image;
+ wxBitmap m_bitmap;
+
+ wxDECLARE_NO_COPY_CLASS(MyGraphicsFrame);
+};
+
+void MyFrame::OnTestGraphics(wxCommandEvent& WXUNUSED(event))
+{
+ new MyGraphicsFrame(this);
+}
+
+#endif // wxUSE_GRAPHICS_CONTEXT
+
#if wxUSE_CLIPBOARD
void MyFrame::OnCopy(wxCommandEvent& WXUNUSED(event))
return GetRenderer()->CreateBitmap(bmp);
}
+#if wxUSE_IMAGE
+wxGraphicsBitmap wxGraphicsContext::CreateBitmapFromImage(const wxImage& image) const
+{
+ return GetRenderer()->CreateBitmapFromImage(image);
+}
+#endif // wxUSE_IMAGE
+
wxGraphicsBitmap wxGraphicsContext::CreateSubBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) const
{
return GetRenderer()->CreateSubBitmap(bmp,x,y,w,h);
return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(window);
}
+#if wxUSE_IMAGE
+/* static */ wxGraphicsContext* wxGraphicsContext::Create(wxImage& image)
+{
+ return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromImage(image);
+}
+#endif // wxUSE_IMAGE
+
wxGraphicsContext* wxGraphicsContext::Create()
{
return wxGraphicsRenderer::GetDefaultRenderer()->CreateMeasuringContext();
{
public:
wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitmap& bmp );
+#if wxUSE_IMAGE
+ wxCairoBitmapData(wxGraphicsRenderer* renderer, const wxImage& image);
+#endif // wxUSE_IMAGE
wxCairoBitmapData( wxGraphicsRenderer* renderer, cairo_surface_t* bitmap );
~wxCairoBitmapData();
protected:
virtual void DoDrawText( const wxString &str, wxDouble x, wxDouble y );
-private:
void Init(cairo_t *context);
+private:
cairo_t* m_context;
wxVector<float> m_layerOpacities;
wxDECLARE_NO_COPY_CLASS(wxCairoContext);
};
+#if wxUSE_IMAGE
+// ----------------------------------------------------------------------------
+// wxCairoImageContext: context associated with a wxImage.
+// ----------------------------------------------------------------------------
+
+class wxCairoImageContext : public wxCairoContext
+{
+public:
+ wxCairoImageContext(wxGraphicsRenderer* renderer, wxImage& image) :
+ wxCairoContext(renderer),
+ m_image(image),
+ m_data(renderer, image)
+ {
+ Init(cairo_create(m_data.GetCairoSurface()));
+ }
+
+ virtual ~wxCairoImageContext()
+ {
+ m_image = m_data.ConvertToImage();
+ }
+
+private:
+ wxImage& m_image;
+ wxCairoBitmapData m_data;
+
+ wxDECLARE_NO_COPY_CLASS(wxCairoImageContext);
+};
+#endif // wxUSE_IMAGE
+
//-----------------------------------------------------------------------------
// wxCairoPenData implementation
//-----------------------------------------------------------------------------
? CAIRO_FORMAT_ARGB32
: CAIRO_FORMAT_RGB24;
- InitBuffer(image.GetWidth(), image.GetHeight(), bufferFormat);
+ int stride = InitBuffer(image.GetWidth(), image.GetHeight(), bufferFormat);
// Copy wxImage data into the buffer. Notice that we work with wxUint32
// values and not bytes becase Cairo always works with buffers in native
for ( int y = 0; y < m_height; y++ )
{
+ wxUint32* const rowStartDst = dst;
+
for ( int x = 0; x < m_width; x++ )
{
const unsigned char a = *alpha++;
Premultiply(a, src[2]);
src += 3;
}
+
+ dst = rowStartDst + stride / 4;
}
}
else // RGB
{
for ( int y = 0; y < m_height; y++ )
{
+ wxUint32* const rowStartDst = dst;
+
for ( int x = 0; x < m_width; x++ )
{
*dst++ = src[0] << 16 |
src[2];
src += 3;
}
+
+ dst = rowStartDst + stride / 4;
}
}
- InitSurface(bufferFormat);
+ InitSurface(bufferFormat, stride);
}
wxImage wxCairoBitmapData::ConvertToImage() const
virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
+#if wxUSE_IMAGE
+ virtual wxGraphicsContext * CreateContextFromImage(wxImage& image);
+#endif // wxUSE_IMAGE
virtual wxGraphicsContext * CreateContext( wxWindow* window );
// create a native bitmap representation
virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap );
+#if wxUSE_IMAGE
+ virtual wxGraphicsBitmap CreateBitmapFromImage(const wxImage& image);
+#endif // wxUSE_IMAGE
// create a graphics bitmap from a native bitmap
virtual wxGraphicsBitmap CreateBitmapFromNativeBitmap( void* bitmap );
#endif
}
+#if wxUSE_IMAGE
+wxGraphicsContext * wxCairoRenderer::CreateContextFromImage(wxImage& image)
+{
+ return new wxCairoImageContext(this, image);
+}
+#endif // wxUSE_IMAGE
+
wxGraphicsContext * wxCairoRenderer::CreateMeasuringContext()
{
ENSURE_LOADED_OR_RETURN(NULL);
return wxNullGraphicsBitmap;
}
+#if wxUSE_IMAGE
+
+wxGraphicsBitmap wxCairoRenderer::CreateBitmapFromImage(const wxImage& image)
+{
+ wxGraphicsBitmap bmp;
+
+ ENSURE_LOADED_OR_RETURN(bmp);
+
+ if ( image.IsOk() )
+ {
+ bmp.SetRefData(new wxCairoBitmapData(this, image));
+ }
+
+ return bmp;
+}
+
+#endif // wxUSE_IMAGE
+
wxGraphicsBitmap wxCairoRenderer::CreateBitmapFromNativeBitmap( void* bitmap )
{
ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
virtual Bitmap* GetGDIPlusBitmap() { return m_bitmap; }
+#if wxUSE_IMAGE
+ wxImage ConvertToImage() const;
+#endif // wxUSE_IMAGE
+
private :
Bitmap* m_bitmap;
Bitmap* m_helper;
wxDECLARE_NO_COPY_CLASS(wxGDIPlusContext);
};
+#if wxUSE_IMAGE
+
+class wxGDIPlusImageContext : public wxGDIPlusContext
+{
+public:
+ wxGDIPlusImageContext(wxGraphicsRenderer* renderer, wxImage& image) :
+ wxGDIPlusContext(renderer),
+ m_image(image),
+ m_bitmap(renderer, image)
+ {
+ Init
+ (
+ new Graphics(m_bitmap.GetGDIPlusBitmap()),
+ image.GetWidth(),
+ image.GetHeight()
+ );
+ }
+
+ virtual ~wxGDIPlusImageContext()
+ {
+ m_image = m_bitmap.ConvertToImage();
+ }
+
+private:
+ wxImage& m_image;
+ wxGDIPlusBitmapData m_bitmap;
+
+ wxDECLARE_NO_COPY_CLASS(wxGDIPlusImageContext);
+};
+
+#endif // wxUSE_IMAGE
+
class wxGDIPlusMeasuringContext : public wxGDIPlusContext
{
public:
virtual wxGraphicsContext * CreateContext( wxWindow* window );
+#if wxUSE_IMAGE
+ virtual wxGraphicsContext * CreateContextFromImage(wxImage& image);
+#endif // wxUSE_IMAGE
+
virtual wxGraphicsContext * CreateMeasuringContext();
// Path
// create a native bitmap representation
virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap );
+#if wxUSE_IMAGE
+ virtual wxGraphicsBitmap CreateBitmapFromImage(const wxImage& image);
+#endif // wxUSE_IMAGE
// stub: should not be called directly
virtual wxGraphicsFont CreateFont( const wxFont& WXUNUSED(font),
m_bitmap = image;
}
+#if wxUSE_IMAGE
+
+wxImage wxGDIPlusBitmapData::ConvertToImage() const
+{
+ // We could use Bitmap::LockBits() and convert to wxImage directly but
+ // passing by wxBitmap is easier. It would be nice to measure performance
+ // of the two methods but for this the second one would need to be written
+ // first...
+ HBITMAP hbmp;
+ if ( m_bitmap->GetHBITMAP(Color(0xffffffff), &hbmp) != Gdiplus::Ok )
+ return wxNullImage;
+
+ wxBitmap bmp;
+ bmp.SetWidth(m_bitmap->GetWidth());
+ bmp.SetHeight(m_bitmap->GetHeight());
+ bmp.SetHBITMAP(hbmp);
+ bmp.SetDepth(IsAlphaPixelFormat(m_bitmap->GetPixelFormat()) ? 32 : 24);
+ return bmp.ConvertToImage();
+}
+
+#endif // wxUSE_IMAGE
+
wxGDIPlusBitmapData::~wxGDIPlusBitmapData()
{
delete m_bitmap;
delete m_helper;
}
+// ----------------------------------------------------------------------------
+// wxGraphicsBitmap implementation
+// ----------------------------------------------------------------------------
+
+#if wxUSE_IMAGE
+
+wxImage wxGraphicsBitmap::ConvertToImage() const
+{
+ const wxGDIPlusBitmapData* const
+ data = static_cast<wxGDIPlusBitmapData*>(GetGraphicsData());
+
+ return data ? data->ConvertToImage() : wxNullImage;
+}
+
+#endif // wxUSE_IMAGE
+
//-----------------------------------------------------------------------------
// wxGDIPlusPath implementation
//-----------------------------------------------------------------------------
return context;
}
+#if wxUSE_IMAGE
+wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromImage(wxImage& image)
+{
+ ENSURE_LOADED_OR_RETURN(NULL);
+ wxGDIPlusContext* context = new wxGDIPlusImageContext(this, image);
+ context->EnableOffset(true);
+ return context;
+}
+
+#endif // wxUSE_IMAGE
+
wxGraphicsContext * wxGDIPlusRenderer::CreateMeasuringContext()
{
ENSURE_LOADED_OR_RETURN(NULL);
return wxNullGraphicsBitmap;
}
+#if wxUSE_IMAGE
+
+wxGraphicsBitmap wxGDIPlusRenderer::CreateBitmapFromImage(const wxImage& image)
+{
+ ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
+ if ( image.IsOk() )
+ {
+ // Notice that we rely on conversion from wxImage to wxBitmap here but
+ // we could probably do it more efficiently by converting from wxImage
+ // to GDI+ Bitmap directly, i.e. copying wxImage pixels to the buffer
+ // returned by Bitmap::LockBits(). However this would require writing
+ // code specific for this task while like this we can reuse existing
+ // code (see also wxGDIPlusBitmapData::ConvertToImage()).
+ wxGraphicsBitmap gb;
+ gb.SetRefData(new wxGDIPlusBitmapData(this, image));
+ return gb;
+ }
+ else
+ return wxNullGraphicsBitmap;
+}
+
+#endif // wxUSE_IMAGE
+
wxGraphicsBitmap wxGDIPlusRenderer::CreateBitmapFromNativeBitmap( void *bitmap )
{
ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
return m;
}
+
+#if wxUSE_IMAGE
+
+// ----------------------------------------------------------------------------
+// wxMacCoreGraphicsImageContext
+// ----------------------------------------------------------------------------
+
+// This is a GC that can be used to draw on wxImage. In this implementation we
+// simply draw on a wxBitmap using wxMemoryDC and then convert it to wxImage in
+// the end so it's not especially interesting and exists mainly for
+// compatibility with the other platforms.
+class wxMacCoreGraphicsImageContext : public wxMacCoreGraphicsContext
+{
+public:
+ wxMacCoreGraphicsImageContext(wxGraphicsRenderer* renderer,
+ wxImage& image) :
+ wxMacCoreGraphicsContext(renderer),
+ m_image(image),
+ m_bitmap(image),
+ m_memDC(m_bitmap)
+ {
+ SetNativeContext
+ (
+ (CGContextRef)(m_memDC.GetGraphicsContext()->GetNativeContext())
+ );
+ m_width = image.GetWidth();
+ m_height = image.GetHeight();
+ }
+
+ virtual ~wxMacCoreGraphicsImageContext()
+ {
+ m_memDC.SelectObject(wxNullBitmap);
+ m_image = m_bitmap.ConvertToImage();
+ }
+
+private:
+ wxImage& m_image;
+ wxBitmap m_bitmap;
+ wxMemoryDC m_memDC;
+};
+
+#endif // wxUSE_IMAGE
+
//
// Renderer
//
virtual wxGraphicsContext * CreateContext( wxWindow* window );
+#if wxUSE_IMAGE
+ virtual wxGraphicsContext * CreateContextFromImage(wxImage& image);
+#endif // wxUSE_IMAGE
+
virtual wxGraphicsContext * CreateMeasuringContext();
// Path
// create a native bitmap representation
virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) ;
+#if wxUSE_IMAGE
+ virtual wxGraphicsBitmap CreateBitmapFromImage(const wxImage& image);
+#endif // wxUSE_IMAGE
+
// create a graphics bitmap from a native bitmap
virtual wxGraphicsBitmap CreateBitmapFromNativeBitmap( void* bitmap );
return new wxMacCoreGraphicsContext(this);
}
+#if wxUSE_IMAGE
+
+wxGraphicsContext*
+wxMacCoreGraphicsRenderer::CreateContextFromImage(wxImage& image)
+{
+ return new wxMacCoreGraphicsImageContext(this, image);
+}
+
+#endif // wxUSE_IMAGE
+
// Path
wxGraphicsPath wxMacCoreGraphicsRenderer::CreatePath()
return wxNullGraphicsBitmap;
}
+#if wxUSE_IMAGE
+
+wxGraphicsBitmap
+wxMacCoreGraphicsRenderer::CreateBitmapFromImage(const wxImage& image)
+{
+ // We don't have any direct way to convert wxImage to CGImage so pass by
+ // wxBitmap. This makes this function pretty useless in this implementation
+ // but it allows to have the same API as with Cairo backend where we can
+ // convert wxImage to a Cairo surface directly, bypassing wxBitmap.
+ return CreateBitmap(wxBitmap(image));
+}
+
+#endif // wxUSE_IMAGE
+
wxGraphicsBitmap wxMacCoreGraphicsRenderer::CreateBitmapFromNativeBitmap( void* bitmap )
{
if ( bitmap != NULL )