Fix alpha channel values when using wxGCDC with wxMemoryDC in wxMSW.
Ensure that 32bpp bitmaps selected in wxMemoryDC use DIB for their internal representation as GDI+ functions don't seem to work correctly with DDBs with alpha channel. Closes #13328. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@75648 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -136,6 +136,8 @@ public:
|
|||||||
#if wxUSE_WXDIB
|
#if wxUSE_WXDIB
|
||||||
// copies from a device independent bitmap
|
// copies from a device independent bitmap
|
||||||
bool CopyFromDIB(const wxDIB& dib);
|
bool CopyFromDIB(const wxDIB& dib);
|
||||||
|
bool IsDIB() const;
|
||||||
|
bool ConvertToDIB();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
virtual bool Create(int width, int height, int depth = wxBITMAP_SCREEN_DEPTH);
|
virtual bool Create(int width, int height, int depth = wxBITMAP_SCREEN_DEPTH);
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#if wxUSE_GRAPHICS_CONTEXT
|
#if wxUSE_GRAPHICS_CONTEXT
|
||||||
|
|
||||||
#include "wx/dcgraph.h"
|
#include "wx/dcgraph.h"
|
||||||
|
#include "wx/rawbmp.h"
|
||||||
|
|
||||||
#ifndef WX_PRECOMP
|
#ifndef WX_PRECOMP
|
||||||
#include "wx/icon.h"
|
#include "wx/icon.h"
|
||||||
@@ -171,6 +172,61 @@ wxGCDCImpl::wxGCDCImpl( wxDC *owner, const wxWindowDC& dc ) :
|
|||||||
wxGCDCImpl::wxGCDCImpl( wxDC *owner, const wxMemoryDC& dc ) :
|
wxGCDCImpl::wxGCDCImpl( wxDC *owner, const wxMemoryDC& dc ) :
|
||||||
wxDCImpl( owner )
|
wxDCImpl( owner )
|
||||||
{
|
{
|
||||||
|
#ifndef NEVER_USE_DIB
|
||||||
|
// It seems that GDI+ sets invalid values for alpha channel when used with
|
||||||
|
// a compatible bitmap (DDB). So we need to convert the currently selected
|
||||||
|
// bitmap to a DIB before using it with any GDI+ functions to ensure that
|
||||||
|
// we get the correct alpha channel values in it at the end.
|
||||||
|
|
||||||
|
wxBitmap bmp = dc.GetSelectedBitmap();
|
||||||
|
wxASSERT_MSG( bmp.IsOk(), "Should select a bitmap before creating wxGCDC" );
|
||||||
|
|
||||||
|
// We don't need to convert it if it can't have alpha at all (any depth but
|
||||||
|
// 32) or is already a DIB with alpha.
|
||||||
|
if ( bmp.GetDepth() == 32 && (!bmp.IsDIB() || !bmp.HasAlpha()) )
|
||||||
|
{
|
||||||
|
// We need to temporarily deselect this bitmap from the memory DC
|
||||||
|
// before modifying it.
|
||||||
|
const_cast<wxMemoryDC&>(dc).SelectObject(wxNullBitmap);
|
||||||
|
|
||||||
|
bmp.ConvertToDIB(); // Does nothing if already a DIB.
|
||||||
|
|
||||||
|
if( !bmp.HasAlpha() )
|
||||||
|
{
|
||||||
|
// Initialize alpha channel, even if we don't have any alpha yet,
|
||||||
|
// we should have correct (opaque) alpha values in it for GDI+
|
||||||
|
// functions to work correctly.
|
||||||
|
{
|
||||||
|
wxAlphaPixelData data(bmp);
|
||||||
|
if ( data )
|
||||||
|
{
|
||||||
|
wxAlphaPixelData::Iterator p(data);
|
||||||
|
for ( int y = 0; y < data.GetHeight(); y++ )
|
||||||
|
{
|
||||||
|
wxAlphaPixelData::Iterator rowStart = p;
|
||||||
|
|
||||||
|
for ( int x = 0; x < data.GetWidth(); x++ )
|
||||||
|
{
|
||||||
|
p.Alpha() = wxALPHA_OPAQUE;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = rowStart;
|
||||||
|
p.OffsetY(data, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // End of block modifying the bitmap.
|
||||||
|
|
||||||
|
// Using wxAlphaPixelData sets the internal "has alpha" flag but we
|
||||||
|
// don't really have any alpha yet, so reset it back for now.
|
||||||
|
bmp.ResetAlpha();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Undo SelectObject() at the beginning of this block.
|
||||||
|
const_cast<wxMemoryDC&>(dc).SelectObjectAsSource(bmp);
|
||||||
|
}
|
||||||
|
#endif // !NEVER_USE_DIB
|
||||||
|
|
||||||
Init(wxGraphicsContext::Create(dc));
|
Init(wxGraphicsContext::Create(dc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -68,8 +68,15 @@ public:
|
|||||||
|
|
||||||
virtual void Free();
|
virtual void Free();
|
||||||
|
|
||||||
|
// Creates a new bitmap (DDB or DIB) from the contents of the given DIB.
|
||||||
void CopyFromDIB(const wxDIB& dib);
|
void CopyFromDIB(const wxDIB& dib);
|
||||||
|
|
||||||
|
#ifndef NEVER_USE_DIB
|
||||||
|
// Takes ownership of the given DIB.
|
||||||
|
bool AssignDIB(wxDIB& dib);
|
||||||
|
#endif // !NEVER_USE_DIB
|
||||||
|
|
||||||
|
|
||||||
// set the mask object to use as the mask, we take ownership of it
|
// set the mask object to use as the mask, we take ownership of it
|
||||||
void SetMask(wxMask *mask)
|
void SetMask(wxMask *mask)
|
||||||
{
|
{
|
||||||
@@ -118,6 +125,11 @@ public:
|
|||||||
private:
|
private:
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
|
// Use the given bitmap handle and take the rest of the characteristics
|
||||||
|
// (size, depth, ...) from the given DIB.
|
||||||
|
void InitFromDIB(const wxDIB& dib, HBITMAP hbitmap);
|
||||||
|
|
||||||
|
|
||||||
// optional mask for transparent drawing
|
// optional mask for transparent drawing
|
||||||
wxMask *m_bitmapMask;
|
wxMask *m_bitmapMask;
|
||||||
|
|
||||||
@@ -249,6 +261,22 @@ void wxBitmapRefData::Free()
|
|||||||
wxDELETE(m_bitmapMask);
|
wxDELETE(m_bitmapMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wxBitmapRefData::InitFromDIB(const wxDIB& dib, HBITMAP hbitmap)
|
||||||
|
{
|
||||||
|
m_width = dib.GetWidth();
|
||||||
|
m_height = dib.GetHeight();
|
||||||
|
m_depth = dib.GetDepth();
|
||||||
|
|
||||||
|
m_hBitmap = (WXHBITMAP)hbitmap;
|
||||||
|
|
||||||
|
#if wxUSE_PALETTE
|
||||||
|
wxPalette *palette = dib.CreatePalette();
|
||||||
|
if ( palette )
|
||||||
|
m_bitmapPalette = *palette;
|
||||||
|
delete palette;
|
||||||
|
#endif // wxUSE_PALETTE
|
||||||
|
}
|
||||||
|
|
||||||
void wxBitmapRefData::CopyFromDIB(const wxDIB& dib)
|
void wxBitmapRefData::CopyFromDIB(const wxDIB& dib)
|
||||||
{
|
{
|
||||||
wxCHECK_RET( !IsOk(), "bitmap already initialized" );
|
wxCHECK_RET( !IsOk(), "bitmap already initialized" );
|
||||||
@@ -264,20 +292,26 @@ void wxBitmapRefData::CopyFromDIB(const wxDIB& dib)
|
|||||||
m_isDIB = true;
|
m_isDIB = true;
|
||||||
#endif // SOMETIMES_USE_DIB/ALWAYS_USE_DIB
|
#endif // SOMETIMES_USE_DIB/ALWAYS_USE_DIB
|
||||||
|
|
||||||
m_width = dib.GetWidth();
|
InitFromDIB(dib, hbitmap);
|
||||||
m_height = dib.GetHeight();
|
|
||||||
m_depth = dib.GetDepth();
|
|
||||||
|
|
||||||
m_hBitmap = (WXHBITMAP)hbitmap;
|
|
||||||
|
|
||||||
#if wxUSE_PALETTE
|
|
||||||
wxPalette *palette = dib.CreatePalette();
|
|
||||||
if ( palette )
|
|
||||||
m_bitmapPalette = *palette;
|
|
||||||
delete palette;
|
|
||||||
#endif // wxUSE_PALETTE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NEVER_USE_DIB
|
||||||
|
|
||||||
|
bool wxBitmapRefData::AssignDIB(wxDIB& dib)
|
||||||
|
{
|
||||||
|
if ( !dib.IsOk() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Free();
|
||||||
|
|
||||||
|
m_isDIB = true;
|
||||||
|
InitFromDIB(dib, dib.Detach());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !NEVER_USE_DIB
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// wxBitmap creation
|
// wxBitmap creation
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -457,6 +491,26 @@ bool wxBitmap::CopyFromDIB(const wxDIB& dib)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wxBitmap::IsDIB() const
|
||||||
|
{
|
||||||
|
return GetBitmapData() && GetBitmapData()->m_isDIB;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wxBitmap::ConvertToDIB()
|
||||||
|
{
|
||||||
|
if ( IsDIB() )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
wxDIB dib(*this);
|
||||||
|
if ( !dib.IsOk() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// It is important to reuse the current GetBitmapData() instead of creating
|
||||||
|
// a new one, as our object identity shouldn't change just because our
|
||||||
|
// internal representation did, but IsSameAs() compares data pointers.
|
||||||
|
return GetBitmapData()->AssignDIB(dib);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // NEVER_USE_DIB
|
#endif // NEVER_USE_DIB
|
||||||
|
|
||||||
wxBitmap::~wxBitmap()
|
wxBitmap::~wxBitmap()
|
||||||
|
Reference in New Issue
Block a user