From 08b2d55fdf75a1656c682cc2773c2d1609f1e7c1 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 9 Oct 2011 22:07:07 +0000 Subject: [PATCH] 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 --- include/wx/graphics.h | 9 ++ interface/wx/graphics.h | 14 +++ src/generic/graphicc.cpp | 179 ++++++++++++++++++++++++++++++++++++ src/osx/carbon/graphics.cpp | 20 ++++ 4 files changed, 222 insertions(+) diff --git a/include/wx/graphics.h b/include/wx/graphics.h index 6e7cf27fe3..a612258a7a 100644 --- a/include/wx/graphics.h +++ b/include/wx/graphics.h @@ -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) }; diff --git a/interface/wx/graphics.h b/interface/wx/graphics.h index 7373e86861..971df3c422 100644 --- a/interface/wx/graphics.h +++ b/interface/wx/graphics.h @@ -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; }; /** diff --git a/src/generic/graphicc.cpp b/src/generic/graphicc.cpp index 0f14fa284b..92893cac39 100644 --- a/src/generic/graphicc.cpp +++ b/src/generic/graphicc.cpp @@ -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(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(GetGraphicsData()); + + return data ? data->ConvertToImage() : wxNullImage; +} +#endif // wxUSE_IMAGE //----------------------------------------------------------------------------- // wxCairoContext implementation diff --git a/src/osx/carbon/graphics.cpp b/src/osx/carbon/graphics.cpp index 4b1df9cdca..e5e2a07b6c 100644 --- a/src/osx/carbon/graphics.cpp +++ b/src/osx/carbon/graphics.cpp @@ -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(GetRefData()); + + return data ? data->ConvertToImage() : wxNullImage; +} + +#endif // wxUSE_IMAGE + // // Graphics Matrix // -- 2.47.2