Added wxGraphicsBitmap::ConvertToImage().

Allow to convert wxGraphicsBitmap directly to wxImage, without passing by
wxBitmap.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@69353 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2011-10-09 22:07:07 +00:00
parent 5f606e6515
commit 08b2d55fdf
4 changed files with 222 additions and 0 deletions

View File

@ -19,6 +19,7 @@
#include "wx/geometry.h"
#include "wx/dynarray.h"
#include "wx/dc.h"
#include "wx/image.h"
#include "wx/vector.h"
enum wxAntialiasMode
@ -166,6 +167,14 @@ class WXDLLIMPEXP_CORE wxGraphicsBitmap : public wxGraphicsObject
public:
wxGraphicsBitmap() {}
virtual ~wxGraphicsBitmap() {}
// Convert bitmap to wxImage: this is more efficient than converting to
// wxBitmap first and then to wxImage and also works without X server
// connection under Unix that wxBitmap requires.
#if wxUSE_IMAGE
wxImage ConvertToImage() const;
#endif // wxUSE_IMAGE
private:
DECLARE_DYNAMIC_CLASS(wxGraphicsBitmap)
};

View File

@ -282,6 +282,20 @@ public:
Default constructor creates an invalid bitmap.
*/
wxGraphicsBitmap() {}
/**
Return the contents of this bitmap as wxImage.
Using this method is more efficient than converting wxGraphicsBitmap to
wxBitmap first and then to wxImage and can be useful if, for example,
you want to save wxGraphicsBitmap as a disk file in a format not
directly supported by wxBitmap.
Invalid image is returned if the bitmap is invalid.
@since 2.9.3
*/
wxImage ConvertToImage() const;
};
/**

View File

@ -317,6 +317,11 @@ public:
virtual cairo_surface_t* GetCairoSurface() { return m_surface; }
virtual cairo_pattern_t* GetCairoPattern() { return m_pattern; }
virtual wxSize GetSize() { return wxSize(m_width, m_height); }
#if wxUSE_IMAGE
wxImage ConvertToImage() const;
#endif // wxUSE_IMAGE
private :
// Allocate m_buffer for the bitmap of the given size in the given format.
//
@ -1249,6 +1254,166 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
#endif // wxHAS_RAW_BITMAP
}
#if wxUSE_IMAGE
// Helper functions for dealing with alpha pre-multiplication.
namespace
{
inline unsigned char Premultiply(unsigned char alpha, unsigned char data)
{
return alpha ? (data * alpha)/0xff : data;
}
inline unsigned char Unpremultiply(unsigned char alpha, unsigned char data)
{
return alpha ? (data * 0xff)/alpha : data;
}
} // anonymous namespace
wxCairoBitmapData::wxCairoBitmapData(wxGraphicsRenderer* renderer,
const wxImage& image)
: wxGraphicsObjectRefData(renderer)
{
const cairo_format_t bufferFormat = image.HasAlpha()
? CAIRO_FORMAT_ARGB32
: CAIRO_FORMAT_RGB24;
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
// endianness.
wxUint32* dst = reinterpret_cast<wxUint32*>(m_buffer);
const unsigned char* src = image.GetData();
if ( bufferFormat == CAIRO_FORMAT_ARGB32 )
{
const unsigned char* alpha = image.GetAlpha();
for ( int y = 0; y < m_height; y++ )
{
for ( int x = 0; x < m_width; x++ )
{
const unsigned char a = *alpha++;
*dst++ = a << 24 |
Premultiply(a, src[0]) << 16 |
Premultiply(a, src[1]) << 8 |
Premultiply(a, src[2]);
src += 3;
}
}
}
else // RGB
{
for ( int y = 0; y < m_height; y++ )
{
for ( int x = 0; x < m_width; x++ )
{
*dst++ = src[0] << 16 |
src[1] << 8 |
src[2];
src += 3;
}
}
}
InitSurface(bufferFormat);
}
wxImage wxCairoBitmapData::ConvertToImage() const
{
wxImage image(m_width, m_height, false /* don't clear */);
// Get the surface type and format.
wxCHECK_MSG( cairo_surface_get_type(m_surface) == CAIRO_SURFACE_TYPE_IMAGE,
wxNullImage,
wxS("Can't convert non-image surface to image.") );
switch ( cairo_image_surface_get_format(m_surface) )
{
case CAIRO_FORMAT_ARGB32:
image.SetAlpha();
break;
case CAIRO_FORMAT_RGB24:
// Nothing to do, we don't use alpha by default.
break;
case CAIRO_FORMAT_A8:
case CAIRO_FORMAT_A1:
wxFAIL_MSG(wxS("Unsupported Cairo image surface type."));
return wxNullImage;
default:
wxFAIL_MSG(wxS("Unknown Cairo image surface type."));
return wxNullImage;
}
// Prepare for copying data.
const wxUint32* src = (wxUint32*)cairo_image_surface_get_data(m_surface);
wxCHECK_MSG( src, wxNullImage, wxS("Failed to get Cairo surface data.") );
int stride = cairo_image_surface_get_stride(m_surface);
wxCHECK_MSG( stride > 0, wxNullImage,
wxS("Failed to get Cairo surface stride.") );
// As we work with wxUint32 pointers and not char ones, we need to adjust
// the stride accordingly. This should be lossless as the stride must be a
// multiple of pixel size.
wxASSERT_MSG( !(stride % sizeof(wxUint32)), wxS("Unexpected stride.") );
stride /= sizeof(wxUint32);
unsigned char* dst = image.GetData();
unsigned char *alpha = image.GetAlpha();
if ( alpha )
{
// We need to also copy alpha and undo the pre-multiplication as Cairo
// stores pre-multiplied values in this format while wxImage does not.
for ( int y = 0; y < m_height; y++ )
{
const wxUint32* const rowStart = src;
for ( int x = 0; x < m_width; x++ )
{
const wxUint32 argb = *src++;
*alpha++ = (argb & 0xff000000) >> 24;
// Copy the RGB data undoing the pre-multiplication.
*dst++ = Unpremultiply(*alpha, (argb & 0x00ff0000) >> 16);
*dst++ = Unpremultiply(*alpha, (argb & 0x0000ff00) >> 8);
*dst++ = Unpremultiply(*alpha, (argb & 0x000000ff));
}
src = rowStart + stride;
}
}
else // RGB
{
// Things are pretty simple in this case, just copy RGB bytes.
for ( int y = 0; y < m_height; y++ )
{
const wxUint32* const rowStart = src;
for ( int x = 0; x < m_width; x++ )
{
const wxUint32 argb = *src++;
*dst++ = (argb & 0x00ff0000) >> 16;
*dst++ = (argb & 0x0000ff00) >> 8;
*dst++ = (argb & 0x000000ff);
}
src = rowStart + stride;
}
}
return image;
}
#endif // wxUSE_IMAGE
wxCairoBitmapData::~wxCairoBitmapData()
{
if (m_pattern)
@ -1260,7 +1425,21 @@ wxCairoBitmapData::~wxCairoBitmapData()
delete [] m_buffer;
}
// ----------------------------------------------------------------------------
// wxGraphicsBitmap implementation
// ----------------------------------------------------------------------------
#if wxUSE_IMAGE
wxImage wxGraphicsBitmap::ConvertToImage() const
{
const wxCairoBitmapData* const
data = static_cast<wxCairoBitmapData*>(GetGraphicsData());
return data ? data->ConvertToImage() : wxNullImage;
}
#endif // wxUSE_IMAGE
//-----------------------------------------------------------------------------
// wxCairoContext implementation

View File

@ -978,6 +978,14 @@ public:
virtual CGImageRef GetBitmap() { return m_bitmap; }
bool IsMonochrome() { return m_monochrome; }
#if wxUSE_IMAGE
wxImage ConvertToImage() const
{
return wxBitmap(m_bitmap).ConvertToImage();
}
#endif // wxUSE_IMAGE
private :
CGImageRef m_bitmap;
bool m_monochrome;
@ -993,6 +1001,18 @@ wxMacCoreGraphicsBitmapData::~wxMacCoreGraphicsBitmapData()
CGImageRelease( m_bitmap );
}
#if wxUSE_IMAGE
wxImage wxGraphicsBitmap::ConvertToImage() const
{
wxMacCoreGraphicsBitmapData* const
data = static_cast<wxMacCoreGraphicsBitmapData*>(GetRefData());
return data ? data->ConvertToImage() : wxNullImage;
}
#endif // wxUSE_IMAGE
//
// Graphics Matrix
//