]> git.saurik.com Git - wxWidgets.git/commitdiff
Added wxGraphicsBitmap::ConvertToImage().
authorVadim Zeitlin <vadim@wxwidgets.org>
Sun, 9 Oct 2011 22:07:07 +0000 (22:07 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sun, 9 Oct 2011 22:07:07 +0000 (22:07 +0000)
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
interface/wx/graphics.h
src/generic/graphicc.cpp
src/osx/carbon/graphics.cpp

index 6e7cf27fe3d2c1c3395984344855f97106d01ea7..a612258a7a37cbdd8084e3a0fe79306cdcdc09cf 100644 (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)
 };
index 7373e868619b9983952595fbb03621e35155f8b2..971df3c422207d3d1fc39bebf4ece2fa791c63c3 100644 (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;
 };
 
 /**
index 0f14fa284b99b87599c20ac3bb7065a6668b624e..92893cac397fada7f6318d6ca57967b4a3b368ed 100644 (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
index 4b1df9cdca5ade5d27a2ca9f2b4dc01a902c7372..e5e2a07b6ccf0d7f7f6dc0aa6d94cf539ac38de3 100644 (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
 //