#include "wx/image.h"
#endif
+#include "wx/scopedptr.h"
#include "wx/msw/private.h"
#include "wx/msw/dc.h"
class WXDLLEXPORT wxBitmapRefData : public wxGDIImageRefData
{
public:
- wxBitmapRefData();
+ wxBitmapRefData() { Init(); }
wxBitmapRefData(const wxBitmapRefData& data);
virtual ~wxBitmapRefData() { Free(); }
virtual void Free();
+ void CopyFromDIB(const wxDIB& dib);
+
// set the mask object to use as the mask, we take ownership of it
void SetMask(wxMask *mask)
{
bool m_isDIB;
private:
+ void Init();
+
// optional mask for transparent drawing
wxMask *m_bitmapMask;
// wxBitmapRefData
// ----------------------------------------------------------------------------
-wxBitmapRefData::wxBitmapRefData()
+void wxBitmapRefData::Init()
{
#if wxDEBUG_LEVEL
m_selectedInto = NULL;
wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData& data)
: wxGDIImageRefData(data)
{
-#if wxDEBUG_LEVEL
- m_selectedInto = NULL;
-#endif
+ Init();
// (deep) copy the mask if present
- m_bitmapMask = NULL;
if (data.m_bitmapMask)
m_bitmapMask = new wxMask(*data.m_bitmapMask);
- // FIXME: we don't copy m_hBitmap currently but we should, see wxBitmap::
- // CloneGDIRefData()
-
- wxASSERT_MSG( !data.m_isDIB,
+ wxASSERT_MSG( !data.m_dib,
wxT("can't copy bitmap locked for raw access!") );
- m_isDIB = false;
m_hasAlpha = data.m_hasAlpha;
+
+#if wxUSE_WXDIB
+ // copy the other bitmap
+ if ( data.m_hBitmap )
+ {
+ wxDIB dib((HBITMAP)(data.m_hBitmap));
+ CopyFromDIB(dib);
+ }
+#endif // wxUSE_WXDIB
}
void wxBitmapRefData::Free()
}
}
- delete m_bitmapMask;
- m_bitmapMask = NULL;
+ wxDELETE(m_bitmapMask);
+}
+
+void wxBitmapRefData::CopyFromDIB(const wxDIB& dib)
+{
+ wxCHECK_RET( !IsOk(), "bitmap already initialized" );
+ wxCHECK_RET( dib.IsOk(), wxT("invalid DIB in CopyFromDIB") );
+
+#ifdef SOMETIMES_USE_DIB
+ HBITMAP hbitmap = dib.CreateDDB();
+ if ( !hbitmap )
+ return;
+ m_isDIB = false;
+#else // ALWAYS_USE_DIB
+ HBITMAP hbitmap = const_cast<wxDIB &>(dib).Detach();
+ m_isDIB = true;
+#endif // SOMETIMES_USE_DIB/ALWAYS_USE_DIB
+
+ 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
}
// ----------------------------------------------------------------------------
return new wxBitmapRefData;
}
-wxGDIRefData *wxBitmap::CloneGDIRefData(const wxGDIRefData *dataOrig) const
+wxGDIRefData *wxBitmap::CloneGDIRefData(const wxGDIRefData *data) const
{
- const wxBitmapRefData *
- data = static_cast<const wxBitmapRefData *>(dataOrig);
- if ( !data )
- return NULL;
-
- // FIXME: this method is backwards, it should just create a new
- // wxBitmapRefData using its copy ctor but instead it modifies this
- // bitmap itself and then returns its m_refData -- which works, of
- // course (except in !wxUSE_WXDIB), but is completely illogical
- wxBitmap *self = const_cast<wxBitmap *>(this);
-
- wxBitmapRefData *selfdata;
-#if wxUSE_WXDIB
- // copy the other bitmap
- if ( data->m_hBitmap )
- {
- wxDIB dib((HBITMAP)(data->m_hBitmap));
- self->CopyFromDIB(dib);
-
- selfdata = static_cast<wxBitmapRefData *>(m_refData);
- selfdata->m_hasAlpha = data->m_hasAlpha;
- }
- else
-#endif // wxUSE_WXDIB
- {
- // copy the bitmap data
- selfdata = new wxBitmapRefData(*data);
- self->m_refData = selfdata;
- }
-
- // copy also the mask
- wxMask * const maskSrc = data->GetMask();
- if ( maskSrc )
- {
- selfdata->SetMask(new wxMask(*maskSrc));
- }
-
- return selfdata;
+ return new wxBitmapRefData(*static_cast<const wxBitmapRefData *>(data));
}
bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon,
wxDIB dib(iconInfo.hbmColor);
if (dib.IsOk())
{
- const unsigned char* pixels = dib.GetData();
- for (int idx = 0; idx < w*h*4; idx+=4)
+ unsigned char* const pixels = dib.GetData();
+ int idx;
+ for ( idx = 0; idx < w*h*4; idx += 4 )
{
if (pixels[idx+3] != 0)
{
break;
}
}
+
+ if ( refData->m_hasAlpha )
+ {
+ // If we do have alpha, ensure we use premultiplied
+ // data for our pixels as this is what the bitmaps
+ // created in other ways do and this is necessary
+ // for e.g. AlphaBlend() to work with this bitmap.
+ for ( idx = 0; idx < w*h*4; idx += 4 )
+ {
+ const unsigned char a = pixels[idx+3];
+
+ pixels[idx] = ((pixels[idx] *a) + 127)/255;
+ pixels[idx+1] = ((pixels[idx+1]*a) + 127)/255;
+ pixels[idx+2] = ((pixels[idx+2]*a) + 127)/255;
+ }
+
+ ::DeleteObject(refData->m_hBitmap);
+ refData->m_hBitmap = dib.Detach();
+ }
}
}
}
{
UnRef();
- if ( !cursor.Ok() )
+ if ( !cursor.IsOk() )
return false;
return CopyFromIconOrCursor(cursor, transp);
{
UnRef();
- if ( !icon.Ok() )
+ if ( !icon.IsOk() )
return false;
return CopyFromIconOrCursor(icon, transp);
bool wxBitmap::CopyFromDIB(const wxDIB& dib)
{
- wxCHECK_MSG( dib.IsOk(), false, wxT("invalid DIB in CopyFromDIB") );
-
-#ifdef SOMETIMES_USE_DIB
- HBITMAP hbitmap = dib.CreateDDB();
- if ( !hbitmap )
+ wxScopedPtr<wxBitmapRefData> newData(new wxBitmapRefData);
+ newData->CopyFromDIB(dib);
+ if ( !newData->IsOk() )
return false;
-#else // ALWAYS_USE_DIB
- HBITMAP hbitmap = ((wxDIB &)dib).Detach(); // const_cast
-#endif // SOMETIMES_USE_DIB/ALWAYS_USE_DIB
UnRef();
-
- wxBitmapRefData *refData = new wxBitmapRefData;
- m_refData = refData;
-
- refData->m_width = dib.GetWidth();
- refData->m_height = dib.GetHeight();
- refData->m_depth = dib.GetDepth();
-
- refData->m_hBitmap = (WXHBITMAP)hbitmap;
-
-#if wxUSE_PALETTE
- wxPalette *palette = dib.CreatePalette();
- if ( palette )
- {
- refData->m_bitmapPalette = *palette;
- }
-
- delete palette;
-#endif // wxUSE_PALETTE
-
+ m_refData = newData.release();
return true;
}
else
{
// bits should already be in Windows standard format
- data = (char *)bits; // const_cast is harmless
+ data = const_cast<char *>(bits);
}
HBITMAP hbmp = ::CreateBitmap(width, height, 1, depth, data);
SetHBITMAP((WXHBITMAP)hbmp);
- return Ok();
+ return IsOk();
}
#if wxUSE_IMAGE
// so the 'depth' argument is ignored.
// TODO: transparency (create a mask image)
- if (!Ok())
+ if (!IsOk())
{
wxFAIL_MSG( wxT("bitmap is invalid") );
return wxNullImage;
wxImage image;
- wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
+ wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid bitmap") );
// create an wxImage object
int width = GetWidth();
bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc)
{
- wxCHECK_MSG( image.Ok(), false, wxT("invalid image") );
+ wxCHECK_MSG( image.IsOk(), false, wxT("invalid image") );
UnRef();
return false;
const bool hasAlpha = image.HasAlpha();
-
+
if (depth == -1)
depth = dib.GetDepth();
// and then DIB to our wxImage
wxImage image = dib.ConvertToImage();
- if ( !image.Ok() )
+ if ( !image.IsOk() )
{
return wxNullImage;
}
else // no bitmap handler found
{
wxImage image;
- if ( image.LoadFile( filename, type ) && image.Ok() )
+ if ( image.LoadFile( filename, type ) && image.IsOk() )
{
*this = wxBitmap(image);
{
// FIXME what about palette? shouldn't we use it?
wxImage image = ConvertToImage();
- if ( image.Ok() )
+ if ( image.IsOk() )
{
return image.SaveFile(filename, type);
}
wxBitmap wxBitmap::GetSubBitmapOfHDC( const wxRect& rect, WXHDC hdc ) const
{
- wxCHECK_MSG( Ok() &&
+ wxCHECK_MSG( IsOk() &&
(rect.x >= 0) && (rect.y >= 0) &&
(rect.x+rect.width <= GetWidth()) &&
(rect.y+rect.height <= GetHeight()),
wxNullBitmap, wxT("Invalid bitmap or bitmap region") );
wxBitmap ret( rect.width, rect.height, GetDepth() );
- wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
+ wxASSERT_MSG( ret.IsOk(), wxT("GetSubBitmap error") );
#ifndef __WXMICROWIN__
// handle alpha channel, if any
void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
{
#if wxUSE_WXDIB
- if ( !Ok() )
+ if ( !IsOk() )
{
// no bitmap, no data (raw or otherwise)
return NULL;
void wxBitmap::UngetRawData(wxPixelDataBase& dataBase)
{
#if wxUSE_WXDIB
- if ( !Ok() )
+ if ( !IsOk() )
return;
if ( !&dataBase )
bool wxMask::Create(const wxBitmap& bitmap)
{
#ifndef __WXMICROWIN__
- wxCHECK_MSG( bitmap.Ok() && bitmap.GetDepth() == 1, false,
+ wxCHECK_MSG( bitmap.IsOk() && bitmap.GetDepth() == 1, false,
wxT("can't create mask from invalid or not monochrome bitmap") );
if ( m_maskBitmap )
}
#if wxUSE_PALETTE
- if (bitmap.Ok() && bitmap.GetPalette()->Ok())
+ if (bitmap.IsOk() && bitmap.GetPalette()->IsOk())
{
unsigned char red, green, blue;
if (bitmap.GetPalette()->GetRGB(paletteIndex, &red, &green, &blue))
bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
{
#ifndef __WXMICROWIN__
- wxCHECK_MSG( bitmap.Ok(), false, wxT("invalid bitmap in wxMask::Create") );
+ wxCHECK_MSG( bitmap.IsOk(), false, wxT("invalid bitmap in wxMask::Create") );
if ( m_maskBitmap )
{
int hotSpotX,
int hotSpotY)
{
- if ( !bmp.Ok() )
+ if ( !bmp.IsOk() )
{
// we can't create an icon/cursor form nothing
return 0;
if ( bmp.HasAlpha() )
{
+ HBITMAP hbmp;
+
+#if wxUSE_WXDIB && wxUSE_IMAGE
+ // CreateIconIndirect() requires non-pre-multiplied pixel data on input
+ // as it does pre-multiplication internally itself so we need to create
+ // a special DIB in such format to pass to it. This is inefficient but
+ // better than creating an icon with wrong colours.
+ AutoHBITMAP hbmpRelease;
+ hbmp = wxDIB(bmp.ConvertToImage(),
+ wxDIB::PixelFormat_NotPreMultiplied).Detach();
+ hbmpRelease.Init(hbmp);
+#else // !(wxUSE_WXDIB && wxUSE_IMAGE)
+ hbmp = GetHbitmapOf(bmp);
+#endif // wxUSE_WXDIB && wxUSE_IMAGE
+
// Create an empty mask bitmap.
// it doesn't seem to work if we mess with the mask at all.
- HBITMAP hMonoBitmap = CreateBitmap(bmp.GetWidth(),bmp.GetHeight(),1,1,NULL);
+ AutoHBITMAP
+ hMonoBitmap(CreateBitmap(bmp.GetWidth(),bmp.GetHeight(),1,1,NULL));
ICONINFO iconInfo;
wxZeroMemory(iconInfo);
}
iconInfo.hbmMask = hMonoBitmap;
- iconInfo.hbmColor = GetHbitmapOf(bmp);
-
- HICON hicon = ::CreateIconIndirect(&iconInfo);
-
- ::DeleteObject(hMonoBitmap);
+ iconInfo.hbmColor = hbmp;
- return hicon;
+ return ::CreateIconIndirect(&iconInfo);
}
wxMask* mask = bmp.GetMask();
iconInfo.yHotspot = hotSpotY;
}
- iconInfo.hbmMask = wxInvertMask((HBITMAP)mask->GetMaskBitmap());
+ AutoHBITMAP hbmpMask(wxInvertMask((HBITMAP)mask->GetMaskBitmap()));
+ iconInfo.hbmMask = hbmpMask;
iconInfo.hbmColor = GetHbitmapOf(bmp);
// black out the transparent area to preserve background colour, because
delete mask;
}
- // delete the inverted mask bitmap we created as well
- ::DeleteObject(iconInfo.hbmMask);
-
return hicon;
}